Home | History | Annotate | Download | only in default
      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 
     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 
     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 
     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 
    114 Contexthub::DeathRecipient::DeathRecipient(sp<Contexthub> contexthub)
    115         : mContexthub(contexthub) {}
    116 
    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 
    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 
    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 
    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 dummy to prevent send_message with empty message from failing prematurely
    159     static uint8_t dummy;
    160     if (txMsg.message_len == 0 && txMsg.message == nullptr) {
    161         txMsg.message = &dummy;
    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 
    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 
    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 
    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 sanity checks on return values
    259     return true;
    260 }
    261 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    572 bool Contexthub::isInitialized() {
    573     return (mInitCheck == OK && mContextHubModule != nullptr);
    574 }
    575 
    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