• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::__anon8c8391430111::PendingMessage84   PendingMessage(PendingMessageType msgType, uint16_t hostClientId) {
85     type = msgType;
86     data.hostClientId = hostClientId;
87   }
88 
PendingMessagechre::__anon8c8391430111::PendingMessage89   PendingMessage(PendingMessageType msgType,
90                  const MessageToHost *msgToHost = nullptr) {
91     type = msgType;
92     data.msgToHost = msgToHost;
93   }
94 
PendingMessagechre::__anon8c8391430111::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 = 80;
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, CHRE_MESSAGE_TO_HOST_MAX_SIZE, chreGetPlatformId(),
295       chreGetVersion(), hostClientId);
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 
sendMetricLog(uint32_t metricId,const uint8_t * encodedMetric,size_t encodedMetricLen)597 bool HostLink::sendMetricLog(uint32_t metricId, const uint8_t *encodedMetric,
598                              size_t encodedMetricLen) {
599   struct MetricLogData {
600     uint32_t metricId;
601     const uint8_t *encodedMetric;
602     size_t encodedMetricLen;
603   };
604 
605   MetricLogData data;
606   data.metricId = metricId;
607   data.encodedMetric = encodedMetric;
608   data.encodedMetricLen = encodedMetricLen;
609 
610   auto msgBuilder = [](ChreFlatBufferBuilder &builder, void *cookie) {
611     const auto *data = static_cast<const MetricLogData *>(cookie);
612     HostProtocolChre::encodeMetricLog(
613         builder, data->metricId, data->encodedMetric, data->encodedMetricLen);
614   };
615 
616   constexpr size_t kInitialSize = 52;
617   buildAndEnqueueMessage(PendingMessageType::MetricLog, kInitialSize,
618                          msgBuilder, &data);
619   return true;
620 }
621 
flushOutboundQueue()622 bool HostLinkBase::flushOutboundQueue() {
623   int waitCount = 5;
624 
625   FARF(MEDIUM, "Draining message queue");
626   while (!gOutboundQueue.empty() && waitCount-- > 0) {
627     timer_sleep(kPollingIntervalUsec, T_USEC, true /* non_deferrable */);
628   }
629 
630   return (waitCount >= 0);
631 }
632 
sendLogMessage(const uint8_t * logMessage,size_t logMessageSize)633 void HostLinkBase::sendLogMessage(const uint8_t *logMessage,
634                                   size_t logMessageSize) {
635   struct LogMessageData {
636     const uint8_t *logMsg;
637     size_t logMsgSize;
638   };
639 
640   LogMessageData logMessageData;
641 
642   logMessageData.logMsg = logMessage;
643   logMessageData.logMsgSize = logMessageSize;
644 
645   auto msgBuilder = [](ChreFlatBufferBuilder &builder, void *cookie) {
646     const auto *data = static_cast<const LogMessageData *>(cookie);
647     HostProtocolChre::encodeLogMessages(builder, data->logMsg,
648                                         data->logMsgSize);
649   };
650 
651   constexpr size_t kInitialSize = 128;
652   buildAndEnqueueMessage(PendingMessageType::EncodedLogMessage, kInitialSize,
653                          msgBuilder, &logMessageData);
654 }
655 
sendLogMessageV2(const uint8_t * logMessage,size_t logMessageSize,uint32_t numLogsDropped)656 void HostLinkBase::sendLogMessageV2(const uint8_t *logMessage,
657                                     size_t logMessageSize,
658                                     uint32_t numLogsDropped) {
659   struct LogMessageData {
660     const uint8_t *logMsg;
661     size_t logMsgSize;
662     uint32_t numLogsDropped;
663   };
664 
665   LogMessageData logMessageData{logMessage, logMessageSize, numLogsDropped};
666 
667   auto msgBuilder = [](ChreFlatBufferBuilder &builder, void *cookie) {
668     const auto *data = static_cast<const LogMessageData *>(cookie);
669     HostProtocolChre::encodeLogMessagesV2(
670         builder, data->logMsg, data->logMsgSize, data->numLogsDropped);
671   };
672 
673   constexpr size_t kInitialSize = 128;
674   buildAndEnqueueMessage(PendingMessageType::EncodedLogMessage, kInitialSize,
675                          msgBuilder, &logMessageData);
676 }
677 
sendNanConfiguration(bool enable)678 void HostLinkBase::sendNanConfiguration(bool enable) {
679   auto msgBuilder = [](ChreFlatBufferBuilder &builder, void *cookie) {
680     const auto *data = static_cast<const bool *>(cookie);
681     HostProtocolChre::encodeNanConfigurationRequest(builder, *data);
682   };
683 
684   constexpr size_t kInitialSize = 48;
685   buildAndEnqueueMessage(PendingMessageType::NanConfigurationRequest,
686                          kInitialSize, msgBuilder, &enable);
687 }
688 
shutdown()689 void HostLinkBase::shutdown() {
690   // Push a null message so the blocking call in chre_slpi_get_message_to_host()
691   // returns and the host can exit cleanly. If the queue is full, try again to
692   // avoid getting stuck (no other new messages should be entering the queue at
693   // this time). Don't wait too long as the host-side binary may have died in
694   // a state where it's not blocked in chre_slpi_get_message_to_host().
695   int retryCount = 5;
696   FARF(MEDIUM, "Shutting down host link");
697   while (!enqueueMessage(PendingMessage(PendingMessageType::Shutdown)) &&
698          --retryCount > 0) {
699     timer_sleep(kPollingIntervalUsec, T_USEC, true /* non_deferrable */);
700   }
701 
702   if (retryCount <= 0) {
703     // Don't use LOGE, as it may involve trying to send a message
704     FARF(ERROR,
705          "No room in outbound queue for shutdown message and host not "
706          "draining queue!");
707   } else {
708     // We were able to push the shutdown message. Wait for the queue to
709     // completely flush before returning.
710     if (!flushOutboundQueue()) {
711       FARF(ERROR, "Host took too long to drain outbound queue; exiting anyway");
712     } else {
713       FARF(MEDIUM, "Finished draining queue");
714     }
715   }
716 }
717 
sendAudioRequest()718 void sendAudioRequest() {
719   auto msgBuilder = [](ChreFlatBufferBuilder &builder, void *cookie) {
720     HostProtocolChre::encodeLowPowerMicAccessRequest(builder);
721   };
722 
723   constexpr size_t kInitialSize = 32;
724   buildAndEnqueueMessage(PendingMessageType::LowPowerMicAccessRequest,
725                          kInitialSize, msgBuilder, nullptr);
726 }
727 
sendAudioRelease()728 void sendAudioRelease() {
729   auto msgBuilder = [](ChreFlatBufferBuilder &builder, void *cookie) {
730     HostProtocolChre::encodeLowPowerMicAccessRelease(builder);
731   };
732 
733   constexpr size_t kInitialSize = 32;
734   buildAndEnqueueMessage(PendingMessageType::LowPowerMicAccessRelease,
735                          kInitialSize, msgBuilder, nullptr);
736 }
737 
sendFragmentResponse(uint16_t hostClientId,uint32_t transactionId,uint32_t fragmentId,bool success)738 void HostMessageHandlers::sendFragmentResponse(uint16_t hostClientId,
739                                                uint32_t transactionId,
740                                                uint32_t fragmentId,
741                                                bool success) {
742   struct FragmentedLoadInfoResponse {
743     uint16_t hostClientId;
744     uint32_t transactionId;
745     uint32_t fragmentId;
746     bool success;
747   };
748 
749   auto msgBuilder = [](ChreFlatBufferBuilder &builder, void *cookie) {
750     auto *cbData = static_cast<FragmentedLoadInfoResponse *>(cookie);
751     HostProtocolChre::encodeLoadNanoappResponse(
752         builder, cbData->hostClientId, cbData->transactionId, cbData->success,
753         cbData->fragmentId);
754   };
755 
756   FragmentedLoadInfoResponse response = {
757       .hostClientId = hostClientId,
758       .transactionId = transactionId,
759       .fragmentId = fragmentId,
760       .success = success,
761   };
762   constexpr size_t kInitialBufferSize = 48;
763   buildAndEnqueueMessage(PendingMessageType::LoadNanoappResponse,
764                          kInitialBufferSize, msgBuilder, &response);
765 }
766 
handleNanoappMessage(uint64_t appId,uint32_t messageType,uint16_t hostEndpoint,const void * messageData,size_t messageDataLen)767 void HostMessageHandlers::handleNanoappMessage(uint64_t appId,
768                                                uint32_t messageType,
769                                                uint16_t hostEndpoint,
770                                                const void *messageData,
771                                                size_t messageDataLen) {
772   LOGD("Parsed nanoapp message from host: app ID 0x%016" PRIx64
773        ", endpoint "
774        "0x%" PRIx16 ", msgType %" PRIu32 ", payload size %zu",
775        appId, hostEndpoint, messageType, messageDataLen);
776 
777   HostCommsManager &manager =
778       EventLoopManagerSingleton::get()->getHostCommsManager();
779   manager.sendMessageToNanoappFromHost(appId, messageType, hostEndpoint,
780                                        messageData, messageDataLen);
781 }
782 
handleHubInfoRequest(uint16_t hostClientId)783 void HostMessageHandlers::handleHubInfoRequest(uint16_t hostClientId) {
784   // We generate the response in the context of chre_slpi_get_message_to_host
785   LOGD("Hub info request from client ID %" PRIu16, hostClientId);
786   enqueueMessage(
787       PendingMessage(PendingMessageType::HubInfoResponse, hostClientId));
788 }
789 
handleNanoappListRequest(uint16_t hostClientId)790 void HostMessageHandlers::handleNanoappListRequest(uint16_t hostClientId) {
791   auto callback = [](uint16_t /*type*/, void *data, void * /*extraData*/) {
792     uint16_t cbHostClientId = NestedDataPtr<uint16_t>(data);
793 
794     NanoappListData cbData = {};
795     cbData.hostClientId = cbHostClientId;
796 
797     size_t expectedNanoappCount =
798         EventLoopManagerSingleton::get()->getEventLoop().getNanoappCount();
799     if (!cbData.nanoappEntries.reserve(expectedNanoappCount)) {
800       LOG_OOM();
801     } else {
802       constexpr size_t kFixedOverhead = 48;
803       constexpr size_t kPerNanoappSize = 32;
804       size_t initialBufferSize =
805           (kFixedOverhead + expectedNanoappCount * kPerNanoappSize);
806 
807       buildAndEnqueueMessage(PendingMessageType::NanoappListResponse,
808                              initialBufferSize, buildNanoappListResponse,
809                              &cbData);
810     }
811   };
812 
813   LOGD("Nanoapp list request from client ID %" PRIu16, hostClientId);
814   EventLoopManagerSingleton::get()->deferCallback(
815       SystemCallbackType::NanoappListResponse,
816       NestedDataPtr<uint16_t>(hostClientId), callback);
817 }
818 
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)819 void HostMessageHandlers::handleLoadNanoappRequest(
820     uint16_t hostClientId, uint32_t transactionId, uint64_t appId,
821     uint32_t appVersion, uint32_t appFlags, uint32_t targetApiVersion,
822     const void *buffer, size_t bufferLen, const char *appFileName,
823     uint32_t fragmentId, size_t appBinaryLen, bool respondBeforeStart) {
824   if (appFileName == nullptr) {
825     loadNanoappData(hostClientId, transactionId, appId, appVersion, appFlags,
826                     targetApiVersion, buffer, bufferLen, fragmentId,
827                     appBinaryLen, respondBeforeStart);
828     return;
829   }
830 
831   UniquePtr<Nanoapp> pendingNanoapp =
832       handleLoadNanoappFile(hostClientId, transactionId, appId, appVersion,
833                             targetApiVersion, appFileName);
834 
835   if (!pendingNanoapp.isNull()) {
836     auto cbData = MakeUnique<LoadNanoappCallbackData>();
837     if (cbData.isNull()) {
838       LOG_OOM();
839     } else {
840       cbData->transactionId = transactionId;
841       cbData->hostClientId = hostClientId;
842       cbData->appId = appId;
843       cbData->fragmentId = fragmentId;
844       cbData->nanoapp = std::move(pendingNanoapp);
845 
846       // Note that if this fails, we'll generate the error response in
847       // the normal deferred callback
848       EventLoopManagerSingleton::get()->deferCallback(
849           SystemCallbackType::FinishLoadingNanoapp, std::move(cbData),
850           finishLoadingNanoappCallback);
851     }
852   }
853 }
854 
handleUnloadNanoappRequest(uint16_t hostClientId,uint32_t transactionId,uint64_t appId,bool allowSystemNanoappUnload)855 void HostMessageHandlers::handleUnloadNanoappRequest(
856     uint16_t hostClientId, uint32_t transactionId, uint64_t appId,
857     bool allowSystemNanoappUnload) {
858   LOGD("Unload nanoapp request (txnID %" PRIu32 ") for appId 0x%016" PRIx64
859        " system %d",
860        transactionId, appId, allowSystemNanoappUnload);
861   auto cbData = MakeUnique<UnloadNanoappCallbackData>();
862   if (cbData == nullptr) {
863     LOG_OOM();
864   } else {
865     cbData->appId = appId;
866     cbData->transactionId = transactionId;
867     cbData->hostClientId = hostClientId;
868     cbData->allowSystemNanoappUnload = allowSystemNanoappUnload;
869 
870     EventLoopManagerSingleton::get()->deferCallback(
871         SystemCallbackType::HandleUnloadNanoapp, std::move(cbData),
872         handleUnloadNanoappCallback);
873   }
874 }
875 
handleTimeSyncMessage(int64_t offset)876 void HostMessageHandlers::handleTimeSyncMessage(int64_t offset) {
877   SystemTime::setEstimatedHostTimeOffset(offset);
878 
879   // Schedule a time sync request since offset may drift
880   constexpr Seconds kClockDriftTimeSyncPeriod =
881       Seconds(60 * 60 * 6);  // 6 hours
882   setTimeSyncRequestTimer(kClockDriftTimeSyncPeriod);
883 }
884 
handleDebugDumpRequest(uint16_t hostClientId)885 void HostMessageHandlers::handleDebugDumpRequest(uint16_t hostClientId) {
886   if (!chre::EventLoopManagerSingleton::get()
887            ->getDebugDumpManager()
888            .onDebugDumpRequested(hostClientId)) {
889     LOGE("Couldn't trigger debug dump process");
890     sendDebugDumpResponse(hostClientId, false /*success*/, 0 /*dataCount*/);
891   }
892 }
893 
handleSettingChangeMessage(fbs::Setting setting,fbs::SettingState state)894 void HostMessageHandlers::handleSettingChangeMessage(fbs::Setting setting,
895                                                      fbs::SettingState state) {
896   Setting chreSetting;
897   bool chreSettingEnabled;
898   if (HostProtocolChre::getSettingFromFbs(setting, &chreSetting) &&
899       HostProtocolChre::getSettingEnabledFromFbs(state, &chreSettingEnabled)) {
900     EventLoopManagerSingleton::get()->getSettingManager().postSettingChange(
901         chreSetting, chreSettingEnabled);
902   }
903 }
904 
handleSelfTestRequest(uint16_t hostClientId)905 void HostMessageHandlers::handleSelfTestRequest(uint16_t hostClientId) {
906   // TODO(b/182201569): Run test
907   bool success = true;
908   sendSelfTestResponse(hostClientId, success);
909 }
910 
handleNanConfigurationUpdate(bool enabled)911 void HostMessageHandlers::handleNanConfigurationUpdate(bool enabled) {
912 #ifdef CHRE_WIFI_NAN_SUPPORT_ENABLED
913   EventLoopManagerSingleton::get()
914       ->getWifiRequestManager()
915       .updateNanAvailability(enabled);
916 #else
917   UNUSED_VAR(enabled);
918 #endif  // CHRE_WIFI_NAN_SUPPORT_ENABLED
919 }
920 
921 }  // namespace chre
922