Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1bec86a1 authored by Ashutosh Joshi's avatar Ashutosh Joshi
Browse files

Contexthub HAL default implementation and service.

Adds the default context hub hal implementation and service.

Test: Context Hub GTS tests still pass.
Change-Id: I7416ce9ec8efca7f98d2bb63606f030f4e8c8ead
parent d5c2cef0
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

cc_library_shared {
    name: "android.hardware.contexthub@1.0-impl",
    relative_install_path: "hw",
    srcs: ["Contexthub.cpp"],
    shared_libs: [
        "liblog",
        "libcutils",
        "libhardware",
        "libhwbinder",
        "libbase",
        "libcutils",
        "libutils",
        "libhidlbase",
        "libhidltransport",
        "android.hardware.contexthub@1.0",
    ],
}
+23 −0
Original line number Diff line number Diff line
LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_MODULE := android.hardware.contexthub@1.0-service
LOCAL_INIT_RC := android.hardware.contexthub@1.0-service.rc
LOCAL_SRC_FILES := \
        service.cpp \

LOCAL_SHARED_LIBRARIES := \
        libbase \
        libcutils \
        libdl \
        libhardware \
        libhardware_legacy \
        libhidlbase \
        libhidltransport \
        libhwbinder \
        liblog \
        libutils \
        android.hardware.contexthub@1.0 \

include $(BUILD_EXECUTABLE)
+528 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "Contexthub.h"

#include <inttypes.h>

#include <android/log.h>
#include <android/hardware/contexthub/1.0/IContexthub.h>
#include <hardware/context_hub.h>

#undef LOG_TAG
#define LOG_TAG "ContextHubHalAdapter"

