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