blob: 4a6b3f278b6eb90bfe8100b5a3be649c94bd4ff7 [file] [log] [blame]
Ashutosh Joshi1bec86a2016-11-15 13:48:58 -08001/*
2 * Copyright (C) 2016 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 "Contexthub.h"
18
19#include <inttypes.h>
20
Mark Salyzyn3ff52602017-01-10 10:16:48 -080021#include <log/log.h>
22
Ashutosh Joshi1bec86a2016-11-15 13:48:58 -080023#include <android/hardware/contexthub/1.0/IContexthub.h>
24#include <hardware/context_hub.h>
Brian Duddiec6d2fd42017-01-12 14:47:58 -080025#include <sys/endian.h>
Ashutosh Joshi1bec86a2016-11-15 13:48:58 -080026
27#undef LOG_TAG
28#define LOG_TAG "ContextHubHalAdapter"
29
30namespace android {
31namespace hardware {
32namespace contexthub {
33namespace V1_0 {
34namespace implementation {
35
36static constexpr uint64_t ALL_APPS = UINT64_C(0xFFFFFFFFFFFFFFFF);
37
38Contexthub::Contexthub()
39 : mInitCheck(NO_INIT),
40 mContextHubModule(nullptr),
41 mIsTransactionPending(false) {
42 const hw_module_t *module;
43
44 mInitCheck = hw_get_module(CONTEXT_HUB_MODULE_ID, &module);
45
46 if (mInitCheck != OK) {
47 ALOGE("Could not load %s module: %s", CONTEXT_HUB_MODULE_ID, strerror(-mInitCheck));
48 } else if (module == nullptr) {
49 ALOGE("hal returned succes but a null module!");
50 // Assign an error, this should not really happen...
51 mInitCheck = UNKNOWN_ERROR;
52 } else {
53 ALOGI("Loaded Context Hub module");
54 mContextHubModule = reinterpret_cast<const context_hub_module_t *>(module);
55 }
56}
57
58bool Contexthub::setOsAppAsDestination(hub_message_t *msg, int hubId) {
59 if (!isValidHubId(hubId)) {
60 ALOGW("%s: Hub information is null for hubHandle %d",
61 __FUNCTION__,
62 hubId);
63 return false;
64 } else {
65 msg->app_name = mCachedHubInfo[hubId].osAppName;
66 return true;
67 }
68}
69
70Return<void> Contexthub::getHubs(getHubs_cb _hidl_cb) {
71 std::vector<ContextHub> hubs;
72 if (isInitialized()) {
73 const context_hub_t *hubArray = nullptr;
74 size_t numHubs;
75
76 // Explicitly discarding const. HAL method discards it.
77 numHubs = mContextHubModule->get_hubs(const_cast<context_hub_module_t *>(mContextHubModule),
78 &hubArray);
79 ALOGI("Context Hub Hal Adapter reports %zu hubs", numHubs);
80
81 mCachedHubInfo.clear();
82
83 for (size_t i = 0; i < numHubs; i++) {
84 CachedHubInformation info;
85 ContextHub c;
86
87 c.hubId = hubArray[i].hub_id;
88 c.name = hubArray[i].name;
89 c.vendor = hubArray[i].vendor;
90 c.toolchain = hubArray[i].toolchain;
91 c.toolchainVersion = hubArray[i].toolchain_version;
92 c.platformVersion = hubArray[i].platform_version;
93 c.maxSupportedMsgLen = hubArray[i].max_supported_msg_len;
94 c.peakMips = hubArray[i].peak_mips;
95 c.peakPowerDrawMw = hubArray[i].peak_power_draw_mw;
96 c.stoppedPowerDrawMw = hubArray[i].stopped_power_draw_mw;
97 c.sleepPowerDrawMw = hubArray[i].sleep_power_draw_mw;
98
99 info.callBack = nullptr;
100 info.osAppName = hubArray[i].os_app_name;
101 mCachedHubInfo[hubArray[i].hub_id] = info;
102
103 hubs.push_back(c);
104 }
105 } else {
106 ALOGW("Context Hub Hal Adapter not initialized");
107 }
108
109 _hidl_cb(hubs);
110 return Void();
111}
112
113bool Contexthub::isValidHubId(uint32_t hubId) {
114 if (!mCachedHubInfo.count(hubId)) {
115 ALOGW("Hub information not found for hubId %" PRIu32, hubId);
116 return false;
117 } else {
118 return true;
119 }
120}
121
122sp<IContexthubCallback> Contexthub::getCallBackForHubId(uint32_t hubId) {
123 if (!isValidHubId(hubId)) {
124 return nullptr;
125 } else {
126 return mCachedHubInfo[hubId].callBack;
127 }
128}
129
130Return<Result> Contexthub::sendMessageToHub(uint32_t hubId,
131 const ContextHubMsg &msg) {
132 if (!isInitialized()) {
133 return Result::NOT_INIT;
134 }
135
136 if (!isValidHubId(hubId) || msg.msg.size() > UINT32_MAX) {
137 return Result::BAD_PARAMS;
138 }
139
140 hub_message_t txMsg = {
141 .app_name.id = msg.appName,
142 .message_type = msg.msgType,
143 .message_len = static_cast<uint32_t>(msg.msg.size()), // Note the check above
144 .message = static_cast<const uint8_t *>(msg.msg.data()),
145 };
146
147 ALOGI("Sending msg of type %" PRIu32 ", size %" PRIu32 " to app 0x%" PRIx64,
148 txMsg.message_type,
149 txMsg.message_len,
150 txMsg.app_name.id);
151
152 if(mContextHubModule->send_message(hubId, &txMsg) != 0) {
153 return Result::TRANSACTION_FAILED;
154 }
155
156 return Result::OK;
157}
158
159Return<Result> Contexthub::reboot(uint32_t hubId) {
160 if (!isInitialized()) {
161 return Result::NOT_INIT;
162 }
163
164 hub_message_t msg;
165
166 if (setOsAppAsDestination(&msg, hubId) == false) {
167 return Result::BAD_PARAMS;
168 }
169
170 msg.message_type = CONTEXT_HUB_OS_REBOOT;
171 msg.message_len = 0;
172 msg.message = nullptr;
173
174 if(mContextHubModule->send_message(hubId, &msg) != 0) {
175 return Result::TRANSACTION_FAILED;
176 } else {
177 return Result::OK;
178 }
179}
180
181Return<Result> Contexthub::registerCallback(uint32_t hubId,
182 const sp<IContexthubCallback> &cb) {
183 Return<Result> retVal = Result::BAD_PARAMS;
184
185 if (!isInitialized()) {
186 // Not initilalized
187 ALOGW("Context hub not initialized successfully");
188 retVal = Result::NOT_INIT;
189 } else if (!isValidHubId(hubId)) {
190 // Initialized, but hubId is not valid
191 retVal = Result::BAD_PARAMS;
192 } else if (mContextHubModule->subscribe_messages(hubId,
193 contextHubCb,
194 this) == 0) {
195 // Initialized && valid hub && subscription successful
196 retVal = Result::OK;
197 mCachedHubInfo[hubId].callBack = cb;
198 } else {
199 // Initalized && valid hubId - but subscription unsuccessful
200 // This is likely an internal error in the HAL implementation, but we
201 // cannot add more information.
202 ALOGW("Could not subscribe to the hub for callback");
203 retVal = Result::UNKNOWN_FAILURE;
204 }
205
206 return retVal;
207}
208
209static bool isValidOsStatus(const uint8_t *msg,
210 size_t msgLen,
211 status_response_t *rsp) {
212 // Workaround a bug in some HALs
213 if (msgLen == 1) {
214 rsp->result = msg[0];
215 return true;
216 }
217
218 if (msg == nullptr || msgLen != sizeof(*rsp)) {
219 ALOGI("Received invalid response (is null : %d, size %zu)",
220 msg == nullptr ? 1 : 0,
221 msgLen);
222 return false;
223 }
224
225 memcpy(rsp, msg, sizeof(*rsp));
226
227 // No sanity checks on return values
228 return true;
229}
230
231int Contexthub::handleOsMessage(sp<IContexthubCallback> cb,
232 uint32_t msgType,
233 const uint8_t *msg,
234 int msgLen) {
235 int retVal = -1;
236
237
238 switch(msgType) {
239 case CONTEXT_HUB_APPS_ENABLE:
240 case CONTEXT_HUB_APPS_DISABLE:
241 case CONTEXT_HUB_LOAD_APP:
242 case CONTEXT_HUB_UNLOAD_APP:
243 {
244 struct status_response_t rsp;
245 TransactionResult result;
246 if (isValidOsStatus(msg, msgLen, &rsp) && rsp.result == 0) {
247 retVal = 0;
248 result = TransactionResult::SUCCESS;
249 } else {
250 result = TransactionResult::FAILURE;
251 }
252
253 if (cb != nullptr) {
254 cb->handleTxnResult(mTransactionId, result);
255 }
256 retVal = 0;
257 mIsTransactionPending = false;
258 break;
259 }
260
261 case CONTEXT_HUB_QUERY_APPS:
262 {
263 std::vector<HubAppInfo> apps;
264 int numApps = msgLen / sizeof(hub_app_info);
265 const hub_app_info *unalignedInfoAddr = reinterpret_cast<const hub_app_info *>(msg);
266
267 for (int i = 0; i < numApps; i++) {
268 hub_app_info query_info;
269 memcpy(&query_info, &unalignedInfoAddr[i], sizeof(query_info));
270 HubAppInfo app;
271 app.appId = query_info.app_name.id;
272 app.version = query_info.version;
273 // TODO :: Add memory ranges
274
275 apps.push_back(app);
276 }
277
278 if (cb != nullptr) {
279 cb->handleAppsInfo(apps);
280 }
281 retVal = 0;
282 break;
283 }
284
285 case CONTEXT_HUB_QUERY_MEMORY:
286 {
287 // Deferring this use
288 retVal = 0;
289 break;
290 }
291
292 case CONTEXT_HUB_OS_REBOOT:
293 {
294 mIsTransactionPending = false;
295 if (cb != nullptr) {
296 cb->handleHubEvent(AsyncEventType::RESTARTED);
297 }
298 retVal = 0;
299 break;
300 }
301
302 default:
303 {
304 retVal = -1;
305 break;
306 }
307 }
308
309 return retVal;
310}
311
312int Contexthub::contextHubCb(uint32_t hubId,
313 const struct hub_message_t *rxMsg,
314 void *cookie) {
315 Contexthub *obj = static_cast<Contexthub *>(cookie);
316
317 if (rxMsg == nullptr) {
318 ALOGW("Ignoring NULL message");
319 return -1;
320 }
321
322 if (!obj->isValidHubId(hubId)) {
323 ALOGW("Invalid hub Id %" PRIu32, hubId);
324 return -1;
325 }
326
327 sp<IContexthubCallback> cb = obj->getCallBackForHubId(hubId);
328
329 if (cb == nullptr) {
330 // This should not ever happen
331 ALOGW("No callback registered, returning");
332 return -1;
333 }
334
335 if (rxMsg->message_type < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE) {
336 obj->handleOsMessage(cb,
337 rxMsg->message_type,
338 static_cast<const uint8_t *>(rxMsg->message),
339 rxMsg->message_len);
340 } else {
341 ContextHubMsg msg;
342
343 msg.appName = rxMsg->app_name.id;
344 msg.msgType = rxMsg->message_type;
345 msg.msg = std::vector<uint8_t>(static_cast<const uint8_t *>(rxMsg->message),
346 static_cast<const uint8_t *>(rxMsg->message) +
347 rxMsg->message_len);
348
349 cb->handleClientMsg(msg);
350 }
351
352 return 0;
353}
354
355Return<Result> Contexthub::unloadNanoApp(uint32_t hubId,
356 uint64_t appId,
357 uint32_t transactionId) {
358 if (!isInitialized()) {
359 return Result::NOT_INIT;
360 }
361
362 if (mIsTransactionPending) {
363 return Result::TRANSACTION_PENDING;
364 }
365
366 hub_message_t msg;
367
368 if (setOsAppAsDestination(&msg, hubId) == false) {
369 return Result::BAD_PARAMS;
370 }
371
372 struct apps_disable_request_t req;
373
374 msg.message_type = CONTEXT_HUB_UNLOAD_APP;
375 msg.message_len = sizeof(req);
376 msg.message = &req;
377 req.app_name.id = appId;
378
379 if(mContextHubModule->send_message(hubId, &msg) != 0) {
380 return Result::TRANSACTION_FAILED;
381 } else {
382 mTransactionId = transactionId;
383 mIsTransactionPending = true;
384 return Result::OK;
385 }
386}
387
388Return<Result> Contexthub::loadNanoApp(uint32_t hubId,
Brian Duddiec6d2fd42017-01-12 14:47:58 -0800389 const NanoAppBinary& appBinary,
Ashutosh Joshi1bec86a2016-11-15 13:48:58 -0800390 uint32_t transactionId) {
391 if (!isInitialized()) {
392 return Result::NOT_INIT;
393 }
394
395 if (mIsTransactionPending) {
396 return Result::TRANSACTION_PENDING;
397 }
398
399 hub_message_t hubMsg;
400
401 if (setOsAppAsDestination(&hubMsg, hubId) == false) {
402 return Result::BAD_PARAMS;
403 }
404
Brian Duddiec6d2fd42017-01-12 14:47:58 -0800405 // Data from the nanoapp header is passed through HIDL as explicit fields,
406 // but the legacy HAL expects it prepended to the binary, therefore we must
407 // reconstruct it here prior to passing to the legacy HAL.
408 uint32_t targetChreApiVersion =
409 (appBinary.targetChreApiMajorVersion << 24) |
410 (appBinary.targetChreApiMinorVersion << 16);
411 const struct nano_app_binary_t header = {
412 .header_version = htole32(1),
413 .magic = htole32(NANOAPP_MAGIC),
414 .app_id.id = htole64(appBinary.appId),
415 .app_version = htole32(appBinary.appVersion),
416 .flags = htole32(appBinary.flags),
417 .hw_hub_type = htole64(0),
418 .reserved[0] = htole32(targetChreApiVersion),
419 .reserved[1] = 0,
420 };
421 const uint8_t *headerBytes = reinterpret_cast<const uint8_t *>(&header);
Ashutosh Joshi1bec86a2016-11-15 13:48:58 -0800422
Brian Duddiec6d2fd42017-01-12 14:47:58 -0800423 std::vector<uint8_t> binaryWithHeader(appBinary.customBinary);
424 binaryWithHeader.insert(binaryWithHeader.begin(),
425 headerBytes,
426 headerBytes + sizeof(header));
427
428 hubMsg.message_type = CONTEXT_HUB_LOAD_APP;
429 hubMsg.message_len = binaryWithHeader.size();
430 hubMsg.message = binaryWithHeader.data();
431
432 if (mContextHubModule->send_message(hubId, &hubMsg) != 0) {
Ashutosh Joshi1bec86a2016-11-15 13:48:58 -0800433 return Result::TRANSACTION_FAILED;
434 } else {
435 mTransactionId = transactionId;
436 mIsTransactionPending = true;
437 return Result::OK;
438 }
439}
440
441Return<Result> Contexthub::enableNanoApp(uint32_t hubId,
442 uint64_t appId,
443 uint32_t transactionId) {
444 if (!isInitialized()) {
445 return Result::NOT_INIT;
446 }
447
448 if (mIsTransactionPending) {
449 return Result::TRANSACTION_PENDING;
450 }
451
452 hub_message_t msg;
453
454 if (setOsAppAsDestination(&msg, hubId) == false) {
455 return Result::BAD_PARAMS;
456 }
457
458 struct apps_enable_request_t req;
459
460 msg.message_type = CONTEXT_HUB_APPS_ENABLE;
461 msg.message_len = sizeof(req);
462 req.app_name.id = appId;
463 msg.message = &req;
464
465 if(mContextHubModule->send_message(hubId, &msg) != 0) {
466 return Result::TRANSACTION_FAILED;
467 } else {
468 mTransactionId = transactionId;
469 mIsTransactionPending = true;
470 return Result::OK;
471 }
472}
473
474Return<Result> Contexthub::disableNanoApp(uint32_t hubId,
475 uint64_t appId,
476 uint32_t transactionId) {
477 if (!isInitialized()) {
478 return Result::NOT_INIT;
479 }
480
481 if (mIsTransactionPending) {
482 return Result::TRANSACTION_PENDING;
483 }
484
485 hub_message_t msg;
486
487 if (setOsAppAsDestination(&msg, hubId) == false) {
488 return Result::BAD_PARAMS;
489 }
490
491 struct apps_disable_request_t req;
492
493 msg.message_type = CONTEXT_HUB_APPS_DISABLE;
494 msg.message_len = sizeof(req);
495 req.app_name.id = appId;
496 msg.message = &req;
497
498 if(mContextHubModule->send_message(hubId, &msg) != 0) {
499 return Result::TRANSACTION_FAILED;
500 } else {
501 mTransactionId = transactionId;
502 mIsTransactionPending = true;
503 return Result::OK;
504 }
505}
506
507Return<Result> Contexthub::queryApps(uint32_t hubId) {
508 if (!isInitialized()) {
509 return Result::NOT_INIT;
510 }
511
512 hub_message_t msg;
513
514 if (setOsAppAsDestination(&msg, hubId) == false) {
515 ALOGW("Could not find hubId %" PRIu32, hubId);
516 return Result::BAD_PARAMS;
517 }
518
519 query_apps_request_t payload;
520 payload.app_name.id = ALL_APPS; // TODO : Pass this in as a parameter
521 msg.message = &payload;
522 msg.message_len = sizeof(payload);
523 msg.message_type = CONTEXT_HUB_QUERY_APPS;
524
525 if(mContextHubModule->send_message(hubId, &msg) != 0) {
526 ALOGW("Query Apps sendMessage failed");
527 return Result::TRANSACTION_FAILED;
528 }
529
530 return Result::OK;
531}
532
533bool Contexthub::isInitialized() {
534 return (mInitCheck == OK && mContextHubModule != nullptr);
535}
536
537IContexthub *HIDL_FETCH_IContexthub(const char * halName) {
538 ALOGI("%s Called for %s", __FUNCTION__, halName);
539 Contexthub *contexthub = new Contexthub;
540
541 if (!contexthub->isInitialized()) {
542 delete contexthub;
543 contexthub = nullptr;
544 }
545
546 return contexthub;
547}
548
549} // namespace implementation
550} // namespace V1_0
551} // namespace contexthub
552} // namespace hardware
553} // namespace android