namespace android {
namespace hardware {
namespace contexthub {
namespace V1_0 {
namespace implementation {

static constexpr uint64_t ALL_APPS = UINT64_C(0xFFFFFFFFFFFFFFFF);

Contexthub::Contexthub()
        : mInitCheck(NO_INIT),
          mContextHubModule(nullptr),
          mIsTransactionPending(false) {
    const hw_module_t *module;

    mInitCheck = hw_get_module(CONTEXT_HUB_MODULE_ID, &module);

    if (mInitCheck != OK) {
        ALOGE("Could not load %s module: %s", CONTEXT_HUB_MODULE_ID, strerror(-mInitCheck));
    } else if (module == nullptr) {
        ALOGE("hal returned succes but a null module!");
        // Assign an error, this should not really happen...
        mInitCheck = UNKNOWN_ERROR;
    } else {
        ALOGI("Loaded Context Hub module");
        mContextHubModule = reinterpret_cast<const context_hub_module_t *>(module);
    }
}

bool Contexthub::setOsAppAsDestination(hub_message_t *msg, int hubId) {
    if (!isValidHubId(hubId)) {
        ALOGW("%s: Hub information is null for hubHandle %d",
              __FUNCTION__,
              hubId);
        return false;
    } else {
        msg->app_name = mCachedHubInfo[hubId].osAppName;
        return true;
    }
}

Return<void> Contexthub::getHubs(getHubs_cb _hidl_cb) {
    std::vector<ContextHub> hubs;
    if (isInitialized()) {
        const context_hub_t *hubArray = nullptr;
        size_t numHubs;

        // Explicitly discarding const. HAL method discards it.
        numHubs = mContextHubModule->get_hubs(const_cast<context_hub_module_t *>(mContextHubModule),
                                              &hubArray);
        ALOGI("Context Hub Hal Adapter reports %zu hubs", numHubs);

        mCachedHubInfo.clear();

        for (size_t i = 0; i < numHubs; i++) {
            CachedHubInformation info;
            ContextHub c;

            c.hubId = hubArray[i].hub_id;
            c.name = hubArray[i].name;
            c.vendor = hubArray[i].vendor;
            c.toolchain = hubArray[i].toolchain;
            c.toolchainVersion = hubArray[i].toolchain_version;
            c.platformVersion = hubArray[i].platform_version;
            c.maxSupportedMsgLen = hubArray[i].max_supported_msg_len;
            c.peakMips = hubArray[i].peak_mips;
            c.peakPowerDrawMw = hubArray[i].peak_power_draw_mw;
            c.stoppedPowerDrawMw = hubArray[i].stopped_power_draw_mw;
            c.sleepPowerDrawMw = hubArray[i].sleep_power_draw_mw;

            info.callBack = nullptr;
            info.osAppName = hubArray[i].os_app_name;
            mCachedHubInfo[hubArray[i].hub_id] = info;

            hubs.push_back(c);
        }
    } else {
        ALOGW("Context Hub Hal Adapter not initialized");
    }

    _hidl_cb(hubs);
    return Void();
}

bool Contexthub::isValidHubId(uint32_t hubId) {
    if (!mCachedHubInfo.count(hubId)) {
        ALOGW("Hub information not found for hubId %" PRIu32, hubId);
        return false;
    } else {
        return true;
    }
}

sp<IContexthubCallback> Contexthub::getCallBackForHubId(uint32_t hubId) {
    if (!isValidHubId(hubId)) {
        return nullptr;
    } else {
        return mCachedHubInfo[hubId].callBack;
    }
}

Return<Result> Contexthub::sendMessageToHub(uint32_t hubId,
                                            const ContextHubMsg &msg) {
    if (!isInitialized()) {
        return Result::NOT_INIT;
    }

    if (!isValidHubId(hubId) || msg.msg.size() > UINT32_MAX) {
        return Result::BAD_PARAMS;
    }

    hub_message_t txMsg = {
        .app_name.id = msg.appName,
        .message_type = msg.msgType,
        .message_len = static_cast<uint32_t>(msg.msg.size()), // Note the check above
        .message = static_cast<const uint8_t *>(msg.msg.data()),
    };

    ALOGI("Sending msg of type %" PRIu32 ", size %" PRIu32 " to app 0x%" PRIx64,
          txMsg.message_type,
          txMsg.message_len,
          txMsg.app_name.id);

    if(mContextHubModule->send_message(hubId, &txMsg) != 0) {
        return Result::TRANSACTION_FAILED;
    }

    return Result::OK;
}

Return<Result> Contexthub::reboot(uint32_t hubId) {
    if (!isInitialized()) {
      return Result::NOT_INIT;
    }

    hub_message_t msg;

    if (setOsAppAsDestination(&msg, hubId) == false) {
        return Result::BAD_PARAMS;
    }

    msg.message_type = CONTEXT_HUB_OS_REBOOT;
    msg.message_len = 0;
    msg.message = nullptr;

    if(mContextHubModule->send_message(hubId, &msg) != 0) {
        return Result::TRANSACTION_FAILED;
    } else {
        return Result::OK;
    }
}

Return<Result> Contexthub::registerCallback(uint32_t hubId,
                                            const sp<IContexthubCallback> &cb) {
    Return<Result> retVal = Result::BAD_PARAMS;

    if (!isInitialized()) {
        // Not initilalized
        ALOGW("Context hub not initialized successfully");
        retVal = Result::NOT_INIT;
    } else if (!isValidHubId(hubId)) {
        // Initialized, but hubId is  not valid
        retVal = Result::BAD_PARAMS;
    } else if (mContextHubModule->subscribe_messages(hubId,
                                                     contextHubCb,
                                                     this) == 0) {
        // Initialized && valid hub && subscription successful
        retVal = Result::OK;
        mCachedHubInfo[hubId].callBack = cb;
    } else {
        // Initalized && valid hubId - but subscription unsuccessful
        // This is likely an internal error in the HAL implementation, but we
        // cannot add more information.
        ALOGW("Could not subscribe to the hub for callback");
        retVal = Result::UNKNOWN_FAILURE;
    }

    return retVal;
}

static bool isValidOsStatus(const uint8_t *msg,
                            size_t msgLen,
                            status_response_t *rsp) {
    // Workaround a bug in some HALs
    if (msgLen == 1) {
        rsp->result = msg[0];
        return true;
    }

    if (msg == nullptr || msgLen != sizeof(*rsp)) {
        ALOGI("Received invalid response (is null : %d, size %zu)",
              msg == nullptr ? 1 : 0,
              msgLen);
        return false;
    }

    memcpy(rsp, msg, sizeof(*rsp));

    // No sanity checks on return values
    return true;
}

int Contexthub::handleOsMessage(sp<IContexthubCallback> cb,
                                uint32_t msgType,
                                const uint8_t *msg,
                                int msgLen) {
    int retVal = -1;


    switch(msgType) {
        case CONTEXT_HUB_APPS_ENABLE:
        case CONTEXT_HUB_APPS_DISABLE:
        case CONTEXT_HUB_LOAD_APP:
        case CONTEXT_HUB_UNLOAD_APP:
        {
            struct status_response_t rsp;
            TransactionResult result;
            if (isValidOsStatus(msg, msgLen, &rsp) && rsp.result == 0) {
                retVal = 0;
                result = TransactionResult::SUCCESS;
            } else {
                result = TransactionResult::FAILURE;
            }

            if (cb != nullptr) {
                cb->handleTxnResult(mTransactionId, result);
            }
            retVal = 0;
            mIsTransactionPending = false;
            break;
        }

        case CONTEXT_HUB_QUERY_APPS:
        {
            std::vector<HubAppInfo> apps;
            int numApps = msgLen / sizeof(hub_app_info);
            const hub_app_info *unalignedInfoAddr = reinterpret_cast<const hub_app_info *>(msg);

            for (int i = 0; i < numApps; i++) {
                hub_app_info query_info;
                memcpy(&query_info, &unalignedInfoAddr[i], sizeof(query_info));
                HubAppInfo app;
                app.appId = query_info.app_name.id;
                app.version = query_info.version;
                // TODO :: Add memory ranges

                apps.push_back(app);
            }

            if (cb != nullptr) {
                cb->handleAppsInfo(apps);
            }
            retVal = 0;
            break;
        }

        case CONTEXT_HUB_QUERY_MEMORY:
        {
            // Deferring this use
            retVal = 0;
            break;
        }

        case CONTEXT_HUB_OS_REBOOT:
        {
            mIsTransactionPending = false;
            if (cb != nullptr) {
                cb->handleHubEvent(AsyncEventType::RESTARTED);
            }
            retVal = 0;
            break;
        }

        default:
        {
            retVal = -1;
            break;
        }
      }

      return retVal;
}

int Contexthub::contextHubCb(uint32_t hubId,
                             const struct hub_message_t *rxMsg,
                             void *cookie) {
    Contexthub *obj = static_cast<Contexthub *>(cookie);

    if (rxMsg == nullptr) {
        ALOGW("Ignoring NULL message");
        return -1;
    }

    if (!obj->isValidHubId(hubId)) {
        ALOGW("Invalid hub Id %" PRIu32, hubId);
        return -1;
    }

    sp<IContexthubCallback> cb = obj->getCallBackForHubId(hubId);

    if (cb == nullptr) {
        // This should not ever happen
        ALOGW("No callback registered, returning");
        return -1;
    }

    if (rxMsg->message_type < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE) {
        obj->handleOsMessage(cb,
                             rxMsg->message_type,
                             static_cast<const uint8_t *>(rxMsg->message),
                             rxMsg->message_len);
    } else {
        ContextHubMsg msg;

        msg.appName = rxMsg->app_name.id;
        msg.msgType = rxMsg->message_type;
        msg.msg = std::vector<uint8_t>(static_cast<const uint8_t *>(rxMsg->message),
                                       static_cast<const uint8_t *>(rxMsg->message) +
                                       rxMsg->message_len);

        cb->handleClientMsg(msg);
    }

    return 0;
}

Return<Result> Contexthub::unloadNanoApp(uint32_t hubId,
                                         uint64_t appId,
                                         uint32_t transactionId) {
    if (!isInitialized()) {
      return Result::NOT_INIT;
    }

    if (mIsTransactionPending) {
        return Result::TRANSACTION_PENDING;
    }

    hub_message_t msg;

    if (setOsAppAsDestination(&msg, hubId) == false) {
        return Result::BAD_PARAMS;
    }

    struct apps_disable_request_t req;

    msg.message_type = CONTEXT_HUB_UNLOAD_APP;
    msg.message_len = sizeof(req);
    msg.message = &req;
    req.app_name.id = appId;

    if(mContextHubModule->send_message(hubId, &msg) != 0) {
        return Result::TRANSACTION_FAILED;
    } else {
        mTransactionId = transactionId;
        mIsTransactionPending = true;
        return Result::OK;
    }
}

Return<Result> Contexthub::loadNanoApp(uint32_t hubId,
                                       const ::android::hardware::hidl_vec<uint8_t>& appBinary,
                                       uint32_t transactionId) {
    if (!isInitialized()) {
      return Result::NOT_INIT;
    }

    if (mIsTransactionPending) {
        return Result::TRANSACTION_PENDING;
    }

    hub_message_t hubMsg;

    if (setOsAppAsDestination(&hubMsg, hubId) == false) {
        return Result::BAD_PARAMS;
    }

    hubMsg.message_type = CONTEXT_HUB_LOAD_APP;
    hubMsg.message_len = appBinary.size();
    hubMsg.message = appBinary.data();

    if(mContextHubModule->send_message(hubId, &hubMsg) != 0) {
        return Result::TRANSACTION_FAILED;
    } else {
        mTransactionId = transactionId;
        mIsTransactionPending = true;
        return Result::OK;
    }
}

Return<Result> Contexthub::enableNanoApp(uint32_t hubId,
                                         uint64_t appId,
                                         uint32_t transactionId) {
    if (!isInitialized()) {
      return Result::NOT_INIT;
    }

    if (mIsTransactionPending) {
        return Result::TRANSACTION_PENDING;
    }

    hub_message_t msg;

    if (setOsAppAsDestination(&msg, hubId) == false) {
        return Result::BAD_PARAMS;
    }

    struct apps_enable_request_t req;

    msg.message_type = CONTEXT_HUB_APPS_ENABLE;
    msg.message_len = sizeof(req);
    req.app_name.id = appId;
    msg.message = &req;

    if(mContextHubModule->send_message(hubId, &msg) != 0) {
        return Result::TRANSACTION_FAILED;
    } else {
        mTransactionId = transactionId;
        mIsTransactionPending = true;
        return Result::OK;
    }
}

Return<Result> Contexthub::disableNanoApp(uint32_t hubId,
                                          uint64_t appId,
                                          uint32_t transactionId) {
    if (!isInitialized()) {
      return Result::NOT_INIT;
    }

    if (mIsTransactionPending) {
        return Result::TRANSACTION_PENDING;
    }

    hub_message_t msg;

    if (setOsAppAsDestination(&msg, hubId) == false) {
        return Result::BAD_PARAMS;
    }

    struct apps_disable_request_t req;

    msg.message_type = CONTEXT_HUB_APPS_DISABLE;
    msg.message_len = sizeof(req);
    req.app_name.id = appId;
    msg.message = &req;

    if(mContextHubModule->send_message(hubId, &msg) != 0) {
        return Result::TRANSACTION_FAILED;
    } else {
        mTransactionId = transactionId;
        mIsTransactionPending = true;
        return Result::OK;
    }
}

Return<Result> Contexthub::queryApps(uint32_t hubId) {
    if (!isInitialized()) {
      return Result::NOT_INIT;
    }

    hub_message_t msg;

    if (setOsAppAsDestination(&msg, hubId) == false) {
        ALOGW("Could not find hubId %" PRIu32, hubId);
        return Result::BAD_PARAMS;
    }

    query_apps_request_t payload;
    payload.app_name.id = ALL_APPS; // TODO : Pass this in as a parameter
    msg.message = &payload;
    msg.message_len = sizeof(payload);
    msg.message_type = CONTEXT_HUB_QUERY_APPS;

    if(mContextHubModule->send_message(hubId, &msg) != 0) {
        ALOGW("Query Apps sendMessage failed");
        return Result::TRANSACTION_FAILED;
    }

    return Result::OK;
}

bool Contexthub::isInitialized() {
    return (mInitCheck == OK && mContextHubModule != nullptr);
}

IContexthub *HIDL_FETCH_IContexthub(const char * halName) {
    ALOGI("%s Called for %s", __FUNCTION__, halName);
    Contexthub *contexthub = new Contexthub;

    if (!contexthub->isInitialized()) {
        delete contexthub;
        contexthub = nullptr;
    }

    return contexthub;
}

}  // namespace implementation
}  // namespace V1_0
}  // namespace contexthub
}  // namespace hardware
}  // namespace android
+105 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ANDROID_HARDWARE_CONTEXTHUB_V1_0_CONTEXTHUB_H_
#define ANDROID_HARDWARE_CONTEXTHUB_V1_0_CONTEXTHUB_H_

