Add binder lifecycle monitor.

Add binder lifecycle monitor for registerSupportedValueChange. If
the client binder dies, we need to call unregister for the client
and clear stored information.

Flag: EXEMPT hal
Test: atest DefaultVehicleHalTest
Bug: 377348572
Change-Id: I7271a609c7eb4cae98eb5fc684d1212ffc921db9
diff --git a/automotive/vehicle/aidl/impl/current/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/current/vhal/src/DefaultVehicleHal.cpp
index 012a430..050f88d 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/current/vhal/src/DefaultVehicleHal.cpp
@@ -953,7 +953,9 @@
     }
 
     {
-        // Lock to make sure onBinderDied would not be called concurrently.
+        // Lock to make sure onBinderDied would not be called concurrently
+        // (before subscribe). Without this, we may create a new subscription for an already dead
+        // client which will never be unsubscribed.
         std::scoped_lock lockGuard(mLock);
         if (!monitorBinderLifeCycleLocked(callback->asBinder().get())) {
             return ScopedAStatus::fromExceptionCodeWithMessage(EX_TRANSACTION_FAILED,
@@ -1178,14 +1180,24 @@
     if (propIdAreaIdsToSubscribe.empty()) {
         return ScopedAStatus::ok();
     }
-    auto result =
-            mSubscriptionManager->subscribeSupportedValueChange(callback, propIdAreaIdsToSubscribe);
-    if (!result.ok()) {
-        ALOGW("registerSupportedValueChangeCallback: failed to subscribe supported value change"
-              " for %s, error: %s",
-              fmt::format("{}", propIdAreaIdsToSubscribe).c_str(),
-              result.error().message().c_str());
-        return toScopedAStatus(result);
+    {
+        // Lock to make sure onBinderDied would not be called concurrently
+        // (before subscribeSupportedValueChange). Without this, we may create a new subscription
+        // for an already dead client which will never be unsubscribed.
+        std::scoped_lock lockGuard(mLock);
+        if (!monitorBinderLifeCycleLocked(callback->asBinder().get())) {
+            return ScopedAStatus::fromExceptionCodeWithMessage(EX_TRANSACTION_FAILED,
+                                                               "client died");
+        }
+        auto result = mSubscriptionManager->subscribeSupportedValueChange(callback,
+                                                                          propIdAreaIdsToSubscribe);
+        if (!result.ok()) {
+            ALOGW("registerSupportedValueChangeCallback: failed to subscribe supported value change"
+                  " for %s, error: %s",
+                  fmt::format("{}", propIdAreaIdsToSubscribe).c_str(),
+                  result.error().message().c_str());
+            return toScopedAStatus(result);
+        }
     }
     return ScopedAStatus::ok();
 }
diff --git a/automotive/vehicle/aidl/impl/current/vhal/test/DefaultVehicleHalTest.cpp b/automotive/vehicle/aidl/impl/current/vhal/test/DefaultVehicleHalTest.cpp
index f87e3d7..90b34c4 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/test/DefaultVehicleHalTest.cpp
+++ b/automotive/vehicle/aidl/impl/current/vhal/test/DefaultVehicleHalTest.cpp
@@ -272,6 +272,10 @@
     void SetUp() override { init(std::make_unique<MockVehicleHardware>()); }
 
     void init(std::unique_ptr<MockVehicleHardware> hardware) {
+        // Default init uses the following static configs to create the mock IVehicleHardware,
+        // individual test case may use setHardware to overwrite the underlying IVehicleHardware
+        // to use a different set of configs.
+
         std::vector<VehiclePropConfig> testConfigs;
         for (size_t i = 0; i < 10000; i++) {
             testConfigs.push_back(VehiclePropConfig{
@@ -420,18 +424,8 @@
                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
         });
         hardware->setPropertyConfigs(testConfigs);
-        mHardwarePtr = hardware.get();
-        mVhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
-        mVhalClient = IVehicle::fromBinder(mVhal->asBinder());
-        mCallback = ndk::SharedRefBase::make<MockVehicleCallback>();
-        // Keep the local binder alive.
-        mBinder = mCallback->asBinder();
-        mCallbackClient = IVehicleCallback::fromBinder(mBinder);
 
-        // Set the linkToDeath to a fake implementation that always returns OK.
-        auto handler = std::make_unique<TestBinderLifecycleHandler>();
-        mBinderLifecycleHandler = handler.get();
-        mVhal->setBinderLifecycleHandler(std::move(handler));
+        setHardware(std::move(hardware));
     }
 
     void TearDown() override {
@@ -548,6 +542,33 @@
         return {};
     }
 
+  protected:
+    // Sets the underlying IVehicleHardware and recreates the DefaultVehicleHal objects under test.
+    // If used, caller should call this at the beginning of the test case.
+    void setHardware(std::unique_ptr<MockVehicleHardware> hardware) {
+        setHardware(std::move(hardware), 0);
+    }
+
+    void setHardware(std::unique_ptr<MockVehicleHardware> hardware, int32_t testInterfaceVersion) {
+        mHardwarePtr = hardware.get();
+        if (testInterfaceVersion == 0) {
+            mVhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
+        } else {
+            mVhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware),
+                                                                testInterfaceVersion);
+        }
+        // Set the linkToDeath to a fake implementation that always returns OK.
+        auto handler = std::make_unique<TestBinderLifecycleHandler>();
+        mBinderLifecycleHandler = handler.get();
+        mVhal->setBinderLifecycleHandler(std::move(handler));
+
+        mVhalClient = IVehicle::fromBinder(mVhal->asBinder());
+        mCallback = ndk::SharedRefBase::make<MockVehicleCallback>();
+        // Keep the local binder alive.
+        mBinder = mCallback->asBinder();
+        mCallbackClient = IVehicleCallback::fromBinder(mBinder);
+    }
+
   private:
     class TestBinderLifecycleHandler final : public DefaultVehicleHal::BinderLifecycleInterface {
       public:
@@ -588,11 +609,10 @@
 
     auto hardware = std::make_unique<MockVehicleHardware>();
     hardware->setPropertyConfigs(testConfigs);
-    auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
-    std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+    setHardware(std::move(hardware));
 
     VehiclePropConfigs output;
-    auto status = client->getAllPropConfigs(&output);
+    auto status = getClient()->getAllPropConfigs(&output);
 
     ASSERT_TRUE(status.isOk()) << "getAllPropConfigs failed: " << status.getMessage();
     ASSERT_THAT(output.payloads, WhenSortedBy(propConfigCmp, Eq(testConfigs)));
@@ -609,11 +629,10 @@
 
     auto hardware = std::make_unique<MockVehicleHardware>();
     hardware->setPropertyConfigs(testConfigs);
-    auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
-    std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+    setHardware(std::move(hardware));
 
     VehiclePropConfigs output;
-    auto status = client->getAllPropConfigs(&output);
+    auto status = getClient()->getAllPropConfigs(&output);
 
     ASSERT_TRUE(status.isOk()) << "getAllPropConfigs failed: " << status.getMessage();
     ASSERT_TRUE(output.payloads.empty());
@@ -637,12 +656,10 @@
 
     auto hardware = std::make_unique<MockVehicleHardware>();
     hardware->setPropertyConfigs(testConfigs);
-    auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware),
-                                                            /* testInterfaceVersion= */ 2);
-    std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+    setHardware(std::move(hardware), /* testInterfaceVersion= */ 2);
 
     VehiclePropConfigs output;
-    auto status = client->getAllPropConfigs(&output);
+    auto status = getClient()->getAllPropConfigs(&output);
 
     ASSERT_TRUE(status.isOk()) << "getAllPropConfigs failed: " << status.getMessage();
     ASSERT_THAT(output.payloads, ElementsAre(VehiclePropConfig{
@@ -666,15 +683,14 @@
     hardware->setPropertyConfigs(testConfigs);
     // Store the pointer for testing. We are sure it is valid.
     MockVehicleHardware* hardwarePtr = hardware.get();
-    auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
-    std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+    setHardware(std::move(hardware));
 
     VehiclePropConfigs output;
-    auto status = client->getPropConfigs(std::vector<int32_t>({propId1, propId2}), &output);
+    auto status = getClient()->getPropConfigs(std::vector<int32_t>({propId1, propId2}), &output);
 
     ASSERT_TRUE(status.isOk()) << "getPropConfigs failed: " << status.getMessage();
     ASSERT_EQ(output.payloads, testConfigs);
-    ASSERT_FALSE(hardwarePtr->getAllPropertyConfigsCalled());
+    ASSERT_FALSE(getHardware()->getAllPropertyConfigsCalled());
 }
 
 TEST_F(DefaultVehicleHalTest, testGetPropConfigsInvalidArg) {
@@ -689,11 +705,10 @@
 
     auto hardware = std::make_unique<MockVehicleHardware>();
     hardware->setPropertyConfigs(testConfigs);
-    auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
-    std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+    setHardware(std::move(hardware));
 
     VehiclePropConfigs output;
-    auto status = client->getPropConfigs(
+    auto status = getClient()->getPropConfigs(
             std::vector<int32_t>({testInt32VecProp(1), testInt32VecProp(2), testInt32VecProp(3)}),
             &output);
 
@@ -2187,8 +2202,7 @@
     auto response = std::vector<SupportedValuesListResult>({resultFromHardware});
     hardware->setSupportedValuesListResponse(response);
 
-    auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
-    std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+    setHardware(std::move(hardware));
 
     SupportedValuesListResults results;
 
@@ -2196,14 +2210,14 @@
     auto propIdAreaId2 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
     auto propIdAreaId3 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(3), .areaId = 0};
     auto propIdAreaId4 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(4), .areaId = 4};
-    auto status = vhal->getSupportedValuesLists(
+    auto status = getClient()->getSupportedValuesLists(
             std::vector<VhalPropIdAreaId>{propIdAreaId1, propIdAreaId2, propIdAreaId3,
                                           propIdAreaId4},
             &results);
 
     ASSERT_TRUE(status.isOk()) << "Get non-okay status from getSupportedValuesLists"
                                << status.getMessage();
-    ASSERT_THAT(hardwarePtr->getSupportedValuesListRequest(),
+    ASSERT_THAT(getHardware()->getSupportedValuesListRequest(),
                 ElementsAre(PropIdAreaId{.propId = testInt32VecWindowProp(4), .areaId = 4}))
             << "Only valid request 4 should get to hardware";
 
@@ -2250,8 +2264,7 @@
     auto hardware = std::make_unique<MockVehicleHardware>();
     hardware->setPropertyConfigs(testConfigs);
 
-    auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
-    std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+    setHardware(std::move(hardware));
 
     SupportedValuesListResults results;
 
@@ -2260,7 +2273,7 @@
     // areaId not valid.
     auto propIdAreaId2 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(1), .areaId = 2};
 
-    auto status = vhal->getSupportedValuesLists(
+    auto status = getClient()->getSupportedValuesLists(
             std::vector<VhalPropIdAreaId>{propIdAreaId1, propIdAreaId2}, &results);
 
     ASSERT_TRUE(status.isOk()) << "Get non-okay status from getSupportedValuesLists"
@@ -2328,8 +2341,7 @@
     auto response = std::vector<MinMaxSupportedValueResult>({resultFromHardware});
     hardware->setMinMaxSupportedValueResponse(response);
 
-    auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
-    std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+    setHardware(std::move(hardware));
 
     MinMaxSupportedValueResults results;
 
@@ -2337,14 +2349,14 @@
     auto propIdAreaId2 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
     auto propIdAreaId3 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(3), .areaId = 0};
     auto propIdAreaId4 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(4), .areaId = 4};
-    auto status = vhal->getMinMaxSupportedValue(
+    auto status = getClient()->getMinMaxSupportedValue(
             std::vector<VhalPropIdAreaId>{propIdAreaId1, propIdAreaId2, propIdAreaId3,
                                           propIdAreaId4},
             &results);
 
     ASSERT_TRUE(status.isOk()) << "Get non-okay status from getMinMaxSupportedValue"
                                << status.getMessage();
-    ASSERT_THAT(hardwarePtr->getMinMaxSupportedValueRequest(),
+    ASSERT_THAT(getHardware()->getMinMaxSupportedValueRequest(),
                 ElementsAre(PropIdAreaId{.propId = testInt32VecWindowProp(4), .areaId = 4}))
             << "Only valid request 4 should get to hardware";
 
@@ -2396,8 +2408,7 @@
     auto hardware = std::make_unique<MockVehicleHardware>();
     hardware->setPropertyConfigs(testConfigs);
 
-    auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
-    std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+    setHardware(std::move(hardware));
 
     MinMaxSupportedValueResults results;
 
@@ -2406,7 +2417,7 @@
     // areaId not valid.
     auto propIdAreaId2 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(1), .areaId = 2};
 
-    auto status = vhal->getMinMaxSupportedValue(
+    auto status = getClient()->getMinMaxSupportedValue(
             std::vector<VhalPropIdAreaId>{propIdAreaId1, propIdAreaId2}, &results);
 
     ASSERT_TRUE(status.isOk()) << "Get non-okay status from getMinMaxSupportedValue"
@@ -2448,22 +2459,20 @@
              }});
 
     auto hardware = std::make_unique<MockVehicleHardware>();
-    MockVehicleHardware* hardwarePtr = hardware.get();
     hardware->setPropertyConfigs(testConfigs);
 
-    auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
-    std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+    setHardware(std::move(hardware));
 
     // This request is ignored because it does not have supported value info.
     auto propIdAreaId1 = VhalPropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
     auto propIdAreaId2 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
-    auto status = client->registerSupportedValueChangeCallback(
+    auto status = getClient()->registerSupportedValueChangeCallback(
             getCallbackClient(), std::vector<VhalPropIdAreaId>{propIdAreaId1, propIdAreaId2});
 
     ASSERT_TRUE(status.isOk()) << "Get non-okay status from registerSupportedValueChangeCallback"
                                << status.getMessage();
     ASSERT_THAT(
-            hardwarePtr->getSubscribedSupportedValueChangePropIdAreaIds(),
+            getHardware()->getSubscribedSupportedValueChangePropIdAreaIds(),
             UnorderedElementsAre(PropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2}));
 }
 
@@ -2478,11 +2487,10 @@
     auto hardware = std::make_unique<MockVehicleHardware>();
     hardware->setPropertyConfigs(testConfigs);
 
-    auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
-    std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+    setHardware(std::move(hardware));
 
     auto propIdAreaId1 = VhalPropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
-    auto status = client->registerSupportedValueChangeCallback(
+    auto status = getClient()->registerSupportedValueChangeCallback(
             getCallbackClient(), std::vector<VhalPropIdAreaId>{propIdAreaId1});
 
     ASSERT_FALSE(status.isOk()) << "registerSupportedValueChangeCallback must return error if one "
@@ -2509,11 +2517,10 @@
     hardware->setStatus("subscribeSupportedValueChange", StatusCode::INTERNAL_ERROR);
     hardware->setPropertyConfigs(testConfigs);
 
-    auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
-    std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+    setHardware(std::move(hardware));
 
     auto propIdAreaId = VhalPropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
-    auto status = client->registerSupportedValueChangeCallback(
+    auto status = getClient()->registerSupportedValueChangeCallback(
             getCallbackClient(), std::vector<VhalPropIdAreaId>{propIdAreaId});
 
     ASSERT_FALSE(status.isOk()) << "registerSupportedValueChangeCallback must return error if "
@@ -2550,27 +2557,25 @@
              }});
 
     auto hardware = std::make_unique<MockVehicleHardware>();
