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
diff --git a/contexthub/1.0/default/Android.bp b/contexthub/1.0/default/Android.bp
new file mode 100644
index 0000000..7c5f79d
--- /dev/null
+++ b/contexthub/1.0/default/Android.bp
@@ -0,0 +1,33 @@
+/*
+ * 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",
+    ],
+}
diff --git a/contexthub/1.0/default/Android.mk b/contexthub/1.0/default/Android.mk
new file mode 100644
index 0000000..ad40878
--- /dev/null
+++ b/contexthub/1.0/default/Android.mk
@@ -0,0 +1,23 @@
+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)
diff --git a/contexthub/1.0/default/Contexthub.cpp b/contexthub/1.0/default/Contexthub.cpp
new file mode 100644
index 0000000..d530a87
--- /dev/null
+++ b/contexthub/1.0/default/Contexthub.cpp
@@ -0,0 +1,528 @@
+/*
+ * 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
diff --git a/contexthub/1.0/default/Contexthub.h b/contexthub/1.0/default/Contexthub.h
new file mode 100644
index 0000000..0883ce8
--- /dev/null
+++ b/contexthub/1.0/default/Contexthub.h
@@ -0,0 +1,105 @@
+/*
+ * 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_
diff --git a/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc b/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc
new file mode 100644
index 0000000..8dba85f
--- /dev/null
+++ b/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc
@@ -0,0 +1,4 @@
+service contexthub-hal-1-0 /system/bin/hw/android.hardware.contexthub@1.0-service
+    class hal
+    user system
+    group system
diff --git a/contexthub/1.0/default/service.cpp b/contexthub/1.0/default/service.cpp
new file mode 100644
index 0000000..db9a4e7
--- /dev/null
+++ b/contexthub/1.0/default/service.cpp
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "android.hardware.contexthub@1.0-service"
+
+#include <android/hardware/contexthub/1.0/IContexthub.h>
+#include <hidl/LegacySupport.h>
+
+using android::hardware::contexthub::V1_0::IContexthub;
+using android::hardware::defaultPassthroughServiceImplementation;
+
+int main() {
+    return defaultPassthroughServiceImplementation<IContexthub>("context_hub");
+}
diff --git a/contexthub/Android.bp b/contexthub/Android.bp
index bbb3e4b..ba90f2c 100644
--- a/contexthub/Android.bp
+++ b/contexthub/Android.bp
@@ -1,4 +1,5 @@
 // This is an autogenerated file, do not edit.
 subdirs = [
     "1.0",
+    "1.0/default",
 ]