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