Home | History | Annotate | Download | only in daemon
      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
    125 static void log_buffer(const uint8_t * /*buffer*/, size_t /*size*/) {}
    126 #else
    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 
    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 
    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 
    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  */
    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 
    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 
    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  */
    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  */
    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  */
    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 
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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 
    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 
    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