/* * 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 #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 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(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(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 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 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()); }