1a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie/*
2a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie * Copyright (C) 2017 The Android Open Source Project
3a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie *
4a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie * Licensed under the Apache License, Version 2.0 (the "License");
5a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie * you may not use this file except in compliance with the License.
6a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie * You may obtain a copy of the License at
7a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie *
8a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie *      http://www.apache.org/licenses/LICENSE-2.0
9a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie *
10a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie * Unless required by applicable law or agreed to in writing, software
11a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie * distributed under the License is distributed on an "AS IS" BASIS,
12a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie * See the License for the specific language governing permissions and
14a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie * limitations under the License.
15a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie */
16a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie
17a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie#include <inttypes.h>
18a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie#include <limits.h>
19a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie
20a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie#include "qurt.h"
21a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie
22a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie#include "chre/core/event_loop_manager.h"
23a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie#include "chre/core/host_comms_manager.h"
24a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie#include "chre/platform/context.h"
25a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie#include "chre/platform/memory.h"
26a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie#include "chre/platform/log.h"
277621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie#include "chre/platform/shared/host_protocol_chre.h"
28a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie#include "chre/platform/slpi/fastrpc.h"
29a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie#include "chre/util/fixed_size_blocking_queue.h"
307621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie#include "chre/util/macros.h"
3147a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie#include "chre/util/unique_ptr.h"
327621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie#include "chre_api/chre/version.h"
337621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie
347621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddieusing flatbuffers::FlatBufferBuilder;
35a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie
36a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddienamespace chre {
37a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie
38a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddienamespace {
39a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie
40a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddieconstexpr size_t kOutboundQueueSize = 32;
41a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie
42f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie//! Used to pass the client ID through the user data pointer in deferCallback
43f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddieunion HostClientIdCallbackData {
44f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie  uint16_t hostClientId;
45f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie  void *ptr;
46f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie};
47f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddiestatic_assert(sizeof(uint16_t) <= sizeof(void*),
48f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie              "Pointer must at least fit a u16 for passing the host client ID");
49f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie
5047a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddiestruct LoadNanoappCallbackData {
5147a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie  uint64_t appId;
5247a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie  uint32_t transactionId;
5347a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie  uint16_t hostClientId;
5447a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie  UniquePtr<Nanoapp> nanoapp = MakeUnique<Nanoapp>();
5547a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie};
5647a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie
577621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddieenum class PendingMessageType {
587621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  Shutdown,
597621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  NanoappMessageToHost,
607621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  HubInfoResponse,
61a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie  NanoappListResponse,
6247a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie  LoadNanoappResponse,
637621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie};
647621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie
657621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddiestruct PendingMessage {
66f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie  PendingMessage(PendingMessageType msgType, uint16_t hostClientId) {
677621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    type = msgType;
68f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie    data.hostClientId = hostClientId;
69f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie  }
70f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie
71f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie  PendingMessage(PendingMessageType msgType,
72f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie                 const MessageToHost *msgToHost = nullptr) {
73f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie    type = msgType;
74f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie    data.msgToHost = msgToHost;
7572833b2fba97751b31b27422d117b05f718760fdBrian Duddie  }
767621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie
77a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie  PendingMessage(PendingMessageType msgType, FlatBufferBuilder *builder) {
78a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie    type = msgType;
79a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie    data.builder = builder;
80a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie  }
81a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie
827621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  PendingMessageType type;
837621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  union {
847621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    const MessageToHost *msgToHost;
85f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie    uint16_t hostClientId;
86a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie    FlatBufferBuilder *builder;
877621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  } data;
8872833b2fba97751b31b27422d117b05f718760fdBrian Duddie};
89ef456c07c1738f624e95259878d41305129e64d9Brian Duddie
907621b3267fd2ff1068d7aa7d75441d68646226abBrian DuddieFixedSizeBlockingQueue<PendingMessage, kOutboundQueueSize>
917621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    gOutboundQueue;
927621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie
937621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddieint copyToHostBuffer(const FlatBufferBuilder& builder, unsigned char *buffer,
947621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie                     size_t bufferSize, unsigned int *messageLen) {
957621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  uint8_t *data = builder.GetBufferPointer();
967621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  size_t size = builder.GetSize();
977621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  int result;
987621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie
997621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  if (size > bufferSize) {
1007621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    LOGE("Encoded structure size %zu too big for host buffer %zu; dropping",
1017621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie         size, bufferSize);
1027621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    result = CHRE_FASTRPC_ERROR;
1037621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  } else {
1047621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    memcpy(buffer, data, size);
1057621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    *messageLen = size;
1067621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    result = CHRE_FASTRPC_SUCCESS;
1077621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  }
1087621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie
1097621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  return result;
1107621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie}
1117621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie
112f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddievoid constructNanoappListCallback(uint16_t /*eventType*/, void *deferCbData) {
113a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie  constexpr size_t kFixedOverhead = 56;
114a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie  constexpr size_t kPerNanoappSize = 16;
115a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie
116f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie  HostClientIdCallbackData clientIdCbData;
117f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie  clientIdCbData.ptr = deferCbData;
118f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie
119a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie  // TODO: need to add support for getting apps from multiple event loops
120a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie  bool pushed = false;
121a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie  EventLoop *eventLoop = getCurrentEventLoop();
122a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie  size_t expectedNanoappCount = eventLoop->getNanoappCount();
123a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie  DynamicVector<NanoappListEntryOffset> nanoappEntries;
124a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie
125a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie  auto *builder = memoryAlloc<FlatBufferBuilder>(
126a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie      kFixedOverhead + expectedNanoappCount * kPerNanoappSize);
127a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie  if (builder == nullptr) {
128a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie    LOGE("Couldn't allocate builder for nanoapp list response");
129a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie  } else if (!nanoappEntries.reserve(expectedNanoappCount)) {
130a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie    LOGE("Couldn't reserve space for list of nanoapp offsets");
131a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie  } else {
132a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie    struct CallbackData {
133a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie      CallbackData(FlatBufferBuilder& builder_,
134a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie                   DynamicVector<NanoappListEntryOffset>& nanoappEntries_)
135a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie          : builder(builder_), nanoappEntries(nanoappEntries_) {}
136a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie
137a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie      FlatBufferBuilder& builder;
138a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie      DynamicVector<NanoappListEntryOffset>& nanoappEntries;
139a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie    };
140a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie
141a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie    auto callback = [](const Nanoapp *nanoapp, void *untypedData) {
142a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie      auto *data = static_cast<CallbackData *>(untypedData);
143a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie      HostProtocolChre::addNanoappListEntry(
144a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie          data->builder, data->nanoappEntries, nanoapp->getAppId(),
145a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie          nanoapp->getAppVersion(), true /*enabled*/,
146a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie          nanoapp->isSystemNanoapp());
147a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie    };
148a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie
149a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie    // Add a NanoappListEntry to the FlatBuffer for each nanoapp
150a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie    CallbackData cbData(*builder, nanoappEntries);
151a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie    eventLoop->forEachNanoapp(callback, &cbData);
152f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie    HostProtocolChre::finishNanoappListResponse(*builder, nanoappEntries,
153f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie                                                clientIdCbData.hostClientId);
154a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie
155a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie    pushed = gOutboundQueue.push(
156a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie        PendingMessage(PendingMessageType::NanoappListResponse, builder));
157a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie    if (!pushed) {
158a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie      LOGE("Couldn't push list response");
159a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie    }
160a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie  }
161a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie
162a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie  if (!pushed && builder != nullptr) {
163a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie    memoryFree(builder);
164a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie  }
165a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie}
166a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie
16747a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddievoid finishLoadingNanoappCallback(uint16_t /*eventType*/, void *data) {
16847a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie  UniquePtr<LoadNanoappCallbackData> cbData(
16947a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie      static_cast<LoadNanoappCallbackData *>(data));
17047a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie
17147a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie  EventLoop *eventLoop = getCurrentEventLoop();
17247a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie  bool startedSuccessfully = (cbData->nanoapp->isLoaded()) ?
17347a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie      eventLoop->startNanoapp(cbData->nanoapp) : false;
17447a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie
17547a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie  constexpr size_t kInitialBufferSize = 48;
17647a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie  auto *builder = memoryAlloc<FlatBufferBuilder>(kInitialBufferSize);
17747a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie  if (builder == nullptr) {
17847a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie    LOGE("Couldn't allocate memory for load nanoapp response");
17947a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie  } else {
18047a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie    HostProtocolChre::encodeLoadNanoappResponse(
18147a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie        *builder, cbData->hostClientId, cbData->transactionId,
18247a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie        startedSuccessfully);
18347a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie
18447a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie    // TODO: if this fails, ideally we should block for some timeout until
18547a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie    // there's space in the queue (like up to 1 second)
18647a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie    if (!gOutboundQueue.push(PendingMessage(
18747a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie            PendingMessageType::LoadNanoappResponse, builder))) {
18847a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie      LOGE("Couldn't push load nanoapp response to outbound queue");
18947a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie      memoryFree(builder);
19047a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie    }
19147a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie  }
19247a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie}
19347a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie
1947621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddieint generateMessageToHost(const MessageToHost *msgToHost, unsigned char *buffer,
1957621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie                          size_t bufferSize, unsigned int *messageLen) {
1967621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  // TODO: ideally we'd construct our flatbuffer directly in the
1977621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  // host-supplied buffer
198a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie  constexpr size_t kFixedSizePortion = 56;
1997621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  FlatBufferBuilder builder(msgToHost->message.size() + kFixedSizePortion);
2007621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  HostProtocolChre::encodeNanoappMessage(
2017621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    builder, msgToHost->appId, msgToHost->toHostData.messageType,
2027621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    msgToHost->toHostData.hostEndpoint, msgToHost->message.data(),
2037621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    msgToHost->message.size());
2047621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie
2057621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  int result = copyToHostBuffer(builder, buffer, bufferSize, messageLen);
2067621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie
2077621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  auto& hostCommsManager =
2087621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie      EventLoopManagerSingleton::get()->getHostCommsManager();
2097621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  hostCommsManager.onMessageToHostComplete(msgToHost);
2107621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie
2117621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  return result;
2127621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie}
2137621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie
214f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddieint generateHubInfoResponse(uint16_t hostClientId, unsigned char *buffer,
215f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie                            size_t bufferSize, unsigned int *messageLen) {
2167621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  constexpr size_t kInitialBufferSize = 192;
2177621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie
2187621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  constexpr char kHubName[] = "CHRE on SLPI";
2197621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  constexpr char kVendor[] = "Google";
2207621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  constexpr char kToolchain[] = "Hexagon Tools 8.0 (clang "
2217621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    STRINGIFY(__clang_major__) "."
2227621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    STRINGIFY(__clang_minor__) "."
2237621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    STRINGIFY(__clang_patchlevel__) ")";
2247621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  constexpr uint32_t kLegacyPlatformVersion = 0;
2257621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  constexpr uint32_t kLegacyToolchainVersion =
2267621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    ((__clang_major__ & 0xFF) << 24) |
2277621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    ((__clang_minor__ & 0xFF) << 16) |
2287621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    (__clang_patchlevel__ & 0xFFFF);
2297621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  constexpr float kPeakMips = 350;
2307621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  constexpr float kStoppedPower = 0;
2317621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  constexpr float kSleepPower = 1;
2327621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  constexpr float kPeakPower = 15;
2337621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie
2347621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  FlatBufferBuilder builder(kInitialBufferSize);
2357621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  HostProtocolChre::encodeHubInfoResponse(
2367621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie      builder, kHubName, kVendor, kToolchain, kLegacyPlatformVersion,
2377621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie      kLegacyToolchainVersion, kPeakMips, kStoppedPower, kSleepPower,
2387621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie      kPeakPower, CHRE_MESSAGE_TO_HOST_MAX_SIZE, chreGetPlatformId(),
239f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie      chreGetVersion(), hostClientId);
2407621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie
2417621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  return copyToHostBuffer(builder, buffer, bufferSize, messageLen);
2427621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie}
2437621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie
24447a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddieint generateMessageFromBuilder(
245a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie    FlatBufferBuilder *builder, unsigned char *buffer, size_t bufferSize,
246a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie    unsigned int *messageLen) {
247a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie  CHRE_ASSERT(builder != nullptr);
248a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie  int result = copyToHostBuffer(*builder, buffer, bufferSize, messageLen);
249a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie  memoryFree(builder);
250a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie  return result;
251a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie}
252a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie
253ef456c07c1738f624e95259878d41305129e64d9Brian Duddie/**
254a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie * FastRPC method invoked by the host to block on messages
255a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie *
256a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie * @param buffer Output buffer to populate with message data
257a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie * @param bufferLen Size of the buffer, in bytes
258a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie * @param messageLen Output parameter to populate with the size of the message
259a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie *        in bytes upon success
260a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie *
261a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie * @return 0 on success, nonzero on failure
262a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie */
263a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddieextern "C" int chre_slpi_get_message_to_host(
264a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie    unsigned char *buffer, int bufferLen, unsigned int *messageLen) {
265a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie  CHRE_ASSERT(buffer != nullptr);
266a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie  CHRE_ASSERT(bufferLen > 0);
267a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie  CHRE_ASSERT(messageLen != nullptr);
2687621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  int result = CHRE_FASTRPC_ERROR;
269a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie
2707621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  if (bufferLen <= 0 || buffer == nullptr || messageLen == nullptr) {
2717621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    // Note that we can't use regular logs here as they can result in sending
2727621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    // a message, leading to an infinite loop if the error is persistent
2737621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    FARF(FATAL, "Invalid buffer size %d or bad pointers (buf %d len %d)",
2747621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie         bufferLen, (buffer == nullptr), (messageLen == nullptr));
275a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie  } else {
2767621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    size_t bufferSize = static_cast<size_t>(bufferLen);
2777621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    PendingMessage pendingMsg = gOutboundQueue.pop();
278a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie
2797621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    switch (pendingMsg.type) {
2807621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie      case PendingMessageType::Shutdown:
2817621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie        result = CHRE_FASTRPC_ERROR_SHUTTING_DOWN;
2827621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie        break;
2837621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie
2847621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie      case PendingMessageType::NanoappMessageToHost:
2857621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie        result = generateMessageToHost(pendingMsg.data.msgToHost, buffer,
2867621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie                                       bufferSize, messageLen);
2877621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie        break;
2887621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie
2897621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie      case PendingMessageType::HubInfoResponse:
290f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie        result = generateHubInfoResponse(pendingMsg.data.hostClientId, buffer,
291f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie                                         bufferSize, messageLen);
2927621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie        break;
2937621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie
294a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie      case PendingMessageType::NanoappListResponse:
29547a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie      case PendingMessageType::LoadNanoappResponse:
29647a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie        result = generateMessageFromBuilder(pendingMsg.data.builder,
29747a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie                                            buffer, bufferSize, messageLen);
298a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie        break;
299a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie
3007621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie      default:
3017621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie        CHRE_ASSERT_LOG(false, "Unexpected pending message type");
3027621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    }
303a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie  }
304a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie
305f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie  LOGD("Returning message to host (result %d length %u)", result, *messageLen);
306a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie  return result;
307a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie}
308a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie
309a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie/**
310a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie * FastRPC method invoked by the host to send a message to the system
311a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie *
312a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie * @param buffer
313a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie * @param size
314a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie *
315a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie * @return 0 on success, nonzero on failure
316a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie */
317a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddieextern "C" int chre_slpi_deliver_message_from_host(const unsigned char *message,
318a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie                                                   int messageLen) {
31918a498cfae5841009e9cd8022f691272a6967a5dBrian Duddie  CHRE_ASSERT(message != nullptr);
32018a498cfae5841009e9cd8022f691272a6967a5dBrian Duddie  CHRE_ASSERT(messageLen > 0);
32118a498cfae5841009e9cd8022f691272a6967a5dBrian Duddie  int result = CHRE_FASTRPC_ERROR;
32218a498cfae5841009e9cd8022f691272a6967a5dBrian Duddie
32372833b2fba97751b31b27422d117b05f718760fdBrian Duddie  if (message == nullptr || messageLen <= 0) {
32418a498cfae5841009e9cd8022f691272a6967a5dBrian Duddie    LOGE("Got null or invalid size (%d) message from host", messageLen);
3257621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  } else if (!HostProtocolChre::decodeMessageFromHost(
3267621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie      message, static_cast<size_t>(messageLen))) {
32772833b2fba97751b31b27422d117b05f718760fdBrian Duddie    LOGE("Failed to decode/handle message");
32818a498cfae5841009e9cd8022f691272a6967a5dBrian Duddie  } else {
32972833b2fba97751b31b27422d117b05f718760fdBrian Duddie    result = CHRE_FASTRPC_SUCCESS;
33018a498cfae5841009e9cd8022f691272a6967a5dBrian Duddie  }
33118a498cfae5841009e9cd8022f691272a6967a5dBrian Duddie
33218a498cfae5841009e9cd8022f691272a6967a5dBrian Duddie  return result;
333a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie}
334a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie
335a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie}  // anonymous namespace
336a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie
337a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddiebool HostLink::sendMessage(const MessageToHost *message) {
3387621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  return gOutboundQueue.push(
3397621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie      PendingMessage(PendingMessageType::NanoappMessageToHost, message));
340a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie}
341a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie
342a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddievoid HostLinkBase::shutdown() {
343a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie  constexpr qurt_timer_duration_t kPollingIntervalUsec = 5000;
344a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie
345a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie  // Push a null message so the blocking call in chre_slpi_get_message_to_host()
346a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie  // returns and the host can exit cleanly. If the queue is full, try again to
347a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie  // avoid getting stuck (no other new messages should be entering the queue at
348a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie  // this time). Don't wait too long as the host-side binary may have died in
349a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie  // a state where it's not blocked in chre_slpi_get_message_to_host().
350a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie  int retryCount = 5;
351a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie  FARF(MEDIUM, "Shutting down host link");
3527621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  while (!gOutboundQueue.push(PendingMessage(PendingMessageType::Shutdown))
3537621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie         && --retryCount > 0) {
354a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie    qurt_timer_sleep(kPollingIntervalUsec);
355a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie  }
356a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie
357a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie  if (retryCount <= 0) {
358a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie    // Don't use LOGE, as it may involve trying to send a message
359a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie    FARF(ERROR, "No room in outbound queue for shutdown message and host not "
360a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie         "draining queue!");
361a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie  } else {
362a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie    FARF(MEDIUM, "Draining message queue");
363a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie
364a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie    // We were able to push the shutdown message. Wait for the queue to
365a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie    // completely flush before returning.
366a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie    int waitCount = 5;
367a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie    while (!gOutboundQueue.empty() && --waitCount > 0) {
368a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie      qurt_timer_sleep(kPollingIntervalUsec);
369a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie    }
370a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie
371a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie    if (waitCount <= 0) {
372a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie      FARF(ERROR, "Host took too long to drain outbound queue; exiting anyway");
373a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie    } else {
374a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie      FARF(MEDIUM, "Finished draining queue");
375a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie    }
376a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie  }
377a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie}
378a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie
3797621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddievoid HostMessageHandlers::handleNanoappMessage(
3807621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    uint64_t appId, uint32_t messageType, uint16_t hostEndpoint,
3817621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie    const void *messageData, size_t messageDataLen) {
3827621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  LOGD("Parsed nanoapp message from host: app ID 0x%016" PRIx64 ", endpoint "
3837621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie       "0x%" PRIx16 ", msgType %" PRIu32 ", payload size %zu",
3847621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie       appId, hostEndpoint, messageType, messageDataLen);
3857621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie
3867621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  HostCommsManager& manager =
3877621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie      EventLoopManagerSingleton::get()->getHostCommsManager();
3887621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  manager.sendMessageToNanoappFromHost(
3897621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie      appId, messageType, hostEndpoint, messageData, messageDataLen);
3907621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie}
3917621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie
392f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddievoid HostMessageHandlers::handleHubInfoRequest(uint16_t hostClientId) {
3937621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie  // We generate the response in the context of chre_slpi_get_message_to_host
394f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie  LOGD("Got hub info request from client ID %" PRIu16, hostClientId);
395f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie  gOutboundQueue.push(PendingMessage(
396f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie      PendingMessageType::HubInfoResponse, hostClientId));
3977621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie}
3987621b3267fd2ff1068d7aa7d75441d68646226abBrian Duddie
399f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddievoid HostMessageHandlers::handleNanoappListRequest(uint16_t hostClientId) {
400f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie  LOGD("Got nanoapp list request from client ID %" PRIu16, hostClientId);
401f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie  HostClientIdCallbackData cbData = {};
402f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie  cbData.hostClientId = hostClientId;
403a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie  EventLoopManagerSingleton::get()->deferCallback(
404f685db3a6b34f8dd6942964ae99836bda87c8134Brian Duddie      SystemCallbackType::NanoappListResponse, cbData.ptr,
405a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie      constructNanoappListCallback);
406a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie}
407a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie
40847a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddievoid HostMessageHandlers::handleLoadNanoappRequest(
40947a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie    uint16_t hostClientId, uint32_t transactionId, uint64_t appId,
41047a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie    uint32_t appVersion, uint32_t targetApiVersion, const void *appBinary,
41147a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie    size_t appBinaryLen) {
41247a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie  auto cbData = MakeUnique<LoadNanoappCallbackData>();
41347a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie
41447a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie  LOGD("Got load nanoapp request (txnId %" PRIu32 ") for appId 0x%016" PRIx64
41547a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie       " version 0x%" PRIx32 " target API version 0x%08" PRIx32 " size %zu",
41647a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie       transactionId, appId, appVersion, targetApiVersion, appBinaryLen);
41747a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie  if (cbData.isNull() || cbData->nanoapp.isNull()) {
41847a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie    LOGE("Couldn't allocate load nanoapp callback data");
41947a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie  } else {
42047a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie    cbData->transactionId = transactionId;
42147a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie    cbData->hostClientId  = hostClientId;
42247a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie    cbData->appId = appId;
42347a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie
42447a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie    // Note that if this fails, we'll generate the error response in
42547a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie    // the normal deferred callback
42647a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie    cbData->nanoapp->loadFromBuffer(appId, appVersion, appBinary, appBinaryLen);
42747a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie    if (!EventLoopManagerSingleton::get()->deferCallback(
42847a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie            SystemCallbackType::FinishLoadingNanoapp, cbData.get(),
42947a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie            finishLoadingNanoappCallback)) {
43047a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie      LOGE("Couldn't post callback to finish loading nanoapp");
43147a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie    } else {
43247a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie      cbData.release();
43347a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie    }
43447a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie  }
43547a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie}
43647a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie
437a0ead37f82267c65e220bd08e28856dce6badf82Brian Duddie}  // namespace chre
438