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 "chre/platform/android/host_link.h"
18
19#include "chre/core/event_loop_manager.h"
20#include "chre/platform/shared/host_protocol_common.h"
21#include "chre/util/macros.h"
22#include "chre_api/chre/version.h"
23#include "chre_host/host_messages_generated.h"
24
25namespace chre {
26
27//! Used to pass the client ID through the user data pointer in deferCallback
28union HostClientIdCallbackData {
29  uint16_t hostClientId;
30  void *ptr;
31};
32
33static_assert(sizeof(uint16_t) <= sizeof(void*),
34              "Pointer must at least fit a u16 for passing the host client ID");
35
36/**
37 * Assigns a vector the contents of a C-style, null-terminated string.
38 *
39 * @param vector The vector to assign with the contents of a string.
40 * @param str The string to assign.
41 */
42void setVectorToString(std::vector<int8_t> *vector, const char *str) {
43  *vector = std::vector<int8_t>(str, str + strlen(str));
44}
45
46/**
47 * Sends a message to the host given a hostClientId.
48 *
49 * @param message The message to send to the host.
50 * @param hostClientId The host who made the original request for which this is
51 *        a reply.
52 */
53template<typename T>
54void sendFlatbufferToHost(T& message, uint16_t hostClientId) {
55  static_assert(
56      fbs::ChreMessageTraits<typename T::TableType>::enum_value
57          != fbs::ChreMessage::NONE,
58      "Only works for message types supported by ChreMessageUnion");
59
60  fbs::MessageContainerT container;
61  container.message.Set(std::move(message));
62  container.host_addr.reset(new fbs::HostAddress(hostClientId));
63
64  flatbuffers::FlatBufferBuilder builder;
65  auto containerOffset = CreateMessageContainer(builder, &container, nullptr);
66  builder.Finish(containerOffset);
67
68  SocketServerSingleton::get()->sendToClientById(
69      builder.GetBufferPointer(), builder.GetSize(), hostClientId);
70}
71
72/**
73 * Handles a message directed to a nanoapp from the system.
74 *
75 * @param message The message to deliver to a nanoapp.
76 */
77void handleNanoappMessage(const fbs::NanoappMessageT& message) {
78  LOGD("handleNanoappMessage");
79  HostCommsManager& manager =
80      EventLoopManagerSingleton::get()->getHostCommsManager();
81  manager.sendMessageToNanoappFromHost(
82      message.app_id, message.message_type, message.host_endpoint,
83      message.message.data(), message.message.size());
84}
85
86/**
87 * Handles a request for information about this context hub instance.
88 *
89 * @param hostClientId The client ID on the host making the request.
90 */
91void handleHubInfoRequest(uint16_t hostClientId) {
92  LOGD("handleHubInfoRequest");
93  fbs::HubInfoResponseT response;
94  setVectorToString(&response.name, "CHRE on Android");
95  setVectorToString(&response.vendor, "Google");
96  setVectorToString(&response.toolchain, "Android NDK API 26 (clang "
97    STRINGIFY(__clang_major__) "."
98    STRINGIFY(__clang_minor__) "."
99    STRINGIFY(__clang_patchlevel__) ")");
100  response.platform_version = 0;
101  response.toolchain_version = ((__clang_major__ & 0xFF) << 24) |
102    ((__clang_minor__ & 0xFF) << 16) |
103    (__clang_patchlevel__ & 0xFFFF);
104  response.peak_mips = 1000;
105  response.stopped_power = 1000;
106  response.sleep_power = 1000;
107  response.peak_power = 10000;
108  response.max_msg_len = CHRE_MESSAGE_TO_HOST_MAX_SIZE;
109  response.platform_id = chreGetPlatformId();
110  response.chre_platform_version = chreGetVersion();
111
112  sendFlatbufferToHost(response, hostClientId);
113}
114
115void constructNanoappListCallback(uint16_t /*eventType*/, void *cookie) {
116  HostClientIdCallbackData clientIdCbData;
117  clientIdCbData.ptr = cookie;
118
119  auto nanoappAddCallback = [](const Nanoapp *nanoapp, void *data) {
120    auto response = static_cast<fbs::NanoappListResponseT *>(data);
121    auto nanoappListEntry =
122        std::unique_ptr<fbs::NanoappListEntryT>(new fbs::NanoappListEntryT());
123    nanoappListEntry->app_id = nanoapp->getAppId();
124    nanoappListEntry->version = nanoapp->getAppVersion();
125    nanoappListEntry->enabled = true;
126    nanoappListEntry->is_system = nanoapp->isSystemNanoapp();
127    response->nanoapps.push_back(std::move(nanoappListEntry));
128  };
129
130  fbs::NanoappListResponseT response;
131  EventLoop& eventLoop = EventLoopManagerSingleton::get()->getEventLoop();
132  eventLoop.forEachNanoapp(nanoappAddCallback, &response);
133
134  sendFlatbufferToHost(response, clientIdCbData.hostClientId);
135}
136
137/**
138 * Handles a request from the host for a list of nanoapps.
139 *
140 * @param hostClientId The client ID on the host making the request.
141 */
142void handleNanoappListRequest(uint16_t hostClientId) {
143  LOGD("handleNanoappListRequest");
144  HostClientIdCallbackData cbData = {};
145  cbData.hostClientId = hostClientId;
146  EventLoopManagerSingleton::get()->deferCallback(
147      SystemCallbackType::NanoappListResponse, cbData.ptr,
148      constructNanoappListCallback);
149}
150
151/**
152 * Handles a request to load a nanoapp.
153 *
154 * @param hostClientId The client ID on the host making the request.
155 * @param loadRequest The details of the nanoapp load request.
156 */
157void handleLoadNanoappRequest(
158    uint16_t hostClientId, const fbs::LoadNanoappRequestT& loadRequest) {
159  LOGD("handleLoadNanoappRequest");
160}
161
162/**
163 * Handles a request to unload a nanoapp.
164 *
165 * @param hostClientId The client ID on the host making the request.
166 * @param unloadRequest The details of the nanoapp unload request.
167 */
168void handleUnloadNanoappRequest(
169    uint16_t hostClientId, const fbs::UnloadNanoappRequestT& unloadRequest) {
170  LOGD("handleUnloadNanoappRequest");
171}
172
173/**
174 * Handles a request for a debug dump.
175 *
176 * @param hostClientId The client OD on the host making the request.
177 */
178void handleDebugDumpRequest(uint16_t hostClientId) {
179  LOGD("handleDebugDumpRequest");
180}
181
182bool handleMessageFromHost(void *message, size_t length) {
183  bool success = HostProtocolCommon::verifyMessage(message, length);
184  if (success) {
185    fbs::MessageContainerT container;
186    fbs::GetMessageContainer(message)->UnPackTo(&container);
187    uint16_t hostClientId = container.host_addr->client_id();
188    switch (container.message.type) {
189      case fbs::ChreMessage::NanoappMessage:
190        handleNanoappMessage(*container.message.AsNanoappMessage());
191        break;
192
193      case fbs::ChreMessage::HubInfoRequest:
194        handleHubInfoRequest(hostClientId);
195        break;
196
197      case fbs::ChreMessage::NanoappListRequest:
198        handleNanoappListRequest(hostClientId);
199        break;
200
201      case fbs::ChreMessage::LoadNanoappRequest:
202        handleLoadNanoappRequest(hostClientId,
203                                 *container.message.AsLoadNanoappRequest());
204        break;
205
206      case fbs::ChreMessage::UnloadNanoappRequest:
207        handleUnloadNanoappRequest(hostClientId,
208                                   *container.message.AsUnloadNanoappRequest());
209        break;
210
211      case fbs::ChreMessage::DebugDumpRequest:
212        handleDebugDumpRequest(hostClientId);
213        break;
214
215      default:
216        LOGW("Got invalid/unexpected message type %" PRIu8,
217             static_cast<uint8_t>(container.message.type));
218        success = false;
219    }
220  }
221
222  return success;
223}
224
225}  // namespace chre
226