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(×tampNanos, 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