-    MockVehicleHardware* hardwarePtr = hardware.get();
     hardware->setPropertyConfigs(testConfigs);
 
-    auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
-    std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+    setHardware(std::move(hardware));
 
     auto propIdAreaId1 = VhalPropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
     auto propIdAreaId2 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
-    auto status = client->registerSupportedValueChangeCallback(
+    auto status = getClient()->registerSupportedValueChangeCallback(
             getCallbackClient(), std::vector<VhalPropIdAreaId>{propIdAreaId1, propIdAreaId2});
 
     ASSERT_TRUE(status.isOk()) << "Get non-okay status from registerSupportedValueChangeCallback"
                                << status.getMessage();
 
-    status = client->unregisterSupportedValueChangeCallback(
+    status = getClient()->unregisterSupportedValueChangeCallback(
             getCallbackClient(), std::vector<VhalPropIdAreaId>{propIdAreaId1, propIdAreaId2});
 
     ASSERT_TRUE(status.isOk()) << "Get non-okay status from unregisterSupportedValueChangeCallback"
                                << status.getMessage();
 
-    ASSERT_TRUE(hardwarePtr->getSubscribedSupportedValueChangePropIdAreaIds().empty())
+    ASSERT_TRUE(getHardware()->getSubscribedSupportedValueChangePropIdAreaIds().empty())
             << "All registered [propId, areaId]s must be unregistered";
 }
 
@@ -2591,20 +2596,18 @@
 
     auto hardware = std::make_unique<MockVehicleHardware>();
     hardware->setStatus("unsubscribeSupportedValueChange", StatusCode::INTERNAL_ERROR);
-    MockVehicleHardware* hardwarePtr = hardware.get();
     hardware->setPropertyConfigs(testConfigs);
 
-    auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
-    std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+    setHardware(std::move(hardware));
 
     auto propIdAreaId = VhalPropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
-    auto status = client->registerSupportedValueChangeCallback(
+    auto status = getClient()->registerSupportedValueChangeCallback(
             getCallbackClient(), std::vector<VhalPropIdAreaId>{propIdAreaId});
 
     ASSERT_TRUE(status.isOk()) << "Get non-okay status from registerSupportedValueChangeCallback"
                                << status.getMessage();
 
-    status = client->unregisterSupportedValueChangeCallback(
+    status = getClient()->unregisterSupportedValueChangeCallback(
             getCallbackClient(), std::vector<VhalPropIdAreaId>{propIdAreaId});
 
     ASSERT_FALSE(status.isOk()) << "unregisterSupportedValueChangeCallback must return error if "
@@ -2641,15 +2644,13 @@
              }});
 
     auto hardware = std::make_unique<MockVehicleHardware>();
