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