#include <unordered_map>

#include <android/hardware/contexthub/1.0/IContexthub.h>
#include <hardware/context_hub.h>

namespace android {
namespace hardware {
namespace contexthub {
namespace V1_0 {
namespace implementation {

struct Contexthub : public ::android::hardware::contexthub::V1_0::IContexthub {
    Contexthub();

    Return<void> getHubs(getHubs_cb _hidl_cb) override;

    Return<Result> registerCallback(uint32_t hubId,
                                    const sp<IContexthubCallback> &cb) override;

    Return<Result> sendMessageToHub(uint32_t hubId,
                                    const ContextHubMsg &msg) override;

    Return<Result> loadNanoApp(uint32_t hubId,
                               const ::android::hardware::hidl_vec<uint8_t>& appBinary,
                               uint32_t transactionId) override;

    Return<Result> unloadNanoApp(uint32_t hubId,
                                 uint64_t appId,
                                 uint32_t transactionId) override;

    Return<Result> enableNanoApp(uint32_t hubId,
                                 uint64_t appId,
                                 uint32_t transactionId) override;

    Return<Result> disableNanoApp(uint32_t hubId,
                                  uint64_t appId,
                                  uint32_t transactionId) override;

    Return<Result> queryApps(uint32_t hubId) override;

    Return<Result> reboot(uint32_t hubId);

