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     // Use a placeholder to prevent send_message with empty message from failing prematurely
159     static uint8_t placeholder;
160     if (txMsg.message_len == 0 && txMsg.message == nullptr) {
161         txMsg.message = &placeholder;
162     }
163 
164     ALOGI("Sending msg of type %" PRIu32 ", size %" PRIu32 " to app 0x%" PRIx64,
165           txMsg.message_type,
166           txMsg.message_len,
167           txMsg.app_name.id);
168 
169     if(mContextHubModule->send_message(hubId, &txMsg) != 0) {
170         return Result::TRANSACTION_FAILED;
171     }
172 
173     return Result::OK;
174 }
175 
reboot(uint32_t hubId)176 Return<Result> Contexthub::reboot(uint32_t hubId) {
177     if (!isInitialized()) {
178       return Result::NOT_INIT;
179     }
180 
181     hub_message_t msg;
182 
183     if (setOsAppAsDestination(&msg, hubId) == false) {
184         return Result::BAD_PARAMS;
185     }
186 
187     msg.message_type = CONTEXT_HUB_OS_REBOOT;
188     msg.message_len = 0;
189     msg.message = nullptr;
190 
191     if(mContextHubModule->send_message(hubId, &msg) != 0) {
192         return Result::TRANSACTION_FAILED;
193     } else {
194         return Result::OK;
195     }
196 }
197 
registerCallback(uint32_t hubId,const sp<IContexthubCallback> & cb)198 Return<Result> Contexthub::registerCallback(uint32_t hubId,
199                                             const sp<IContexthubCallback> &cb) {
200     Return<Result> retVal = Result::BAD_PARAMS;
201 
202     if (!isInitialized()) {
203         // Not initilalized
204         ALOGW("Context hub not initialized successfully");
205         retVal = Result::NOT_INIT;
206     } else if (!isValidHubId(hubId)) {
207         // Initialized, but hubId is  not valid
208         retVal = Result::BAD_PARAMS;
209     } else if (mContextHubModule->subscribe_messages(hubId,
210                                                      contextHubCb,
211                                                      this) == 0) {
212         // Initialized && valid hub && subscription successful
213         if (mCachedHubInfo[hubId].callback != nullptr) {
214             ALOGD("Modifying callback for hubId %" PRIu32, hubId);
215             mCachedHubInfo[hubId].callback->unlinkToDeath(mDeathRecipient);
216         }
217 
218         mCachedHubInfo[hubId].callback = cb;
219         if (cb != nullptr) {
220             Return<bool> linkResult = cb->linkToDeath(mDeathRecipient, hubId);
221             bool linkSuccess = linkResult.isOk() ?
222                 static_cast<bool>(linkResult) : false;
223             if (!linkSuccess) {
224                 ALOGW("Couldn't link death recipient for hubId %" PRIu32,
225                       hubId);
226             }
227         }
228         retVal = Result::OK;
229     } else {
230         // Initalized && valid hubId - but subscription unsuccessful
231         // This is likely an internal error in the HAL implementation, but we
232         // cannot add more information.
233         ALOGW("Could not subscribe to the hub for callback");
234         retVal = Result::UNKNOWN_FAILURE;
235     }
236 
237     return retVal;
238 }
239 
isValidOsStatus(const uint8_t * msg,size_t msgLen,status_response_t * rsp)240 static bool isValidOsStatus(const uint8_t *msg,
241                             size_t msgLen,
242                             status_response_t *rsp) {
243     // Workaround a bug in some HALs
244     if (msgLen == 1) {
245         rsp->result = msg[0];
246         return true;
247     }
248 
249     if (msg == nullptr || msgLen != sizeof(*rsp)) {
250         ALOGI("Received invalid response (is null : %d, size %zu)",
251               msg == nullptr ? 1 : 0,
252               msgLen);
253         return false;
254     }
255 
256     memcpy(rsp, msg, sizeof(*rsp));
257 
258     // No validations on return values
259     return true;
260 }
261 
handleOsMessage(sp<IContexthubCallback> cb,uint32_t msgType,const uint8_t * msg,int msgLen)262 int Contexthub::handleOsMessage(sp<IContexthubCallback> cb,
263                                 uint32_t msgType,
264                                 const uint8_t *msg,
265                                 int msgLen) {
266     int retVal = -1;
267 
268 
269     switch(msgType) {
270         case CONTEXT_HUB_APPS_ENABLE:
271         case CONTEXT_HUB_APPS_DISABLE:
272         case CONTEXT_HUB_LOAD_APP:
273         case CONTEXT_HUB_UNLOAD_APP:
274         {
275             struct status_response_t rsp;
276             TransactionResult result;
277             if (isValidOsStatus(msg, msgLen, &rsp) && rsp.result == 0) {
278                 retVal = 0;
279                 result = TransactionResult::SUCCESS;
280             } else {
281                 result = TransactionResult::FAILURE;
282             }
283 
284             mIsTransactionPending = false;
285             if (cb != nullptr) {
286                 cb->handleTxnResult(mTransactionId, result);
287             }
288             retVal = 0;
289             break;
290         }
291 
292         case CONTEXT_HUB_QUERY_APPS:
293         {
294             std::vector<HubAppInfo> apps;
295             int numApps = msgLen / sizeof(hub_app_info);
296             const hub_app_info *unalignedInfoAddr = reinterpret_cast<const hub_app_info *>(msg);
297 
298             for (int i = 0; i < numApps; i++) {
299                 hub_app_info query_info;
300                 memcpy(&query_info, &unalignedInfoAddr[i], sizeof(query_info));
301                 HubAppInfo app;
302                 app.appId = query_info.app_name.id;
303                 app.version = query_info.version;
304                 // TODO :: Add memory ranges
305 
306                 apps.push_back(app);
307             }
308 
309             if (cb != nullptr) {
310                 cb->handleAppsInfo(apps);
311             }
312             retVal = 0;
313             break;
314         }
315 
316         case CONTEXT_HUB_QUERY_MEMORY:
317         {
318             // Deferring this use
319             retVal = 0;
320             break;
321         }
322 
323         case CONTEXT_HUB_OS_REBOOT:
324         {
325             mIsTransactionPending = false;
326             if (cb != nullptr) {
327                 cb->handleHubEvent(AsyncEventType::RESTARTED);
328             }
329             retVal = 0;
330             break;
331         }
332 
333         default:
334         {
335             retVal = -1;
336             break;
337         }
338       }
339 
340       return retVal;
341 }
342 
handleServiceDeath(uint32_t hubId)343 void Contexthub::handleServiceDeath(uint32_t hubId) {
344     ALOGI("Callback/service died for hubId %" PRIu32, hubId);
345     int ret = mContextHubModule->subscribe_messages(hubId, nullptr, nullptr);
346     if (ret != 0) {
347         ALOGW("Failed to unregister callback from hubId %" PRIu32 ": %d",
348               hubId, ret);
349     }
350     mCachedHubInfo[hubId].callback.clear();
351 }
352 
contextHubCb(uint32_t hubId,const struct hub_message_t * rxMsg,void * cookie)353 int Contexthub::contextHubCb(uint32_t hubId,
354                              const struct hub_message_t *rxMsg,
355                              void *cookie) {
356     Contexthub *obj = static_cast<Contexthub *>(cookie);
357 
358     if (rxMsg == nullptr) {
359         ALOGW("Ignoring NULL message");
360         return -1;
361     }
362 
363     if (!obj->isValidHubId(hubId)) {
364         ALOGW("Invalid hub Id %" PRIu32, hubId);
365         return -1;
366     }
367 
368     sp<IContexthubCallback> cb = obj->getCallBackForHubId(hubId);
369 
370     if (cb == nullptr) {
371         // This should not ever happen
372         ALOGW("No callback registered, returning");
373         return -1;
374     }
375 
376     if (rxMsg->message_type < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE) {
377         obj->handleOsMessage(cb,
378                              rxMsg->message_type,
379                              static_cast<const uint8_t *>(rxMsg->message),
380                              rxMsg->message_len);
381     } else {
382         ContextHubMsg msg;
383 
384         msg.appName = rxMsg->app_name.id;
385         msg.msgType = rxMsg->message_type;
386         msg.hostEndPoint = static_cast<uint16_t>(HostEndPoint::BROADCAST);
387         msg.msg = std::vector<uint8_t>(static_cast<const uint8_t *>(rxMsg->message),
388                                        static_cast<const uint8_t *>(rxMsg->message) +
389                                        rxMsg->message_len);
390 
391         cb->handleClientMsg(msg);
392     }
393 
394     return 0;
395 }
396 
unloadNanoApp(uint32_t hubId,uint64_t appId,uint32_t transactionId)397 Return<Result> Contexthub::unloadNanoApp(uint32_t hubId,
398                                          uint64_t appId,
399                                          uint32_t transactionId) {
400     if (!isInitialized()) {
401       return Result::NOT_INIT;
402     }
403 
404     if (mIsTransactionPending) {
405         return Result::TRANSACTION_PENDING;
406     }
407 
408     hub_message_t msg;
409 
410     if (setOsAppAsDestination(&msg, hubId) == false) {
411         return Result::BAD_PARAMS;
412     }
413 
414     struct apps_disable_request_t req;
415 
416     msg.message_type = CONTEXT_HUB_UNLOAD_APP;
417     msg.message_len = sizeof(req);
418     msg.message = &req;
419     req.app_name.id = appId;
420 
421     if(mContextHubModule->send_message(hubId, &msg) != 0) {
422         return Result::TRANSACTION_FAILED;
423     } else {
424         mTransactionId = transactionId;
425         mIsTransactionPending = true;
426         return Result::OK;
427     }
428 }
429 
loadNanoApp(uint32_t hubId,const NanoAppBinary & appBinary,uint32_t transactionId)430 Return<Result> Contexthub::loadNanoApp(uint32_t hubId,
431                                        const NanoAppBinary& appBinary,
432                                        uint32_t transactionId) {
433     if (!isInitialized()) {
434       return Result::NOT_INIT;
435     }
436 
437     if (mIsTransactionPending) {
438         return Result::TRANSACTION_PENDING;
439     }
440 
441     hub_message_t hubMsg;
442 
443     if (setOsAppAsDestination(&hubMsg, hubId) == false) {
444         return Result::BAD_PARAMS;
445     }
446 
447     // Data from the nanoapp header is passed through HIDL as explicit fields,
448     // but the legacy HAL expects it prepended to the binary, therefore we must
449     // reconstruct it here prior to passing to the legacy HAL.
450     const struct nano_app_binary_t header = {
451         .header_version = htole32(1),
452         .magic = htole32(NANOAPP_MAGIC),
453         .app_id.id = htole64(appBinary.appId),
454         .app_version = htole32(appBinary.appVersion),
455         .flags = htole32(appBinary.flags),
456         .hw_hub_type = htole64(0),
457         .target_chre_api_major_version = appBinary.targetChreApiMajorVersion,
458         .target_chre_api_minor_version = appBinary.targetChreApiMinorVersion,
459     };
460     const uint8_t *headerBytes = reinterpret_cast<const uint8_t *>(&header);
461 
462     std::vector<uint8_t> binaryWithHeader(appBinary.customBinary);
463     binaryWithHeader.insert(binaryWithHeader.begin(),
464                             headerBytes,
465                             headerBytes + sizeof(header));
466 
467     hubMsg.message_type = CONTEXT_HUB_LOAD_APP;
468     hubMsg.message_len = binaryWithHeader.size();
469     hubMsg.message = binaryWithHeader.data();
470 
471     if (mContextHubModule->send_message(hubId, &hubMsg) != 0) {
472         return Result::TRANSACTION_FAILED;
473     } else {
474         mTransactionId = transactionId;
475         mIsTransactionPending = true;
476         return Result::OK;
477     }
478 }
479 
enableNanoApp(uint32_t hubId,uint64_t appId,uint32_t transactionId)480 Return<Result> Contexthub::enableNanoApp(uint32_t hubId,
481                                          uint64_t appId,
482                                          uint32_t transactionId) {
483     if (!isInitialized()) {
484       return Result::NOT_INIT;
485     }
486 
487     if (mIsTransactionPending) {
488         return Result::TRANSACTION_PENDING;
489     }
490 
491     hub_message_t msg;
492 
493     if (setOsAppAsDestination(&msg, hubId) == false) {
494         return Result::BAD_PARAMS;
495     }
496 
497     struct apps_enable_request_t req;
498 
499     msg.message_type = CONTEXT_HUB_APPS_ENABLE;
500     msg.message_len = sizeof(req);
501     req.app_name.id = appId;
502     msg.message = &req;
503 
504     if(mContextHubModule->send_message(hubId, &msg) != 0) {
505         return Result::TRANSACTION_FAILED;
506     } else {
507         mTransactionId = transactionId;
508         mIsTransactionPending = true;
509         return Result::OK;
510     }
511 }
512 
disableNanoApp(uint32_t hubId,uint64_t appId,uint32_t transactionId)513 Return<Result> Contexthub::disableNanoApp(uint32_t hubId,
514                                           uint64_t appId,
515                                           uint32_t transactionId) {
516     if (!isInitialized()) {
517       return Result::NOT_INIT;
518     }
519 
520     if (mIsTransactionPending) {
521         return Result::TRANSACTION_PENDING;
522     }
523 
524     hub_message_t msg;
525 
526     if (setOsAppAsDestination(&msg, hubId) == false) {
527         return Result::BAD_PARAMS;
528     }
529 
530     struct apps_disable_request_t req;
531 
532     msg.message_type = CONTEXT_HUB_APPS_DISABLE;
533     msg.message_len = sizeof(req);
534     req.app_name.id = appId;
535     msg.message = &req;
536 
537     if(mContextHubModule->send_message(hubId, &msg) != 0) {
538         return Result::TRANSACTION_FAILED;
539     } else {
540         mTransactionId = transactionId;
541         mIsTransactionPending = true;
542         return Result::OK;
543     }
544 }
545 
queryApps(uint32_t hubId)546 Return<Result> Contexthub::queryApps(uint32_t hubId) {
547     if (!isInitialized()) {
548       return Result::NOT_INIT;
549     }
550 
551     hub_message_t msg;
552 
553     if (setOsAppAsDestination(&msg, hubId) == false) {
554         ALOGW("Could not find hubId %" PRIu32, hubId);
555         return Result::BAD_PARAMS;
556     }
557 
558     query_apps_request_t payload;
559     payload.app_name.id = ALL_APPS; // TODO : Pass this in as a parameter
560     msg.message = &payload;
561     msg.message_len = sizeof(payload);
562     msg.message_type = CONTEXT_HUB_QUERY_APPS;
563 
564     if(mContextHubModule->send_message(hubId, &msg) != 0) {
565         ALOGW("Query Apps sendMessage failed");
566         return Result::TRANSACTION_FAILED;
567     }
568 
569     return Result::OK;
570 }
571 
isInitialized()572 bool Contexthub::isInitialized() {
573     return (mInitCheck == OK && mContextHubModule != nullptr);
574 }
575 
HIDL_FETCH_IContexthub(const char * halName)576 IContexthub *HIDL_FETCH_IContexthub(const char * halName) {
577     ALOGI("%s Called for %s", __FUNCTION__, halName);
578     Contexthub *contexthub = new Contexthub;
579 
580     if (!contexthub->isInitialized()) {
581         delete contexthub;
582         contexthub = nullptr;
583     }
584 
585     return contexthub;
586 }
587 
588 }  // namespace implementation
589 }  // namespace V1_0
590 }  // namespace contexthub
591 }  // namespace hardware
592 }  // namespace android
593