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