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
38using flatbuffers::FlatBufferBuilder;
39
40namespace chre {
41
42namespace {
43
44constexpr size_t kOutboundQueueSize = 32;
45
46//! Used to pass the client ID through the user data pointer in deferCallback
47union HostClientIdCallbackData {
48  uint16_t hostClientId;
49  void *ptr;
50};
51static_assert(sizeof(uint16_t) <= sizeof(void*),
52              "Pointer must at least fit a u16 for passing the host client ID");
53
54struct LoadNanoappCallbackData {
55  uint64_t appId;
56  uint32_t transactionId;
57  uint16_t hostClientId;
58  UniquePtr<Nanoapp> nanoapp = MakeUnique<Nanoapp>();
59};
60
61struct NanoappListData {
62  FlatBufferBuilder *builder;
63  DynamicVector<NanoappListEntryOffset> nanoappEntries;
64  uint16_t hostClientId;
65};
66
67enum class PendingMessageType {
68  Shutdown,
69  NanoappMessageToHost,
70  LogMessage,
71  HubInfoResponse,
72  NanoappListResponse,
73  LoadNanoappResponse,
74  UnloadNanoappResponse,
75  DebugDumpData,
76  DebugDumpResponse,
77  TimeSyncRequest,
78};
79
80struct 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
105struct UnloadNanoappCallbackData {
106  uint64_t appId;
107  uint32_t transactionId;
108  uint16_t hostClientId;
109  bool allowSystemNanoappUnload;
110};
111
112struct DebugDumpCallbackData {
113  uint32_t dataCount;
114  uint16_t hostClientId;
115  bool success;
116};
117
118/**
119 * @see buildAndEnqueueMessage()
120 */
121typedef void (MessageBuilderFunction)(FlatBufferBuilder& builder, void *cookie);
122
123FixedSizeBlockingQueue<PendingMessage, kOutboundQueueSize>
124    gOutboundQueue;
125
126int 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 */
153bool 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 */
180bool 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 */
210void 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
228void 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
251void 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
272void 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
296int 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
316int 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
329int 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
360int 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
370void 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
393void 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 */
408void 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 */
434extern "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 */
501extern "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
521void 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
539bool HostLink::sendMessage(const MessageToHost *message) {
540  return enqueueMessage(
541      PendingMessage(PendingMessageType::NanoappMessageToHost, message));
542}
543
544bool 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
556void 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
584void 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
595void 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
603void 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
616void 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
623void 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
632void 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
661void 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
684void HostMessageHandlers::handleTimeSyncMessage(int64_t offset) {
685  setEstimatedHostTimeOffset(offset);
686}
687
688void 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