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 #ifndef FARF_MEDIUM 18 #define FARF_MEDIUM 1 19 #endif 20 21 #include "HAP_farf.h" 22 #include "timer.h" 23 24 #include "chre/core/event_loop_manager.h" 25 #include "chre/core/host_comms_manager.h" 26 #include "chre/core/settings.h" 27 #include "chre/platform/fatal_error.h" 28 #include "chre/platform/log.h" 29 #include "chre/platform/memory.h" 30 #include "chre/platform/shared/host_protocol_chre.h" 31 #include "chre/platform/slpi/fastrpc.h" 32 #include "chre/platform/slpi/nanoapp_load_manager.h" 33 #include "chre/platform/slpi/power_control_util.h" 34 #include "chre/platform/slpi/system_time.h" 35 #include "chre/platform/system_time.h" 36 #include "chre/platform/system_timer.h" 37 #include "chre/util/fixed_size_blocking_queue.h" 38 #include "chre/util/macros.h" 39 #include "chre/util/unique_ptr.h" 40 #include "chre_api/chre/version.h" 41 42 #include <inttypes.h> 43 #include <limits.h> 44 45 using flatbuffers::FlatBufferBuilder; 46 47 namespace chre { 48 49 namespace { 50 51 constexpr size_t kOutboundQueueSize = 32; 52 53 //! The last time a time sync request message has been sent. 54 //! TODO: Make this a member of HostLinkBase 55 Nanoseconds gLastTimeSyncRequestNanos(0); 56 57 //! Used to pass the client ID through the user data pointer in deferCallback 58 union HostClientIdCallbackData { 59 uint16_t hostClientId; 60 void *ptr; 61 }; 62 static_assert(sizeof(uint16_t) <= sizeof(void *), 63 "Pointer must at least fit a u16 for passing the host client ID"); 64 65 struct LoadNanoappCallbackData { 66 uint64_t appId; 67 uint32_t transactionId; 68 uint16_t hostClientId; 69 UniquePtr<Nanoapp> nanoapp; 70 uint32_t fragmentId; 71 }; 72 73 struct NanoappListData { 74 FlatBufferBuilder *builder; 75 DynamicVector<NanoappListEntryOffset> nanoappEntries; 76 uint16_t hostClientId; 77 }; 78 79 enum class PendingMessageType { 80 Shutdown, 81 NanoappMessageToHost, 82 HubInfoResponse, 83 NanoappListResponse, 84 LoadNanoappResponse, 85 UnloadNanoappResponse, 86 DebugDumpData, 87 DebugDumpResponse, 88 TimeSyncRequest, 89 LowPowerMicAccessRequest, 90 LowPowerMicAccessRelease, 91 EncodedLogMessage, 92 }; 93 94 struct PendingMessage { 95 PendingMessage(PendingMessageType msgType, uint16_t hostClientId) { 96 type = msgType; 97 data.hostClientId = hostClientId; 98 } 99 100 PendingMessage(PendingMessageType msgType, 101 const MessageToHost *msgToHost = nullptr) { 102 type = msgType; 103 data.msgToHost = msgToHost; 104 } 105 106 PendingMessage(PendingMessageType msgType, FlatBufferBuilder *builder) { 107 type = msgType; 108 data.builder = builder; 109 } 110 111 PendingMessageType type; 112 union { 113 const MessageToHost *msgToHost; 114 uint16_t hostClientId; 115 FlatBufferBuilder *builder; 116 } data; 117 }; 118 119 struct UnloadNanoappCallbackData { 120 uint64_t appId; 121 uint32_t transactionId; 122 uint16_t hostClientId; 123 bool allowSystemNanoappUnload; 124 }; 125 126 /** 127 * @see buildAndEnqueueMessage() 128 */ 129 typedef void(MessageBuilderFunction)(FlatBufferBuilder &builder, void *cookie); 130 131 FixedSizeBlockingQueue<PendingMessage, kOutboundQueueSize> gOutboundQueue; 132 133 int copyToHostBuffer(const FlatBufferBuilder &builder, unsigned char *buffer, 134 size_t bufferSize, unsigned int *messageLen) { 135 uint8_t *data = builder.GetBufferPointer(); 136 size_t size = builder.GetSize(); 137 int result; 138 139 if (size > bufferSize) { 140 LOGE("Encoded structure size %zu too big for host buffer %zu; dropping", 141 size, bufferSize); 142 result = CHRE_FASTRPC_ERROR; 143 } else { 144 memcpy(buffer, data, size); 145 *messageLen = size; 146 result = CHRE_FASTRPC_SUCCESS; 147 } 148 149 return result; 150 } 151 152 /** 153 * Wrapper function to enqueue a message on the outbound message queue. All 154 * outgoing message to the host must be called through this function. 155 * 156 * @param message The message to send to host. 157 * 158 * @return true if the message was successfully added to the queue. 159 */ 160 bool enqueueMessage(PendingMessage message) { 161 // Vote for big image temporarily when waking up the main thread waiting for 162 // the message 163 bool voteSuccess = slpiForceBigImage(); 164 bool success = gOutboundQueue.push(message); 165 166 // Remove the vote only if we successfully made a big image transition 167 if (voteSuccess) { 168 slpiRemoveBigImageVote(); 169 } 170 171 return success; 172 } 173 174 /** 175 * Helper function that takes care of the boilerplate for allocating a 176 * FlatBufferBuilder on the heap and adding it to the outbound message queue. 177 * 178 * @param msgType Identifies the message while in the outboud queue 179 * @param initialBufferSize Number of bytes to reserve when first allocating the 180 * FlatBufferBuilder 181 * @param buildMsgFunc Synchronous callback used to encode the FlatBuffer 182 * message. Will not be invoked if allocation fails. 183 * @param cookie Opaque pointer that will be passed through to buildMsgFunc 184 * 185 * @return true if the message was successfully added to the queue 186 */ 187 bool buildAndEnqueueMessage(PendingMessageType msgType, 188 size_t initialBufferSize, 189 MessageBuilderFunction *msgBuilder, void *cookie) { 190 bool pushed = false; 191 192 auto builder = MakeUnique<FlatBufferBuilder>(initialBufferSize); 193 if (builder.isNull()) { 194 LOGE("Couldn't allocate memory for message type %d", 195 static_cast<int>(msgType)); 196 } else { 197 msgBuilder(*builder, cookie); 198 199 // TODO: if this fails, ideally we should block for some timeout until 200 // there's space in the queue 201 if (!enqueueMessage(PendingMessage(msgType, builder.get()))) { 202 LOGE("Couldn't push message type %d to outbound queue", 203 static_cast<int>(msgType)); 204 } else { 205 builder.release(); 206 pushed = true; 207 } 208 } 209 210 return pushed; 211 } 212 213 /** 214 * FlatBuffer message builder callback used with constructNanoappListCallback() 215 */ 216 void buildNanoappListResponse(FlatBufferBuilder &builder, void *cookie) { 217 auto nanoappAdderCallback = [](const Nanoapp *nanoapp, void *data) { 218 auto *cbData = static_cast<NanoappListData *>(data); 219 HostProtocolChre::addNanoappListEntry( 220 *(cbData->builder), cbData->nanoappEntries, nanoapp->getAppId(), 221 nanoapp->getAppVersion(), true /*enabled*/, nanoapp->isSystemNanoapp()); 222 }; 223 224 // Add a NanoappListEntry to the FlatBuffer for each nanoapp 225 auto *cbData = static_cast<NanoappListData *>(cookie); 226 cbData->builder = &builder; 227 EventLoop &eventLoop = EventLoopManagerSingleton::get()->getEventLoop(); 228 eventLoop.forEachNanoapp(nanoappAdderCallback, cbData); 229 HostProtocolChre::finishNanoappListResponse(builder, cbData->nanoappEntries, 230 cbData->hostClientId); 231 } 232 233 void constructNanoappListCallback(uint16_t /*eventType*/, void *deferCbData) { 234 HostClientIdCallbackData clientIdCbData; 235 clientIdCbData.ptr = deferCbData; 236 237 NanoappListData cbData = {}; 238 cbData.hostClientId = clientIdCbData.hostClientId; 239 240 const EventLoop &eventLoop = EventLoopManagerSingleton::get()->getEventLoop(); 241 size_t expectedNanoappCount = eventLoop.getNanoappCount(); 242 if (!cbData.nanoappEntries.reserve(expectedNanoappCount)) { 243 LOG_OOM(); 244 } else { 245 constexpr size_t kFixedOverhead = 48; 246 constexpr size_t kPerNanoappSize = 32; 247 size_t initialBufferSize = 248 (kFixedOverhead + expectedNanoappCount * kPerNanoappSize); 249 250 buildAndEnqueueMessage(PendingMessageType::NanoappListResponse, 251 initialBufferSize, buildNanoappListResponse, 252 &cbData); 253 } 254 } 255 256 void finishLoadingNanoappCallback(uint16_t /*eventType*/, void *data) { 257 auto msgBuilder = [](FlatBufferBuilder &builder, void *cookie) { 258 auto *cbData = static_cast<LoadNanoappCallbackData *>(cookie); 259 260 EventLoop &eventLoop = EventLoopManagerSingleton::get()->getEventLoop(); 261 bool success = 262 cbData->nanoapp->isLoaded() && eventLoop.startNanoapp(cbData->nanoapp); 263 264 HostProtocolChre::encodeLoadNanoappResponse(builder, cbData->hostClientId, 265 cbData->transactionId, success, 266 cbData->fragmentId); 267 }; 268 269 // Re-wrap the callback data struct, so it is destructed and freed, ensuring 270 // we don't leak the embedded UniquePtr<Nanoapp> 271 UniquePtr<LoadNanoappCallbackData> dataWrapped( 272 static_cast<LoadNanoappCallbackData *>(data)); 273 constexpr size_t kInitialBufferSize = 48; 274 buildAndEnqueueMessage(PendingMessageType::LoadNanoappResponse, 275 kInitialBufferSize, msgBuilder, data); 276 } 277 278 void handleUnloadNanoappCallback(uint16_t /*eventType*/, void *data) { 279 auto msgBuilder = [](FlatBufferBuilder &builder, void *cookie) { 280 auto *cbData = static_cast<UnloadNanoappCallbackData *>(cookie); 281 282 bool success = false; 283 uint32_t instanceId; 284 EventLoop &eventLoop = EventLoopManagerSingleton::get()->getEventLoop(); 285 if (!eventLoop.findNanoappInstanceIdByAppId(cbData->appId, &instanceId)) { 286 LOGE("Couldn't unload app ID 0x%016" PRIx64 ": not found", cbData->appId); 287 } else { 288 success = 289 eventLoop.unloadNanoapp(instanceId, cbData->allowSystemNanoappUnload); 290 } 291 292 HostProtocolChre::encodeUnloadNanoappResponse( 293 builder, cbData->hostClientId, cbData->transactionId, success); 294 }; 295 296 constexpr size_t kInitialBufferSize = 52; 297 buildAndEnqueueMessage(PendingMessageType::UnloadNanoappResponse, 298 kInitialBufferSize, msgBuilder, data); 299 memoryFree(data); 300 } 301 302 int generateMessageToHost(const MessageToHost *msgToHost, unsigned char *buffer, 303 size_t bufferSize, unsigned int *messageLen) { 304 // TODO: ideally we'd construct our flatbuffer directly in the 305 // host-supplied buffer 306 constexpr size_t kFixedSizePortion = 80; 307 FlatBufferBuilder builder(msgToHost->message.size() + kFixedSizePortion); 308 HostProtocolChre::encodeNanoappMessage( 309 builder, msgToHost->appId, msgToHost->toHostData.messageType, 310 msgToHost->toHostData.hostEndpoint, msgToHost->message.data(), 311 msgToHost->message.size()); 312 313 int result = copyToHostBuffer(builder, buffer, bufferSize, messageLen); 314 315 auto &hostCommsManager = 316 EventLoopManagerSingleton::get()->getHostCommsManager(); 317 hostCommsManager.onMessageToHostComplete(msgToHost); 318 319 return result; 320 } 321 322 int generateHubInfoResponse(uint16_t hostClientId, unsigned char *buffer, 323 size_t bufferSize, unsigned int *messageLen) { 324 constexpr size_t kInitialBufferSize = 192; 325 326 constexpr char kHubName[] = "CHRE on SLPI"; 327 constexpr char kVendor[] = "Google"; 328 constexpr char kToolchain[] = 329 "Hexagon Tools 8.x (clang " STRINGIFY(__clang_major__) "." STRINGIFY( 330 __clang_minor__) "." STRINGIFY(__clang_patchlevel__) ")"; 331 constexpr uint32_t kLegacyPlatformVersion = 0; 332 constexpr uint32_t kLegacyToolchainVersion = 333 ((__clang_major__ & 0xFF) << 24) | ((__clang_minor__ & 0xFF) << 16) | 334 (__clang_patchlevel__ & 0xFFFF); 335 constexpr float kPeakMips = 350; 336 constexpr float kStoppedPower = 0; 337 constexpr float kSleepPower = 1; 338 constexpr float kPeakPower = 15; 339 340 // Note that this may execute prior to EventLoopManager::lateInit() completing 341 FlatBufferBuilder builder(kInitialBufferSize); 342 HostProtocolChre::encodeHubInfoResponse( 343 builder, kHubName, kVendor, kToolchain, kLegacyPlatformVersion, 344 kLegacyToolchainVersion, kPeakMips, kStoppedPower, kSleepPower, 345 kPeakPower, CHRE_MESSAGE_TO_HOST_MAX_SIZE, chreGetPlatformId(), 346 chreGetVersion(), hostClientId); 347 348 return copyToHostBuffer(builder, buffer, bufferSize, messageLen); 349 } 350 351 int generateMessageFromBuilder(FlatBufferBuilder *builder, 352 unsigned char *buffer, size_t bufferSize, 353 unsigned int *messageLen) { 354 CHRE_ASSERT(builder != nullptr); 355 int result = copyToHostBuffer(*builder, buffer, bufferSize, messageLen); 356 builder->~FlatBufferBuilder(); 357 memoryFree(builder); 358 return result; 359 } 360 361 void sendDebugDumpData(uint16_t hostClientId, const char *debugStr, 362 size_t debugStrSize) { 363 struct DebugDumpMessageData { 364 uint16_t hostClientId; 365 const char *debugStr; 366 size_t debugStrSize; 367 }; 368 369 auto msgBuilder = [](FlatBufferBuilder &builder, void *cookie) { 370 const auto *data = static_cast<const DebugDumpMessageData *>(cookie); 371 HostProtocolChre::encodeDebugDumpData(builder, data->hostClientId, 372 data->debugStr, data->debugStrSize); 373 }; 374 375 constexpr size_t kFixedSizePortion = 52; 376 DebugDumpMessageData data; 377 data.hostClientId = hostClientId; 378 data.debugStr = debugStr; 379 data.debugStrSize = debugStrSize; 380 buildAndEnqueueMessage(PendingMessageType::DebugDumpData, 381 kFixedSizePortion + debugStrSize, msgBuilder, &data); 382 } 383 384 void sendDebugDumpResponse(uint16_t hostClientId, bool success, 385 uint32_t dataCount) { 386 struct DebugDumpResponseData { 387 uint16_t hostClientId; 388 bool success; 389 uint32_t dataCount; 390 }; 391 392 auto msgBuilder = [](FlatBufferBuilder &builder, void *cookie) { 393 const auto *data = static_cast<const DebugDumpResponseData *>(cookie); 394 HostProtocolChre::encodeDebugDumpResponse(builder, data->hostClientId, 395 data->success, data->dataCount); 396 }; 397 398 constexpr size_t kInitialSize = 52; 399 DebugDumpResponseData data; 400 data.hostClientId = hostClientId; 401 data.success = success; 402 data.dataCount = dataCount; 403 buildAndEnqueueMessage(PendingMessageType::DebugDumpResponse, kInitialSize, 404 msgBuilder, &data); 405 } 406 407 void sendFragmentResponse(uint16_t hostClientId, uint32_t transactionId, 408 uint32_t fragmentId, bool success) { 409 struct FragmentedLoadInfoResponse { 410 uint16_t hostClientId; 411 uint32_t transactionId; 412 uint32_t fragmentId; 413 bool success; 414 }; 415 416 auto msgBuilder = [](FlatBufferBuilder &builder, void *cookie) { 417 auto *cbData = static_cast<FragmentedLoadInfoResponse *>(cookie); 418 HostProtocolChre::encodeLoadNanoappResponse( 419 builder, cbData->hostClientId, cbData->transactionId, cbData->success, 420 cbData->fragmentId); 421 }; 422 423 FragmentedLoadInfoResponse response = { 424 .hostClientId = hostClientId, 425 .transactionId = transactionId, 426 .fragmentId = fragmentId, 427 .success = success, 428 }; 429 constexpr size_t kInitialBufferSize = 48; 430 buildAndEnqueueMessage(PendingMessageType::LoadNanoappResponse, 431 kInitialBufferSize, msgBuilder, &response); 432 } 433 434 /** 435 * Sends a request to the host for a time sync message. 436 */ 437 void sendTimeSyncRequest() { 438 auto msgBuilder = [](FlatBufferBuilder &builder, void *cookie) { 439 HostProtocolChre::encodeTimeSyncRequest(builder); 440 }; 441 442 constexpr size_t kInitialSize = 52; 443 buildAndEnqueueMessage(PendingMessageType::TimeSyncRequest, kInitialSize, 444 msgBuilder, nullptr); 445 446 gLastTimeSyncRequestNanos = SystemTime::getMonotonicTime(); 447 } 448 449 void setTimeSyncRequestTimer(Nanoseconds delay) { 450 static SystemTimer sTimeSyncRequestTimer; 451 static bool sTimeSyncRequestTimerInitialized = false; 452 453 // Check for timer init since this method might be called before CHRE 454 // init is called. 455 if (!sTimeSyncRequestTimerInitialized) { 456 if (!sTimeSyncRequestTimer.init()) { 457 FATAL_ERROR("Failed to initialize time sync request timer."); 458 } else { 459 sTimeSyncRequestTimerInitialized = true; 460 } 461 } 462 if (sTimeSyncRequestTimer.isActive()) { 463 sTimeSyncRequestTimer.cancel(); 464 } 465 auto callback = [](void * /* data */) { sendTimeSyncRequest(); }; 466 if (!sTimeSyncRequestTimer.set(callback, nullptr /* data */, delay)) { 467 LOGE("Failed to set time sync request timer."); 468 } 469 } 470 471 /** 472 * Helper function that prepares a nanoapp that can be loaded into the system 473 * from a file stored on disk. 474 * 475 * @param hostClientId the ID of client that originated this transaction 476 * @param transactionId the ID of the transaction 477 * @param appId the ID of the app to load 478 * @param appVersion the version of the app to load 479 * @param targetApiVersion the API version this nanoapp is targeted for 480 * @param appFilename Null-terminated ASCII string containing the file name that 481 * contains the app binary to be loaded. 482 * 483 * @return A valid pointer to a nanoapp that can be loaded into the system. A 484 * nullptr if the preparation process fails. 485 */ 486 UniquePtr<Nanoapp> handleLoadNanoappFile(uint16_t hostClientId, 487 uint32_t transactionId, uint64_t appId, 488 uint32_t appVersion, 489 uint32_t targetApiVersion, 490 const char *appFilename) { 491 LOGD("Load nanoapp request for app ID 0x%016" PRIx64 " ver 0x%" PRIx32 492 " target API 0x%08" PRIx32 " (txnId %" PRIu32 " client %" PRIu16 ")", 493 appId, appVersion, targetApiVersion, transactionId, hostClientId); 494 495 auto nanoapp = MakeUnique<Nanoapp>(); 496 497 if (nanoapp.isNull()) { 498 LOG_OOM(); 499 } else if (!nanoapp->setAppInfo(appId, appVersion, appFilename) || 500 !nanoapp->isLoaded()) { 501 nanoapp.reset(nullptr); 502 } 503 504 return nanoapp; 505 } 506 507 /** 508 * Helper function that prepares a nanoapp that can be loaded into the system 509 * from a buffer sent over in 1 or more fragments. 510 * 511 * @param hostClientId the ID of client that originated this transaction 512 * @param transactionId the ID of the transaction 513 * @param appId the ID of the app to load 514 * @param appVersion the version of the app to load 515 * @param targetApiVersion the API version this nanoapp is targeted for 516 * @param buffer the nanoapp binary data. May be only part of the nanoapp's 517 * binary if it's being sent over multiple fragments 518 * @param bufferLen the size of buffer in bytes 519 * @param fragmentId the identifier indicating which fragment is being loaded 520 * @param appBinaryLen the full size of the nanoapp binary to be loaded 521 * 522 * @return A valid pointer to a nanoapp that can be loaded into the system. A 523 * nullptr if the preparation process fails. 524 */ 525 UniquePtr<Nanoapp> handleLoadNanoappData( 526 uint16_t hostClientId, uint32_t transactionId, uint64_t appId, 527 uint32_t appVersion, uint32_t targetApiVersion, const void *buffer, 528 size_t bufferLen, uint32_t fragmentId, size_t appBinaryLen) { 529 static NanoappLoadManager sLoadManager; 530 531 bool success = true; 532 if (fragmentId == 0 || fragmentId == 1) { // first fragment 533 size_t totalAppBinaryLen = (fragmentId == 0) ? bufferLen : appBinaryLen; 534 LOGD("Load nanoapp request for app ID 0x%016" PRIx64 " ver 0x%" PRIx32 535 " target API 0x%08" PRIx32 " size %zu (txnId %" PRIu32 536 " client %" PRIu16 ")", 537 appId, appVersion, targetApiVersion, totalAppBinaryLen, transactionId, 538 hostClientId); 539 540 if (sLoadManager.hasPendingLoadTransaction()) { 541 FragmentedLoadInfo info = sLoadManager.getTransactionInfo(); 542 sendFragmentResponse(info.hostClientId, info.transactionId, 543 0 /* fragmentId */, false /* success */); 544 sLoadManager.markFailure(); 545 } 546 547 success = sLoadManager.prepareForLoad(hostClientId, transactionId, appId, 548 appVersion, totalAppBinaryLen); 549 } 550 success &= sLoadManager.copyNanoappFragment( 551 hostClientId, transactionId, (fragmentId == 0) ? 1 : fragmentId, buffer, 552 bufferLen); 553 554 UniquePtr<Nanoapp> nanoapp; 555 if (!sLoadManager.isLoadComplete()) { 556 sendFragmentResponse(hostClientId, transactionId, fragmentId, success); 557 } else { 558 nanoapp = sLoadManager.releaseNanoapp(); 559 } 560 return nanoapp; 561 } 562 563 bool getSettingFromFbs(fbs::Setting setting, Setting *chreSetting) { 564 bool success = true; 565 switch (setting) { 566 case fbs::Setting::LOCATION: 567 *chreSetting = Setting::LOCATION; 568 break; 569 default: 570 LOGE("Unknown setting %" PRIu8, setting); 571 success = false; 572 } 573 574 return success; 575 } 576 577 bool getSettingStateFromFbs(fbs::SettingState state, 578 SettingState *chreSettingState) { 579 bool success = true; 580 switch (state) { 581 case fbs::SettingState::DISABLED: 582 *chreSettingState = SettingState::DISABLED; 583 break; 584 case fbs::SettingState::ENABLED: 585 *chreSettingState = SettingState::ENABLED; 586 break; 587 default: 588 LOGE("Unknown state %" PRIu8, state); 589 success = false; 590 } 591 592 return success; 593 } 594 595 /** 596 * FastRPC method invoked by the host to block on messages 597 * 598 * @param buffer Output buffer to populate with message data 599 * @param bufferLen Size of the buffer, in bytes 600 * @param messageLen Output parameter to populate with the size of the message 601 * in bytes upon success 602 * 603 * @return 0 on success, nonzero on failure 604 */ 605 extern "C" int chre_slpi_get_message_to_host(unsigned char *buffer, 606 int bufferLen, 607 unsigned int *messageLen) { 608 CHRE_ASSERT(buffer != nullptr); 609 CHRE_ASSERT(bufferLen > 0); 610 CHRE_ASSERT(messageLen != nullptr); 611 int result = CHRE_FASTRPC_ERROR; 612 613 if (bufferLen <= 0 || buffer == nullptr || messageLen == nullptr) { 614 // Note that we can't use regular logs here as they can result in sending 615 // a message, leading to an infinite loop if the error is persistent 616 FARF(FATAL, "Invalid buffer size %d or bad pointers (buf %d len %d)", 617 bufferLen, (buffer == nullptr), (messageLen == nullptr)); 618 } else { 619 size_t bufferSize = static_cast<size_t>(bufferLen); 620 PendingMessage pendingMsg = gOutboundQueue.pop(); 621 622 switch (pendingMsg.type) { 623 case PendingMessageType::Shutdown: 624 result = CHRE_FASTRPC_ERROR_SHUTTING_DOWN; 625 break; 626 627 case PendingMessageType::NanoappMessageToHost: 628 result = generateMessageToHost(pendingMsg.data.msgToHost, buffer, 629 bufferSize, messageLen); 630 break; 631 632 case PendingMessageType::HubInfoResponse: 633 result = generateHubInfoResponse(pendingMsg.data.hostClientId, buffer, 634 bufferSize, messageLen); 635 break; 636 637 case PendingMessageType::NanoappListResponse: 638 case PendingMessageType::LoadNanoappResponse: 639 case PendingMessageType::UnloadNanoappResponse: 640 case PendingMessageType::DebugDumpData: 641 case PendingMessageType::DebugDumpResponse: 642 case PendingMessageType::TimeSyncRequest: 643 case PendingMessageType::LowPowerMicAccessRequest: 644 case PendingMessageType::LowPowerMicAccessRelease: 645 case PendingMessageType::EncodedLogMessage: 646 result = generateMessageFromBuilder(pendingMsg.data.builder, buffer, 647 bufferSize, messageLen); 648 break; 649 650 default: 651 CHRE_ASSERT_LOG(false, "Unexpected pending message type"); 652 } 653 } 654 655 // Opportunistically send a time sync message (1 hour period threshold) 656 constexpr Seconds kOpportunisticTimeSyncPeriod = Seconds(60 * 60 * 1); 657 if (SystemTime::getMonotonicTime() > 658 gLastTimeSyncRequestNanos + kOpportunisticTimeSyncPeriod) { 659 sendTimeSyncRequest(); 660 } 661 662 return result; 663 } 664 665 /** 666 * FastRPC method invoked by the host to send a message to the system 667 * 668 * @param buffer 669 * @param size 670 * 671 * @return 0 on success, nonzero on failure 672 */ 673 extern "C" int chre_slpi_deliver_message_from_host(const unsigned char *message, 674 int messageLen) { 675 CHRE_ASSERT(message != nullptr); 676 CHRE_ASSERT(messageLen > 0); 677 int result = CHRE_FASTRPC_ERROR; 678 679 if (message == nullptr || messageLen <= 0) { 680 LOGE("Got null or invalid size (%d) message from host", messageLen); 681 } else if (!HostProtocolChre::decodeMessageFromHost( 682 message, static_cast<size_t>(messageLen))) { 683 LOGE("Failed to decode/handle message"); 684 } else { 685 result = CHRE_FASTRPC_SUCCESS; 686 } 687 688 return result; 689 } 690 691 } // anonymous namespace 692 693 void sendDebugDumpResultToHost(uint16_t hostClientId, const char *debugStr, 694 size_t debugStrSize, bool complete, 695 uint32_t dataCount) { 696 if (debugStrSize > 0) { 697 sendDebugDumpData(hostClientId, debugStr, debugStrSize); 698 } 699 700 if (complete) { 701 sendDebugDumpResponse(hostClientId, true /*success*/, dataCount); 702 } 703 } 704 705 void HostLink::flushMessagesSentByNanoapp(uint64_t /*appId*/) { 706 // TODO: this is not completely safe since it's timer-based, but should work 707 // well enough for the initial implementation. To be fully safe, we'd need 708 // some synchronization with the thread that runs 709 // chre_slpi_get_message_to_host(), e.g. a mutex that is held by that thread 710 // prior to calling pop() and only released after onMessageToHostComplete 711 // would've been called. If we acquire that mutex here, and hold it while 712 // purging any messages sent by the nanoapp in the queue, we can be certain 713 // that onMessageToHostComplete will not be called after this function returns 714 // for messages sent by that nanoapp 715 flushOutboundQueue(); 716 717 // One extra sleep to try to ensure that any messages popped just before 718 // checking empty() are fully processed before we return 719 constexpr time_timetick_type kFinalDelayUsec = 10000; 720 timer_sleep(kFinalDelayUsec, T_USEC, true /* non_deferrable */); 721 } 722 723 bool HostLink::sendMessage(const MessageToHost *message) { 724 return enqueueMessage( 725 PendingMessage(PendingMessageType::NanoappMessageToHost, message)); 726 } 727 728 bool HostLinkBase::flushOutboundQueue() { 729 int waitCount = 5; 730 731 FARF(MEDIUM, "Draining message queue"); 732 while (!gOutboundQueue.empty() && waitCount-- > 0) { 733 timer_sleep(kPollingIntervalUsec, T_USEC, true /* non_deferrable */); 734 } 735 736 return (waitCount >= 0); 737 } 738 739 void HostLinkBase::shutdown() { 740 // Push a null message so the blocking call in chre_slpi_get_message_to_host() 741 // returns and the host can exit cleanly. If the queue is full, try again to 742 // avoid getting stuck (no other new messages should be entering the queue at 743 // this time). Don't wait too long as the host-side binary may have died in 744 // a state where it's not blocked in chre_slpi_get_message_to_host(). 745 int retryCount = 5; 746 FARF(MEDIUM, "Shutting down host link"); 747 while (!enqueueMessage(PendingMessage(PendingMessageType::Shutdown)) && 748 --retryCount > 0) { 749 timer_sleep(kPollingIntervalUsec, T_USEC, true /* non_deferrable */); 750 } 751 752 if (retryCount <= 0) { 753 // Don't use LOGE, as it may involve trying to send a message 754 FARF(ERROR, 755 "No room in outbound queue for shutdown message and host not " 756 "draining queue!"); 757 } else { 758 // We were able to push the shutdown message. Wait for the queue to 759 // completely flush before returning. 760 if (!flushOutboundQueue()) { 761 FARF(ERROR, "Host took too long to drain outbound queue; exiting anyway"); 762 } else { 763 FARF(MEDIUM, "Finished draining queue"); 764 } 765 } 766 } 767 768 void sendAudioRequest() { 769 auto msgBuilder = [](FlatBufferBuilder &builder, void *cookie) { 770 HostProtocolChre::encodeLowPowerMicAccessRequest(builder); 771 }; 772 773 constexpr size_t kInitialSize = 32; 774 buildAndEnqueueMessage(PendingMessageType::LowPowerMicAccessRequest, 775 kInitialSize, msgBuilder, nullptr); 776 } 777 778 void sendAudioRelease() { 779 auto msgBuilder = [](FlatBufferBuilder &builder, void *cookie) { 780 HostProtocolChre::encodeLowPowerMicAccessRelease(builder); 781 }; 782 783 constexpr size_t kInitialSize = 32; 784 buildAndEnqueueMessage(PendingMessageType::LowPowerMicAccessRelease, 785 kInitialSize, msgBuilder, nullptr); 786 } 787 788 void HostMessageHandlers::handleNanoappMessage(uint64_t appId, 789 uint32_t messageType, 790 uint16_t hostEndpoint, 791 const void *messageData, 792 size_t messageDataLen) { 793 LOGD("Parsed nanoapp message from host: app ID 0x%016" PRIx64 794 ", endpoint " 795 "0x%" PRIx16 ", msgType %" PRIu32 ", payload size %zu", 796 appId, hostEndpoint, messageType, messageDataLen); 797 798 HostCommsManager &manager = 799 EventLoopManagerSingleton::get()->getHostCommsManager(); 800 manager.sendMessageToNanoappFromHost(appId, messageType, hostEndpoint, 801 messageData, messageDataLen); 802 } 803 804 void HostMessageHandlers::handleHubInfoRequest(uint16_t hostClientId) { 805 // We generate the response in the context of chre_slpi_get_message_to_host 806 LOGD("Hub info request from client ID %" PRIu16, hostClientId); 807 enqueueMessage( 808 PendingMessage(PendingMessageType::HubInfoResponse, hostClientId)); 809 } 810 811 void HostMessageHandlers::handleNanoappListRequest(uint16_t hostClientId) { 812 LOGD("Nanoapp list request from client ID %" PRIu16, hostClientId); 813 HostClientIdCallbackData cbData = {}; 814 cbData.hostClientId = hostClientId; 815 EventLoopManagerSingleton::get()->deferCallback( 816 SystemCallbackType::NanoappListResponse, cbData.ptr, 817 constructNanoappListCallback); 818 } 819 820 void HostMessageHandlers::handleLoadNanoappRequest( 821 uint16_t hostClientId, uint32_t transactionId, uint64_t appId, 822 uint32_t appVersion, uint32_t targetApiVersion, const void *buffer, 823 size_t bufferLen, const char *appFileName, uint32_t fragmentId, 824 size_t appBinaryLen) { 825 UniquePtr<Nanoapp> pendingNanoapp; 826 if (appFileName != nullptr) { 827 pendingNanoapp = 828 handleLoadNanoappFile(hostClientId, transactionId, appId, appVersion, 829 targetApiVersion, appFileName); 830 } else { 831 pendingNanoapp = handleLoadNanoappData(hostClientId, transactionId, appId, 832 appVersion, targetApiVersion, buffer, 833 bufferLen, fragmentId, appBinaryLen); 834 } 835 836 if (!pendingNanoapp.isNull()) { 837 auto cbData = MakeUnique<LoadNanoappCallbackData>(); 838 if (cbData.isNull()) { 839 LOG_OOM(); 840 } else { 841 cbData->transactionId = transactionId; 842 cbData->hostClientId = hostClientId; 843 cbData->appId = appId; 844 cbData->fragmentId = fragmentId; 845 cbData->nanoapp = std::move(pendingNanoapp); 846 847 // Note that if this fails, we'll generate the error response in 848 // the normal deferred callback 849 EventLoopManagerSingleton::get()->deferCallback( 850 SystemCallbackType::FinishLoadingNanoapp, cbData.release(), 851 finishLoadingNanoappCallback); 852 } 853 } 854 } 855 856 void HostMessageHandlers::handleUnloadNanoappRequest( 857 uint16_t hostClientId, uint32_t transactionId, uint64_t appId, 858 bool allowSystemNanoappUnload) { 859 LOGD("Unload nanoapp request (txnID %" PRIu32 ") for appId 0x%016" PRIx64 860 " system %d", 861 transactionId, appId, allowSystemNanoappUnload); 862 auto *cbData = memoryAlloc<UnloadNanoappCallbackData>(); 863 if (cbData == nullptr) { 864 LOG_OOM(); 865 } else { 866 cbData->appId = appId; 867 cbData->transactionId = transactionId; 868 cbData->hostClientId = hostClientId; 869 cbData->allowSystemNanoappUnload = allowSystemNanoappUnload; 870 871 EventLoopManagerSingleton::get()->deferCallback( 872 SystemCallbackType::HandleUnloadNanoapp, cbData, 873 handleUnloadNanoappCallback); 874 } 875 } 876 877 void HostMessageHandlers::handleTimeSyncMessage(int64_t offset) { 878 setEstimatedHostTimeOffset(offset); 879 880 // Schedule a time sync request since offset may drift 881 constexpr Seconds kClockDriftTimeSyncPeriod = 882 Seconds(60 * 60 * 6); // 6 hours 883 setTimeSyncRequestTimer(kClockDriftTimeSyncPeriod); 884 } 885 886 void HostMessageHandlers::handleDebugDumpRequest(uint16_t hostClientId) { 887 if (!chre::EventLoopManagerSingleton::get() 888 ->getDebugDumpManager() 889 .onDebugDumpRequested(hostClientId)) { 890 LOGE("Couldn't trigger debug dump process"); 891 sendDebugDumpResponse(hostClientId, false /*success*/, 0 /*dataCount*/); 892 } 893 } 894 895 void HostLink::sendLogMessage(const char *logMessage, size_t logMessageSize) { 896 struct LogMessageData { 897 const char *logMsg; 898 size_t logMsgSize; 899 }; 900 901 LogMessageData logMessageData; 902 903 logMessageData.logMsg = logMessage; 904 logMessageData.logMsgSize = logMessageSize; 905 906 auto msgBuilder = [](FlatBufferBuilder &builder, void *cookie) { 907 const auto *data = static_cast<const LogMessageData *>(cookie); 908 HostProtocolChre::encodeLogMessages(builder, data->logMsg, 909 data->logMsgSize); 910 }; 911 912 constexpr size_t kInitialSize = 128; 913 buildAndEnqueueMessage(PendingMessageType::EncodedLogMessage, kInitialSize, 914 msgBuilder, &logMessageData); 915 } 916 917 void HostMessageHandlers::handleSettingChangeMessage(fbs::Setting setting, 918 fbs::SettingState state) { 919 Setting chreSetting; 920 SettingState chreSettingState; 921 if (getSettingFromFbs(setting, &chreSetting) && 922 getSettingStateFromFbs(state, &chreSettingState)) { 923 postSettingChange(chreSetting, chreSettingState); 924 } 925 } 926 927 } // namespace chre 928