Home | History | Annotate | Download | only in hal_generic
      1 /*
      2  * Copyright (C) 2017 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 #define LOG_TAG "ContextHubHal"
     18 #define LOG_NDEBUG 0
     19 
     20 #include "generic_context_hub.h"
     21 
     22 #include <chrono>
     23 #include <cinttypes>
     24 #include <vector>
     25 
     26 #include <utils/Log.h>
     27 
     28 namespace android {
     29 namespace hardware {
     30 namespace contexthub {
     31 namespace V1_0 {
     32 namespace implementation {
     33 
     34 using ::android::hardware::Return;
     35 using ::android::hardware::contexthub::V1_0::AsyncEventType;
     36 using ::android::hardware::contexthub::V1_0::Result;
     37 using ::android::hardware::contexthub::V1_0::TransactionResult;
     38 using ::android::chre::HostProtocolHost;
     39 using ::flatbuffers::FlatBufferBuilder;
     40 
     41 // Aliased for consistency with the way these symbols are referenced in
     42 // CHRE-side code
     43 namespace fbs = ::chre::fbs;
     44 
     45 namespace {
     46 
     47 constexpr uint32_t kDefaultHubId = 0;
     48 
     49 // TODO: remove this macro once all methods are implemented
     50 #define UNUSED(param) (void) (param)
     51 
     52 constexpr uint8_t extractChreApiMajorVersion(uint32_t chreVersion) {
     53   return static_cast<uint8_t>(chreVersion >> 24);
     54 }
     55 
     56 constexpr uint8_t extractChreApiMinorVersion(uint32_t chreVersion) {
     57   return static_cast<uint8_t>(chreVersion >> 16);
     58 }
     59 
     60 constexpr uint16_t extractChrePatchVersion(uint32_t chreVersion) {
     61   return static_cast<uint16_t>(chreVersion);
     62 }
     63 
     64 }  // anonymous namespace
     65 
     66 GenericContextHub::GenericContextHub() {
     67   constexpr char kChreSocketName[] = "chre";
     68 
     69   mSocketCallbacks = new SocketCallbacks(*this);
     70   if (!mClient.connectInBackground(kChreSocketName, mSocketCallbacks)) {
     71     ALOGE("Couldn't start socket client");
     72   }
     73 }
     74 
     75 Return<void> GenericContextHub::getHubs(getHubs_cb _hidl_cb) {
     76   constexpr auto kHubInfoQueryTimeout = std::chrono::seconds(5);
     77   std::vector<ContextHub> hubs;
     78   ALOGV("%s", __func__);
     79 
     80   // If we're not connected yet, give it some time
     81   int maxSleepIterations = 50;
     82   while (!mHubInfoValid && !mClient.isConnected() && --maxSleepIterations > 0) {
     83     std::this_thread::sleep_for(std::chrono::milliseconds(100));
     84   }
     85 
     86   if (!mClient.isConnected()) {
     87     ALOGE("Couldn't connect to hub daemon");
     88   } else if (!mHubInfoValid) {
     89     // We haven't cached the hub details yet, so send a request and block
     90     // waiting on a response
     91     std::unique_lock<std::mutex> lock(mHubInfoMutex);
     92     FlatBufferBuilder builder;
     93     HostProtocolHost::encodeHubInfoRequest(builder);
     94 
     95     ALOGD("Sending hub info request");
     96     if (!mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
     97       ALOGE("Couldn't send hub info request");
     98     } else {
     99       mHubInfoCond.wait_for(lock, kHubInfoQueryTimeout,
    100                             [this]() { return mHubInfoValid; });
    101     }
    102   }
    103 
    104   if (mHubInfoValid) {
    105     hubs.push_back(mHubInfo);
    106   } else {
    107     ALOGE("Unable to get hub info from CHRE");
    108   }
    109 
    110   _hidl_cb(hubs);
    111   return Void();
    112 }
    113 
    114 Return<Result> GenericContextHub::registerCallback(
    115     uint32_t hubId, const sp<IContexthubCallback>& cb) {
    116   Result result;
    117   ALOGV("%s", __func__);
    118 
    119   // TODO: currently we only support 1 hub behind this HAL implementation
    120   if (hubId == kDefaultHubId) {
    121     mCallbacks = cb; // TODO: special handling for null?
    122     result = Result::OK;
    123   } else {
    124     result = Result::BAD_PARAMS;
    125   }
    126 
    127   return result;
    128 }
    129 
    130 Return<Result> GenericContextHub::sendMessageToHub(uint32_t hubId,
    131                                                    const ContextHubMsg& msg) {
    132   Result result;
    133   ALOGV("%s", __func__);
    134 
    135   if (hubId != kDefaultHubId) {
    136     result = Result::BAD_PARAMS;
    137   } else {
    138     FlatBufferBuilder builder(1024);
    139     HostProtocolHost::encodeNanoappMessage(
    140         builder, msg.appName, msg.msgType, msg.hostEndPoint, msg.msg.data(),
    141         msg.msg.size());
    142 
    143     if (!mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
    144       result = Result::UNKNOWN_FAILURE;
    145     } else {
    146       result = Result::OK;
    147     }
    148   }
    149 
    150   return result;
    151 }
    152 
    153 Return<Result> GenericContextHub::loadNanoApp(
    154     uint32_t hubId, const NanoAppBinary& appBinary, uint32_t transactionId) {
    155   Result result;
    156   ALOGV("%s", __func__);
    157 
    158   if (hubId != kDefaultHubId) {
    159     result = Result::BAD_PARAMS;
    160   } else {
    161     FlatBufferBuilder builder(128 + appBinary.customBinary.size());
    162     uint32_t targetApiVersion = (appBinary.targetChreApiMajorVersion << 24) |
    163                                 (appBinary.targetChreApiMinorVersion << 16);
    164     HostProtocolHost::encodeLoadNanoappRequest(
    165         builder, transactionId, appBinary.appId, appBinary.appVersion,
    166         targetApiVersion, appBinary.customBinary);
    167     if (!mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
    168       result = Result::UNKNOWN_FAILURE;
    169     } else {
    170       result = Result::OK;
    171     }
    172   }
    173 
    174   ALOGD("Attempted to send load nanoapp request for app of size %zu with ID "
    175         "0x%016" PRIx64 " as transaction ID %" PRIu32 ": result %" PRIu32,
    176         appBinary.customBinary.size(), appBinary.appId, transactionId, result);
    177 
    178   return result;
    179 }
    180 
    181 Return<Result> GenericContextHub::unloadNanoApp(
    182     uint32_t hubId, uint64_t appId, uint32_t transactionId) {
    183   // TODO
    184   UNUSED(hubId);
    185   UNUSED(appId);
    186   UNUSED(transactionId);
    187   ALOGV("%s", __func__);
    188   return Result::UNKNOWN_FAILURE;
    189 }
    190 
    191 Return<Result> GenericContextHub::enableNanoApp(
    192     uint32_t hubId, uint64_t appId, uint32_t transactionId) {
    193   // TODO
    194   UNUSED(hubId);
    195   UNUSED(appId);
    196   UNUSED(transactionId);
    197   ALOGV("%s", __func__);
    198   return Result::UNKNOWN_FAILURE;
    199 }
    200 
    201 Return<Result> GenericContextHub::disableNanoApp(
    202     uint32_t hubId, uint64_t appId, uint32_t transactionId) {
    203   // TODO
    204   UNUSED(hubId);
    205   UNUSED(appId);
    206   UNUSED(transactionId);
    207   ALOGV("%s", __func__);
    208   return Result::UNKNOWN_FAILURE;
    209 }
    210 
    211 Return<Result> GenericContextHub::queryApps(uint32_t hubId) {
    212   Result result;
    213   ALOGV("%s", __func__);
    214 
    215   if (hubId != kDefaultHubId) {
    216     result = Result::BAD_PARAMS;
    217   } else {
    218     FlatBufferBuilder builder(64);
    219     HostProtocolHost::encodeNanoappListRequest(builder);
    220     if (!mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
    221       result = Result::UNKNOWN_FAILURE;
    222     } else {
    223       result = Result::OK;
    224     }
    225   }
    226 
    227   return Result::UNKNOWN_FAILURE;
    228 }
    229 
    230 GenericContextHub::SocketCallbacks::SocketCallbacks(GenericContextHub& parent)
    231     : mParent(parent) {}
    232 
    233 void GenericContextHub::SocketCallbacks::onMessageReceived(const void *data,
    234                                                            size_t length) {
    235   if (!HostProtocolHost::decodeMessageFromChre(data, length, *this)) {
    236     ALOGE("Failed to decode message");
    237   }
    238 }
    239 
    240 void GenericContextHub::SocketCallbacks::onConnected() {
    241   if (mHaveConnected) {
    242     ALOGI("Reconnected to CHRE daemon");
    243     if (mParent.mCallbacks != nullptr) {
    244       mParent.mCallbacks->handleHubEvent(AsyncEventType::RESTARTED);
    245     }
    246   }
    247   mHaveConnected = true;
    248 }
    249 
    250 void GenericContextHub::SocketCallbacks::onDisconnected() {
    251   ALOGW("Lost connection to CHRE daemon");
    252 }
    253 
    254 void GenericContextHub::SocketCallbacks::handleNanoappMessage(
    255     uint64_t appId, uint32_t messageType, uint16_t hostEndpoint,
    256     const void *messageData, size_t messageDataLen) {
    257   // TODO: this is not thread-safe w/registerCallback... we need something else
    258   // to confirm that it's safe for us to invoke the callback, and likely a lock
    259   // on stuff
    260   if (mParent.mCallbacks != nullptr) {
    261     ContextHubMsg msg;
    262     msg.appName = appId;
    263     msg.hostEndPoint = hostEndpoint;
    264     msg.msgType = messageType;
    265 
    266     // Dropping const from messageData when we wrap it in hidl_vec here. This is
    267     // safe because we won't modify it here, and the ContextHubMsg we pass to
    268     // the callback is const.
    269     msg.msg.setToExternal(
    270         const_cast<uint8_t *>(static_cast<const uint8_t *>(messageData)),
    271         messageDataLen, false /* shouldOwn */);
    272 
    273     mParent.mCallbacks->handleClientMsg(msg);
    274   }
    275 }
    276 
    277 void GenericContextHub::SocketCallbacks::handleHubInfoResponse(
    278     const char *name, const char *vendor,
    279     const char *toolchain, uint32_t legacyPlatformVersion,
    280     uint32_t legacyToolchainVersion, float peakMips, float stoppedPower,
    281     float sleepPower, float peakPower, uint32_t maxMessageLen,
    282     uint64_t platformId, uint32_t version) {
    283   ALOGD("Got hub info response");
    284 
    285   std::lock_guard<std::mutex> lock(mParent.mHubInfoMutex);
    286   if (mParent.mHubInfoValid) {
    287     ALOGI("Ignoring duplicate/unsolicited hub info response");
    288   } else {
    289     mParent.mHubInfo.name = name;
    290     mParent.mHubInfo.vendor = vendor;
    291     mParent.mHubInfo.toolchain = toolchain;
    292     mParent.mHubInfo.platformVersion = legacyPlatformVersion;
    293     mParent.mHubInfo.toolchainVersion = legacyToolchainVersion;
    294     mParent.mHubInfo.hubId = kDefaultHubId;
    295 
    296     mParent.mHubInfo.peakMips = peakMips;
    297     mParent.mHubInfo.stoppedPowerDrawMw = stoppedPower;
    298     mParent.mHubInfo.sleepPowerDrawMw = sleepPower;
    299     mParent.mHubInfo.peakPowerDrawMw = peakPower;
    300 
    301     mParent.mHubInfo.maxSupportedMsgLen = maxMessageLen;
    302     mParent.mHubInfo.chrePlatformId = platformId;
    303 
    304     mParent.mHubInfo.chreApiMajorVersion = extractChreApiMajorVersion(version);
    305     mParent.mHubInfo.chreApiMinorVersion = extractChreApiMinorVersion(version);
    306     mParent.mHubInfo.chrePatchVersion = extractChrePatchVersion(version);
    307 
    308     mParent.mHubInfoValid = true;
    309     mParent.mHubInfoCond.notify_all();
    310   }
    311 }
    312 
    313 void GenericContextHub::SocketCallbacks::handleNanoappListResponse(
    314     const fbs::NanoappListResponseT& response) {
    315   std::vector<HubAppInfo> appInfoList;
    316 
    317   ALOGV("Got nanoapp list response with %zu apps", response.nanoapps.size());
    318   for (const std::unique_ptr<fbs::NanoappListEntryT>& nanoapp
    319          : response.nanoapps) {
    320     // TODO: determine if this is really required, and if so, have
    321     // HostProtocolHost strip out null entries as part of decode
    322     if (nanoapp == nullptr) {
    323       continue;
    324     }
    325 
    326     ALOGV("App 0x%016" PRIx64 " ver 0x%" PRIx32 " enabled %d system %d",
    327           nanoapp->app_id, nanoapp->version, nanoapp->enabled,
    328           nanoapp->is_system);
    329     if (!nanoapp->is_system) {
    330       HubAppInfo appInfo;
    331 
    332       appInfo.appId = nanoapp->app_id;
    333       appInfo.version = nanoapp->version;
    334       appInfo.enabled = nanoapp->enabled;
    335 
    336       appInfoList.push_back(appInfo);
    337     }
    338   }
    339 
    340   // TODO: make this thread-safe w/setCallback
    341   mParent.mCallbacks->handleAppsInfo(appInfoList);
    342 }
    343 
    344 void GenericContextHub::SocketCallbacks::handleLoadNanoappResponse(
    345     const ::chre::fbs::LoadNanoappResponseT& response) {
    346   ALOGV("Got load nanoapp response for transaction %" PRIu32 " with result %d",
    347         response.transaction_id, response.success);
    348 
    349   TransactionResult result = (response.success) ?
    350       TransactionResult::SUCCESS : TransactionResult::FAILURE;
    351   mParent.mCallbacks->handleTxnResult(response.transaction_id, result);
    352 }
    353 
    354 IContexthub* HIDL_FETCH_IContexthub(const char* /* name */) {
    355   return new GenericContextHub();
    356 }
    357 
    358 }  // namespace implementation
    359 }  // namespace V1_0
    360 }  // namespace contexthub
    361 }  // namespace hardware
    362 }  // namespace android
    363