• 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 the SLPI via FastRPC.
20  *
21  * Several threads are required for this functionality:
22  *   - Main thread: blocked waiting on SIGINT/SIGTERM, and requests graceful
23  *     shutdown of CHRE when caught
24  *   - Monitor thread: persistently blocked in a FastRPC call to the SLPI that
25  *     only returns when CHRE exits or the SLPI crashes
26  *     - TODO: see whether we can merge this with the RX thread
27  *   - Reverse monitor thread: after initializing the SLPI-side monitor for this
28  *     process, blocks on a condition variable. If this thread exits, CHRE on
29  *     the SLPI side will be notified and shut down (this is only possible if
30  *     this thread is not blocked in a FastRPC call).
31  *     - TODO: confirm this and see whether we can merge this responsibility
32  *       into the TX thread
33  *   - Message to host (RX) thread: blocks in FastRPC call, waiting on incoming
34  *     message from CHRE
35  *   - Message to CHRE (TX) thread: blocks waiting on outbound queue, delivers
36  *     messages to CHRE over FastRPC
37  *
38  * TODO: This file originated from an implementation for another device, and was
39  * written in C, but then it was converted to C++ when adding socket support. It
40  * should be fully converted to C++.
41  */
42 
43 // Disable verbose logging
44 // TODO: use property_get_bool to make verbose logging runtime configurable
45 // #define LOG_NDEBUG 0
46 
47 #include <ctype.h>
48 #include <inttypes.h>
49 #include <pthread.h>
50 #include <stdbool.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <unistd.h>
55 
56 #include "chre/platform/slpi/fastrpc.h"
57 #include "chre_host/log.h"
58 #include "chre_host/host_protocol_host.h"
59 #include "chre_host/socket_server.h"
60 #include "generated/chre_slpi.h"
61 
62 #include <utils/SystemClock.h>
63 
64 //! The format string to use for logs from the CHRE implementation.
65 #define HUB_LOG_FORMAT_STR "Hub (t=%.6f): %s"
66 
67 #ifdef CHRE_DAEMON_LPMA_ENABLED
68 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
69 
70 using android::sp;
71 using android::hardware::Return;
72 using android::hardware::soundtrigger::V2_0::ISoundTriggerHw;
73 using android::hardware::soundtrigger::V2_0::SoundModelHandle;
74 using android::hardware::soundtrigger::V2_0::SoundModelType;
75 #endif  // CHRE_DAEMON_LPMA_ENABLED
76 
77 using android::chre::HostProtocolHost;
78 using android::elapsedRealtimeNano;
79 
80 // Aliased for consistency with the way these symbols are referenced in
81 // CHRE-side code
82 namespace fbs = ::chre::fbs;
83 
84 typedef void *(thread_entry_point_f)(void *);
85 
86 struct reverse_monitor_thread_data {
87   pthread_t       thread;
88   pthread_mutex_t mutex;
89   pthread_cond_t  cond;
90 };
91 
92 static void *chre_message_to_host_thread(void *arg);
93 static void *chre_monitor_thread(void *arg);
94 static void *chre_reverse_monitor_thread(void *arg);
95 static bool init_reverse_monitor(struct reverse_monitor_thread_data *data);
96 static bool start_thread(pthread_t *thread_handle,
97                          thread_entry_point_f *thread_entry,
98                          void *arg);
99 
100 #ifdef CHRE_DAEMON_LPMA_ENABLED
101 //! The name of the wakelock to use for the CHRE daemon.
102 static const char kWakeLockName[] = "chre_daemon";
103 
104 //! The file descriptor to wake lock.
105 static int gWakeLockFd = -1;
106 
107 //! The file descriptor to wake unlock.
108 static int gWakeUnlockFd = -1;
109 
110 struct LpmaEnableThreadData {
111   pthread_t thread;
112   pthread_mutex_t mutex;
113   pthread_cond_t cond;
114   bool currentLpmaEnabled;
115   bool targetLpmaEnabled;
116 };
117 
118 static LpmaEnableThreadData lpmaEnableThread;
119 #endif  // CHRE_DAEMON_LPMA_ENABLED
120 
121 //! Set to true when we request a graceful shutdown of CHRE
122 static volatile bool chre_shutdown_requested = false;
123 
124 #if !defined(LOG_NDEBUG) || LOG_NDEBUG != 0
log_buffer(const uint8_t *,size_t)125 static void log_buffer(const uint8_t * /*buffer*/, size_t /*size*/) {}
126 #else
log_buffer(const uint8_t * buffer,size_t size)127 static void log_buffer(const uint8_t *buffer, size_t size) {
128   char line[32];
129   int offset = 0;
130   char line_chars[32];
131   int offset_chars = 0;
132 
133   size_t orig_size = size;
134   if (size > 128) {
135     size = 128;
136     LOGV("Dumping first 128 bytes of buffer of size %zu", orig_size);
137   } else {
138     LOGV("Dumping buffer of size %zu bytes", size);
139   }
140   for (size_t i = 1; i <= size; ++i) {
141     offset += snprintf(&line[offset], sizeof(line) - offset, "%02x ",
142                        buffer[i - 1]);
143     offset_chars += snprintf(
144         &line_chars[offset_chars], sizeof(line_chars) - offset_chars,
145         "%c", (isprint(buffer[i - 1])) ? buffer[i - 1] : '.');
146     if ((i % 8) == 0) {
147       LOGV("  %s\t%s", line, line_chars);
148       offset = 0;
149       offset_chars = 0;
150     } else if ((i % 4) == 0) {
151       offset += snprintf(&line[offset], sizeof(line) - offset, " ");
152     }
153   }
154 
155   if (offset > 0) {
156     char tabs[8];
157     char *pos = tabs;
158     while (offset < 28) {
159       *pos++ = '\t';
160       offset += 8;
161     }
162     *pos = '\0';
163     LOGV("  %s%s%s", line, tabs, line_chars);
164   }
165 }
166 #endif
167 
parseAndEmitLogMessages(unsigned char * message)168 static void parseAndEmitLogMessages(unsigned char *message) {
169   const fbs::MessageContainer *container = fbs::GetMessageContainer(message);
170   const auto *logMessage = static_cast<const fbs::LogMessage *>(
171       container->message());
172 
173   constexpr size_t kLogMessageHeaderSize = 2 + sizeof(uint64_t);
174   const flatbuffers::Vector<int8_t>& logData = *logMessage->buffer();
175   for (size_t i = 0; i <= (logData.size() - kLogMessageHeaderSize);) {
176     // Parse out the log level.
177     const char *log = reinterpret_cast<const char *>(&logData.data()[i]);
178     char logLevel = *log;
179     log++;
180 
181     // Parse out the timestampNanos.
182     uint64_t timestampNanos;
183     memcpy(&timestampNanos, log, sizeof(uint64_t));
184     timestampNanos = le64toh(timestampNanos);
185     log += sizeof(uint64_t);
186 
187     float timestampSeconds = timestampNanos / 1e9;
188 
189     // Log the message.
190     switch (logLevel) {
191       case 1:
192         LOGE(HUB_LOG_FORMAT_STR, timestampSeconds, log);
193         break;
194       case 2:
195         LOGW(HUB_LOG_FORMAT_STR, timestampSeconds, log);
196         break;
197       case 3:
198         LOGI(HUB_LOG_FORMAT_STR, timestampSeconds, log);
199         break;
200       case 4:
201         LOGD(HUB_LOG_FORMAT_STR, timestampSeconds, log);
202         break;
203       default:
204         LOGE("Invalid CHRE hub log level, omitting log");
205     }
206 
207     // Advance the log pointer.
208     size_t strLen = strlen(log);
209     i += kLogMessageHeaderSize + strLen;
210   }
211 }
212 
getTimeOffset(bool * success)213 static int64_t getTimeOffset(bool *success) {
214   int64_t timeOffset = 0;
215 
216 #if defined(__aarch64__)
217   // Reads the system time counter (CNTVCT) and its frequency (CNTFRQ)
218   // CNTVCT is used in the sensors HAL for time synchronization.
219   // More information can be found in the ARM reference manual
220   // (http://infocenter.arm.com/help/index.jsp?topic=
221   // /com.arm.doc.100048_0002_05_en/jfa1406793266982.html)
222   // Use uint64_t to store since the MRS instruction uses 64 bit (X) registers
223   // (http://infocenter.arm.com/help/topic/
224   // com.arm.doc.den0024a/ch06s05s02.html)
225   uint64_t qTimerCount = 0, qTimerFreq = 0;
226   uint64_t hostTimeNano = elapsedRealtimeNano();
227   asm volatile("mrs %0, cntvct_el0" : "=r"(qTimerCount));
228   asm volatile("mrs %0, cntfrq_el0" : "=r"(qTimerFreq));
229 
230   constexpr uint64_t kOneSecondInNanoseconds = 1000000000;
231   if (qTimerFreq != 0) {
232     // Get the seconds part first, then convert the remainder to prevent
233     // overflow
234     uint64_t qTimerNanos = (qTimerCount / qTimerFreq);
235     if (qTimerNanos > UINT64_MAX / kOneSecondInNanoseconds) {
236       LOGE("CNTVCT_EL0 conversion to nanoseconds overflowed during time sync."
237            " Aborting time sync.");
238       *success = false;
239     } else {
240       qTimerNanos *= kOneSecondInNanoseconds;
241 
242       // Round the remainder portion to the nearest nanosecond
243       uint64_t remainder = (qTimerCount % qTimerFreq);
244       qTimerNanos +=
245           (remainder * kOneSecondInNanoseconds + qTimerFreq / 2) / qTimerFreq;
246 
247       timeOffset = hostTimeNano - qTimerNanos;
248       *success = true;
249     }
250   } else {
251     LOGE("CNTFRQ_EL0 had 0 value. Aborting time sync.");
252     *success = false;
253   }
254 #else
255 #error "Unsupported CPU architecture type"
256 #endif
257 
258   return timeOffset;
259 }
260 
sendTimeSyncMessage()261 static void sendTimeSyncMessage() {
262   bool timeSyncSuccess = true;
263   int64_t timeOffset = getTimeOffset(&timeSyncSuccess);
264 
265   if (timeSyncSuccess) {
266     flatbuffers::FlatBufferBuilder builder(64);
267     HostProtocolHost::encodeTimeSyncMessage(builder, timeOffset);
268     int success = chre_slpi_deliver_message_from_host(
269         static_cast<const unsigned char *>(builder.GetBufferPointer()),
270         static_cast<int>(builder.GetSize()));
271 
272     if (success != 0) {
273       LOGE("Failed to deliver timestamp message from host to CHRE: %d", success);
274     }
275   }
276 }
277 
278 #ifdef CHRE_DAEMON_LPMA_ENABLED
279 
280 /**
281  * Initializes the wakelock file descriptors used to acquire/release wakelocks
282  * for CHRE.
283  */
initWakeLockFds()284 static void initWakeLockFds() {
285   const char kWakeLockPath[] = "/sys/power/wake_lock";
286   const char kWakeUnlockPath[] = "/sys/power/wake_unlock";
287 
288   bool success = false;
289   if ((gWakeLockFd = open(kWakeLockPath, O_RDWR | O_CLOEXEC)) < 0) {
290     LOGE("Failed to open wake lock file with %s", strerror(errno));
291   } else if ((gWakeUnlockFd = open(kWakeUnlockPath, O_RDWR | O_CLOEXEC)) < 0) {
292     close(gWakeLockFd);
293     LOGE("Failed to open wake unlock file with %s", strerror(errno));
294   } else {
295     success = true;
296   }
297 
298   if (!success) {
299     gWakeLockFd = -1;
300     gWakeUnlockFd = -1;
301   }
302 }
303 
acquireWakeLock()304 static void acquireWakeLock() {
305   if (gWakeLockFd < 0) {
306     LOGW("Failing to acquire wakelock due to invalid file descriptor");
307   } else {
308     const size_t len = strlen(kWakeLockName);
309     ssize_t result = write(gWakeLockFd, kWakeLockName, len);
310     if (result < 0) {
311       LOGE("Failed to acquire wakelock with error %s", strerror(errno));
312     } else if (result != static_cast<ssize_t>(len)) {
313       LOGE("Wrote incomplete id to wakelock file descriptor");
314     }
315   }
316 }
317 
releaseWakeLock()318 static void releaseWakeLock() {
319   if (gWakeUnlockFd < 0) {
320     LOGW("Failed to release wakelock due to invalid file descriptor");
321   } else {
322     const size_t len = strlen(kWakeLockName);
323     ssize_t result = write(gWakeUnlockFd, kWakeLockName, len);
324     if (result < 0) {
325       LOGE("Failed to release wakelock with error %s", strerror(errno));
326     } else if (result != static_cast<ssize_t>(len)) {
327       LOGE("Wrote incomplete id to wakeunlock file descriptor");
328     }
329   }
330 }
331 
332 /**
333  * Sets the target state for LPMA to be enabled. This triggers another thread to
334  * perform the async operation of enabling or disabling the LPMA use case.
335  *
336  * @param enabled Whether LPMA is to be enabled or disabled.
337  */
setLpmaState(bool enabled)338 static void setLpmaState(bool enabled) {
339   pthread_mutex_lock(&lpmaEnableThread.mutex);
340   lpmaEnableThread.targetLpmaEnabled = enabled;
341   pthread_mutex_unlock(&lpmaEnableThread.mutex);
342   pthread_cond_signal(&lpmaEnableThread.cond);
343 }
344 
345 /**
346  * Loads the LPMA use case via the SoundTrigger HAL HIDL service.
347  *
348  * @param lpmaHandle The handle that was generated as a result of enabling
349  *        the LPMA use case successfully.
350  * @return true if LPMA was enabled successfully, false otherwise.
351  */
loadLpma(SoundModelHandle * lpmaHandle)352 static bool loadLpma(SoundModelHandle *lpmaHandle) {
353   LOGD("Loading LPMA");
354 
355   ISoundTriggerHw::SoundModel soundModel;
356   soundModel.type = SoundModelType::GENERIC;
357   soundModel.vendorUuid.timeLow = 0x57CADDB1;
358   soundModel.vendorUuid.timeMid = 0xACDB;
359   soundModel.vendorUuid.versionAndTimeHigh = 0x4DCE;
360   soundModel.vendorUuid.variantAndClockSeqHigh = 0x8CB0;
361 
362   const uint8_t uuidNode[6] = { 0x2E, 0x95, 0xA2, 0x31, 0x3A, 0xEE };
363   memcpy(&soundModel.vendorUuid.node[0], uuidNode, sizeof(uuidNode));
364   soundModel.data.resize(1);  // Insert a dummy byte to bypass HAL NULL checks.
365 
366   bool loaded = false;
367   sp<ISoundTriggerHw> stHal = ISoundTriggerHw::getService();
368   if (stHal == nullptr) {
369     LOGE("Failed to get ST HAL service for LPMA load");
370   } else {
371     int32_t loadResult;
372     Return<void> hidlResult = stHal->loadSoundModel(soundModel, NULL, 0,
373         [&](int32_t retval, SoundModelHandle handle) {
374             loadResult = retval;
375             *lpmaHandle = handle;
376         });
377 
378     if (hidlResult.isOk()) {
379       if (loadResult == 0) {
380         LOGI("Loaded LPMA");
381         loaded = true;
382       } else {
383         LOGE("Failed to load LPMA with %" PRId32, loadResult);
384       }
385     } else {
386       LOGE("Failed to load LPMA due to hidl error %s",
387            hidlResult.description().c_str());
388     }
389   }
390 
391   return loaded;
392 }
393 
394 /**
395  * Unloads the LPMA use case via the SoundTrigger HAL HIDL service.
396  *
397  * @param lpmaHandle A handle that was previously produced by the setLpmaEnabled
398  *        function. This is the handle that is unloaded from the ST HAL to
399  *        disable LPMA.
400  * @return true if LPMA was disabled successfully, false otherwise.
401  */
unloadLpma(SoundModelHandle lpmaHandle)402 static bool unloadLpma(SoundModelHandle lpmaHandle) {
403   LOGD("Unloading LPMA");
404 
405   bool unloaded = false;
406   sp<ISoundTriggerHw> stHal = ISoundTriggerHw::getService();
407   if (stHal == nullptr) {
408     LOGE("Failed to get ST HAL service for LPMA unload");
409   } else {
410     Return<int32_t> hidlResult = stHal->unloadSoundModel(lpmaHandle);
411 
412     if (hidlResult.isOk()) {
413       if (hidlResult == 0) {
414         LOGI("Unloaded LPMA");
415         unloaded = true;
416       } else {
417         LOGE("Failed to unload LPMA with %" PRId32, int32_t(hidlResult));
418       }
419     } else {
420       LOGE("Failed to unload LPMA due to hidl error %s",
421            hidlResult.description().c_str());
422     }
423   }
424 
425   return unloaded;
426 }
427 
chreLpmaEnableThread(void * arg)428 static void *chreLpmaEnableThread(void *arg) {
429   auto *state = static_cast<LpmaEnableThreadData *>(arg);
430 
431   const useconds_t kInitialRetryDelayUs = 500000;
432   const int kRetryGrowthFactor = 2;
433   const int kRetryGrowthLimit = 5;  // Terminates at 8s retry interval.
434   const int kRetryWakeLockLimit = 10;  // Retry with a wakelock 10 times.
435 
436   int retryCount = 0;
437   useconds_t retryDelay = 0;
438   SoundModelHandle lpmaHandle;
439 
440   while (true) {
441     pthread_mutex_lock(&state->mutex);
442     if (state->currentLpmaEnabled == state->targetLpmaEnabled) {
443       retryCount = 0;
444       retryDelay = 0;
445       releaseWakeLock();  // Allow the system to suspend while waiting.
446       pthread_cond_wait(&state->cond, &state->mutex);
447       acquireWakeLock();  // Ensure the system stays up while retrying.
448     } else if ((state->targetLpmaEnabled && loadLpma(&lpmaHandle))
449                || (!state->targetLpmaEnabled && unloadLpma(lpmaHandle))) {
450       state->currentLpmaEnabled = state->targetLpmaEnabled;
451     } else {
452       // Unlock while delaying to avoid blocking the client thread. No shared
453       // state is modified here.
454       pthread_mutex_unlock(&state->mutex);
455 
456       if (retryDelay == 0) {
457         retryDelay = kInitialRetryDelayUs;
458       } else if (retryCount < kRetryGrowthLimit) {
459         retryDelay *= kRetryGrowthFactor;
460       }
461 
462       LOGD("Delaying retry %d for %uus", retryCount, retryDelay);
463       usleep(retryDelay);
464 
465       retryCount++;
466       if (retryCount > kRetryWakeLockLimit) {
467         releaseWakeLock();
468       }
469 
470       pthread_mutex_lock(&state->mutex);
471     }
472 
473     pthread_mutex_unlock(&state->mutex);
474   }
475 
476   LOGV("LPMA enable thread exited");
477   return NULL;
478 }
479 
480 /**
481  * Initializes the data shared with the LPMA enable thread and starts the
482  * thread.
483  *
484  * @param data Pointer to structure containing the (uninitialized) condition
485  *        variable and associated data passed to the LPMA enable thread.
486  * @return true on success, false otherwise.
487  */
initLpmaEnableThread(LpmaEnableThreadData * data)488 static bool initLpmaEnableThread(LpmaEnableThreadData *data) {
489   bool success = false;
490   int ret;
491 
492   if ((ret = pthread_mutex_init(&data->mutex, NULL)) != 0) {
493     LOG_ERROR("Failed to initialize lpma enable mutex", ret);
494   } else if ((ret = pthread_cond_init(&data->cond, NULL)) != 0) {
495     LOG_ERROR("Failed to initialize lpma enable condition variable", ret);
496   } else if (!start_thread(&data->thread, chreLpmaEnableThread, data)) {
497     LOGE("Couldn't start lpma enable thread");
498   } else {
499     data->currentLpmaEnabled = false;
500     data->targetLpmaEnabled = false;
501     success = true;
502   }
503 
504   return success;
505 }
506 
507 #endif  // CHRE_DAEMON_LPMA_ENABLED
508 
509 /**
510  * Entry point for the thread that receives messages sent by CHRE.
511  *
512  * @return always returns NULL
513  */
chre_message_to_host_thread(void * arg)514 static void *chre_message_to_host_thread(void *arg) {
515   unsigned char messageBuffer[4096];
516   unsigned int messageLen;
517   int result = 0;
518   auto *server = static_cast<::android::chre::SocketServer *>(arg);
519 
520   while (true) {
521     messageLen = 0;
522     LOGV("Calling into chre_slpi_get_message_to_host");
523     result = chre_slpi_get_message_to_host(
524         messageBuffer, sizeof(messageBuffer), &messageLen);
525     LOGV("Got message from CHRE with size %u (result %d)", messageLen, result);
526 
527     if (result == CHRE_FASTRPC_ERROR_SHUTTING_DOWN) {
528       LOGD("CHRE shutting down, exiting CHRE->Host message thread");
529       break;
530     } else if (result == CHRE_FASTRPC_SUCCESS && messageLen > 0) {
531       log_buffer(messageBuffer, messageLen);
532       uint16_t hostClientId;
533       fbs::ChreMessage messageType;
534       if (!HostProtocolHost::extractHostClientIdAndType(
535           messageBuffer, messageLen, &hostClientId, &messageType)) {
536         LOGW("Failed to extract host client ID from message - sending "
537              "broadcast");
538         hostClientId = chre::kHostClientIdUnspecified;
539       }
540 
541       if (messageType == fbs::ChreMessage::LogMessage) {
542         parseAndEmitLogMessages(messageBuffer);
543       } else if (messageType == fbs::ChreMessage::TimeSyncRequest) {
544         sendTimeSyncMessage();
545 #ifdef CHRE_DAEMON_LPMA_ENABLED
546       } else if (messageType == fbs::ChreMessage::LowPowerMicAccessRequest) {
547         setLpmaState(true);
548       } else if (messageType == fbs::ChreMessage::LowPowerMicAccessRelease) {
549         setLpmaState(false);
550 #endif  // CHRE_DAEMON_LPMA_ENABLED
551       } else if (hostClientId == chre::kHostClientIdUnspecified) {
552         server->sendToAllClients(messageBuffer,
553                                  static_cast<size_t>(messageLen));
554       } else {
555         server->sendToClientById(messageBuffer,
556                                  static_cast<size_t>(messageLen), hostClientId);
557       }
558     } else if (!chre_shutdown_requested) {
559       LOGE("Received an unknown result and no shutdown was requested. Quitting");
560       exit(-1);
561     } else {
562       // Received an unknown result but a shutdown was requested. Break from the
563       // loop to allow the daemon to cleanup.
564       break;
565     }
566   }
567 
568   LOGV("Message to host thread exited");
569   return NULL;
570 }
571 
572 /**
573  * Entry point for the thread that blocks in a FastRPC call to monitor for
574  * abnormal exit of CHRE or reboot of the SLPI.
575  *
576  * @return always returns NULL
577  */
chre_monitor_thread(void * arg)578 static void *chre_monitor_thread(void *arg) {
579   (void) arg;
580   int ret = chre_slpi_wait_on_thread_exit();
581   if (!chre_shutdown_requested) {
582     LOGE("Detected unexpected CHRE thread exit (%d)\n", ret);
583     exit(EXIT_FAILURE);
584   }
585 
586   LOGV("Monitor thread exited");
587   return NULL;
588 }
589 
590 /**
591  * Entry point for the "reverse" monitor thread, which invokes a FastRPC method
592  * to register a thread destructor, and blocks waiting on a condition variable.
593  * This allows for the code running in the SLPI to detect abnormal shutdown of
594  * the host-side binary and perform graceful cleanup.
595  *
596  * @return always returns NULL
597  */
chre_reverse_monitor_thread(void * arg)598 static void *chre_reverse_monitor_thread(void *arg) {
599   struct reverse_monitor_thread_data *thread_data =
600       (struct reverse_monitor_thread_data *) arg;
601 
602   int ret = chre_slpi_initialize_reverse_monitor();
603   if (ret != CHRE_FASTRPC_SUCCESS) {
604     LOGE("Failed to initialize reverse monitor on SLPI: %d", ret);
605   } else {
606     // Block here on the condition variable until the main thread notifies
607     // us to exit
608     pthread_mutex_lock(&thread_data->mutex);
609     pthread_cond_wait(&thread_data->cond, &thread_data->mutex);
610     pthread_mutex_unlock(&thread_data->mutex);
611   }
612 
613   LOGV("Reverse monitor thread exited");
614   return NULL;
615 }
616 
617 /**
618  * Initializes the data shared with the reverse monitor thread, and starts the
619  * thread.
620  *
621  * @param data Pointer to structure containing the (uninitialized) condition
622  *        variable and associated data passed to the reverse monitor thread
623  *
624  * @return true on success
625  */
init_reverse_monitor(struct reverse_monitor_thread_data * data)626 static bool init_reverse_monitor(struct reverse_monitor_thread_data *data) {
627   bool success = false;
628   int ret;
629 
630   if ((ret = pthread_mutex_init(&data->mutex, NULL)) != 0) {
631     LOG_ERROR("Failed to initialize mutex", ret);
632   } else if ((ret = pthread_cond_init(&data->cond, NULL)) != 0) {
633     LOG_ERROR("Failed to initialize condition variable", ret);
634   } else if (!start_thread(&data->thread, chre_reverse_monitor_thread, data)) {
635     LOGE("Couldn't start reverse monitor thread");
636   } else {
637     success = true;
638   }
639 
640   return success;
641 }
642 
643 /**
644  * Start a thread with default attributes, or log an error on failure
645  *
646  * @return bool true if the thread was successfully started
647  */
start_thread(pthread_t * thread_handle,thread_entry_point_f * thread_entry,void * arg)648 static bool start_thread(pthread_t *thread_handle,
649                          thread_entry_point_f *thread_entry,
650                          void *arg) {
651   int ret = pthread_create(thread_handle, NULL, thread_entry, arg);
652   if (ret != 0) {
653     LOG_ERROR("pthread_create failed", ret);
654   }
655   return (ret == 0);
656 }
657 
658 namespace {
659 
onMessageReceivedFromClient(uint16_t clientId,void * data,size_t length)660 void onMessageReceivedFromClient(uint16_t clientId, void *data, size_t length) {
661   constexpr size_t kMaxPayloadSize = 1024 * 1024;  // 1 MiB
662 
663   // This limitation is due to FastRPC, but there's no case where we should come
664   // close to this limit...
665   static_assert(kMaxPayloadSize <= INT32_MAX,
666                 "SLPI uses 32-bit signed integers to represent message size");
667 
668   if (length > kMaxPayloadSize) {
669     LOGE("Message too large to pass to SLPI (got %zu, max %zu bytes)", length,
670          kMaxPayloadSize);
671   } else if (!HostProtocolHost::mutateHostClientId(data, length, clientId)) {
672     LOGE("Couldn't set host client ID in message container!");
673   } else {
674     LOGV("Delivering message from host (size %zu)", length);
675     log_buffer(static_cast<const uint8_t *>(data), length);
676     int ret = chre_slpi_deliver_message_from_host(
677         static_cast<const unsigned char *>(data), static_cast<int>(length));
678     if (ret != 0) {
679       LOGE("Failed to deliver message from host to CHRE: %d", ret);
680     }
681   }
682 }
683 
684 }  // anonymous namespace
685 
main()686 int main() {
687   int ret = -1;
688   pthread_t monitor_thread;
689   pthread_t msg_to_host_thread;
690 
691   struct reverse_monitor_thread_data reverse_monitor;
692   ::android::chre::SocketServer server;
693 
694 #ifdef CHRE_DAEMON_LPMA_ENABLED
695   initWakeLockFds();
696 #endif  // CHRE_DAEMON_LPMA_ENABLED
697 
698   if (!init_reverse_monitor(&reverse_monitor)) {
699     LOGE("Couldn't initialize reverse monitor");
700 #ifdef CHRE_DAEMON_LPMA_ENABLED
701   } else if (!initLpmaEnableThread(&lpmaEnableThread)) {
702     LOGE("Couldn't initialize LPMA enable thread");
703 #endif  // CHRE_DAEMON_LPMA_ENABLED
704   } else {
705     // Send time offset message before nanoapps start
706     sendTimeSyncMessage();
707     if ((ret = chre_slpi_start_thread()) != CHRE_FASTRPC_SUCCESS) {
708       LOGE("Failed to start CHRE on SLPI: %d", ret);
709     } else {
710       if (!start_thread(&monitor_thread, chre_monitor_thread, NULL)) {
711         LOGE("Couldn't start monitor thread");
712       } else if (!start_thread(&msg_to_host_thread, chre_message_to_host_thread,
713                                &server)) {
714         LOGE("Couldn't start CHRE->Host message thread");
715       } else {
716         LOGI("CHRE on SLPI started");
717         // TODO: take 2nd argument as command-line parameter
718         server.run("chre", true, onMessageReceivedFromClient);
719       }
720 
721       chre_shutdown_requested = true;
722       ret = chre_slpi_stop_thread();
723       if (ret != CHRE_FASTRPC_SUCCESS) {
724         LOGE("Failed to stop CHRE on SLPI: %d", ret);
725       } else {
726         // TODO: don't call pthread_join if the thread failed to start
727         LOGV("Joining monitor thread");
728         ret = pthread_join(monitor_thread, NULL);
729         if (ret != 0) {
730           LOG_ERROR("Join on monitor thread failed", ret);
731         }
732 
733         LOGV("Joining reverse monitor thread");
734         pthread_cond_signal(&reverse_monitor.cond);
735         ret = pthread_join(reverse_monitor.thread, NULL);
736         if (ret != 0) {
737           LOG_ERROR("Join on reverse monitor thread failed", ret);
738         }
739 
740         LOGV("Joining message to host thread");
741         ret = pthread_join(msg_to_host_thread, NULL);
742         if (ret != 0) {
743           LOG_ERROR("Join on monitor thread failed", ret);
744         }
745 
746         LOGI("Shutdown complete");
747       }
748     }
749   }
750 
751   return ret;
752 }
753 
754