    bool isInitialized();

private:

    struct CachedHubInformation{
        struct hub_app_name_t osAppName;
        sp<IContexthubCallback> callBack;
    };

    status_t mInitCheck;
    const struct context_hub_module_t *mContextHubModule;
    std::unordered_map<uint32_t, CachedHubInformation> mCachedHubInfo;

    sp<IContexthubCallback> mCb;
    bool mIsTransactionPending;
    uint32_t mTransactionId;

    bool isValidHubId(uint32_t hubId);

    sp<IContexthubCallback> getCallBackForHubId(uint32_t hubId);

    int handleOsMessage(sp<IContexthubCallback> cb,
                        uint32_t msgType,
                        const uint8_t *msg,
                        int msgLen);

    static int contextHubCb(uint32_t hubId,
                            const struct hub_message_t *rxMsg,
                            void *cookie);

    bool setOsAppAsDestination(hub_message_t *msg, int hubId);

    DISALLOW_COPY_AND_ASSIGN(Contexthub);
};

extern "C" IContexthub *HIDL_FETCH_IContexthub(const char *name);

}  // namespace implementation
}  // namespace V1_0
}  // namespace contexthub
}  // namespace hardware
}  // namespace android

#endif  // ANDROID_HARDWARE_CONTEXTHUB_V1_0_CONTEXTHUB_H_
+4 −0
Original line number Diff line number Diff line
service contexthub-hal-1-0 /system/bin/hw/android.hardware.contexthub@1.0-service
    class hal
    user system
    group system
Loading