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