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