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