-    MockVehicleHardware* hardwarePtr = hardware.get();
     hardware->setPropertyConfigs(testConfigs);
 
-    auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
-    std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+    setHardware(std::move(hardware));
 
     auto propIdAreaId1 = VhalPropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
     auto propIdAreaId2 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
-    auto status = client->unregisterSupportedValueChangeCallback(
+    auto status = getClient()->unregisterSupportedValueChangeCallback(
             getCallbackClient(), std::vector<VhalPropIdAreaId>{propIdAreaId1, propIdAreaId2});
 
     ASSERT_TRUE(status.isOk());
@@ -2685,24 +2686,22 @@
              }});
 
     auto hardware = std::make_unique<MockVehicleHardware>();
-    MockVehicleHardware* hardwarePtr = hardware.get();
     hardware->setPropertyConfigs(testConfigs);
 
-    auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
-    std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+    setHardware(std::move(hardware));
 
     auto vhalPropIdAreaId1 = VhalPropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
     auto vhalPropIdAreaId2 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
     auto propIdAreaId1 = PropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
     auto propIdAreaId2 = PropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
-    auto status = client->registerSupportedValueChangeCallback(
+    auto status = getClient()->registerSupportedValueChangeCallback(
             getCallbackClient(),
             std::vector<VhalPropIdAreaId>{vhalPropIdAreaId1, vhalPropIdAreaId2});
 
     ASSERT_TRUE(status.isOk()) << "Get non-okay status from registerSupportedValueChangeCallback"
                                << status.getMessage();
 
-    hardwarePtr->sendSupportedValueChangeEvent(
+    getHardware()->sendSupportedValueChangeEvent(
             std::vector<PropIdAreaId>{propIdAreaId1, propIdAreaId2});
 
     getCallback()->waitForOnSupportedValueChange(/*size=*/2, /*timeoutInNano=*/1'000'000'000);
@@ -2741,17 +2740,15 @@
              }});
 
     auto hardware = std::make_unique<MockVehicleHardware>();
