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