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