Files
2026-08-24 10:03:24 +08:00

183 lines
7.3 KiB
C++

/*
* Copyright (C) 2014-2026 Amlogic, Inc. All rights reserved.
*
* All information contained herein is Amlogic confidential.
*
* This software is provided to you pursuant to Software License Agreement
* (SLA) with Amlogic Inc ("Amlogic"). This software may be used
* only in accordance with the terms of this agreement.
*
* Redistribution and use in source and binary forms, with or without
* modification is strictly prohibited without prior written permission from
* Amlogic.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define LOG_TAG "FmqReceiver"
#include "FmqReceiver.h"
#include <utils/CallStack.h>
#include "ringbuffer.h"
using ::android::CallStack;
static inline void dumpBuffer(const char *buf, int size) {
char str[64] = {0};
for (int i = 0; i < size; i++) {
char chars[6] = {0};
sprintf(chars, "%02x ", buf[i]);
strcat(str, chars);
if (i % 8 == 7) {
SUBTITLE_LOGI("%s", str);
str[0] = str[1] = 0;
}
}
SUBTITLE_LOGI("%s", str);
}
FmqReceiver::FmqReceiver(std::unique_ptr<FmqReader> reader) {
mStop = false;
mReader = std::move(reader);
SUBTITLE_LOGI("enter: mReader=%p", mReader.get());
mReaderThread = std::thread(&FmqReceiver::readLoop, this);
}
FmqReceiver::~FmqReceiver() {
SUBTITLE_LOGI_FUNC_IN();
mStop = true;
mReaderThread.join();
SUBTITLE_LOGI_FUNC_OUT();
}
bool FmqReceiver::readLoop() {
SUBTITLE_LOGI_FUNC_IN();
IpcPackageHeader curHeader;
rbuf_handle_t bufferHandle = ringbuffer_create(1024 * 1024, "fmqbuffer");
if (bufferHandle == nullptr) {
SUBTITLE_LOGE("fail to create ring buffer");
return false;
}
while (!mStop) {
if (mClients.size() <= 0) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
// no consumer attached, avoid lost message, wait here
continue;
}
if (mReader != nullptr) {
size_t available = mReader->availableSize();
if (available > 0) {
char *recvBuf = (char *)malloc(available);
if (recvBuf == nullptr) {
SUBTITLE_LOGE("malloc error = %m");
continue;
}
size_t read = mReader->read((uint8_t *)recvBuf, available);
if (read <= 0) {
usleep(1000);
free(recvBuf);
continue;
}
// SUBTITLE_LOGI("read: available %d size: %d", available, read);
ringbuffer_write(bufferHandle, recvBuf, read, RBUF_MODE_BLOCK);
free(recvBuf);
} else {
usleep(1000);
}
// TODO coverity no 94:q
// consume all data.
while (!mStop && (ringbuffer_read_avail(bufferHandle) >
static_cast<int>(sizeof(IpcPackageHeader)))) {
char buffer[sizeof(IpcPackageHeader)];
uint32_t size = ringbuffer_peek(bufferHandle, buffer, sizeof(IpcPackageHeader),
RBUF_MODE_BLOCK);
if (size < sizeof(IpcPackageHeader)) {
SUBTITLE_LOGE("wrong read size: %d, request %zu", size,
sizeof(IpcPackageHeader));
}
if (peekAsSocketWord(buffer) != START_FLAG &&
peekAsSocketWord(buffer + 8) != MAGIC_FLAG) {
SUBTITLE_LOGE("wrong Sync header found: %x %x", peekAsSocketWord(buffer),
peekAsSocketWord(buffer + 8));
ringbuffer_read(bufferHandle, buffer, 4, RBUF_MODE_BLOCK);
continue; // ignore and try next.
}
curHeader.syncWord = peekAsSocketWord(buffer);
curHeader.sessionId = peekAsSocketWord(buffer + 4);
curHeader.magicWord = peekAsSocketWord(buffer + 8); // need check magic or not??
curHeader.dataSize = peekAsSocketWord(buffer + 12);
curHeader.pkgType = peekAsSocketWord(buffer + 16);
// SUBTITLE_LOGI("data: syncWord:%x session:%x magic:%x subType:%x size:%x",
// curHeader.syncWord, curHeader.sessionId, curHeader.magicWord,
// curHeader.pkgType, curHeader.dataSize);
if (ringbuffer_read_avail(bufferHandle) <
static_cast<int>(sizeof(IpcPackageHeader) + curHeader.dataSize)) {
SUBTITLE_LOGE("not enough data, try next...");
break; // not enough data. try next
}
// eat the header
ringbuffer_read(bufferHandle, buffer, sizeof(IpcPackageHeader), RBUF_MODE_BLOCK);
char *payloads = (char *)malloc(curHeader.dataSize + 4);
if (!payloads) {
SUBTITLE_LOGE("fail to malloc payloads: %m");
continue;
}
memcpy(payloads, &curHeader.pkgType, 4); // fill package type
ringbuffer_read(bufferHandle, payloads + 4, curHeader.dataSize, RBUF_MODE_BLOCK);
{ // notify listener
std::lock_guard<std::mutex> guard(mLock);
if (mClients.size() > 0) {
auto listener = mClients.front();
if (listener != nullptr) {
if (listener->onData(payloads, curHeader.dataSize + 4) < 0) {
// For some ext and internal sub switch, if here return, then ext
// sub(now this no data) switch to internal will no sub. so not
// return.
SUBTITLE_LOGE("no need free buffer handle, need wait stop now!");
}
}
}
}
free(payloads);
}
}
}
ringbuffer_free(bufferHandle);
SUBTITLE_LOGI_FUNC_OUT();
return true;
}
void FmqReceiver::dump(int fd, const char *prefix) {
dprintf(fd, "%s FastMessageQueue Receiver:\n", prefix);
{
std::unique_lock<std::mutex> autolock(mLock);
for (auto it = mClients.begin(); it != mClients.end(); it++) {
auto lstn = (*it);
if (lstn != nullptr) dprintf(fd, "%s InfoListener: %p\n", prefix, lstn.get());
}
}
dprintf(fd, "%s mStop: %d\n", prefix, mStop);
dprintf(fd, "%s mReader: %p\n", prefix, mReader.get());
}