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