-    MockVehicleHardware* hardwarePtr = hardware.get();
     hardware->setPropertyConfigs(testConfigs);
 
-    auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
-    std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+    setHardware(std::move(hardware));
 
     auto vhalPropIdAreaId1 = VhalPropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
     auto vhalPropIdAreaId2 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
     auto propIdAreaId1 = PropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
     auto propIdAreaId2 = PropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
-    auto status = client->registerSupportedValueChangeCallback(
+    auto status = getClient()->registerSupportedValueChangeCallback(
             getCallbackClient(),
             std::vector<VhalPropIdAreaId>{vhalPropIdAreaId1, vhalPropIdAreaId2});
 
@@ -2759,13 +2756,13 @@
                                << status.getMessage();
 
     // After unregistering for propIdAreaId1, we should no longer receive events for it.
-    status = client->unregisterSupportedValueChangeCallback(
+    status = getClient()->unregisterSupportedValueChangeCallback(
             getCallbackClient(), std::vector<VhalPropIdAreaId>{vhalPropIdAreaId1});
 
     ASSERT_TRUE(status.isOk()) << "Get non-okay status from unregisterSupportedValueChangeCallback"
                                << status.getMessage();
 
-    hardwarePtr->sendSupportedValueChangeEvent(
+    getHardware()->sendSupportedValueChangeEvent(
             std::vector<PropIdAreaId>{propIdAreaId1, propIdAreaId2});
 
     getCallback()->waitForOnSupportedValueChange(/*size=*/1, /*timeoutInNano=*/1'000'000'000);
@@ -2804,11 +2801,9 @@
              }});
 
     auto hardware = std::make_unique<MockVehicleHardware>();
-    MockVehicleHardware* hardwarePtr = hardware.get();
     hardware->setPropertyConfigs(testConfigs);
 
-    auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
-    std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+    setHardware(std::move(hardware));
 
     auto vhalPropIdAreaId1 = VhalPropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
     auto vhalPropIdAreaId2 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
@@ -2821,41 +2816,73 @@
     // Keep binder alive to prevent binder reuse.
     SpAIBinder binder2 = callback2->asBinder();
 
-    auto status = client->registerSupportedValueChangeCallback(
+    auto status = getClient()->registerSupportedValueChangeCallback(
             callback1, std::vector<VhalPropIdAreaId>{vhalPropIdAreaId1, vhalPropIdAreaId2});
 
     ASSERT_TRUE(status.isOk()) << "Get non-okay status from registerSupportedValueChangeCallback"
                                << status.getMessage();
 
-    status = client->registerSupportedValueChangeCallback(
+    status = getClient()->registerSupportedValueChangeCallback(
             callback2, std::vector<VhalPropIdAreaId>{vhalPropIdAreaId1, vhalPropIdAreaId2});
 
     ASSERT_TRUE(status.isOk()) << "Get non-okay status from registerSupportedValueChangeCallback"
                                << status.getMessage();
 
-    ASSERT_THAT(hardwarePtr->getSubscribedSupportedValueChangePropIdAreaIds(),
+    ASSERT_THAT(getHardware()->getSubscribedSupportedValueChangePropIdAreaIds(),
                 UnorderedElementsAre(propIdAreaId1, propIdAreaId2));
 
-    status = client->unregisterSupportedValueChangeCallback(
+    status = getClient()->unregisterSupportedValueChangeCallback(
             callback1, std::vector<VhalPropIdAreaId>{vhalPropIdAreaId1, vhalPropIdAreaId2});
 
     ASSERT_TRUE(status.isOk()) << "Get non-okay status from unregisterSupportedValueChangeCallback"
                                << status.getMessage();
 
-    ASSERT_THAT(hardwarePtr->getSubscribedSupportedValueChangePropIdAreaIds(),
+    ASSERT_THAT(getHardware()->getSubscribedSupportedValueChangePropIdAreaIds(),
                 UnorderedElementsAre(propIdAreaId1, propIdAreaId2))
             << "[propId, areaId] must still be subscribed if one of the two clients unsubscribe";
 
-    status = client->unregisterSupportedValueChangeCallback(
+    status = getClient()->unregisterSupportedValueChangeCallback(
             callback2, std::vector<VhalPropIdAreaId>{vhalPropIdAreaId1, vhalPropIdAreaId2});
 
     ASSERT_TRUE(status.isOk()) << "Get non-okay status from unregisterSupportedValueChangeCallback"
                                << status.getMessage();
 
-    ASSERT_TRUE(hardwarePtr->getSubscribedSupportedValueChangePropIdAreaIds().empty())
+    ASSERT_TRUE(getHardware()->getSubscribedSupportedValueChangePropIdAreaIds().empty())
             << "All registered [propId, areaId]s must be unregistered";
 }
 
+TEST_F(DefaultVehicleHalTest, testRegisterSupportedValueChange_monitorBinderLifecycle) {
+    auto testConfigs = std::vector<VehiclePropConfig>({VehiclePropConfig{
+            .prop = testInt32VecProp(1),
+            .areaConfigs =
+                    {
+                            {.areaId = 0,
+                             .hasSupportedValueInfo =
+                                     HasSupportedValueInfo{
+                                             .hasMinSupportedValue = false,
+                                             .hasMaxSupportedValue = false,
+                                             .hasSupportedValuesList = true,
+                                     }},
+                    },
+    }});
+
+    auto hardware = std::make_unique<MockVehicleHardware>();
+    hardware->setPropertyConfigs(testConfigs);
+
+    setHardware(std::move(hardware));
+
+    auto vhalPropIdAreaId = VhalPropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
+
+    auto status = getClient()->registerSupportedValueChangeCallback(
+            getCallbackClient(), std::vector<VhalPropIdAreaId>{vhalPropIdAreaId});
+
+    ASSERT_TRUE(status.isOk()) << "Get non-okay status from registerSupportedValueChangeCallback"
+                               << status.getMessage();
+
+    ASSERT_EQ(countOnBinderDiedContexts(), static_cast<size_t>(1))
+            << "expect one OnBinderDied context when one client is registered";
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware