blob: a879c1320becf151622c6709d797a56d4748eaca [file] [log] [blame]
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "FreeRTOS.h"
#include "task.h"
#include "chre/core/event_loop_manager.h"
#include "chre/core/host_comms_manager.h"
#include "chre/platform/host_link.h"
#include "chre/platform/log.h"
#include "chre/platform/shared/host_protocol_chre.h"
#include "chre/platform/shared/log_buffer_manager.h"
#include "chre/platform/shared/nanoapp_load_manager.h"
#include "chre/platform/system_time.h"
#include "chre/platform/system_timer.h"
#include "chre/util/flatbuffers/helpers.h"
#include "chre/util/nested_data_ptr.h"
// TODO(b/265046038): MTK headers are not c++ friendly,
// should be modified to wrap function proto with "extern C"
#include "dma_api.h"
#include "ipi.h"
#include "ipi_id.h"
#include "scp_dram_region.h"
// Because the LOGx macros are being redirected to logcat through
// HostLink::sendLogMessageV2 and HostLink::send, calling them from
// inside HostLink impl could result in endless recursion.
// So redefine them to just printf function to SCP console.
#if CHRE_MINIMUM_LOG_LEVEL >= CHRE_LOG_LEVEL_ERROR
#undef LOGE
#define LOGE(fmt, arg...) PRINTF_E("[CHRE]" fmt "\n", ##arg)
#endif
#if CHRE_MINIMUM_LOG_LEVEL >= CHRE_LOG_LEVEL_WARN
#undef LOGW
#define LOGW(fmt, arg...) PRINTF_W("[CHRE]" fmt "\n", ##arg)
#endif
#if CHRE_MINIMUM_LOG_LEVEL >= CHRE_LOG_LEVEL_INFO
#undef LOGI
#define LOGI(fmt, arg...) PRINTF_I("[CHRE]" fmt "\n", ##arg)
#endif
#if CHRE_MINIMUM_LOG_LEVEL >= CHRE_LOG_LEVEL_DEBUG
#undef LOGD
#define LOGD(fmt, arg...) PRINTF_D("[CHRE]" fmt "\n", ##arg)
#endif
#if CHRE_MINIMUM_LOG_LEVEL >= CHRE_LOG_LEVEL_VERBOSE
#undef LOGV
#define LOGV(fmt, arg...) PRINTF_D("[CHRE]" fmt "\n", ##arg)
#endif
namespace chre {
namespace {
struct UnloadNanoappCallbackData {
uint64_t appId;
uint32_t transactionId;
uint16_t hostClientId;
bool allowSystemNanoappUnload;
};
uint32_t gChreIpiRecvData[2];
uint32_t gChreIpiAckToHost[2]; // SCP reply ack data (AP to SCP)
int gChreIpiAckFromHost[2]; // SCP get ack data from AP (SCP to AP)
void *gChreSubregionRecvAddr;
size_t gChreSubregionRecvSize;
void *gChreSubregionSendAddr;
size_t gChreSubregionSendSize;
// TODO(b/263958729): move it to HostLinkBase, and revisit buffer size
// payload buffers
#define CHRE_IPI_RECV_BUFFER_SIZE (CHRE_MESSAGE_TO_HOST_MAX_SIZE + 128)
uint32_t gChreRecvBuffer[CHRE_IPI_RECV_BUFFER_SIZE / sizeof(uint32_t)]
__attribute__((aligned(CACHE_LINE_SIZE)));
#ifdef SCP_CHRE_USE_DMA
static inline uint32_t align(uint32_t target, uint32_t size) {
return (target + size - 1) & ~(size - 1);
}
#endif
#define SCP_CHRE_MAGIC 0x67728269
struct ScpChreIpiMsg {
uint32_t magic;
uint32_t size;
};
struct NanoappListData {
ChreFlatBufferBuilder *builder;
DynamicVector<NanoappListEntryOffset> nanoappEntries;
uint16_t hostClientId;
};
enum class PendingMessageType {
Shutdown,
NanoappMessageToHost,
HubInfoResponse,
NanoappListResponse,
LoadNanoappResponse,
UnloadNanoappResponse,
DebugDumpData,
DebugDumpResponse,
TimeSyncRequest,
LowPowerMicAccessRequest,
LowPowerMicAccessRelease,
EncodedLogMessage,
SelfTestResponse,
MetricLog,
NanConfigurationRequest,
};
struct PendingMessage {
PendingMessage(PendingMessageType msgType, uint16_t hostClientId) {
type = msgType;
data.hostClientId = hostClientId;
}
PendingMessage(PendingMessageType msgType,
const HostMessage *msgToHost = nullptr) {
type = msgType;
data.msgToHost = msgToHost;
}
PendingMessage(PendingMessageType msgType, ChreFlatBufferBuilder *builder) {
type = msgType;
data.builder = builder;
}
PendingMessageType type;
union {
const HostMessage *msgToHost;
uint16_t hostClientId;
ChreFlatBufferBuilder *builder;
} data;
};
constexpr size_t kOutboundQueueSize = 100;
FixedSizeBlockingQueue<PendingMessage, kOutboundQueueSize> gOutboundQueue;
typedef void(MessageBuilderFunction)(ChreFlatBufferBuilder &builder,
void *cookie);
inline HostCommsManager &getHostCommsManager() {
return EventLoopManagerSingleton::get()->getHostCommsManager();
}
bool generateMessageFromBuilder(ChreFlatBufferBuilder *builder) {
CHRE_ASSERT(builder != nullptr);
LOGV("%s: message size %d", __func__, builder->GetSize());
bool result =
HostLinkBase::send(builder->GetBufferPointer(), builder->GetSize());
// clean up
builder->~ChreFlatBufferBuilder();
memoryFree(builder);
return result;
}
bool generateMessageToHost(const HostMessage *message) {
LOGV("%s: message size %zu", __func__, message->message.size());
// TODO(b/263958729): ideally we'd construct our flatbuffer directly in the
// host-supplied buffer
constexpr size_t kFixedReserveSize = 80;
ChreFlatBufferBuilder builder(message->message.size() + kFixedReserveSize);
HostProtocolChre::encodeNanoappMessage(
builder, message->appId, message->toHostData.messageType,
message->toHostData.hostEndpoint, message->message.data(),
message->message.size(), message->toHostData.appPermissions,
message->toHostData.messagePermissions, message->toHostData.wokeHost);
bool result =
HostLinkBase::send(builder.GetBufferPointer(), builder.GetSize());
// clean up
getHostCommsManager().onMessageToHostComplete(message);
return result;
}
int generateHubInfoResponse(uint16_t hostClientId) {
constexpr size_t kInitialBufferSize = 192;
constexpr char kHubName[] = "CHRE on Tinysys";
constexpr char kVendor[] = "Google";
constexpr char kToolchain[] =
"Clang " STRINGIFY(__clang_major__) "." STRINGIFY(
__clang_minor__) "." STRINGIFY(__clang_patchlevel__);
constexpr uint32_t kLegacyPlatformVersion = 0;
constexpr uint32_t kLegacyToolchainVersion =
((__clang_major__ & 0xFF) << 24) | ((__clang_minor__ & 0xFF) << 16) |
(__clang_patchlevel__ & 0xFFFF);
constexpr float kPeakMips = 350;
constexpr float kStoppedPower = 0;
constexpr float kSleepPower = 1;
constexpr float kPeakPower = 15;
// Note that this may execute prior to EventLoopManager::lateInit() completing
ChreFlatBufferBuilder builder(kInitialBufferSize);
HostProtocolChre::encodeHubInfoResponse(
builder, kHubName, kVendor, kToolchain, kLegacyPlatformVersion,
kLegacyToolchainVersion, kPeakMips, kStoppedPower, kSleepPower,
kPeakPower, CHRE_MESSAGE_TO_HOST_MAX_SIZE, chreGetPlatformId(),
chreGetVersion(), hostClientId);
return HostLinkBase::send(builder.GetBufferPointer(), builder.GetSize());
}
bool dequeueMessage(PendingMessage pendingMsg) {
LOGV("%s: message type %d", __func__, pendingMsg.type);
bool result = false;
switch (pendingMsg.type) {
case PendingMessageType::NanoappMessageToHost:
result = generateMessageToHost(pendingMsg.data.msgToHost);
break;
case PendingMessageType::HubInfoResponse:
result = generateHubInfoResponse(pendingMsg.data.hostClientId);
break;
case PendingMessageType::NanoappListResponse:
case PendingMessageType::LoadNanoappResponse:
case PendingMessageType::UnloadNanoappResponse:
case PendingMessageType::DebugDumpData:
case PendingMessageType::DebugDumpResponse:
case PendingMessageType::TimeSyncRequest:
case PendingMessageType::LowPowerMicAccessRequest:
case PendingMessageType::LowPowerMicAccessRelease:
case PendingMessageType::EncodedLogMessage:
case PendingMessageType::SelfTestResponse:
case PendingMessageType::MetricLog:
case PendingMessageType::NanConfigurationRequest:
result = generateMessageFromBuilder(pendingMsg.data.builder);
break;
default:
CHRE_ASSERT_LOG(false, "Unexpected pending message type");
}
return result;
}
/**
* Wrapper function to enqueue a message on the outbound message queue. All
* outgoing message to the host must be called through this function.
*
* @param message The message to send to host.
*
* @return true if the message was successfully added to the queue.
*/
bool enqueueMessage(PendingMessage pendingMsg) {
return gOutboundQueue.push(pendingMsg);
}
/**
* Helper function that takes care of the boilerplate for allocating a
* ChreFlatBufferBuilder on the heap and adding it to the outbound message
* queue.
*
* @param msgType Identifies the message while in the outbound queue
* @param initialBufferSize Number of bytes to reserve when first allocating the
* ChreFlatBufferBuilder
* @param buildMsgFunc Synchronous callback used to encode the FlatBuffer
* message. Will not be invoked if allocation fails.
* @param cookie Opaque pointer that will be passed through to buildMsgFunc
*
* @return true if the message was successfully added to the queue
*/
bool buildAndEnqueueMessage(PendingMessageType msgType,
size_t initialBufferSize,
MessageBuilderFunction *msgBuilder, void *cookie) {
LOGV("%s: message type %d, size %zu", __func__, msgType, initialBufferSize);
bool pushed = false;
auto builder = MakeUnique<ChreFlatBufferBuilder>(initialBufferSize);
if (builder.isNull()) {
LOGE("Couldn't allocate memory for message type %d",
static_cast<int>(msgType));
} else {
msgBuilder(*builder, cookie);
// TODO(b/263958729): if this fails, ideally we should block for some
// timeout until there's space in the queue
if (!enqueueMessage(PendingMessage(msgType, builder.get()))) {
LOGE("Couldn't push message type %d to outbound queue",
static_cast<int>(msgType));
} else {
builder.release();
pushed = true;
}
}
return pushed;
}
/**
* FlatBuffer message builder callback used with handleNanoappListRequest()
*/
void buildNanoappListResponse(ChreFlatBufferBuilder &builder, void *cookie) {
LOGV("%s", __func__);
auto nanoappAdderCallback = [](const Nanoapp *nanoapp, void *data) {
auto *cbData = static_cast<NanoappListData *>(data);
HostProtocolChre::addNanoappListEntry(
*(cbData->builder), cbData->nanoappEntries, nanoapp->getAppId(),
nanoapp->getAppVersion(), true /*enabled*/, nanoapp->isSystemNanoapp(),
nanoapp->getAppPermissions(), nanoapp->getRpcServices());
};
// Add a NanoappListEntry to the FlatBuffer for each nanoapp
auto *cbData = static_cast<NanoappListData *>(cookie);
cbData->builder = &builder;
EventLoop &eventLoop = EventLoopManagerSingleton::get()->getEventLoop();
eventLoop.forEachNanoapp(nanoappAdderCallback, cbData);
HostProtocolChre::finishNanoappListResponse(builder, cbData->nanoappEntries,
cbData->hostClientId);
}
void handleUnloadNanoappCallback(uint16_t /*type*/, void *data,
void * /*extraData*/) {
auto *cbData = static_cast<UnloadNanoappCallbackData *>(data);
bool success = false;
uint16_t instanceId;
EventLoop &eventLoop = EventLoopManagerSingleton::get()->getEventLoop();
if (!eventLoop.findNanoappInstanceIdByAppId(cbData->appId, &instanceId)) {
LOGE("Couldn't unload app ID 0x%016" PRIx64 ": not found", cbData->appId);
} else {
success =
eventLoop.unloadNanoapp(instanceId, cbData->allowSystemNanoappUnload);
}
constexpr size_t kInitialBufferSize = 52;
auto builder = MakeUnique<ChreFlatBufferBuilder>(kInitialBufferSize);
HostProtocolChre::encodeUnloadNanoappResponse(*builder, cbData->hostClientId,
cbData->transactionId, success);
if (!enqueueMessage(PendingMessage(PendingMessageType::UnloadNanoappResponse,
builder.get()))) {
LOGE("Failed to send unload response to host: %x transactionID: 0x%x",
cbData->hostClientId, cbData->transactionId);
} else {
builder.release();
}
memoryFree(data);
}
} // anonymous namespace
void sendDebugDumpResultToHost(uint16_t hostClientId, const char * /*debugStr*/,
size_t /*debugStrSize*/, bool /*complete*/,
uint32_t /*dataCount*/) {
LOGV("%s: host client id %d", __func__, hostClientId);
// TODO(b/263958729): Implement this.
}
HostLinkBase::HostLinkBase() {
LOGV("HostLinkBase::%s", __func__);
initializeIpi();
}
HostLinkBase::~HostLinkBase() {
LOGV("HostLinkBase::%s", __func__);
}
void HostLinkBase::vChreReceiveTask(void *pvParameters) {
int i = 0;
int ret = 0;
LOGV("%s", __func__);
while (true) {
LOGV("%s calling ipi_recv_reply(), Cnt=%d", __func__, i++);
ret = ipi_recv_reply(IPI_IN_C_HOST_SCP_CHRE, (void *)&gChreIpiAckToHost[0],
1);
if (ret != IPI_ACTION_DONE)
LOGE("%s ipi_recv_reply() ret = %d", __func__, ret);
LOGV("%s reply_end", __func__);
}
}
void HostLinkBase::vChreSendTask(void *pvParameters) {
while (true) {
auto msg = gOutboundQueue.pop();
dequeueMessage(msg);
}
}
void HostLinkBase::chreIpiHandler(unsigned int id, void *prdata, void *data,
unsigned int len) {
/* receive magic and cmd */
struct ScpChreIpiMsg msg = *(struct ScpChreIpiMsg *)data;
// check the magic number and payload size need to be copy(if need) */
LOGV("%s: msg.magic=0x%x, msg.size=%u", __func__, msg.magic, msg.size);
if (msg.magic != SCP_CHRE_MAGIC) {
LOGE("Invalid magic number, skip message");
gChreIpiAckToHost[0] = IPI_NO_MEMORY;
gChreIpiAckToHost[1] = 0;
return;
}
// Mapping the physical address of share memory for SCP
uint32_t srcAddr =
ap_to_scp(reinterpret_cast<uint32_t>(gChreSubregionRecvAddr));
#ifdef SCP_CHRE_USE_DMA
// Using SCP DMA HW to copy the data from share memory to SCP side, ex:
// gChreRecvBuffer gChreRecvBuffer could be a global variables or a SCP heap
// memory at SRAM/DRAM
scp_dma_transaction_dram(reinterpret_cast<uint32_t>(&gChreRecvBuffer[0]),
srcAddr, msg.size, DMA_MEM_ID, NO_RESERVED);
// Invalid cache to update the newest data before using
mrv_dcache_invalid_multi_addr(reinterpret_cast<uint32_t>(&gChreRecvBuffer[0]),
align(msg.size, CACHE_LINE_SIZE));
#else
memcpy(static_cast<void *>(gChreRecvBuffer),
reinterpret_cast<void *>(srcAddr), msg.size);
#endif
// process the message
LOGV("chre_rcvbuf: 0x%x 0x%x 0x%x 0x%x", gChreRecvBuffer[0],
gChreRecvBuffer[1], gChreRecvBuffer[2], gChreRecvBuffer[3]);
receive(static_cast<HostLinkBase *>(prdata), gChreRecvBuffer, msg.size);
// After finishing the job, akc the message to host
gChreIpiAckToHost[0] = IPI_ACTION_DONE;
gChreIpiAckToHost[1] = msg.size;
}
void HostLinkBase::initializeIpi(void) {
LOGV("%s", __func__);
bool success = false;
int ret;
constexpr size_t kBackgroundTaskStackSize = 1024;
constexpr UBaseType_t kBackgroundTaskPriority = 2;
// prepared share memory information and register the callback functions
if (!(ret = scp_get_reserve_mem_by_id(SCP_CHRE_FROM_MEM_ID,
&gChreSubregionRecvAddr,
&gChreSubregionRecvSize))) {
LOGE("%s: get SCP_CHRE_FROM_MEM_ID memory fail", __func__);
} else if (!(ret = scp_get_reserve_mem_by_id(SCP_CHRE_TO_MEM_ID,
&gChreSubregionSendAddr,
&gChreSubregionSendSize))) {
LOGE("%s: get SCP_CHRE_TO_MEM_ID memory fail", __func__);
} else if (pdPASS != xTaskCreate(vChreReceiveTask, "CHRE_RECEIVE",
kBackgroundTaskStackSize, (void *)0,
kBackgroundTaskPriority, NULL)) {
LOGE("%s failed to create ipi receiver task", __func__);
} else if (pdPASS != xTaskCreate(vChreSendTask, "CHRE_SEND",
kBackgroundTaskStackSize, (void *)0,
kBackgroundTaskPriority, NULL)) {
LOGE("%s failed to create ipi outbound message queue task", __func__);
} else if (IPI_ACTION_DONE !=
(ret = ipi_register(IPI_IN_C_HOST_SCP_CHRE, (void *)chreIpiHandler,
(void *)this, (void *)&gChreIpiRecvData[0]))) {
LOGE("ipi_register IPI_IN_C_HOST_SCP_CHRE failed, %d", ret);
} else if (IPI_ACTION_DONE !=
(ret = ipi_register(IPI_OUT_C_SCP_HOST_CHRE, NULL, (void *)this,
(void *)&gChreIpiAckFromHost[0]))) {
LOGE("ipi_register IPI_OUT_C_SCP_HOST_CHRE failed, %d", ret);
} else {
success = true;
}
if (!success) {
FATAL_ERROR("HostLinkBase::initializeIpi() failed");
}
}
void HostLinkBase::receive(HostLinkBase *instance, void *message,
int messageLen) {
LOGV("%s: message len %d", __func__, messageLen);
// TODO(b/263958729): A crude way to initially determine daemon's up - set
// a flag on the first message received. This is temporary until a better
// way to do this is available.
instance->setInitialized(true);
if (!HostProtocolChre::decodeMessageFromHost(message, messageLen)) {
LOGE("Failed to decode msg %p of len %u", message, messageLen);
}
}
bool HostLinkBase::send(uint8_t *data, size_t dataLen) {
#ifndef HOST_LINK_IPI_SEND_TIMEOUT_MS
#define HOST_LINK_IPI_SEND_TIMEOUT_MS 100
#endif
#ifndef HOST_LINK_IPI_RESPONSE_TIMEOUT_MS
#define HOST_LINK_IPI_RESPONSE_TIMEOUT_MS 100
#endif
LOGV("HostLinkBase::%s: %zu, %p", __func__, dataLen, data);
struct ScpChreIpiMsg msg;
msg.magic = SCP_CHRE_MAGIC;
msg.size = dataLen;
// Mapping the physical address of share memory for SCP
void *dstAddr = reinterpret_cast<void *>(
ap_to_scp(reinterpret_cast<uint32_t>(gChreSubregionSendAddr)));
#ifdef SCP_CHRE_USE_DMA
// TODO(b/263958729): use DMA for larger payload
// No need cache operation, because src_dst handled by SCP CPU and dstAddr is
// non-cacheable
#else
memcpy(dstAddr, data, dataLen);
#endif
// NB: len param for ipi_send is in number of 32-bit words
int ret = ipi_send_compl(
IPI_OUT_C_SCP_HOST_CHRE, &msg, sizeof(msg) / sizeof(uint32_t),
HOST_LINK_IPI_SEND_TIMEOUT_MS, HOST_LINK_IPI_RESPONSE_TIMEOUT_MS);
if (ret) {
LOGE("chre ipi send fail(%d)", ret);
} else {
/* check ack data for make sure IPI wasn't busy */
LOGV("chre ipi send, check ack data: 0x%x", gChreIpiAckFromHost[0]);
if (gChreIpiAckFromHost[0] == IPI_ACTION_DONE) {
LOGV("chre ipi send done, you can send another IPI");
} else if (gChreIpiAckFromHost[0] == IPI_PIN_BUSY) {
/* you may have to re-send the IPI, or drop this one */
LOGV(
"chre ipi send busy, user thread has not wait the IPI until job "
"finished");
} else if (gChreIpiAckFromHost[0] == IPI_NO_MEMORY) {
LOGV("chre ipi send with wrong size(%zu)", dataLen);
} else {
LOGV("chre ipi send unknown case");
}
}
return ret == IPI_ACTION_DONE;
}
void HostLinkBase::sendTimeSyncRequest() {
LOGV("%s", __func__);
// TODO(b/263958729): Implement this.
}
void HostLinkBase::sendLogMessageV2(const uint8_t *logMessage,
size_t logMessageSize,
uint32_t numLogsDropped) {
LOGV("%s: size %zu", __func__, logMessageSize);
struct LogMessageData {
const uint8_t *logMsg;
size_t logMsgSize;
uint32_t numLogsDropped;
};
LogMessageData logMessageData{logMessage, logMessageSize, numLogsDropped};
auto msgBuilder = [](ChreFlatBufferBuilder &builder, void *cookie) {
const auto *data = static_cast<const LogMessageData *>(cookie);
HostProtocolChre::encodeLogMessagesV2(
builder, data->logMsg, data->logMsgSize, data->numLogsDropped);
};
constexpr size_t kInitialSize = 128;
bool result = false;
if (isInitialized()) {
result = buildAndEnqueueMessage(
PendingMessageType::EncodedLogMessage,
kInitialSize + logMessageSize + sizeof(numLogsDropped), msgBuilder,
&logMessageData);
}
#ifdef CHRE_USE_BUFFERED_LOGGING
if (LogBufferManagerSingleton::isInitialized()) {
LogBufferManagerSingleton::get()->onLogsSentToHost(result);
}
#else
UNUSED_VAR(result);
#endif
}
bool HostLink::sendMessage(HostMessage const *message) {
LOGV("HostLink::%s size(%zu)", __func__, message->message.size());
bool success = false;
if (isInitialized()) {
success = enqueueMessage(
PendingMessage(PendingMessageType::NanoappMessageToHost, message));
} else {
LOGW("Dropping outbound message: host link not initialized yet");
}
return success;
}
// TODO(b/263958729): HostMessageHandlers member function implementations are
// expected to be (mostly) identical for any platform that uses flatbuffers
// to encode messages - refactor the host link to merge the multiple copies
// we currently have.
void HostMessageHandlers::handleNanoappMessage(uint64_t appId,
uint32_t messageType,
uint16_t hostEndpoint,
const void *messageData,
size_t messageDataLen) {
LOGV("Parsed nanoapp message from host: app ID 0x%016" PRIx64
", endpoint "
"0x%" PRIx16 ", msgType %" PRIu32 ", payload size %zu",
appId, hostEndpoint, messageType, messageDataLen);
// TODO(b/263958729): Implement this.
getHostCommsManager().sendMessageToNanoappFromHost(
appId, messageType, hostEndpoint, messageData, messageDataLen);
}
void HostMessageHandlers::handleHubInfoRequest(uint16_t hostClientId) {
LOGV("%s: host client id %d", __func__, hostClientId);
enqueueMessage(
PendingMessage(PendingMessageType::HubInfoResponse, hostClientId));
}
void HostMessageHandlers::handleNanoappListRequest(uint16_t hostClientId) {
auto callback = [](uint16_t /*type*/, void *data, void * /*extraData*/) {
uint16_t cbHostClientId = NestedDataPtr<uint16_t>(data);
NanoappListData cbData = {};
cbData.hostClientId = cbHostClientId;
size_t expectedNanoappCount =
EventLoopManagerSingleton::get()->getEventLoop().getNanoappCount();
if (!cbData.nanoappEntries.reserve(expectedNanoappCount)) {
LOG_OOM();
} else {
constexpr size_t kFixedOverhead = 48;
constexpr size_t kPerNanoappSize = 32;
size_t initialBufferSize =
(kFixedOverhead + expectedNanoappCount * kPerNanoappSize);
buildAndEnqueueMessage(PendingMessageType::NanoappListResponse,
initialBufferSize, buildNanoappListResponse,
&cbData);
}
};
LOGD("Nanoapp list request from client ID %" PRIu16, hostClientId);
EventLoopManagerSingleton::get()->deferCallback(
SystemCallbackType::NanoappListResponse,
NestedDataPtr<uint16_t>(hostClientId), callback);
}
void HostMessageHandlers::sendFragmentResponse(uint16_t hostClientId,
uint32_t transactionId,
uint32_t fragmentId,
bool success) {
struct FragmentedLoadInfoResponse {
uint16_t hostClientId;
uint32_t transactionId;
uint32_t fragmentId;
bool success;
};
auto msgBuilder = [](ChreFlatBufferBuilder &builder, void *cookie) {
auto *cbData = static_cast<FragmentedLoadInfoResponse *>(cookie);
HostProtocolChre::encodeLoadNanoappResponse(
builder, cbData->hostClientId, cbData->transactionId, cbData->success,
cbData->fragmentId);
};
FragmentedLoadInfoResponse response = {
.hostClientId = hostClientId,
.transactionId = transactionId,
.fragmentId = fragmentId,
.success = success,
};
constexpr size_t kInitialBufferSize = 52;
buildAndEnqueueMessage(PendingMessageType::LoadNanoappResponse,
kInitialBufferSize, msgBuilder, &response);
}
void HostMessageHandlers::handleLoadNanoappRequest(
uint16_t hostClientId, uint32_t transactionId, uint64_t appId,
uint32_t appVersion, uint32_t appFlags, uint32_t targetApiVersion,
const void *buffer, size_t bufferLen, const char *appFileName,
uint32_t fragmentId, size_t appBinaryLen, bool respondBeforeStart) {
UNUSED_VAR(appFileName);
loadNanoappData(hostClientId, transactionId, appId, appVersion, appFlags,
targetApiVersion, buffer, bufferLen, fragmentId, appBinaryLen,
respondBeforeStart);
}
void HostMessageHandlers::handleUnloadNanoappRequest(
uint16_t hostClientId, uint32_t transactionId, uint64_t appId,
bool allowSystemNanoappUnload) {
LOGD("Unload nanoapp request from client %" PRIu16 " (txnID %" PRIu32
") for appId 0x%016" PRIx64 " system %d",
hostClientId, transactionId, appId, allowSystemNanoappUnload);
auto *cbData = memoryAlloc<UnloadNanoappCallbackData>();
if (cbData == nullptr) {
LOG_OOM();
} else {
cbData->appId = appId;
cbData->transactionId = transactionId;
cbData->hostClientId = hostClientId;
cbData->allowSystemNanoappUnload = allowSystemNanoappUnload;
EventLoopManagerSingleton::get()->deferCallback(
SystemCallbackType::HandleUnloadNanoapp, cbData,
handleUnloadNanoappCallback);
}
}
void HostLink::flushMessagesSentByNanoapp(uint64_t /* appId */) {
// Not implemented
}
void HostMessageHandlers::handleTimeSyncMessage(int64_t offset) {
LOGE("%s unsupported.", __func__);
}
void HostMessageHandlers::handleDebugDumpRequest(uint16_t hostClientId) {
LOGV("%s: host client id %d", __func__, hostClientId);
// TODO(b/263958729): Implement this.
}
void HostMessageHandlers::handleSettingChangeMessage(fbs::Setting setting,
fbs::SettingState state) {
// TODO(b/267207477): Refactor handleSettingChangeMessage to shared code
Setting chreSetting;
bool chreSettingEnabled;
if (HostProtocolChre::getSettingFromFbs(setting, &chreSetting) &&
HostProtocolChre::getSettingEnabledFromFbs(state, &chreSettingEnabled)) {
EventLoopManagerSingleton::get()->getSettingManager().postSettingChange(
chreSetting, chreSettingEnabled);
}
}
void HostMessageHandlers::handleSelfTestRequest(uint16_t hostClientId) {
LOGV("%s: host client id %d", __func__, hostClientId);
// TODO(b/263958729): Implement this.
}
void HostMessageHandlers::handleNanConfigurationUpdate(bool /* enabled */) {
LOGE("%s NAN unsupported.", __func__);
}
void sendAudioRequest() {
auto msgBuilder = [](ChreFlatBufferBuilder &builder, void * /*cookie*/) {
HostProtocolChre::encodeLowPowerMicAccessRequest(builder);
};
constexpr size_t kInitialSize = 32;
buildAndEnqueueMessage(PendingMessageType::LowPowerMicAccessRequest,
kInitialSize, msgBuilder, /* cookie= */ nullptr);
}
void sendAudioRelease() {
auto msgBuilder = [](ChreFlatBufferBuilder &builder, void * /*cookie*/) {
HostProtocolChre::encodeLowPowerMicAccessRelease(builder);
};
constexpr size_t kInitialSize = 32;
buildAndEnqueueMessage(PendingMessageType::LowPowerMicAccessRelease,
kInitialSize, msgBuilder, /* cookie= */ nullptr);
}
} // namespace chre