Home | History | Annotate | Download | only in slpi
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "ash/debug.h"
     18 #include "qurt.h"
     19 
     20 #include "chre/core/event_loop_manager.h"
     21 #include "chre/core/host_comms_manager.h"
     22 #include "chre/platform/memory.h"
     23 #include "chre/platform/log.h"
     24 #include "chre/platform/system_time.h"
     25 #include "chre/platform/shared/host_protocol_chre.h"
     26 #include "chre/platform/shared/platform_log.h"
     27 #include "chre/platform/slpi/fastrpc.h"
     28 #include "chre/platform/slpi/power_control_util.h"
     29 #include "chre/platform/slpi/system_time.h"
     30 #include "chre/util/fixed_size_blocking_queue.h"
     31 #include "chre/util/macros.h"
     32 #include "chre/util/unique_ptr.h"
     33 #include "chre_api/chre/version.h"
     34 
     35 #include <inttypes.h>
     36 #include <limits.h>
     37 
     38 using flatbuffers::FlatBufferBuilder;
     39 
     40 namespace chre {
     41 
     42 namespace {
     43 
     44 constexpr size_t kOutboundQueueSize = 32;
     45 
     46 //! Used to pass the client ID through the user data pointer in deferCallback
     47 union HostClientIdCallbackData {
     48   uint16_t hostClientId;
     49   void *ptr;
     50 };
     51 static_assert(sizeof(uint16_t) <= sizeof(void*),
     52               "Pointer must at least fit a u16 for passing the host client ID");
     53 
     54 struct LoadNanoappCallbackData {
     55   uint64_t appId;
     56   uint32_t transactionId;
     57   uint16_t hostClientId;
     58   UniquePtr<Nanoapp> nanoapp = MakeUnique<Nanoapp>();
     59 };
     60 
     61 struct NanoappListData {
     62   FlatBufferBuilder *builder;
     63   DynamicVector<NanoappListEntryOffset> nanoappEntries;
     64   uint16_t hostClientId;
     65 };
     66 
     67 enum class PendingMessageType {
     68   Shutdown,
     69   NanoappMessageToHost,
     70   LogMessage,
     71   HubInfoResponse,
     72   NanoappListResponse,
     73   LoadNanoappResponse,
     74   UnloadNanoappResponse,
     75   DebugDumpData,
     76   DebugDumpResponse,
     77   TimeSyncRequest,
     78 };
     79 
     80 struct PendingMessage {
     81   PendingMessage(PendingMessageType msgType, uint16_t hostClientId) {
     82     type = msgType;
     83     data.hostClientId = hostClientId;
     84   }
     85 
     86   PendingMessage(PendingMessageType msgType,
     87                  const MessageToHost *msgToHost = nullptr) {
     88     type = msgType;
     89     data.msgToHost = msgToHost;
     90   }
     91 
     92   PendingMessage(PendingMessageType msgType, FlatBufferBuilder *builder) {
     93     type = msgType;
     94     data.builder = builder;
     95   }
     96 
     97   PendingMessageType type;
     98   union {
     99     const MessageToHost *msgToHost;
    100     uint16_t hostClientId;
    101     FlatBufferBuilder *builder;
    102   } data;
    103 };
    104 
    105 struct UnloadNanoappCallbackData {
    106   uint64_t appId;
    107   uint32_t transactionId;
    108   uint16_t hostClientId;
    109   bool allowSystemNanoappUnload;
    110 };
    111 
    112 struct DebugDumpCallbackData {
    113   uint32_t dataCount;
    114   uint16_t hostClientId;
    115   bool success;
    116 };
    117 
    118 /**
    119  * @see buildAndEnqueueMessage()
    120  */
    121 typedef void (MessageBuilderFunction)(FlatBufferBuilder& builder, void *cookie);
    122 
    123 FixedSizeBlockingQueue<PendingMessage, kOutboundQueueSize>
    124     gOutboundQueue;
    125 
    126 int copyToHostBuffer(const FlatBufferBuilder& builder, unsigned char *buffer,
    127                      size_t bufferSize, unsigned int *messageLen) {
    128   uint8_t *data = builder.GetBufferPointer();
    129   size_t size = builder.GetSize();
    130   int result;
    131 
    132   if (size > bufferSize) {
    133     LOGE("Encoded structure size %zu too big for host buffer %zu; dropping",
    134          size, bufferSize);
    135     result = CHRE_FASTRPC_ERROR;
    136   } else {
    137     memcpy(buffer, data, size);
    138     *messageLen = size;
    139     result = CHRE_FASTRPC_SUCCESS;
    140   }
    141 
    142   return result;
    143 }
    144 
    145 /**
    146  * Wrapper function to enqueue a message on the outbound message queue. All
    147  * outgoing message to the host must be called through this function.
    148  *
    149  * @param message The message to send to host.
    150  *
    151  * @return true if the message was successfully added to the queue.
    152  */
    153 bool enqueueMessage(PendingMessage message) {
    154   // Vote for big image temporarily when waking up the main thread waiting for
    155   // the message
    156   bool voteSuccess = slpiForceBigImage();
    157   bool success = gOutboundQueue.push(message);
    158 
    159   // Remove the vote only if we successfully made a big image transition
    160   if (voteSuccess) {
    161     slpiRemoveBigImageVote();
    162   }
    163 
    164   return success;
    165 }
    166 
    167 /**
    168  * Helper function that takes care of the boilerplate for allocating a
    169  * FlatBufferBuilder on the heap and adding it to the outbound message queue.
    170  *
    171  * @param msgType Identifies the message while in the outboud queue
    172  * @param initialBufferSize Number of bytes to reserve when first allocating the
    173  *        FlatBufferBuilder
    174  * @param buildMsgFunc Synchronous callback used to encode the FlatBuffer
    175  *        message. Will not be invoked if allocation fails.
    176  * @param cookie Opaque pointer that will be passed through to buildMsgFunc
    177  *
    178  * @return true if the message was successfully added to the queue
    179  */
    180 bool buildAndEnqueueMessage(PendingMessageType msgType,
    181                             size_t initialBufferSize,
    182                             MessageBuilderFunction *msgBuilder,
    183                             void *cookie) {
    184   bool pushed = false;
    185 
    186   auto builder = MakeUnique<FlatBufferBuilder>(initialBufferSize);
    187   if (builder.isNull()) {
    188     LOGE("Couldn't allocate memory for message type %d",
    189          static_cast<int>(msgType));
    190   } else {
    191     msgBuilder(*builder, cookie);
    192 
    193     // TODO: if this fails, ideally we should block for some timeout until
    194     // there's space in the queue
    195     if (!enqueueMessage(PendingMessage(msgType, builder.get()))) {
    196       LOGE("Couldn't push message type %d to outbound queue",
    197            static_cast<int>(msgType));
    198     } else {
    199       builder.release();
    200       pushed = true;
    201     }
    202   }
    203 
    204   return pushed;
    205 }
    206 
    207 /**
    208  * FlatBuffer message builder callback used with constructNanoappListCallback()
    209  */
    210 void buildNanoappListResponse(FlatBufferBuilder& builder, void *cookie) {
    211   auto nanoappAdderCallback = [](const Nanoapp *nanoapp, void *data) {
    212     auto *cbData = static_cast<NanoappListData *>(data);
    213     HostProtocolChre::addNanoappListEntry(
    214         *(cbData->builder), cbData->nanoappEntries, nanoapp->getAppId(),
    215         nanoapp->getAppVersion(), true /*enabled*/,
    216         nanoapp->isSystemNanoapp());
    217   };
    218 
    219   // Add a NanoappListEntry to the FlatBuffer for each nanoapp
    220   auto *cbData = static_cast<NanoappListData *>(cookie);
    221   cbData->builder = &builder;
    222   EventLoop& eventLoop = EventLoopManagerSingleton::get()->getEventLoop();
    223   eventLoop.forEachNanoapp(nanoappAdderCallback, cbData);
    224   HostProtocolChre::finishNanoappListResponse(
    225       builder, cbData->nanoappEntries, cbData->hostClientId);
    226 }
    227 
    228 void constructNanoappListCallback(uint16_t /*eventType*/, void *deferCbData) {
    229   HostClientIdCallbackData clientIdCbData;
    230   clientIdCbData.ptr = deferCbData;
    231 
    232   NanoappListData cbData = {};
    233   cbData.hostClientId = clientIdCbData.hostClientId;
    234 
    235   const EventLoop& eventLoop = EventLoopManagerSingleton::get()->getEventLoop();
    236   size_t expectedNanoappCount = eventLoop.getNanoappCount();
    237   if (!cbData.nanoappEntries.reserve(expectedNanoappCount)) {
    238     LOGE("Couldn't reserve space for list of nanoapp offsets");
    239   } else {
    240     constexpr size_t kFixedOverhead  = 48;
    241     constexpr size_t kPerNanoappSize = 32;
    242     size_t initialBufferSize =
    243         (kFixedOverhead + expectedNanoappCount * kPerNanoappSize);
    244 
    245     buildAndEnqueueMessage(PendingMessageType::NanoappListResponse,
    246                            initialBufferSize, buildNanoappListResponse,
    247                            &cbData);
    248   }
    249 }
    250 
    251 void finishLoadingNanoappCallback(uint16_t /*eventType*/, void *data) {
    252   auto msgBuilder = [](FlatBufferBuilder& builder, void *cookie) {
    253     auto *cbData = static_cast<LoadNanoappCallbackData *>(cookie);
    254     EventLoop& eventLoop = EventLoopManagerSingleton::get()->getEventLoop();
    255     bool startedSuccessfully = (cbData->nanoapp->isLoaded()) ?
    256         eventLoop.startNanoapp(cbData->nanoapp) : false;
    257 
    258     HostProtocolChre::encodeLoadNanoappResponse(
    259         builder, cbData->hostClientId, cbData->transactionId,
    260         startedSuccessfully);
    261   };
    262 
    263   // Re-wrap the callback data struct, so it is destructed and freed, ensuring
    264   // we don't leak the embedded UniquePtr<Nanoapp>
    265   UniquePtr<LoadNanoappCallbackData> dataWrapped(
    266       static_cast<LoadNanoappCallbackData *>(data));
    267   constexpr size_t kInitialBufferSize = 48;
    268   buildAndEnqueueMessage(PendingMessageType::LoadNanoappResponse,
    269                          kInitialBufferSize, msgBuilder, data);
    270 }
    271 
    272 void handleUnloadNanoappCallback(uint16_t /*eventType*/, void *data) {
    273   auto msgBuilder = [](FlatBufferBuilder& builder, void *cookie) {
    274     auto *cbData = static_cast<UnloadNanoappCallbackData *>(cookie);
    275 
    276     bool success = false;
    277     uint32_t instanceId;
    278     EventLoop& eventLoop = EventLoopManagerSingleton::get()->getEventLoop();
    279     if (!eventLoop.findNanoappInstanceIdByAppId(cbData->appId, &instanceId)) {
    280       LOGE("Couldn't unload app ID 0x%016" PRIx64 ": not found", cbData->appId);
    281     } else {
    282       success = eventLoop.unloadNanoapp(instanceId,
    283                                         cbData->allowSystemNanoappUnload);
    284     }
    285 
    286     HostProtocolChre::encodeUnloadNanoappResponse(
    287         builder, cbData->hostClientId, cbData->transactionId, success);
    288   };
    289 
    290   constexpr size_t kInitialBufferSize = 52;
    291   buildAndEnqueueMessage(PendingMessageType::UnloadNanoappResponse,
    292                          kInitialBufferSize, msgBuilder, data);
    293   memoryFree(data);
    294 }
    295 
    296 int generateMessageToHost(const MessageToHost *msgToHost, unsigned char *buffer,
    297                           size_t bufferSize, unsigned int *messageLen) {
    298   // TODO: ideally we'd construct our flatbuffer directly in the
    299   // host-supplied buffer
    300   constexpr size_t kFixedSizePortion = 80;
    301   FlatBufferBuilder builder(msgToHost->message.size() + kFixedSizePortion);
    302   HostProtocolChre::encodeNanoappMessage(
    303     builder, msgToHost->appId, msgToHost->toHostData.messageType,
    304     msgToHost->toHostData.hostEndpoint, msgToHost->message.data(),
    305     msgToHost->message.size());
    306 
    307   int result = copyToHostBuffer(builder, buffer, bufferSize, messageLen);
    308 
    309   auto& hostCommsManager =
    310       EventLoopManagerSingleton::get()->getHostCommsManager();
    311   hostCommsManager.onMessageToHostComplete(msgToHost);
    312 
    313   return result;
    314 }
    315 
    316 int generateLogMessage(unsigned char *buffer, size_t bufferSize,
    317                        unsigned int *messageLen) {
    318   FlatBufferBuilder builder;
    319   PlatformLogSingleton::get()->flushLogBuffer([](const char *logBuffer,
    320                                                  size_t size,
    321                                                  void *context) {
    322     auto *contextBuilder = static_cast<FlatBufferBuilder *>(context);
    323     HostProtocolChre::encodeLogMessages(*contextBuilder, logBuffer, size);
    324   }, &builder);
    325 
    326   return copyToHostBuffer(builder, buffer, bufferSize, messageLen);
    327 }
    328 
    329 int generateHubInfoResponse(uint16_t hostClientId, unsigned char *buffer,
    330                             size_t bufferSize, unsigned int *messageLen) {
    331   constexpr size_t kInitialBufferSize = 192;
    332 
    333   constexpr char kHubName[] = "CHRE on SLPI";
    334   constexpr char kVendor[] = "Google";
    335   constexpr char kToolchain[] = "Hexagon Tools 8.0 (clang "
    336     STRINGIFY(__clang_major__) "."
    337     STRINGIFY(__clang_minor__) "."
    338     STRINGIFY(__clang_patchlevel__) ")";
    339   constexpr uint32_t kLegacyPlatformVersion = 0;
    340   constexpr uint32_t kLegacyToolchainVersion =
    341     ((__clang_major__ & 0xFF) << 24) |
    342     ((__clang_minor__ & 0xFF) << 16) |
    343     (__clang_patchlevel__ & 0xFFFF);
    344   constexpr float kPeakMips = 350;
    345   constexpr float kStoppedPower = 0;
    346   constexpr float kSleepPower = 1;
    347   constexpr float kPeakPower = 15;
    348 
    349   // Note that this may execute prior to EventLoopManager::lateInit() completing
    350   FlatBufferBuilder builder(kInitialBufferSize);
    351   HostProtocolChre::encodeHubInfoResponse(
    352       builder, kHubName, kVendor, kToolchain, kLegacyPlatformVersion,
    353       kLegacyToolchainVersion, kPeakMips, kStoppedPower, kSleepPower,
    354       kPeakPower, CHRE_MESSAGE_TO_HOST_MAX_SIZE, chreGetPlatformId(),
    355       chreGetVersion(), hostClientId);
    356 
    357   return copyToHostBuffer(builder, buffer, bufferSize, messageLen);
    358 }
    359 
    360 int generateMessageFromBuilder(
    361     FlatBufferBuilder *builder, unsigned char *buffer, size_t bufferSize,
    362     unsigned int *messageLen) {
    363   CHRE_ASSERT(builder != nullptr);
    364   int result = copyToHostBuffer(*builder, buffer, bufferSize, messageLen);
    365   builder->~FlatBufferBuilder();
    366   memoryFree(builder);
    367   return result;
    368 }
    369 
    370 void sendDebugDumpData(uint16_t hostClientId, const char *debugStr,
    371                        size_t debugStrSize) {
    372   struct DebugDumpMessageData {
    373     uint16_t hostClientId;
    374     const char *debugStr;
    375     size_t debugStrSize;
    376   };
    377 
    378   auto msgBuilder = [](FlatBufferBuilder& builder, void *cookie) {
    379     const auto *data = static_cast<const DebugDumpMessageData *>(cookie);
    380     HostProtocolChre::encodeDebugDumpData(
    381         builder, data->hostClientId, data->debugStr, data->debugStrSize);
    382   };
    383 
    384   constexpr size_t kInitialSize = 48;
    385   DebugDumpMessageData data;
    386   data.hostClientId = hostClientId;
    387   data.debugStr     = debugStr;
    388   data.debugStrSize = debugStrSize;
    389   buildAndEnqueueMessage(PendingMessageType::DebugDumpData, kInitialSize,
    390                          msgBuilder, &data);
    391 }
    392 
    393 void sendDebugDumpResponse(DebugDumpCallbackData *data) {
    394   auto msgBuilder = [](FlatBufferBuilder& builder, void *cookie) {
    395     const auto *cbData = static_cast<const DebugDumpCallbackData *>(cookie);
    396     HostProtocolChre::encodeDebugDumpResponse(
    397         builder, cbData->hostClientId, cbData->success, cbData->dataCount);
    398   };
    399 
    400   constexpr size_t kInitialSize = 52;
    401   buildAndEnqueueMessage(PendingMessageType::DebugDumpResponse, kInitialSize,
    402                          msgBuilder, data);
    403 }
    404 
    405 /**
    406  * @see ashDebugDumpReadyCbFunc
    407  */
    408 void onDebugDumpDataReady(void *cookie, const char *debugStr,
    409                           size_t debugStrSize, bool complete) {
    410   auto *cbData = static_cast<DebugDumpCallbackData *>(cookie);
    411   if (debugStrSize > 0) {
    412     sendDebugDumpData(cbData->hostClientId, debugStr, debugStrSize);
    413     cbData->dataCount++;
    414   }
    415 
    416   if (complete) {
    417     sendDebugDumpResponse(cbData);
    418 
    419     // This needs to persist across multiple calls
    420     memoryFree(cbData);
    421   }
    422 }
    423 
    424 /**
    425  * FastRPC method invoked by the host to block on messages
    426  *
    427  * @param buffer Output buffer to populate with message data
    428  * @param bufferLen Size of the buffer, in bytes
    429  * @param messageLen Output parameter to populate with the size of the message
    430  *        in bytes upon success
    431  *
    432  * @return 0 on success, nonzero on failure
    433  */
    434 extern "C" int chre_slpi_get_message_to_host(
    435     unsigned char *buffer, int bufferLen, unsigned int *messageLen) {
    436   CHRE_ASSERT(buffer != nullptr);
    437   CHRE_ASSERT(bufferLen > 0);
    438   CHRE_ASSERT(messageLen != nullptr);
    439   int result = CHRE_FASTRPC_ERROR;
    440 
    441   if (bufferLen <= 0 || buffer == nullptr || messageLen == nullptr) {
    442     // Note that we can't use regular logs here as they can result in sending
    443     // a message, leading to an infinite loop if the error is persistent
    444     FARF(FATAL, "Invalid buffer size %d or bad pointers (buf %d len %d)",
    445          bufferLen, (buffer == nullptr), (messageLen == nullptr));
    446   } else {
    447     size_t bufferSize = static_cast<size_t>(bufferLen);
    448     PendingMessage pendingMsg = gOutboundQueue.pop();
    449 
    450     switch (pendingMsg.type) {
    451       case PendingMessageType::Shutdown:
    452         result = CHRE_FASTRPC_ERROR_SHUTTING_DOWN;
    453         break;
    454 
    455       case PendingMessageType::NanoappMessageToHost:
    456         result = generateMessageToHost(pendingMsg.data.msgToHost, buffer,
    457                                        bufferSize, messageLen);
    458         break;
    459 
    460       case PendingMessageType::LogMessage:
    461         result = generateLogMessage(buffer, bufferSize, messageLen);
    462         break;
    463 
    464       case PendingMessageType::HubInfoResponse:
    465         result = generateHubInfoResponse(pendingMsg.data.hostClientId, buffer,
    466                                          bufferSize, messageLen);
    467         break;
    468 
    469       case PendingMessageType::NanoappListResponse:
    470       case PendingMessageType::LoadNanoappResponse:
    471       case PendingMessageType::UnloadNanoappResponse:
    472       case PendingMessageType::DebugDumpData:
    473       case PendingMessageType::DebugDumpResponse:
    474       case PendingMessageType::TimeSyncRequest:
    475         result = generateMessageFromBuilder(pendingMsg.data.builder,
    476                                             buffer, bufferSize, messageLen);
    477         break;
    478 
    479       default:
    480         CHRE_ASSERT_LOG(false, "Unexpected pending message type");
    481     }
    482   }
    483 
    484   FARF(MEDIUM, "Returning message to host (result %d length %u)",
    485        result, *messageLen);
    486 
    487   // Opportunistically send a time sync message
    488   requestTimeSyncIfStale();
    489 
    490   return result;
    491 }
    492 
    493 /**
    494  * FastRPC method invoked by the host to send a message to the system
    495  *
    496  * @param buffer
    497  * @param size
    498  *
    499  * @return 0 on success, nonzero on failure
    500  */
    501 extern "C" int chre_slpi_deliver_message_from_host(const unsigned char *message,
    502                                                    int messageLen) {
    503   CHRE_ASSERT(message != nullptr);
    504   CHRE_ASSERT(messageLen > 0);
    505   int result = CHRE_FASTRPC_ERROR;
    506 
    507   if (message == nullptr || messageLen <= 0) {
    508     LOGE("Got null or invalid size (%d) message from host", messageLen);
    509   } else if (!HostProtocolChre::decodeMessageFromHost(
    510       message, static_cast<size_t>(messageLen))) {
    511     LOGE("Failed to decode/handle message");
    512   } else {
    513     result = CHRE_FASTRPC_SUCCESS;
    514   }
    515 
    516   return result;
    517 }
    518 
    519 }  // anonymous namespace
    520 
    521 void HostLink::flushMessagesSentByNanoapp(uint64_t /*appId*/) {
    522   // TODO: this is not completely safe since it's timer-based, but should work
    523   // well enough for the initial implementation. To be fully safe, we'd need
    524   // some synchronization with the thread that runs
    525   // chre_slpi_get_message_to_host(), e.g. a mutex that is held by that thread
    526   // prior to calling pop() and only released after onMessageToHostComplete
    527   // would've been called. If we acquire that mutex here, and hold it while
    528   // purging any messages sent by the nanoapp in the queue, we can be certain
    529   // that onMessageToHostComplete will not be called after this function returns
    530   // for messages sent by that nanoapp
    531   flushOutboundQueue();
    532 
    533   // One extra sleep to try to ensure that any messages popped just before
    534   // checking empty() are fully processed before we return
    535   constexpr qurt_timer_duration_t kFinalDelayUsec = 10000;
    536   qurt_timer_sleep(kFinalDelayUsec);
    537 }
    538 
    539 bool HostLink::sendMessage(const MessageToHost *message) {
    540   return enqueueMessage(
    541       PendingMessage(PendingMessageType::NanoappMessageToHost, message));
    542 }
    543 
    544 bool HostLinkBase::flushOutboundQueue() {
    545   // This function is used in preFatalError() so it must never call FATAL_ERROR
    546   int waitCount = 5;
    547 
    548   FARF(LOW, "Draining message queue");
    549   while (!gOutboundQueue.empty() && waitCount-- > 0) {
    550     qurt_timer_sleep(kPollingIntervalUsec);
    551   }
    552 
    553   return (waitCount >= 0);
    554 }
    555 
    556 void HostLinkBase::shutdown() {
    557   // Push a null message so the blocking call in chre_slpi_get_message_to_host()
    558   // returns and the host can exit cleanly. If the queue is full, try again to
    559   // avoid getting stuck (no other new messages should be entering the queue at
    560   // this time). Don't wait too long as the host-side binary may have died in
    561   // a state where it's not blocked in chre_slpi_get_message_to_host().
    562   int retryCount = 5;
    563   FARF(MEDIUM, "Shutting down host link");
    564   while (!enqueueMessage(PendingMessage(PendingMessageType::Shutdown))
    565          && --retryCount > 0) {
    566     qurt_timer_sleep(kPollingIntervalUsec);
    567   }
    568 
    569   if (retryCount <= 0) {
    570     // Don't use LOGE, as it may involve trying to send a message
    571     FARF(ERROR, "No room in outbound queue for shutdown message and host not "
    572          "draining queue!");
    573   } else {
    574     // We were able to push the shutdown message. Wait for the queue to
    575     // completely flush before returning.
    576     if (!flushOutboundQueue()) {
    577       FARF(ERROR, "Host took too long to drain outbound queue; exiting anyway");
    578     } else {
    579       FARF(MEDIUM, "Finished draining queue");
    580     }
    581   }
    582 }
    583 
    584 void sendTimeSyncRequest() {
    585   auto msgBuilder = [](FlatBufferBuilder& builder, void *cookie) {
    586     HostProtocolChre::encodeTimeSyncRequest(builder);
    587   };
    588 
    589   constexpr size_t kInitialSize = 52;
    590   buildAndEnqueueMessage(PendingMessageType::TimeSyncRequest, kInitialSize,
    591                          msgBuilder, nullptr);
    592   updateLastTimeSyncRequest();
    593 }
    594 
    595 void requestHostLinkLogBufferFlush() {
    596   if (!enqueueMessage(PendingMessage(PendingMessageType::LogMessage))) {
    597     // Use FARF as there is a problem sending logs to the host.
    598     FARF(ERROR, "Failed to enqueue log flush");
    599     CHRE_ASSERT(false);
    600   }
    601 }
    602 
    603 void HostMessageHandlers::handleNanoappMessage(
    604     uint64_t appId, uint32_t messageType, uint16_t hostEndpoint,
    605     const void *messageData, size_t messageDataLen) {
    606   LOGD("Parsed nanoapp message from host: app ID 0x%016" PRIx64 ", endpoint "
    607        "0x%" PRIx16 ", msgType %" PRIu32 ", payload size %zu",
    608        appId, hostEndpoint, messageType, messageDataLen);
    609 
    610   HostCommsManager& manager =
    611       EventLoopManagerSingleton::get()->getHostCommsManager();
    612   manager.sendMessageToNanoappFromHost(
    613       appId, messageType, hostEndpoint, messageData, messageDataLen);
    614 }
    615 
    616 void HostMessageHandlers::handleHubInfoRequest(uint16_t hostClientId) {
    617   // We generate the response in the context of chre_slpi_get_message_to_host
    618   LOGD("Got hub info request from client ID %" PRIu16, hostClientId);
    619   enqueueMessage(PendingMessage(
    620       PendingMessageType::HubInfoResponse, hostClientId));
    621 }
    622 
    623 void HostMessageHandlers::handleNanoappListRequest(uint16_t hostClientId) {
    624   LOGD("Got nanoapp list request from client ID %" PRIu16, hostClientId);
    625   HostClientIdCallbackData cbData = {};
    626   cbData.hostClientId = hostClientId;
    627   EventLoopManagerSingleton::get()->deferCallback(
    628       SystemCallbackType::NanoappListResponse, cbData.ptr,
    629       constructNanoappListCallback);
    630 }
    631 
    632 void HostMessageHandlers::handleLoadNanoappRequest(
    633     uint16_t hostClientId, uint32_t transactionId, uint64_t appId,
    634     uint32_t appVersion, uint32_t targetApiVersion, const void *appBinary,
    635     size_t appBinaryLen) {
    636   auto cbData = MakeUnique<LoadNanoappCallbackData>();
    637 
    638   LOGD("Got load nanoapp request (txnId %" PRIu32 ") for appId 0x%016" PRIx64
    639        " version 0x%" PRIx32 " target API version 0x%08" PRIx32 " size %zu",
    640        transactionId, appId, appVersion, targetApiVersion, appBinaryLen);
    641   if (cbData.isNull() || cbData->nanoapp.isNull()) {
    642     LOGE("Couldn't allocate load nanoapp callback data");
    643   } else {
    644     cbData->transactionId = transactionId;
    645     cbData->hostClientId  = hostClientId;
    646     cbData->appId = appId;
    647 
    648     // Note that if this fails, we'll generate the error response in
    649     // the normal deferred callback
    650     cbData->nanoapp->loadFromBuffer(appId, appVersion, appBinary, appBinaryLen);
    651     if (!EventLoopManagerSingleton::get()->deferCallback(
    652             SystemCallbackType::FinishLoadingNanoapp, cbData.get(),
    653             finishLoadingNanoappCallback)) {
    654       LOGE("Couldn't post callback to finish loading nanoapp");
    655     } else {
    656       cbData.release();
    657     }
    658   }
    659 }
    660 
    661 void HostMessageHandlers::handleUnloadNanoappRequest(
    662     uint16_t hostClientId, uint32_t transactionId, uint64_t appId,
    663     bool allowSystemNanoappUnload) {
    664   LOGD("Got unload nanoapp request (txnID %" PRIu32 ") for appId 0x%016" PRIx64
    665        " system %d", transactionId, appId, allowSystemNanoappUnload);
    666   auto *cbData = memoryAlloc<UnloadNanoappCallbackData>();
    667   if (cbData == nullptr) {
    668     LOGE("Couldn't allocate unload nanoapp callback data");
    669   } else {
    670     cbData->appId = appId;
    671     cbData->transactionId = transactionId;
    672     cbData->hostClientId = hostClientId;
    673     cbData->allowSystemNanoappUnload = allowSystemNanoappUnload;
    674 
    675     if (!EventLoopManagerSingleton::get()->deferCallback(
    676             SystemCallbackType::HandleUnloadNanoapp, cbData,
    677             handleUnloadNanoappCallback)) {
    678       LOGE("Couldn't post callback to unload nanoapp");
    679       memoryFree(cbData);
    680     }
    681   }
    682 }
    683 
    684 void HostMessageHandlers::handleTimeSyncMessage(int64_t offset) {
    685   setEstimatedHostTimeOffset(offset);
    686 }
    687 
    688 void HostMessageHandlers::handleDebugDumpRequest(uint16_t hostClientId) {
    689   auto *cbData = memoryAlloc<DebugDumpCallbackData>();
    690   if (cbData == nullptr) {
    691     LOGE("Couldn't allocate debug dump callback data");
    692   } else {
    693     cbData->hostClientId = hostClientId;
    694     cbData->dataCount = 0;
    695     cbData->success = ashTriggerDebugDump(onDebugDumpDataReady, cbData);
    696 
    697     if (!cbData->success) {
    698       LOGE("Couldn't post callback to complete debug dump");
    699       sendDebugDumpResponse(cbData);
    700       memoryFree(cbData);
    701     }
    702   }
    703 }
    704 
    705 }  // namespace chre
    706