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