contexthub: Handle service death

Register for notification of service death for callbacks registered with
the context hub HAL. Upon this notification, unregister the callback to
avoid crashing if an event occurs prior to the service coming back up.

Bug: 36202367
Test: adb shell stop, confirm death notification received via log;
  vts-tradefed run commandAndExit vts --module VtsHalContexthubV1_0Target
Change-Id: I3c25229806cb9f2a116007939c752841edbf0985
diff --git a/contexthub/1.0/default/Contexthub.cpp b/contexthub/1.0/default/Contexthub.cpp
index 4a6b3f2..bf45900 100644
--- a/contexthub/1.0/default/Contexthub.cpp
+++ b/contexthub/1.0/default/Contexthub.cpp
@@ -38,6 +38,7 @@
 Contexthub::Contexthub()
         : mInitCheck(NO_INIT),
           mContextHubModule(nullptr),
+          mDeathRecipient(new DeathRecipient(this)),
           mIsTransactionPending(false) {
     const hw_module_t *module;
 
@@ -96,7 +97,7 @@
             c.stoppedPowerDrawMw = hubArray[i].stopped_power_draw_mw;
             c.sleepPowerDrawMw = hubArray[i].sleep_power_draw_mw;
 
-            info.callBack = nullptr;
+            info.callback = nullptr;
             info.osAppName = hubArray[i].os_app_name;
             mCachedHubInfo[hubArray[i].hub_id] = info;
 
@@ -110,6 +111,16 @@
     return Void();
 }
 
+Contexthub::DeathRecipient::DeathRecipient(sp<Contexthub> contexthub)
+        : mContexthub(contexthub) {}
+
+void Contexthub::DeathRecipient::serviceDied(
+        uint64_t cookie,
+        const wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
+    uint32_t hubId = static_cast<uint32_t>(cookie);
+    mContexthub->handleServiceDeath(hubId);
+}
+
 bool Contexthub::isValidHubId(uint32_t hubId) {
     if (!mCachedHubInfo.count(hubId)) {
         ALOGW("Hub information not found for hubId %" PRIu32, hubId);
@@ -123,7 +134,7 @@
     if (!isValidHubId(hubId)) {
         return nullptr;
     } else {
-        return mCachedHubInfo[hubId].callBack;
+        return mCachedHubInfo[hubId].callback;
     }
 }
 
@@ -193,8 +204,22 @@
                                                      contextHubCb,
                                                      this) == 0) {
         // Initialized && valid hub && subscription successful
+        if (mCachedHubInfo[hubId].callback != nullptr) {
+            ALOGD("Modifying callback for hubId %" PRIu32, hubId);
+            mCachedHubInfo[hubId].callback->unlinkToDeath(mDeathRecipient);
+        }
+
+        mCachedHubInfo[hubId].callback = cb;
+        if (cb != nullptr) {
+            Return<bool> linkResult = cb->linkToDeath(mDeathRecipient, hubId);
+            bool linkSuccess = linkResult.isOk() ?
+                static_cast<bool>(linkResult) : false;
+            if (!linkSuccess) {
+                ALOGW("Couldn't link death recipient for hubId %" PRIu32,
+                      hubId);
+            }
+        }
         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
@@ -309,6 +334,16 @@
       return retVal;
 }
 
+void Contexthub::handleServiceDeath(uint32_t hubId) {
+    ALOGI("Callback/service died for hubId %" PRIu32, hubId);
+    int ret = mContextHubModule->subscribe_messages(hubId, nullptr, nullptr);
+    if (ret != 0) {
+        ALOGW("Failed to unregister callback from hubId %" PRIu32 ": %d",
+              hubId, ret);
+    }
+    mCachedHubInfo[hubId].callback.clear();
+}
+
 int Contexthub::contextHubCb(uint32_t hubId,
                              const struct hub_message_t *rxMsg,
                              void *cookie) {