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