• 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 /**
18  * @file
19  * The daemon that hosts CHRE on a hexagon DSP via FastRPC. This is typically
20  * the SLPI but could be the ADSP or another DSP that supports FastRPC.
21  *
22  * Several threads are required for this functionality:
23  *   - Main thread: blocked waiting on SIGINT/SIGTERM, and requests graceful
24  *     shutdown of CHRE when caught
25  *   - Monitor thread: persistently blocked in a FastRPC call to the DSP that
26  *     only returns when CHRE exits or the DSP crashes
27  *     - TODO: see whether we can merge this with the RX thread
28  *   - Reverse monitor thread: after initializing the DSP-side monitor for this
29  *     process, blocks on a condition variable. If this thread exits, CHRE on
30  *     the DSP side will be notified and shut down (this is only possible if
31  *     this thread is not blocked in a FastRPC call).
32  *     - TODO: confirm this and see whether we can merge this responsibility
33  *       into the TX thread
34  *   - Message to host (RX) thread: blocks in FastRPC call, waiting on incoming
35  *     message from CHRE
36  *   - Message to CHRE (TX) thread: blocks waiting on outbound queue, delivers
37  *     messages to CHRE over FastRPC
38  *
39  * TODO: This file originated from an implementation for another device, and was
40  * written in C, but then it was converted to C++ when adding socket support. It
41  * should be fully converted to C++.
42  */
43 
44 // Disable verbose logging
45 // TODO: use property_get_bool to make verbose logging runtime configurable
46 // #define LOG_NDEBUG 0
47 
48 #include <ctype.h>
49 #include <inttypes.h>
50 #include <pthread.h>
51 #include <stdbool.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56 
57 #include <fstream>
58 #include <string>
59 #include <queue>
60 
61 #include "chre/platform/slpi/fastrpc.h"
62 #include "chre_host/log.h"
63 #include "chre_host/host_protocol_host.h"
64 #include "chre_host/socket_server.h"
65 #include "generated/chre_slpi.h"
66 
67 #include <json/json.h>
68 #include <utils/SystemClock.h>
69 
70 #ifdef ADSPRPC
71 #include "remote.h"
72 
73 #define ITRANSPORT_PREFIX "'\":;./\\"
74 #endif  // ADSPRPC
75 
76 //! The format string to use for logs from the CHRE implementation.
77 #define HUB_LOG_FORMAT_STR "Hub (t=%.6f): %s"
78 
79 #ifdef CHRE_DAEMON_LPMA_ENABLED
80 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
81 #include <hardware_legacy/power.h>
82 
83 using android::sp;
84 using android::hardware::Return;
85 using android::hardware::soundtrigger::V2_0::ISoundTriggerHw;
86 using android::hardware::soundtrigger::V2_0::SoundModelHandle;
87 using android::hardware::soundtrigger::V2_0::SoundModelType;
88 #endif  // CHRE_DAEMON_LPMA_ENABLED
89 
90 using android::chre::HostProtocolHost;
91 using android::chre::FragmentedLoadTransaction;
92 using android::elapsedRealtimeNano;
93 
94 // Aliased for consistency with the way these symbols are referenced in
95 // CHRE-side code
96 namespace fbs = ::chre::fbs;
97 
98 typedef void *(thread_entry_point_f)(void *);
99 
100 struct reverse_monitor_thread_data {
101   pthread_t       thread;
102   pthread_mutex_t mutex;
103   pthread_cond_t  cond;
104 };
105 
106 static void *chre_message_to_host_thread(void *arg);
107 static void *chre_monitor_thread(void *arg);
108 static void *chre_reverse_monitor_thread(void *arg);
109 static bool init_reverse_monitor(struct reverse_monitor_thread_data *data);
110 static bool start_thread(pthread_t *thread_handle,
111                          thread_entry_point_f *thread_entry,
112                          void *arg);
113 
114 #ifdef CHRE_DAEMON_LPMA_ENABLED
115 //! The name of the wakelock to use for the CHRE daemon.
116 static const char kWakeLockName[] = "chre_daemon";
117 
118 struct LpmaEnableThreadData {
119   pthread_t thread;
120   pthread_mutex_t mutex;
121   pthread_cond_t cond;
122   bool currentLpmaEnabled;
123   bool targetLpmaEnabled;
124 };
125 
126 static LpmaEnableThreadData lpmaEnableThread;
127 #endif  // CHRE_DAEMON_LPMA_ENABLED
128 
129 //! The host ID to use when preloading nanoapps. This is used before the server
130 //! is started and is sufficiently high enough so as to not collide with any
131 //! clients after the server starts.
132 static const uint16_t kHostClientIdDaemon = UINT16_MAX;
133 
134 //! Contains a set of transaction IDs used to load the preloaded nanoapps.
135 //! The IDs are stored in the order they are sent.
136 static std::queue<uint32_t> gPreloadedNanoappPendingTransactionIds;
137 
138 //! Set to true when we request a graceful shutdown of CHRE
139 static volatile bool chre_shutdown_requested = false;
140 
141 #if !defined(LOG_NDEBUG) || LOG_NDEBUG != 0
log_buffer(const uint8_t *,size_t)142 static void log_buffer(const uint8_t * /*buffer*/, size_t /*size*/) {}
143 #else
log_buffer(const uint8_t * buffer,size_t size)144 static void log_buffer(const uint8_t *buffer, size_t size) {
145   char line[32];
146   int offset = 0;
147   char line_chars[32];
148   int offset_chars = 0;
149 
150   size_t orig_size = size;
151   if (size > 128) {
152     size = 128;
153     LOGV("Dumping first 128 bytes of buffer of size %zu", orig_size);
154   } else {
155     LOGV("Dumping buffer of size %zu bytes", size);
156   }
157   for (size_t i = 1; i <= size; ++i) {
158     offset += snprintf(&line[offset], sizeof(line) - offset, "%02x ",
159                        buffer[i - 1]);
160     offset_chars += snprintf(
161         &line_chars[offset_chars], sizeof(line_chars) - offset_chars,
162         "%c", (isprint(buffer[i - 1])) ? buffer[i - 1] : '.');
163     if ((i % 8) == 0) {
164       LOGV("  %s\t%s", line, line_chars);
165       offset = 0;
166       offset_chars = 0;
167     } else if ((i % 4) == 0) {
168       offset += snprintf(&line[offset], sizeof(line) - offset, " ");
169     }
170   }
171 
172   if (offset > 0) {
173     char tabs[8];
174     char *pos = tabs;
175     while (offset < 28) {
176       *pos++ = '\t';
177       offset += 8;
178     }
179     *pos = '\0';
180     LOGV("  %s%s%s", line, tabs, line_chars);
181   }
182 }
183 #endif
184 
parseAndEmitLogMessages(unsigned char * message)185 static void parseAndEmitLogMessages(unsigned char *message) {
186   const fbs::MessageContainer *container = fbs::GetMessageContainer(message);
187   const auto *logMessage = static_cast<const fbs::LogMessage *>(
188       container->message());
189 
190   constexpr size_t kLogMessageHeaderSize = 2 + sizeof(uint64_t);
191   const flatbuffers::Vector<int8_t>& logData = *logMessage->buffer();
192   for (size_t i = 0; i <= (logData.size() - kLogMessageHeaderSize);) {
193     // Parse out the log level.
194     const char *log = reinterpret_cast<const char *>(&logData.data()[i]);
195     char logLevel = *log;
196     log++;
197 
198     // Parse out the timestampNanos.
199     uint64_t timestampNanos;
200     memcpy(&timestampNanos, log, sizeof(uint64_t));
201     timestampNanos = le64toh(timestampNanos);
202     log += sizeof(uint64_t);
203 
204     float timestampSeconds = timestampNanos / 1e9;
205 
206     // Log the message.
207     switch (logLevel) {
208       case 1:
209         LOGE(HUB_LOG_FORMAT_STR, timestampSeconds, log);
210         break;
211       case 2:
212         LOGW(HUB_LOG_FORMAT_STR, timestampSeconds, log);
213         break;
214       case 3:
215         LOGI(HUB_LOG_FORMAT_STR, timestampSeconds, log);
216         break;
217       case 4:
218         LOGD(HUB_LOG_FORMAT_STR, timestampSeconds, log);
219         break;
220       default:
221         LOGE("Invalid CHRE hub log level, omitting log");
222     }
223 
224     // Advance the log pointer.
225     size_t strLen = strlen(log);
226     i += kLogMessageHeaderSize + strLen;
227   }
228 }
229 
getTimeOffset(bool * success)230 static int64_t getTimeOffset(bool *success) {
231   int64_t timeOffset = 0;
232 
233 #if defined(__aarch64__)
234   // Reads the system time counter (CNTVCT) and its frequency (CNTFRQ)
235   // CNTVCT is used in the sensors HAL for time synchronization.
236   // More information can be found in the ARM reference manual
237   // (http://infocenter.arm.com/help/index.jsp?topic=
238   // /com.arm.doc.100048_0002_05_en/jfa1406793266982.html)
239   // Use uint64_t to store since the MRS instruction uses 64 bit (X) registers
240   // (http://infocenter.arm.com/help/topic/
241   // com.arm.doc.den0024a/ch06s05s02.html)
242   uint64_t qTimerCount = 0, qTimerFreq = 0;
243   uint64_t hostTimeNano = elapsedRealtimeNano();
244   asm volatile("mrs %0, cntvct_el0" : "=r"(qTimerCount));
245   asm volatile("mrs %0, cntfrq_el0" : "=r"(qTimerFreq));
246 
247   constexpr uint64_t kOneSecondInNanoseconds = 1000000000;
248   if (qTimerFreq != 0) {
249     // Get the seconds part first, then convert the remainder to prevent
250     // overflow
251     uint64_t qTimerNanos = (qTimerCount / qTimerFreq);
252     if (qTimerNanos > UINT64_MAX / kOneSecondInNanoseconds) {
253       LOGE("CNTVCT_EL0 conversion to nanoseconds overflowed during time sync."
254            " Aborting time sync.");
255       *success = false;
256     } else {
257       qTimerNanos *= kOneSecondInNanoseconds;
258 
259       // Round the remainder portion to the nearest nanosecond
260       uint64_t remainder = (qTimerCount % qTimerFreq);
261       qTimerNanos +=
262           (remainder * kOneSecondInNanoseconds + qTimerFreq / 2) / qTimerFreq;
263 
264       timeOffset = hostTimeNano - qTimerNanos;
265       *success = true;
266     }
267   } else {
268     LOGE("CNTFRQ_EL0 had 0 value. Aborting time sync.");
269     *success = false;
270   }
271 #else
272 #error "Unsupported CPU architecture type"
273 #endif
274 
275   return timeOffset;
276 }
277 
sendTimeSyncMessage()278 static void sendTimeSyncMessage() {
279   bool timeSyncSuccess = true;
280   int64_t timeOffset = getTimeOffset(&timeSyncSuccess);
281 
282   if (timeSyncSuccess) {
283     flatbuffers::FlatBufferBuilder builder(64);
284     HostProtocolHost::encodeTimeSyncMessage(builder, timeOffset);
285     int success = chre_slpi_deliver_message_from_host(
286         static_cast<const unsigned char *>(builder.GetBufferPointer()),
287         static_cast<int>(builder.GetSize()));
288 
289     if (success != 0) {
290       LOGE("Failed to deliver timestamp message from host to CHRE: %d", success);
291     }
292   }
293 }
294 
295 #ifdef CHRE_DAEMON_LPMA_ENABLED
296 
acquireWakeLock()297 static void acquireWakeLock() {
298   if (acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLockName) != 0) {
299     LOGE("Failed to acquire wakelock");
300   }
301 }
302 
releaseWakeLock()303 static void releaseWakeLock() {
304   static bool initialRelease = true;
305 
306   // It's expected to get an error when we first try to release the wakelock
307   // as it won't exist unless it was leaked previously - don't output a
308   // false warning for this case
309   if (release_wake_lock(kWakeLockName) != 0 && !initialRelease) {
310     LOGE("Failed to release wakelock");
311   }
312 
313   initialRelease = false;
314 }
315 
316 /**
317  * Sets the target state for LPMA to be enabled. This triggers another thread to
318  * perform the async operation of enabling or disabling the LPMA use case.
319  *
320  * @param enabled Whether LPMA is to be enabled or disabled.
321  */
setLpmaState(bool enabled)322 static void setLpmaState(bool enabled) {
323   pthread_mutex_lock(&lpmaEnableThread.mutex);
324   lpmaEnableThread.targetLpmaEnabled = enabled;
325   pthread_mutex_unlock(&lpmaEnableThread.mutex);
326   pthread_cond_signal(&lpmaEnableThread.cond);
327 }
328 
329 /**
330  * Loads the LPMA use case via the SoundTrigger HAL HIDL service.
331  *
332  * @param lpmaHandle The handle that was generated as a result of enabling
333  *        the LPMA use case successfully.
334  * @return true if LPMA was enabled successfully, false otherwise.
335  */
loadLpma(SoundModelHandle * lpmaHandle)336 static bool loadLpma(SoundModelHandle *lpmaHandle) {
337   LOGD("Loading LPMA");
338 
339   ISoundTriggerHw::SoundModel soundModel;
340   soundModel.type = SoundModelType::GENERIC;
341   soundModel.vendorUuid.timeLow = 0x57CADDB1;
342   soundModel.vendorUuid.timeMid = 0xACDB;
343   soundModel.vendorUuid.versionAndTimeHigh = 0x4DCE;
344   soundModel.vendorUuid.variantAndClockSeqHigh = 0x8CB0;
345 
346   const uint8_t uuidNode[6] = { 0x2E, 0x95, 0xA2, 0x31, 0x3A, 0xEE };
347   memcpy(&soundModel.vendorUuid.node[0], uuidNode, sizeof(uuidNode));
348   soundModel.data.resize(1);  // Insert a dummy byte to bypass HAL NULL checks.
349 
350   bool loaded = false;
351   sp<ISoundTriggerHw> stHal = ISoundTriggerHw::getService();
352   if (stHal == nullptr) {
353     LOGE("Failed to get ST HAL service for LPMA load");
354   } else {
355     int32_t loadResult;
356     Return<void> hidlResult = stHal->loadSoundModel(soundModel, NULL, 0,
357         [&](int32_t retval, SoundModelHandle handle) {
358             loadResult = retval;
359             *lpmaHandle = handle;
360         });
361 
362     if (hidlResult.isOk()) {
363       if (loadResult == 0) {
364         LOGI("Loaded LPMA");
365         loaded = true;
366       } else {
367         LOGE("Failed to load LPMA with %" PRId32, loadResult);
368       }
369     } else {
370       LOGE("Failed to load LPMA due to hidl error %s",
371            hidlResult.description().c_str());
372     }
373   }
374 
375   return loaded;
376 }
377 
378 /**
379  * Unloads the LPMA use case via the SoundTrigger HAL HIDL service. This
380  * function does not indicate success/failure as it is expected that even in the
381  * event of a failure to unload, the use case will be unloaded. As long as the
382  * sound trigger HAL received the request we can be assured that the use case
383  * will be unloaded (even if it means reseting the codec or otherwise).
384  *
385  * @param lpmaHandle A handle that was previously produced by the setLpmaEnabled
386  *        function. This is the handle that is unloaded from the ST HAL to
387  *        disable LPMA.
388  */
unloadLpma(SoundModelHandle lpmaHandle)389 static void unloadLpma(SoundModelHandle lpmaHandle) {
390   LOGD("Unloading LPMA");
391 
392   sp<ISoundTriggerHw> stHal = ISoundTriggerHw::getService();
393   if (stHal == nullptr) {
394     LOGE("Failed to get ST HAL service for LPMA unload");
395   } else {
396     Return<int32_t> hidlResult = stHal->unloadSoundModel(lpmaHandle);
397 
398     if (hidlResult.isOk()) {
399       if (hidlResult == 0) {
400         LOGI("Unloaded LPMA");
401       } else {
402         LOGE("Failed to unload LPMA with %" PRId32, int32_t(hidlResult));
403       }
404     } else {
405       LOGE("Failed to unload LPMA due to hidl error %s",
406            hidlResult.description().c_str());
407     }
408   }
409 }
410 
chreLpmaEnableThread(void * arg)411 static void *chreLpmaEnableThread(void *arg) {
412   auto *state = static_cast<LpmaEnableThreadData *>(arg);
413 
414   const useconds_t kInitialRetryDelayUs = 500000;
415   const int kRetryGrowthFactor = 2;
416   const int kRetryGrowthLimit = 5;  // Terminates at 8s retry interval.
417   const int kRetryWakeLockLimit = 10;  // Retry with a wakelock 10 times.
418 
419   int retryCount = 0;
420   useconds_t retryDelay = 0;
421   SoundModelHandle lpmaHandle;
422 
423   while (true) {
424     pthread_mutex_lock(&state->mutex);
425     if (state->currentLpmaEnabled == state->targetLpmaEnabled) {
426       retryCount = 0;
427       retryDelay = 0;
428       releaseWakeLock();  // Allow the system to suspend while waiting.
429       pthread_cond_wait(&state->cond, &state->mutex);
430       acquireWakeLock();  // Ensure the system stays up while retrying.
431     } else if (state->targetLpmaEnabled && loadLpma(&lpmaHandle)) {
432       state->currentLpmaEnabled = state->targetLpmaEnabled;
433     } else if (!state->targetLpmaEnabled) {
434       // Regardless of whether the use case fails to unload, set the
435       // currentLpmaEnabled to the targetLpmaEnabled. This will allow the next
436       // enable request to proceed. After a failure to unload occurs, the
437       // supplied handle is invalid and should not be unloaded again.
438       unloadLpma(lpmaHandle);
439       state->currentLpmaEnabled = state->targetLpmaEnabled;
440     } else {
441       // Unlock while delaying to avoid blocking the client thread. No shared
442       // state is modified here.
443       pthread_mutex_unlock(&state->mutex);
444 
445       if (retryDelay == 0) {
446         retryDelay = kInitialRetryDelayUs;
447       } else if (retryCount < kRetryGrowthLimit) {
448         retryDelay *= kRetryGrowthFactor;
449       }
450 
451       LOGD("Delaying retry %d for %uus", retryCount, retryDelay);
452       usleep(retryDelay);
453 
454       retryCount++;
455       if (retryCount > kRetryWakeLockLimit) {
456         releaseWakeLock();
457       }
458 
459       pthread_mutex_lock(&state->mutex);
460     }
461 
462     pthread_mutex_unlock(&state->mutex);
463   }
464 
465   LOGV("LPMA enable thread exited");
466   return NULL;
467 }
468 
469 /**
470  * Initializes the data shared with the LPMA enable thread and starts the
471  * thread.
472  *
473  * @param data Pointer to structure containing the (uninitialized) condition
474  *        variable and associated data passed to the LPMA enable thread.
475  * @return true on success, false otherwise.
476  */
initLpmaEnableThread(LpmaEnableThreadData * data)477 static bool initLpmaEnableThread(LpmaEnableThreadData *data) {
478   bool success = false;
479   int ret;
480 
481   if ((ret = pthread_mutex_init(&data->mutex, NULL)) != 0) {
482     LOG_ERROR("Failed to initialize lpma enable mutex", ret);
483   } else if ((ret = pthread_cond_init(&data->cond, NULL)) != 0) {
484     LOG_ERROR("Failed to initialize lpma enable condition variable", ret);
485   } else if (!start_thread(&data->thread, chreLpmaEnableThread, data)) {
486     LOGE("Couldn't start lpma enable thread");
487   } else {
488     data->currentLpmaEnabled = false;
489     data->targetLpmaEnabled = false;
490     success = true;
491   }
492 
493   return success;
494 }
495 
496 #endif  // CHRE_DAEMON_LPMA_ENABLED
497 
498 /**
499  * Sends a message to CHRE.
500  *
501  * @param clientId The client ID that this message originates from.
502  * @param data The data to pass down.
503  * @param length The size of the data to send.
504  * @return true if successful, false otherwise.
505  */
sendMessageToChre(uint16_t clientId,void * data,size_t length)506 static bool sendMessageToChre(uint16_t clientId, void *data, size_t length) {
507   constexpr size_t kMaxPayloadSize = 1024 * 1024;  // 1 MiB
508 
509   // This limitation is due to FastRPC, but there's no case where we should come
510   // close to this limit...
511   static_assert(kMaxPayloadSize <= INT32_MAX,
512                 "DSP uses 32-bit signed integers to represent message size");
513 
514   bool success = false;
515   if (length > kMaxPayloadSize) {
516     LOGE("Message too large (got %zu, max %zu bytes)", length, kMaxPayloadSize);
517   } else if (!HostProtocolHost::mutateHostClientId(data, length, clientId)) {
518     LOGE("Couldn't set host client ID in message container!");
519   } else {
520     LOGV("Delivering message from host (size %zu)", length);
521     log_buffer(static_cast<const uint8_t *>(data), length);
522     int ret = chre_slpi_deliver_message_from_host(
523         static_cast<const unsigned char *>(data), static_cast<int>(length));
524     if (ret != 0) {
525       LOGE("Failed to deliver message from host to CHRE: %d", ret);
526     } else {
527       success = true;
528     }
529   }
530 
531   return success;
532 }
533 
534 /**
535  * Loads a nanoapp by sending the nanoapp filename to the CHRE framework. This
536  * method will return after sending the request so no guarantee is made that
537  * the nanoapp is loaded until after the response is received.
538  *
539  * @param appId The ID of the nanoapp to load.
540  * @param appVersion The version of the nanoapp to load.
541  * @param appTargetApiVersion The version of the CHRE API that the app targets.
542  * @param appBinaryName The name of the binary as stored in the filesystem. This
543  *     will be used to load the nanoapp into CHRE.
544  * @param transactionId The transaction ID to use when loading.
545  * @return true if a request was successfully sent, false otherwise.
546  */
sendNanoappLoad(uint64_t appId,uint32_t appVersion,uint32_t appTargetApiVersion,const std::string & appBinaryName,uint32_t transactionId)547 static bool sendNanoappLoad(
548     uint64_t appId, uint32_t appVersion, uint32_t appTargetApiVersion,
549     const std::string& appBinaryName, uint32_t transactionId) {
550   flatbuffers::FlatBufferBuilder builder;
551   HostProtocolHost::encodeLoadNanoappRequestForFile(
552       builder, transactionId, appId, appVersion, appTargetApiVersion,
553       appBinaryName.c_str());
554 
555   bool success = sendMessageToChre(
556       kHostClientIdDaemon, builder.GetBufferPointer(), builder.GetSize());
557 
558   if (!success) {
559     LOGE("Failed to send nanoapp filename.");
560   } else {
561     gPreloadedNanoappPendingTransactionIds.push(transactionId);
562   }
563 
564   return success;
565 }
566 
567 /**
568  * Sends a preloaded nanoapp filename / metadata to CHRE.
569  *
570  * @param header The nanoapp header binary blob.
571  * @param nanoappName The filename of the nanoapp to be loaded.
572  * @param transactionId The transaction ID to use when loading the app.
573  * @return true if successful, false otherwise.
574  */
loadNanoapp(const std::vector<uint8_t> & header,const std::string & nanoappName,uint32_t transactionId)575 static bool loadNanoapp(const std::vector<uint8_t>& header,
576                         const std::string& nanoappName,
577                         uint32_t transactionId) {
578   // This struct comes from build/build_template.mk and must not be modified.
579   // Refer to that file for more details.
580   struct NanoAppBinaryHeader {
581     uint32_t headerVersion;
582     uint32_t magic;
583     uint64_t appId;
584     uint32_t appVersion;
585     uint32_t flags;
586     uint64_t hwHubType;
587     uint8_t targetChreApiMajorVersion;
588     uint8_t targetChreApiMinorVersion;
589     uint8_t reserved[6];
590   } __attribute__((packed));
591 
592   bool success = false;
593   if (header.size() != sizeof(NanoAppBinaryHeader)) {
594     LOGE("Header size mismatch");
595   } else {
596     // The header blob contains the struct above.
597     const auto *appHeader = reinterpret_cast<
598         const NanoAppBinaryHeader *>(header.data());
599 
600     // Build the target API version from major and minor.
601     uint32_t targetApiVersion = (appHeader->targetChreApiMajorVersion << 24)
602         | (appHeader->targetChreApiMinorVersion << 16);
603 
604     success = sendNanoappLoad(appHeader->appId, appHeader->appVersion,
605                               targetApiVersion, nanoappName, transactionId);
606   }
607 
608   return success;
609 }
610 
611 /**
612  * Loads the supplied file into the provided buffer.
613  *
614  * @param filename The name of the file to load.
615  * @param buffer The buffer to load into.
616  * @return true if successful, false otherwise.
617  */
readFileContents(const char * filename,std::vector<uint8_t> * buffer)618 static bool readFileContents(const char *filename,
619                              std::vector<uint8_t> *buffer) {
620   bool success = false;
621   std::ifstream file(filename, std::ios::binary | std::ios::ate);
622   if (!file) {
623     LOGE("Couldn't open file '%s': %d (%s)", filename, errno, strerror(errno));
624   } else {
625     ssize_t size = file.tellg();
626     file.seekg(0, std::ios::beg);
627 
628     buffer->resize(size);
629     if (!file.read(reinterpret_cast<char *>(buffer->data()), size)) {
630       LOGE("Couldn't read from file '%s': %d (%s)",
631            filename, errno, strerror(errno));
632     } else {
633       success = true;
634     }
635   }
636 
637   return success;
638 }
639 
640 /**
641  * Loads a preloaded nanoapp given a filename to load from. Allows the
642  * transaction to complete before the nanoapp starts so the server can start
643  * serving requests as soon as possible.
644  *
645  * @param name The filepath to load the nanoapp from.
646  * @param transactionId The transaction ID to use when loading the app.
647  */
loadPreloadedNanoapp(const std::string & name,uint32_t transactionId)648 static void loadPreloadedNanoapp(const std::string& name,
649                                  uint32_t transactionId) {
650   std::vector<uint8_t> headerBuffer;
651 
652   std::string headerFilename = std::string(name) + ".napp_header";
653   std::string nanoappFilename = std::string(name) + ".so";
654 
655   // Only send the filename itself e.g activity.so since CHRE will load from
656   // the same directory its own binary resides in.
657   nanoappFilename = nanoappFilename.substr(
658       nanoappFilename.find_last_of("/\\") + 1);
659   if (nanoappFilename.empty()) {
660     LOGE("Failed to get the name of the nanoapp %s", name.c_str());
661   } else if (readFileContents(headerFilename.c_str(), &headerBuffer)
662       && !loadNanoapp(headerBuffer, nanoappFilename, transactionId)) {
663     LOGE("Failed to load nanoapp: '%s'", name.c_str());
664   }
665 }
666 
667 /**
668  * Attempts to load all preloaded nanoapps from a config file. The config file
669  * is expected to be valid JSON with the following structure:
670  *
671  * { "nanoapps": [
672  *     "/path/to/nanoapp_1",
673  *     "/path/to/nanoapp_2"
674  * ]}
675  *
676  * The napp_header and so files will both be loaded. All errors are logged.
677  */
loadPreloadedNanoapps()678 static void loadPreloadedNanoapps() {
679   constexpr char kPreloadedNanoappsConfigPath[] =
680       "/vendor/etc/chre/preloaded_nanoapps.json";
681   std::ifstream configFileStream(kPreloadedNanoappsConfigPath);
682 
683   Json::Reader reader;
684   Json::Value config;
685   if (!configFileStream) {
686     LOGE("Failed to open config file '%s': %d (%s)",
687          kPreloadedNanoappsConfigPath, errno, strerror(errno));
688   } else if (!reader.parse(configFileStream, config)) {
689     LOGE("Failed to parse nanoapp config file");
690   } else if (!config.isMember("nanoapps")) {
691     LOGE("Malformed preloaded nanoapps config");
692   } else {
693     for (Json::ArrayIndex i = 0; i < config["nanoapps"].size(); i++) {
694       const Json::Value& nanoapp = config["nanoapps"][i];
695       loadPreloadedNanoapp(nanoapp.asString(), static_cast<uint32_t>(i));
696     }
697   }
698 }
699 
700 /**
701  * Handles a message that is directed towards the daemon.
702  *
703  * @param message The message sent to the daemon.
704  */
handleDaemonMessage(const uint8_t * message)705 static void handleDaemonMessage(const uint8_t *message) {
706   std::unique_ptr<fbs::MessageContainerT> container =
707       fbs::UnPackMessageContainer(message);
708   if (container->message.type
709           != fbs::ChreMessage::LoadNanoappResponse) {
710     LOGE("Invalid message from CHRE directed to daemon");
711   } else {
712     const auto *response = container->message.AsLoadNanoappResponse();
713     if (gPreloadedNanoappPendingTransactionIds.empty()) {
714       LOGE("Received nanoapp load response with no pending load");
715     } else if (gPreloadedNanoappPendingTransactionIds.front()
716                    != response->transaction_id) {
717       LOGE("Received nanoapp load response with ID %" PRIu32
718            " expected transaction id %" PRIu32, response->transaction_id,
719            gPreloadedNanoappPendingTransactionIds.front());
720     } else {
721       if (!response->success) {
722         LOGE("Received unsuccessful nanoapp load response with ID %" PRIu32,
723              gPreloadedNanoappPendingTransactionIds.front());
724       }
725       gPreloadedNanoappPendingTransactionIds.pop();
726     }
727   }
728 }
729 
730 /**
731  * Entry point for the thread that receives messages sent by CHRE.
732  *
733  * @return always returns NULL
734  */
chre_message_to_host_thread(void * arg)735 static void *chre_message_to_host_thread(void *arg) {
736   unsigned char messageBuffer[4096];
737   unsigned int messageLen;
738   int result = 0;
739   auto *server = static_cast<::android::chre::SocketServer *>(arg);
740 
741   while (true) {
742     messageLen = 0;
743     LOGV("Calling into chre_slpi_get_message_to_host");
744     result = chre_slpi_get_message_to_host(
745         messageBuffer, sizeof(messageBuffer), &messageLen);
746     LOGV("Got message from CHRE with size %u (result %d)", messageLen, result);
747 
748     if (result == CHRE_FASTRPC_ERROR_SHUTTING_DOWN) {
749       LOGD("CHRE shutting down, exiting CHRE->Host message thread");
750       break;
751     } else if (result == CHRE_FASTRPC_SUCCESS && messageLen > 0) {
752       log_buffer(messageBuffer, messageLen);
753       uint16_t hostClientId;
754       fbs::ChreMessage messageType;
755       if (!HostProtocolHost::extractHostClientIdAndType(
756           messageBuffer, messageLen, &hostClientId, &messageType)) {
757         LOGW("Failed to extract host client ID from message - sending "
758              "broadcast");
759         hostClientId = chre::kHostClientIdUnspecified;
760       }
761 
762       if (messageType == fbs::ChreMessage::LogMessage) {
763         parseAndEmitLogMessages(messageBuffer);
764       } else if (messageType == fbs::ChreMessage::TimeSyncRequest) {
765         sendTimeSyncMessage();
766 #ifdef CHRE_DAEMON_LPMA_ENABLED
767       } else if (messageType == fbs::ChreMessage::LowPowerMicAccessRequest) {
768         setLpmaState(true);
769       } else if (messageType == fbs::ChreMessage::LowPowerMicAccessRelease) {
770         setLpmaState(false);
771 #endif  // CHRE_DAEMON_LPMA_ENABLED
772       } else if (hostClientId == kHostClientIdDaemon) {
773         handleDaemonMessage(messageBuffer);
774       } else if (hostClientId == chre::kHostClientIdUnspecified) {
775         server->sendToAllClients(messageBuffer,
776                                  static_cast<size_t>(messageLen));
777       } else {
778         server->sendToClientById(messageBuffer,
779                                  static_cast<size_t>(messageLen), hostClientId);
780       }
781     } else if (!chre_shutdown_requested) {
782       LOGE("Received an unknown result and no shutdown was requested. Quitting");
783       exit(-1);
784     } else {
785       // Received an unknown result but a shutdown was requested. Break from the
786       // loop to allow the daemon to cleanup.
787       break;
788     }
789   }
790 
791   LOGV("Message to host thread exited");
792   return NULL;
793 }
794 
795 /**
796  * Entry point for the thread that blocks in a FastRPC call to monitor for
797  * abnormal exit of CHRE or reboot of the DSP.
798  *
799  * @return always returns NULL
800  */
chre_monitor_thread(void * arg)801 static void *chre_monitor_thread(void *arg) {
802   (void) arg;
803   int ret = chre_slpi_wait_on_thread_exit();
804   if (!chre_shutdown_requested) {
805     LOGE("Detected unexpected CHRE thread exit (%d)\n", ret);
806     exit(EXIT_FAILURE);
807   }
808 
809   LOGV("Monitor thread exited");
810   return NULL;
811 }
812 
813 /**
814  * Entry point for the "reverse" monitor thread, which invokes a FastRPC method
815  * to register a thread destructor, and blocks waiting on a condition variable.
816  * This allows for the code running in the DSP to detect abnormal shutdown of
817  * the host-side binary and perform graceful cleanup.
818  *
819  * @return always returns NULL
820  */
chre_reverse_monitor_thread(void * arg)821 static void *chre_reverse_monitor_thread(void *arg) {
822   struct reverse_monitor_thread_data *thread_data =
823       (struct reverse_monitor_thread_data *) arg;
824 
825   int ret = chre_slpi_initialize_reverse_monitor();
826   if (ret != CHRE_FASTRPC_SUCCESS) {
827     LOGE("Failed to initialize reverse monitor: %d", ret);
828   } else {
829     // Block here on the condition variable until the main thread notifies
830     // us to exit
831     pthread_mutex_lock(&thread_data->mutex);
832     pthread_cond_wait(&thread_data->cond, &thread_data->mutex);
833     pthread_mutex_unlock(&thread_data->mutex);
834   }
835 
836   LOGV("Reverse monitor thread exited");
837   return NULL;
838 }
839 
840 /**
841  * Initializes the data shared with the reverse monitor thread, and starts the
842  * thread.
843  *
844  * @param data Pointer to structure containing the (uninitialized) condition
845  *        variable and associated data passed to the reverse monitor thread
846  *
847  * @return true on success
848  */
init_reverse_monitor(struct reverse_monitor_thread_data * data)849 static bool init_reverse_monitor(struct reverse_monitor_thread_data *data) {
850   bool success = false;
851   int ret;
852 
853   if ((ret = pthread_mutex_init(&data->mutex, NULL)) != 0) {
854     LOG_ERROR("Failed to initialize mutex", ret);
855   } else if ((ret = pthread_cond_init(&data->cond, NULL)) != 0) {
856     LOG_ERROR("Failed to initialize condition variable", ret);
857   } else if (!start_thread(&data->thread, chre_reverse_monitor_thread, data)) {
858     LOGE("Couldn't start reverse monitor thread");
859   } else {
860     success = true;
861   }
862 
863   return success;
864 }
865 
866 /**
867  * Start a thread with default attributes, or log an error on failure
868  *
869  * @return bool true if the thread was successfully started
870  */
start_thread(pthread_t * thread_handle,thread_entry_point_f * thread_entry,void * arg)871 static bool start_thread(pthread_t *thread_handle,
872                          thread_entry_point_f *thread_entry,
873                          void *arg) {
874   int ret = pthread_create(thread_handle, NULL, thread_entry, arg);
875   if (ret != 0) {
876     LOG_ERROR("pthread_create failed", ret);
877   }
878   return (ret == 0);
879 }
880 
881 namespace {
882 
onMessageReceivedFromClient(uint16_t clientId,void * data,size_t length)883 void onMessageReceivedFromClient(uint16_t clientId, void *data, size_t length) {
884   sendMessageToChre(clientId, data, length);
885 }
886 
887 }  // anonymous namespace
888 
main()889 int main() {
890   int ret = -1;
891   pthread_t monitor_thread;
892   pthread_t msg_to_host_thread;
893 
894   struct reverse_monitor_thread_data reverse_monitor;
895   ::android::chre::SocketServer server;
896 
897 #ifdef ADSPRPC
898   remote_handle remote_handle_fd = 0xFFFFFFFF;
899   LOGD("Attaching to ADSP sensors PD");
900   if (remote_handle_open(ITRANSPORT_PREFIX "createstaticpd:sensorspd",
901                          &remote_handle_fd)) {
902     LOGE("Failed to open remote handle for sensorspd");
903   } else {
904     LOGV("Successfully opened remote handle for sensorspd");
905   }
906 #endif  // ADSPRPC
907 
908   if (!init_reverse_monitor(&reverse_monitor)) {
909     LOGE("Couldn't initialize reverse monitor");
910 #ifdef CHRE_DAEMON_LPMA_ENABLED
911   } else if (!initLpmaEnableThread(&lpmaEnableThread)) {
912     LOGE("Couldn't initialize LPMA enable thread");
913 #endif  // CHRE_DAEMON_LPMA_ENABLED
914   } else {
915     // Send time offset message before nanoapps start
916     sendTimeSyncMessage();
917     if ((ret = chre_slpi_start_thread()) != CHRE_FASTRPC_SUCCESS) {
918       LOGE("Failed to start CHRE: %d", ret);
919     } else {
920       if (!start_thread(&monitor_thread, chre_monitor_thread, NULL)) {
921         LOGE("Couldn't start monitor thread");
922       } else if (!start_thread(&msg_to_host_thread, chre_message_to_host_thread,
923                                &server)) {
924         LOGE("Couldn't start CHRE->Host message thread");
925       } else {
926         LOGI("CHRE started");
927         loadPreloadedNanoapps();
928 
929         // TODO: take 2nd argument as command-line parameter
930         server.run("chre", true, onMessageReceivedFromClient);
931       }
932 
933       chre_shutdown_requested = true;
934       ret = chre_slpi_stop_thread();
935       if (ret != CHRE_FASTRPC_SUCCESS) {
936         LOGE("Failed to stop CHRE: %d", ret);
937       } else {
938         // TODO: don't call pthread_join if the thread failed to start
939         LOGV("Joining monitor thread");
940         ret = pthread_join(monitor_thread, NULL);
941         if (ret != 0) {
942           LOG_ERROR("Join on monitor thread failed", ret);
943         }
944 
945         LOGV("Joining reverse monitor thread");
946         pthread_cond_signal(&reverse_monitor.cond);
947         ret = pthread_join(reverse_monitor.thread, NULL);
948         if (ret != 0) {
949           LOG_ERROR("Join on reverse monitor thread failed", ret);
950         }
951 
952         LOGV("Joining message to host thread");
953         ret = pthread_join(msg_to_host_thread, NULL);
954         if (ret != 0) {
955           LOG_ERROR("Join on monitor thread failed", ret);
956         }
957 
958         LOGI("Shutdown complete");
959       }
960     }
961   }
962 
963   return ret;
964 }
965 
966