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