Merge changes Id08f5100,I10113c78,I06ea6fff,Ib57f3985,I6cc23c41, ... into main

* changes:
  Update doc for data_enum props.
  Update doc for SEAT_HEADREST_FORE_AFT
  Update doc for SEAT_HEADREST_ANGLE
  Update doc for SEAT_HEADREST_HEIGHT
  Update doc for SEAT_LUMBAR
  Update doc for SEAT_TILT
  Update doc for SEAT_DEPTH
  Update doc for SEAT_HEIGHT
  Update doc for SEAT_BACKREST_ANGLE_MOVE
  Update doc for SEAT_BACKREST_ANGLE_POS
  Update doc for SEAT_FORE_AFT
  Update doc for SEAT_BELT.
  Update doc for SEAT_MEMORY.
  Update doc for MIRROR_MOVE.
  Update doc for MIRROR_POS.
  Update doc for DOOR_MOVE.
  Update doc for DOOR_POS.
  Update doc for EV_BATTERY_DISPLAY_UNITS.
  Update doc for TIRE_PRESSURE_DISPLAY_UNITS.
  Update doc for FUEL_VOLUME_DISPLAY_UNITS.
diff --git a/audio/aidl/default/EngineConfigXmlConverter.cpp b/audio/aidl/default/EngineConfigXmlConverter.cpp
index 5a8b0a3..d945b17 100644
--- a/audio/aidl/default/EngineConfigXmlConverter.cpp
+++ b/audio/aidl/default/EngineConfigXmlConverter.cpp
@@ -179,8 +179,13 @@
         const eng_xsd::ProductStrategies::ProductStrategy& xsdcProductStrategy) {
     AudioHalProductStrategy aidlProductStrategy;
 
-    aidlProductStrategy.id =
-            VALUE_OR_FATAL(convertProductStrategyIdToAidl(xsdcProductStrategy.getId()));
+    if (xsdcProductStrategy.hasId()) {
+        aidlProductStrategy.id =
+                VALUE_OR_FATAL(convertProductStrategyIdToAidl(xsdcProductStrategy.getId()));
+    } else {
+        aidlProductStrategy.id =
+                VALUE_OR_FATAL(convertProductStrategyNameToAidl(xsdcProductStrategy.getName()));
+    }
     aidlProductStrategy.name = xsdcProductStrategy.getName();
 
     if (xsdcProductStrategy.hasAttributesGroup()) {
diff --git a/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd b/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd
index 7d9b06e..02250c7 100644
--- a/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd
+++ b/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd
@@ -105,7 +105,8 @@
                         <xs:element name="AttributesGroup" type="AttributesGroup" minOccurs="1" maxOccurs="unbounded"/>
                     </xs:sequence>
                     <xs:attribute name="name" type="xs:string" use="required"/>
-                    <xs:attribute name="id" type="xs:int" use="required"/>
+                    <!-- Only needs to be specified for vendor strategies. -->
+                    <xs:attribute name="id" type="xs:int" use="optional"/>
                 </xs:complexType>
             </xs:element>
         </xs:sequence>
diff --git a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
index 02e593a..2b86049 100644
--- a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
+++ b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
@@ -105,7 +105,7 @@
                         <xs:element name="AttributesGroup" type="AttributesGroup" minOccurs="1" maxOccurs="unbounded"/>
                     </xs:sequence>
                     <xs:attribute name="name" type="xs:string" use="required"/>
-                    <xs:attribute name="id" type="xs:int" use="required"/>
+                    <xs:attribute name="id" type="xs:int" use="optional"/>
                 </xs:complexType>
             </xs:element>
         </xs:sequence>
diff --git a/automotive/vehicle/aidl/impl/3/utils/common/test/PendingRequestPoolTest.cpp b/automotive/vehicle/aidl/impl/3/utils/common/test/PendingRequestPoolTest.cpp
index 734c739..cc690d7 100644
--- a/automotive/vehicle/aidl/impl/3/utils/common/test/PendingRequestPoolTest.cpp
+++ b/automotive/vehicle/aidl/impl/3/utils/common/test/PendingRequestPoolTest.cpp
@@ -57,7 +57,7 @@
 
   private:
     // Test timeout is 0.1s.
-    static const int64_t TEST_TIMEOUT = 100000000;
+    static constexpr int64_t TEST_TIMEOUT = 100000000;
 
     std::unique_ptr<PendingRequestPool> mPool;
 };
diff --git a/automotive/vehicle/aidl/impl/current/utils/common/test/PendingRequestPoolTest.cpp b/automotive/vehicle/aidl/impl/current/utils/common/test/PendingRequestPoolTest.cpp
index 734c739..cc690d7 100644
--- a/automotive/vehicle/aidl/impl/current/utils/common/test/PendingRequestPoolTest.cpp
+++ b/automotive/vehicle/aidl/impl/current/utils/common/test/PendingRequestPoolTest.cpp
@@ -57,7 +57,7 @@
 
   private:
     // Test timeout is 0.1s.
-    static const int64_t TEST_TIMEOUT = 100000000;
+    static constexpr int64_t TEST_TIMEOUT = 100000000;
 
     std::unique_ptr<PendingRequestPool> mPool;
 };
diff --git a/automotive/vehicle/aidl/impl/current/utils/test_vendor_properties/android/hardware/automotive/vehicle/TestVendorProperty.aidl b/automotive/vehicle/aidl/impl/current/utils/test_vendor_properties/android/hardware/automotive/vehicle/TestVendorProperty.aidl
index 3c877fa..217387f 100644
--- a/automotive/vehicle/aidl/impl/current/utils/test_vendor_properties/android/hardware/automotive/vehicle/TestVendorProperty.aidl
+++ b/automotive/vehicle/aidl/impl/current/utils/test_vendor_properties/android/hardware/automotive/vehicle/TestVendorProperty.aidl
@@ -19,6 +19,7 @@
 /**
  * Test vendor properties used in reference VHAL implementation.
  */
+@JavaDerive(toString=true)
 @Backing(type="int")
 enum TestVendorProperty {
 
diff --git a/automotive/vehicle/aidl/impl/current/vhal/include/ConnectedClient.h b/automotive/vehicle/aidl/impl/current/vhal/include/ConnectedClient.h
index addc901..335f5c0 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/include/ConnectedClient.h
+++ b/automotive/vehicle/aidl/impl/current/vhal/include/ConnectedClient.h
@@ -116,6 +116,10 @@
             CallbackType callback,
             std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropError>&&
                     vehiclePropErrors);
+
+    // Invokes onSupportedValueChange callback.
+    static void sendSupportedValueChangeEvents(CallbackType callback,
+                                               std::vector<PropIdAreaId> propIdAreaIds);
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/current/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/current/vhal/include/DefaultVehicleHal.h
index 02dbe9e..42902fe 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/include/DefaultVehicleHal.h
+++ b/automotive/vehicle/aidl/impl/current/vhal/include/DefaultVehicleHal.h
@@ -255,6 +255,10 @@
             const std::weak_ptr<SubscriptionManager>& subscriptionManager,
             const std::vector<SetValueErrorEvent>& errorEvents);
 
+    static void onSupportedValueChange(
+            const std::weak_ptr<SubscriptionManager>& subscriptionManager,
+            const std::vector<PropIdAreaId>& updatedPropIdAreaIds);
+
     static void checkHealth(IVehicleHardware* hardware,
                             std::weak_ptr<SubscriptionManager> subscriptionManager);
 
diff --git a/automotive/vehicle/aidl/impl/current/vhal/include/SubscriptionManager.h b/automotive/vehicle/aidl/impl/current/vhal/include/SubscriptionManager.h
index 59c21aa..fa438ec 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/include/SubscriptionManager.h
+++ b/automotive/vehicle/aidl/impl/current/vhal/include/SubscriptionManager.h
@@ -118,6 +118,11 @@
                        std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropError>>
     getSubscribedClientsForErrorEvents(const std::vector<SetValueErrorEvent>& errorEvents);
 
+    // For a list of [propId, areaId]s that has updated supported value, returns a map that maps
+    // subscribing clients to updated [propId, areaId]s.
+    std::unordered_map<CallbackType, std::vector<PropIdAreaId>>
+    getSubscribedClientsForSupportedValueChange(const std::vector<PropIdAreaId>& propIdAreaIds);
+
     // Subscribes to supported values change.
     VhalResult<void> subscribeSupportedValueChange(const CallbackType& callback,
                                                    const std::vector<PropIdAreaId>& propIdAreaIds);
diff --git a/automotive/vehicle/aidl/impl/current/vhal/src/ConnectedClient.cpp b/automotive/vehicle/aidl/impl/current/vhal/src/ConnectedClient.cpp
index 35b93d2..ac2691a 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/src/ConnectedClient.cpp
+++ b/automotive/vehicle/aidl/impl/current/vhal/src/ConnectedClient.cpp
@@ -306,6 +306,30 @@
     }
 }
 
+void SubscriptionClient::sendSupportedValueChangeEvents(std::shared_ptr<IVehicleCallback> callback,
+                                                        std::vector<PropIdAreaId> propIdAreaIds) {
+    if (propIdAreaIds.empty()) {
+        return;
+    }
+
+    std::vector<aidl::android::hardware::automotive::vehicle::PropIdAreaId> vhalPropIdAreaIds;
+    for (const auto& propIdAreaId : propIdAreaIds) {
+        vhalPropIdAreaIds.push_back(aidl::android::hardware::automotive::vehicle::PropIdAreaId{
+                .propId = propIdAreaId.propId,
+                .areaId = propIdAreaId.areaId,
+        });
+    }
+
+    if (ScopedAStatus callbackStatus = callback->onSupportedValueChange(vhalPropIdAreaIds);
+        !callbackStatus.isOk()) {
+        ALOGE("subscribe: failed to call onSupportedValueChange callback, client ID: %p, error: "
+              "%s, "
+              "exception: %d, service specific error: %d",
+              callback->asBinder().get(), callbackStatus.getMessage(),
+              callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError());
+    }
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/current/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/current/vhal/src/DefaultVehicleHal.cpp
index 25af50e..050f88d 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/current/vhal/src/DefaultVehicleHal.cpp
@@ -160,6 +160,11 @@
                     [subscriptionManagerCopy](std::vector<SetValueErrorEvent> errorEvents) {
                         onPropertySetErrorEvent(subscriptionManagerCopy, errorEvents);
                     }));
+    mVehicleHardware->registerSupportedValueChangeCallback(
+            std::make_unique<IVehicleHardware::SupportedValueChangeCallback>(
+                    [subscriptionManagerCopy](std::vector<PropIdAreaId> propIdAreaIds) {
+                        onSupportedValueChange(subscriptionManagerCopy, propIdAreaIds);
+                    }));
 
     // Register heartbeat event.
     mRecurrentAction = std::make_shared<std::function<void()>>(
@@ -207,7 +212,8 @@
         std::vector<VehiclePropValue>&& updatedValues) {
     auto batchedEventQueueStrong = batchedEventQueue.lock();
     if (batchedEventQueueStrong == nullptr) {
-        ALOGW("the batched property events queue is destroyed, DefaultVehicleHal is ending");
+        ALOGW("%s: the batched property events queue is destroyed, DefaultVehicleHal is ending",
+              __func__);
         return;
     }
     batchedEventQueueStrong->push(std::move(updatedValues));
@@ -223,7 +229,7 @@
     ATRACE_CALL();
     auto manager = subscriptionManager.lock();
     if (manager == nullptr) {
-        ALOGW("the SubscriptionManager is destroyed, DefaultVehicleHal is ending");
+        ALOGW("%s: the SubscriptionManager is destroyed, DefaultVehicleHal is ending", __func__);
         return;
     }
     auto updatedValuesByClients = manager->getSubscribedClients(std::move(updatedValues));
@@ -237,7 +243,7 @@
         const std::vector<SetValueErrorEvent>& errorEvents) {
     auto manager = subscriptionManager.lock();
     if (manager == nullptr) {
-        ALOGW("the SubscriptionManager is destroyed, DefaultVehicleHal is ending");
+        ALOGW("%s: the SubscriptionManager is destroyed, DefaultVehicleHal is ending", __func__);
         return;
     }
     auto vehiclePropErrorsByClient = manager->getSubscribedClientsForErrorEvents(errorEvents);
@@ -246,6 +252,22 @@
     }
 }
 
+void DefaultVehicleHal::onSupportedValueChange(
+        const std::weak_ptr<SubscriptionManager>& subscriptionManager,
+        const std::vector<PropIdAreaId>& propIdAreaIds) {
+    auto manager = subscriptionManager.lock();
+    if (manager == nullptr) {
+        ALOGW("%s: the SubscriptionManager is destroyed, DefaultVehicleHal is ending", __func__);
+        return;
+    }
+    auto updatedPropIdAreaIdsByClient =
+            manager->getSubscribedClientsForSupportedValueChange(propIdAreaIds);
+    for (auto& [callback, updatedPropIdAreaIds] : updatedPropIdAreaIdsByClient) {
+        SubscriptionClient::sendSupportedValueChangeEvents(callback,
+                                                           std::move(updatedPropIdAreaIds));
+    }
+}
+
 template <class T>
 std::shared_ptr<T> DefaultVehicleHal::getOrCreateClient(
         std::unordered_map<const AIBinder*, std::shared_ptr<T>>* clients,
@@ -931,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,
@@ -1156,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/src/SubscriptionManager.cpp b/automotive/vehicle/aidl/impl/current/vhal/src/SubscriptionManager.cpp
index f790033..946c217 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/src/SubscriptionManager.cpp
+++ b/automotive/vehicle/aidl/impl/current/vhal/src/SubscriptionManager.cpp
@@ -414,6 +414,7 @@
     std::scoped_lock<std::mutex> lockGuard(mLock);
 
     ClientIdType clientId = callback->asBinder().get();
+    ALOGE("ClientId: %p", clientId);
 
     // It is possible that some of the [propId, areaId]s are already subscribed, IVehicleHardware
     // will ignore them.
@@ -581,6 +582,25 @@
     return clients;
 }
 
+std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<PropIdAreaId>>
+SubscriptionManager::getSubscribedClientsForSupportedValueChange(
+        const std::vector<PropIdAreaId>& propIdAreaIds) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<PropIdAreaId>>
+            propIdAreaIdsByClient;
+
+    for (const auto& propIdAreaId : propIdAreaIds) {
+        const auto clientIter = mSupportedValueChangeClientsByPropIdAreaId.find(propIdAreaId);
+        if (clientIter == mSupportedValueChangeClientsByPropIdAreaId.end()) {
+            continue;
+        }
+        for (const auto& [_, client] : clientIter->second) {
+            propIdAreaIdsByClient[client].push_back(propIdAreaId);
+        }
+    }
+    return propIdAreaIdsByClient;
+}
+
 bool SubscriptionManager::isEmpty() {
     std::scoped_lock<std::mutex> lockGuard(mLock);
     return mSubscribedPropsByClient.empty() && mClientsByPropIdAreaId.empty() &&
diff --git a/automotive/vehicle/aidl/impl/current/vhal/test/DefaultVehicleHalTest.cpp b/automotive/vehicle/aidl/impl/current/vhal/test/DefaultVehicleHalTest.cpp
index 0526f7d..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,21 @@
              }});
 
     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(),
-                ElementsAre(PropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2}));
+    ASSERT_THAT(
+            getHardware()->getSubscribedSupportedValueChangePropIdAreaIds(),
+            UnorderedElementsAre(PropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2}));
 }
 
 TEST_F(DefaultVehicleHalTest, testRegisterSupportedValueChangeCallback_invalidRequest) {
@@ -2477,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 "
@@ -2508,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 "
@@ -2549,30 +2557,63 @@
              }});
 
     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";
 }
 
+TEST_F(DefaultVehicleHalTest, testUnregisterSupportedValueChangeCallback_errorFromHardware) {
+    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->setStatus("unsubscribeSupportedValueChange", StatusCode::INTERNAL_ERROR);
+    hardware->setPropertyConfigs(testConfigs);
+
+    setHardware(std::move(hardware));
+
+    auto propIdAreaId = VhalPropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
+    auto status = getClient()->registerSupportedValueChangeCallback(
+            getCallbackClient(), std::vector<VhalPropIdAreaId>{propIdAreaId});
+
+    ASSERT_TRUE(status.isOk()) << "Get non-okay status from registerSupportedValueChangeCallback"
+                               << status.getMessage();
+
+    status = getClient()->unregisterSupportedValueChangeCallback(
+            getCallbackClient(), std::vector<VhalPropIdAreaId>{propIdAreaId});
+
+    ASSERT_FALSE(status.isOk()) << "unregisterSupportedValueChangeCallback must return error if "
+                                   "VehicleHardware returns error";
+}
+
 TEST_F(DefaultVehicleHalTest, testUnregisterSupportedValueChangeCallback_ignoreUnregistered) {
     auto testConfigs = std::vector<VehiclePropConfig>(
             {VehiclePropConfig{
@@ -2603,20 +2644,245 @@
              }});
 
     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());
 }
 
+TEST_F(DefaultVehicleHalTest, testSupportedValueChangeCallback) {
+    auto testConfigs = std::vector<VehiclePropConfig>(
+            {VehiclePropConfig{
+                     .prop = testInt32VecProp(1),
+                     .areaConfigs =
+                             {
+                                     {.areaId = 0,
+                                      .hasSupportedValueInfo =
+                                              HasSupportedValueInfo{
+                                                      .hasMinSupportedValue = false,
+                                                      .hasMaxSupportedValue = false,
+                                                      .hasSupportedValuesList = true,
+                                              }},
+                             },
+             },
+             VehiclePropConfig{
+                     .prop = testInt32VecWindowProp(2),
+                     .areaConfigs =
+                             {
+                                     {.areaId = 2,
+                                      .hasSupportedValueInfo =
+                                              HasSupportedValueInfo{
+                                                      .hasMinSupportedValue = true,
+                                                      .hasMaxSupportedValue = false,
+                                                      .hasSupportedValuesList = false,
+                                              }},
+                             },
+             }});
+
+    auto hardware = std::make_unique<MockVehicleHardware>();
+    hardware->setPropertyConfigs(testConfigs);
+
+    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 = getClient()->registerSupportedValueChangeCallback(
+            getCallbackClient(),
+            std::vector<VhalPropIdAreaId>{vhalPropIdAreaId1, vhalPropIdAreaId2});
+
+    ASSERT_TRUE(status.isOk()) << "Get non-okay status from registerSupportedValueChangeCallback"
+                               << status.getMessage();
+
+    getHardware()->sendSupportedValueChangeEvent(
+            std::vector<PropIdAreaId>{propIdAreaId1, propIdAreaId2});
+
+    getCallback()->waitForOnSupportedValueChange(/*size=*/2, /*timeoutInNano=*/1'000'000'000);
+
+    ASSERT_THAT(getCallback()->getOnSupportedValueChangePropIdAreaIds(),
+                ElementsAre(vhalPropIdAreaId1, vhalPropIdAreaId2));
+}
+
+TEST_F(DefaultVehicleHalTest, testSupportedValueChangeCallback_unregister) {
+    auto testConfigs = std::vector<VehiclePropConfig>(
+            {VehiclePropConfig{
+                     .prop = testInt32VecProp(1),
+                     .areaConfigs =
+                             {
+                                     {.areaId = 0,
+                                      .hasSupportedValueInfo =
+                                              HasSupportedValueInfo{
+                                                      .hasMinSupportedValue = false,
+                                                      .hasMaxSupportedValue = false,
+                                                      .hasSupportedValuesList = true,
+                                              }},
+                             },
+             },
+             VehiclePropConfig{
+                     .prop = testInt32VecWindowProp(2),
+                     .areaConfigs =
+                             {
+                                     {.areaId = 2,
+                                      .hasSupportedValueInfo =
+                                              HasSupportedValueInfo{
+                                                      .hasMinSupportedValue = true,
+                                                      .hasMaxSupportedValue = false,
+                                                      .hasSupportedValuesList = false,
+                                              }},
+                             },
+             }});
+
+    auto hardware = std::make_unique<MockVehicleHardware>();
+    hardware->setPropertyConfigs(testConfigs);
+
+    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 = getClient()->registerSupportedValueChangeCallback(
+            getCallbackClient(),
+            std::vector<VhalPropIdAreaId>{vhalPropIdAreaId1, vhalPropIdAreaId2});
+
+    ASSERT_TRUE(status.isOk()) << "Get non-okay status from registerSupportedValueChangeCallback"
+                               << status.getMessage();
+
+    // After unregistering for propIdAreaId1, we should no longer receive events for it.
+    status = getClient()->unregisterSupportedValueChangeCallback(
+            getCallbackClient(), std::vector<VhalPropIdAreaId>{vhalPropIdAreaId1});
+
+    ASSERT_TRUE(status.isOk()) << "Get non-okay status from unregisterSupportedValueChangeCallback"
+                               << status.getMessage();
+
+    getHardware()->sendSupportedValueChangeEvent(
+            std::vector<PropIdAreaId>{propIdAreaId1, propIdAreaId2});
+
+    getCallback()->waitForOnSupportedValueChange(/*size=*/1, /*timeoutInNano=*/1'000'000'000);
+
+    ASSERT_THAT(getCallback()->getOnSupportedValueChangePropIdAreaIds(),
+                ElementsAre(vhalPropIdAreaId2));
+}
+
+TEST_F(DefaultVehicleHalTest, testRegisterSupportedValueChangeCallback_twoClients) {
+    auto testConfigs = std::vector<VehiclePropConfig>(
+            {VehiclePropConfig{
+                     .prop = testInt32VecProp(1),
+                     .areaConfigs =
+                             {
+                                     {.areaId = 0,
+                                      .hasSupportedValueInfo =
+                                              HasSupportedValueInfo{
+                                                      .hasMinSupportedValue = false,
+                                                      .hasMaxSupportedValue = false,
+                                                      .hasSupportedValuesList = true,
+                                              }},
+                             },
+             },
+             VehiclePropConfig{
+                     .prop = testInt32VecWindowProp(2),
+                     .areaConfigs =
+                             {
+                                     {.areaId = 2,
+                                      .hasSupportedValueInfo =
+                                              HasSupportedValueInfo{
+                                                      .hasMinSupportedValue = true,
+                                                      .hasMaxSupportedValue = false,
+                                                      .hasSupportedValuesList = false,
+                                              }},
+                             },
+             }});
+
+    auto hardware = std::make_unique<MockVehicleHardware>();
+    hardware->setPropertyConfigs(testConfigs);
+
+    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};
+    std::shared_ptr<IVehicleCallback> callback1 = ndk::SharedRefBase::make<MockVehicleCallback>();
+    std::shared_ptr<IVehicleCallback> callback2 = ndk::SharedRefBase::make<MockVehicleCallback>();
+    // Keep binder alive to prevent binder reuse.
+    SpAIBinder binder1 = callback1->asBinder();
+    // Keep binder alive to prevent binder reuse.
+    SpAIBinder binder2 = callback2->asBinder();
+
+    auto status = getClient()->registerSupportedValueChangeCallback(
+            callback1, std::vector<VhalPropIdAreaId>{vhalPropIdAreaId1, vhalPropIdAreaId2});
+
+    ASSERT_TRUE(status.isOk()) << "Get non-okay status from registerSupportedValueChangeCallback"
+                               << status.getMessage();
+
+    status = getClient()->registerSupportedValueChangeCallback(
+            callback2, std::vector<VhalPropIdAreaId>{vhalPropIdAreaId1, vhalPropIdAreaId2});
+
+    ASSERT_TRUE(status.isOk()) << "Get non-okay status from registerSupportedValueChangeCallback"
+                               << status.getMessage();
+
+    ASSERT_THAT(getHardware()->getSubscribedSupportedValueChangePropIdAreaIds(),
+                UnorderedElementsAre(propIdAreaId1, propIdAreaId2));
+
+    status = getClient()->unregisterSupportedValueChangeCallback(
+            callback1, std::vector<VhalPropIdAreaId>{vhalPropIdAreaId1, vhalPropIdAreaId2});
+
+    ASSERT_TRUE(status.isOk()) << "Get non-okay status from unregisterSupportedValueChangeCallback"
+                               << status.getMessage();
+
+    ASSERT_THAT(getHardware()->getSubscribedSupportedValueChangePropIdAreaIds(),
+                UnorderedElementsAre(propIdAreaId1, propIdAreaId2))
+            << "[propId, areaId] must still be subscribed if one of the two clients unsubscribe";
+
+    status = getClient()->unregisterSupportedValueChangeCallback(
+            callback2, std::vector<VhalPropIdAreaId>{vhalPropIdAreaId1, vhalPropIdAreaId2});
+
+    ASSERT_TRUE(status.isOk()) << "Get non-okay status from unregisterSupportedValueChangeCallback"
+                               << status.getMessage();
+
+    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
diff --git a/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleCallback.cpp b/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleCallback.cpp
index 72c5dc5..a557b05 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleCallback.cpp
+++ b/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleCallback.cpp
@@ -92,9 +92,14 @@
     return result;
 }
 
-ScopedAStatus MockVehicleCallback::onSupportedValueChange(const std::vector<PropIdAreaId>&) {
-    // TODO(b/381020465): Add relevant implementation.
-    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ScopedAStatus MockVehicleCallback::onSupportedValueChange(
+        const std::vector<PropIdAreaId>& propIdAreaIds) {
+    {
+        std::scoped_lock<std::mutex> lockGuard(mLock);
+        mOnSupportedValueChangePropIdAreaIds = propIdAreaIds;
+    }
+    mCond.notify_all();
+    return ScopedAStatus::ok();
 }
 
 std::optional<GetValueResults> MockVehicleCallback::nextGetValueResults() {
@@ -151,6 +156,19 @@
     });
 }
 
+bool MockVehicleCallback::waitForOnSupportedValueChange(size_t size, size_t timeoutInNano) {
+    std::unique_lock lk(mLock);
+    return mCond.wait_for(lk, std::chrono::nanoseconds(timeoutInNano), [this, size] {
+        ScopedLockAssertion lockAssertion(mLock);
+        return mOnSupportedValueChangePropIdAreaIds.size() >= size;
+    });
+}
+
+std::vector<PropIdAreaId> MockVehicleCallback::getOnSupportedValueChangePropIdAreaIds() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return mOnSupportedValueChangePropIdAreaIds;
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleCallback.h b/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleCallback.h
index 81a85ff..be181a5 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleCallback.h
+++ b/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleCallback.h
@@ -73,6 +73,9 @@
     bool waitForSetValueResults(size_t size, size_t timeoutInNano);
     bool waitForGetValueResults(size_t size, size_t timeoutInNano);
     bool waitForOnPropertyEventResults(size_t size, size_t timeoutInNano);
+    bool waitForOnSupportedValueChange(size_t size, size_t timeoutInNano);
+    std::vector<aidl::android::hardware::automotive::vehicle::PropIdAreaId>
+    getOnSupportedValueChangePropIdAreaIds();
 
   private:
     std::mutex mLock;
@@ -86,6 +89,8 @@
     int32_t mSharedMemoryFileCount GUARDED_BY(mLock);
     std::list<aidl::android::hardware::automotive::vehicle::VehiclePropErrors>
             mOnPropertySetErrorResults GUARDED_BY(mLock);
+    std::vector<aidl::android::hardware::automotive::vehicle::PropIdAreaId>
+            mOnSupportedValueChangePropIdAreaIds GUARDED_BY(mLock);
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleHardware.cpp b/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleHardware.cpp
index 11f1835..197e99d 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleHardware.cpp
@@ -228,6 +228,12 @@
     mPropertySetErrorCallback = std::move(callback);
 }
 
+void MockVehicleHardware::registerSupportedValueChangeCallback(
+        std::unique_ptr<const SupportedValueChangeCallback> callback) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    mSupportedValueChangeCallback = std::move(callback);
+}
+
 void MockVehicleHardware::setPropertyConfigs(const std::vector<VehiclePropConfig>& configs) {
     std::scoped_lock<std::mutex> lockGuard(mLock);
     mPropertyConfigs = configs;
@@ -419,6 +425,12 @@
     (*mPropertySetErrorCallback)(errorEvents);
 }
 
+void MockVehicleHardware::sendSupportedValueChangeEvent(
+        const std::vector<PropIdAreaId>& propIdAreaIds) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    (*mSupportedValueChangeCallback)(propIdAreaIds);
+}
+
 bool MockVehicleHardware::getAllPropertyConfigsCalled() {
     std::scoped_lock<std::mutex> lockGuard(mLock);
     return mGetAllPropertyConfigsCalled;
diff --git a/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleHardware.h b/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleHardware.h
index e7359db..444166b 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleHardware.h
@@ -62,6 +62,8 @@
     void registerOnPropertyChangeEvent(
             std::unique_ptr<const PropertyChangeCallback> callback) override;
     void registerOnPropertySetErrorEvent(std::unique_ptr<const PropertySetErrorCallback>) override;
+    void registerSupportedValueChangeCallback(
+            std::unique_ptr<const SupportedValueChangeCallback>) override;
     aidl::android::hardware::automotive::vehicle::StatusCode subscribe(
             aidl::android::hardware::automotive::vehicle::SubscribeOptions options) override;
     aidl::android::hardware::automotive::vehicle::StatusCode unsubscribe(int32_t propId,
@@ -112,6 +114,7 @@
     void setDumpResult(DumpResult result);
     void sendOnPropertySetErrorEvent(const std::vector<SetValueErrorEvent>& errorEvents);
     void setPropertyOnChangeEventBatchingWindow(std::chrono::nanoseconds window);
+    void sendSupportedValueChangeEvent(const std::vector<PropIdAreaId>& propIdAreaIds);
 
     std::set<std::pair<int32_t, int32_t>> getSubscribedOnChangePropIdAreaIds();
     std::set<std::pair<int32_t, int32_t>> getSubscribedContinuousPropIdAreaIds();
@@ -150,6 +153,8 @@
     int64_t mSleepTime GUARDED_BY(mLock) = 0;
     std::unique_ptr<const PropertyChangeCallback> mPropertyChangeCallback GUARDED_BY(mLock);
     std::unique_ptr<const PropertySetErrorCallback> mPropertySetErrorCallback GUARDED_BY(mLock);
+    std::unique_ptr<const SupportedValueChangeCallback> mSupportedValueChangeCallback
+            GUARDED_BY(mLock);
     std::function<aidl::android::hardware::automotive::vehicle::StatusCode(
             std::shared_ptr<const GetValuesCallback>,
             const std::vector<aidl::android::hardware::automotive::vehicle::GetValueRequest>&)>
diff --git a/automotive/vehicle/aidl/impl/current/vhal/test/SubscriptionManagerTest.cpp b/automotive/vehicle/aidl/impl/current/vhal/test/SubscriptionManagerTest.cpp
index 2ac3a73..6d0844a 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/test/SubscriptionManagerTest.cpp
+++ b/automotive/vehicle/aidl/impl/current/vhal/test/SubscriptionManagerTest.cpp
@@ -887,6 +887,67 @@
             << "Must filter out outdated property events if VUR is enabled";
 }
 
+TEST_F(SubscriptionManagerTest, testSubscribeSupportedValueChange) {
+    SpAIBinder binder1 = ndk::SharedRefBase::make<PropertyCallback>()->asBinder();
+    std::shared_ptr<IVehicleCallback> client1 = IVehicleCallback::fromBinder(binder1);
+    SpAIBinder binder2 = ndk::SharedRefBase::make<PropertyCallback>()->asBinder();
+    std::shared_ptr<IVehicleCallback> client2 = IVehicleCallback::fromBinder(binder2);
+
+    PropIdAreaId propIdAreaId1 = {.propId = 0, .areaId = 0};
+    PropIdAreaId propIdAreaId2 = {.propId = 1, .areaId = 1};
+
+    auto result = getManager()->subscribeSupportedValueChange(client1, {propIdAreaId1});
+
+    ASSERT_TRUE(result.ok()) << "failed to call subscribeSupportedValueChange"
+                             << result.error().message();
+
+    result = getManager()->subscribeSupportedValueChange(client2, {propIdAreaId1, propIdAreaId2});
+
+    ASSERT_TRUE(result.ok()) << "failed to call subscribeSupportedValueChange"
+                             << result.error().message();
+
+    auto clients = getManager()->getSubscribedClientsForSupportedValueChange(
+            {propIdAreaId1, propIdAreaId2});
+
+    ASSERT_THAT(clients[client1], UnorderedElementsAre(propIdAreaId1))
+            << "Incorrect supported value change events for client1";
+    ASSERT_THAT(clients[client2], UnorderedElementsAre(propIdAreaId1, propIdAreaId2))
+            << "Incorrect supported value change events for client2";
+}
+
+TEST_F(SubscriptionManagerTest, testUnsubscribeSupportedValueChange) {
+    SpAIBinder binder1 = ndk::SharedRefBase::make<PropertyCallback>()->asBinder();
+    std::shared_ptr<IVehicleCallback> client1 = IVehicleCallback::fromBinder(binder1);
+    SpAIBinder binder2 = ndk::SharedRefBase::make<PropertyCallback>()->asBinder();
+    std::shared_ptr<IVehicleCallback> client2 = IVehicleCallback::fromBinder(binder2);
+
+    PropIdAreaId propIdAreaId1 = {.propId = 0, .areaId = 0};
+    PropIdAreaId propIdAreaId2 = {.propId = 1, .areaId = 1};
+
+    auto result = getManager()->subscribeSupportedValueChange(client1, {propIdAreaId1});
+
+    ASSERT_TRUE(result.ok()) << "failed to call subscribeSupportedValueChange"
+                             << result.error().message();
+
+    result = getManager()->subscribeSupportedValueChange(client2, {propIdAreaId1, propIdAreaId2});
+
+    ASSERT_TRUE(result.ok()) << "failed to call subscribeSupportedValueChange"
+                             << result.error().message();
+
+    result = getManager()->unsubscribeSupportedValueChange(binder2.get(), {propIdAreaId1});
+
+    ASSERT_TRUE(result.ok()) << "failed to call unsubscribeSupportedValueChange"
+                             << result.error().message();
+
+    auto clients = getManager()->getSubscribedClientsForSupportedValueChange(
+            {propIdAreaId1, propIdAreaId2});
+
+    ASSERT_THAT(clients[client1], UnorderedElementsAre(propIdAreaId1))
+            << "Incorrect supported value change events for client1";
+    ASSERT_THAT(clients[client2], UnorderedElementsAre(propIdAreaId2))
+            << "Incorrect supported value change events for client2";
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
index 6188dd9..5abf667 100644
--- a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum VehicleProperty {
   INVALID = 0x00000000,
   INFO_VIN = (((0x0100 + 0x10000000) + 0x01000000) + 0x00100000) /* 286261504 */,
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
index d7654d0..09f7941 100644
--- a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -39,6 +39,7 @@
  * in response to such ill formed requests.
  */
 @VintfStability
+@JavaDerive(toString=true)
 @Backing(type="int")
 enum VehicleProperty {
     /**
diff --git a/graphics/composer/aidl/vts/ReadbackVts.cpp b/graphics/composer/aidl/vts/ReadbackVts.cpp
index 9d5928d..b45c8c0 100644
--- a/graphics/composer/aidl/vts/ReadbackVts.cpp
+++ b/graphics/composer/aidl/vts/ReadbackVts.cpp
@@ -37,6 +37,12 @@
     writer.setLayerBlendMode(mDisplay, mLayer, mBlendMode);
     writer.setLayerBrightness(mDisplay, mLayer, mBrightness);
     writer.setLayerDataspace(mDisplay, mLayer, mDataspace);
+    Luts luts{
+            .pfd = ::ndk::ScopedFileDescriptor(dup(mLuts.pfd.get())),
+            .offsets = mLuts.offsets,
+            .lutProperties = mLuts.lutProperties,
+    };
+    writer.setLayerLuts(mDisplay, mLayer, luts);
 }
 
 std::string ReadbackHelper::getColorModeString(ColorMode mode) {
@@ -103,6 +109,24 @@
     layerSettings.geometry.positionTransform = scale * translation;
     layerSettings.whitePointNits = mWhitePointNits;
     layerSettings.sourceDataspace = static_cast<::android::ui::Dataspace>(mDataspace);
+    if (mLuts.pfd.get() >= 0 && mLuts.offsets) {
+        std::vector<int32_t> dimensions;
+        std::vector<int32_t> sizes;
+        std::vector<int32_t> keys;
+        dimensions.reserve(mLuts.lutProperties.size());
+        sizes.reserve(mLuts.lutProperties.size());
+        keys.reserve(mLuts.lutProperties.size());
+
+        for (auto& l : mLuts.lutProperties) {
+            dimensions.emplace_back(static_cast<int32_t>(l.dimension));
+            sizes.emplace_back(static_cast<int32_t>(l.size));
+            keys.emplace_back(static_cast<int32_t>(l.samplingKeys[0]));
+        }
+
+        layerSettings.luts = std::make_shared<::android::gui::DisplayLuts>(
+                ::android::base::unique_fd(dup(mLuts.pfd.get())), *mLuts.offsets, dimensions, sizes,
+                keys);
+    }
 
     return layerSettings;
 }
diff --git a/graphics/composer/aidl/vts/ReadbackVts.h b/graphics/composer/aidl/vts/ReadbackVts.h
index e3b2384..c04e37a 100644
--- a/graphics/composer/aidl/vts/ReadbackVts.h
+++ b/graphics/composer/aidl/vts/ReadbackVts.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <aidl/android/hardware/graphics/composer3/IComposerClient.h>
+#include <aidl/android/hardware/graphics/composer3/Luts.h>
 #include <android-base/unique_fd.h>
 #include <android/hardware/graphics/composer3/ComposerClientReader.h>
 #include <android/hardware/graphics/composer3/ComposerClientWriter.h>
@@ -26,6 +27,8 @@
 #include "GraphicsComposerCallback.h"
 #include "VtsComposerClient.h"
 
+using aidl::android::hardware::graphics::composer3::Luts;
+
 namespace aidl::android::hardware::graphics::composer3::vts {
 
 using ::android::renderengine::LayerSettings;
@@ -80,6 +83,7 @@
     void setTransform(Transform transform) { mTransform = transform; }
     void setAlpha(float alpha) { mAlpha = alpha; }
     void setBlendMode(BlendMode blendMode) { mBlendMode = blendMode; }
+    void setLuts(Luts luts) { mLuts = std::move(luts); }
 
     BlendMode getBlendMode() const { return mBlendMode; }
 
@@ -105,6 +109,7 @@
     BlendMode mBlendMode = BlendMode::NONE;
     uint32_t mZOrder = 0;
     Dataspace mDataspace = Dataspace::UNKNOWN;
+    Luts mLuts;
 };
 
 class TestColorLayer : public TestLayer {
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
index 9db8794..f81289a 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
@@ -20,6 +20,7 @@
 #include <aidl/Vintf.h>
 #include <aidl/android/hardware/graphics/common/BufferUsage.h>
 #include <aidl/android/hardware/graphics/composer3/IComposer.h>
+#include <cutils/ashmem.h>
 #include <gtest/gtest.h>
 #include <ui/DisplayId.h>
 #include <ui/DisplayIdentification.h>
@@ -527,6 +528,118 @@
     }
 }
 
+void generateLuts(Luts* luts, LutProperties::Dimension dimension, int32_t size,
+                  LutProperties::SamplingKey key) {
+    size_t bufferSize = dimension == LutProperties::Dimension::ONE_D
+                                ? static_cast<size_t>(size) * sizeof(float)
+                                : static_cast<size_t>(size * size * size) * sizeof(float);
+    int32_t fd = ashmem_create_region("lut_shared_mem", bufferSize);
+    void* ptr = mmap(nullptr, bufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+    std::vector<float> buffers(static_cast<size_t>(size), 0.5f);
+    memcpy(ptr, buffers.data(), bufferSize);
+    munmap(ptr, bufferSize);
+    luts->pfd = ndk::ScopedFileDescriptor(fd);
+    luts->offsets = std::vector<int32_t>{0};
+    luts->lutProperties = {LutProperties{dimension, size, {key}}};
+}
+
+TEST_P(GraphicsCompositionTest, Luts) {
+    ASSERT_TRUE(
+            mComposerClient->setClientTargetSlotCount(getPrimaryDisplayId(), kClientTargetSlotCount)
+                    .isOk());
+    const auto& [status, properties] = mComposerClient->getOverlaySupport();
+    if (!status.isOk() && status.getExceptionCode() == EX_SERVICE_SPECIFIC &&
+        status.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED) {
+        GTEST_SKIP() << "getOverlaySupport is not supported";
+        return;
+    }
+
+    if (!properties.lutProperties) {
+        GTEST_SKIP() << "lutProperties is not supported";
+        return;
+    }
+
+    for (const auto& lutProperties : *properties.lutProperties) {
+        if (!lutProperties) {
+            continue;
+        }
+        auto& l = *lutProperties;
+
+        for (const auto& key : l.samplingKeys) {
+            for (ColorMode mode : mTestColorModes) {
+                EXPECT_TRUE(mComposerClient
+                                    ->setColorMode(getPrimaryDisplayId(), mode,
+                                                   RenderIntent::COLORIMETRIC)
+                                    .isOk());
+
+                bool isSupported;
+                ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
+                if (!isSupported) {
+                    GTEST_SUCCEED()
+                            << "Readback not supported or unsupported pixelFormat/dataspace";
+                    return;
+                }
+
+                common::Rect coloredSquare({0, 0, getDisplayWidth(), getDisplayHeight()});
+
+                // expected color for each pixel
+                std::vector<Color> expectedColors(
+                        static_cast<size_t>(getDisplayWidth() * getDisplayHeight()));
+                ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), coloredSquare,
+                                               WHITE);
+
+                auto layer = std::make_shared<TestBufferLayer>(
+                        mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(),
+                        getDisplayWidth(), getDisplayHeight(), PixelFormat::RGBA_8888, *mWriter);
+                layer->setDisplayFrame(coloredSquare);
+                layer->setZOrder(10);
+                layer->setDataspace(Dataspace::SRGB);
+
+                Luts luts;
+                generateLuts(&luts, l.dimension, l.size, key);
+                layer->setLuts(std::move(luts));
+
+                ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
+
+                std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+                ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient,
+                                              getDisplayWidth(), getDisplayHeight(), mPixelFormat,
+                                              mDataspace);
+                ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+                writeLayers(layers);
+                ASSERT_TRUE(mReader.takeErrors().empty());
+                mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                                         VtsComposerClient::kNoFrameIntervalNs);
+                execute();
+                // if hwc cannot handle and asks for composition change,
+                // just succeed the test
+                if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
+                    GTEST_SUCCEED();
+                    return;
+                }
+
+                auto changedCompositionTypes =
+                        mReader.takeChangedCompositionTypes(getPrimaryDisplayId());
+                ASSERT_TRUE(changedCompositionTypes.empty());
+
+                mWriter->presentDisplay(getPrimaryDisplayId());
+                execute();
+                ASSERT_TRUE(mReader.takeErrors().empty());
+
+                ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), coloredSquare,
+                                               {188.f / 255.f, 188.f / 255.f, 188.f / 255.f, 1.0f});
+
+                ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+                mTestRenderEngine->setRenderLayers(layers);
+                ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+                ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
+            }
+        }
+    }
+}
+
 TEST_P(GraphicsCompositionTest, MixedColorSpaces) {
     ASSERT_TRUE(
             mComposerClient->setClientTargetSlotCount(getPrimaryDisplayId(), kClientTargetSlotCount)
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SupportInfo.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SupportInfo.aidl
index c90125c..d2fcae2 100644
--- a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SupportInfo.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SupportInfo.aidl
@@ -55,5 +55,10 @@
     boolean isGpuSupported;
     int cpuMinIntervalMillis;
     int gpuMinIntervalMillis;
+    int cpuMinCalculationWindowMillis = 50;
+    int cpuMaxCalculationWindowMillis = 10000;
+    int gpuMinCalculationWindowMillis = 50;
+    int gpuMaxCalculationWindowMillis = 10000;
+    int cpuMaxTidCount = 5;
   }
 }
diff --git a/power/aidl/android/hardware/power/CpuHeadroomParams.aidl b/power/aidl/android/hardware/power/CpuHeadroomParams.aidl
index fab8f43..83a46ae 100644
--- a/power/aidl/android/hardware/power/CpuHeadroomParams.aidl
+++ b/power/aidl/android/hardware/power/CpuHeadroomParams.aidl
@@ -35,9 +35,8 @@
     CalculationType calculationType = CalculationType.MIN;
 
     /**
-     * The calculation rolling window size in milliseconds.
-     * The device should support a superset of [50, 10000] and try to use the closest feasible
-     * window size to the provided value param.
+     * The device should support the range specified in SupportInfo#HeadroomSupportInfo and try to
+     * use the closest feasible window size to the provided value param.
      */
     int calculationWindowMillis = 1000;
 
@@ -50,6 +49,8 @@
      * This should handle all the cases including but not limited to core affinity and app cpuset
      * that change the available CPU cores for the caller. And the HAL should check that the TIDs
      * have the same core affinity.
+     *
+     * The device should support the maximum TID count specified SupportInfo#HeadroomSupportInfo.
      */
     int[] tids;
 }
diff --git a/power/aidl/android/hardware/power/GpuHeadroomParams.aidl b/power/aidl/android/hardware/power/GpuHeadroomParams.aidl
index 68848d8..2d64bd3 100644
--- a/power/aidl/android/hardware/power/GpuHeadroomParams.aidl
+++ b/power/aidl/android/hardware/power/GpuHeadroomParams.aidl
@@ -35,8 +35,8 @@
     CalculationType calculationType = CalculationType.MIN;
 
     /**
-     * The device should support a superset of [50, 10000] and try to use the closest feasible
-     * window size to the provided value param.
+     * The device should support the range specified in SupportInfo#HeadroomSupportInfo and try to
+     * use the closest feasible window size to the provided value param.
      */
     int calculationWindowMillis = 1000;
 }
diff --git a/power/aidl/android/hardware/power/SupportInfo.aidl b/power/aidl/android/hardware/power/SupportInfo.aidl
index 55287cb..011dc18 100644
--- a/power/aidl/android/hardware/power/SupportInfo.aidl
+++ b/power/aidl/android/hardware/power/SupportInfo.aidl
@@ -139,5 +139,39 @@
          * than the interval.
          */
         int gpuMinIntervalMillis;
+
+        /**
+         * Minimum calculation window size for getCpuHeadroom in milliseconds.
+         *
+         * This should be no larger than 50ms.
+         */
+        int cpuMinCalculationWindowMillis = 50;
+
+        /**
+         * Maximum calculation window size for getCpuHeadroom in milliseconds.
+         *
+         * This should be no smaller than 10000ms.
+         */
+        int cpuMaxCalculationWindowMillis = 10000;
+
+        /**
+         * Minimum calculation window size for getGpuHeadroom in milliseconds.
+         *
+         * This should be no larger than 50ms.
+         */
+        int gpuMinCalculationWindowMillis = 50;
+
+        /**
+         * Maximum calculation window size for getGpuHeadroom in milliseconds.
+         *
+         * This should be no smaller than 10000ms.
+         */
+        int gpuMaxCalculationWindowMillis = 10000;
+
+        /**
+         * Maximum number of TIDs this device can support.
+         * This should be no smaller than 5.
+         */
+        int cpuMaxTidCount = 5;
     }
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioAccessFamily.aidl b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioAccessFamily.aidl
index 471916f..f44385a 100644
--- a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioAccessFamily.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioAccessFamily.aidl
@@ -80,5 +80,4 @@
    */
   LTE_CA = (1 << android.hardware.radio.RadioTechnology.LTE_CA) /* 524288 */,
   NR = (1 << android.hardware.radio.RadioTechnology.NR) /* 1048576 */,
-  NB_IOT_NTN = (1 << android.hardware.radio.RadioTechnology.NB_IOT_NTN) /* 2097152 */,
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioTechnology.aidl b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioTechnology.aidl
index 201e694..7aae601 100644
--- a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioTechnology.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioTechnology.aidl
@@ -80,5 +80,4 @@
    */
   LTE_CA,
   NR,
-  NB_IOT_NTN,
 }
diff --git a/radio/aidl/android/hardware/radio/RadioAccessFamily.aidl b/radio/aidl/android/hardware/radio/RadioAccessFamily.aidl
index 8c10bb9..9588ed9 100644
--- a/radio/aidl/android/hardware/radio/RadioAccessFamily.aidl
+++ b/radio/aidl/android/hardware/radio/RadioAccessFamily.aidl
@@ -55,8 +55,4 @@
      * 5G NR. This is only use in 5G Standalone mode.
      */
     NR = 1 << RadioTechnology.NR,
-    /**
-     * 3GPP NB-IOT (Narrowband Internet of Things) over Non-Terrestrial-Networks technology.
-     */
-    NB_IOT_NTN = 1 << RadioTechnology.NB_IOT_NTN,
 }
diff --git a/radio/aidl/android/hardware/radio/RadioTechnology.aidl b/radio/aidl/android/hardware/radio/RadioTechnology.aidl
index 843bfd0..de93a2b 100644
--- a/radio/aidl/android/hardware/radio/RadioTechnology.aidl
+++ b/radio/aidl/android/hardware/radio/RadioTechnology.aidl
@@ -62,8 +62,4 @@
      * 5G NR. This is only used in 5G Standalone mode.
      */
     NR,
-    /**
-     * 3GPP NB-IOT (Narrowband Internet of Things) over Non-Terrestrial-Networks technology.
-     */
-    NB_IOT_NTN,
 }
diff --git a/wifi/aidl/default/aidl_struct_util.cpp b/wifi/aidl/default/aidl_struct_util.cpp
index 6bd5a7f..6de150e 100644
--- a/wifi/aidl/default/aidl_struct_util.cpp
+++ b/wifi/aidl/default/aidl_struct_util.cpp
@@ -3883,7 +3883,8 @@
         return false;
     }
     *aidl_scan_result = {};
-    aidl_scan_result->timeStampInUs = ts_us - legacy_scan_result.age_ms * 1000;
+    aidl_scan_result->timeStampInUs =
+            ts_us - (static_cast<uint64_t>(legacy_scan_result.age_ms) * 1000);
     if (aidl_scan_result->timeStampInUs < 0) {
         aidl_scan_result->timeStampInUs = 0;
         return false;
diff --git a/wifi/aidl/vts/functional/wifi_chip_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_chip_aidl_test.cpp
index b4cb030..1ef02af 100644
--- a/wifi/aidl/vts/functional/wifi_chip_aidl_test.cpp
+++ b/wifi/aidl/vts/functional/wifi_chip_aidl_test.cpp
@@ -30,6 +30,9 @@
 
 #include "wifi_aidl_test_utils.h"
 
+using aidl::android::hardware::wifi::AfcChannelAllowance;
+using aidl::android::hardware::wifi::AvailableAfcChannelInfo;
+using aidl::android::hardware::wifi::AvailableAfcFrequencyInfo;
 using aidl::android::hardware::wifi::BnWifiChipEventCallback;
 using aidl::android::hardware::wifi::IfaceType;
 using aidl::android::hardware::wifi::IWifiApIface;
@@ -38,6 +41,7 @@
 using aidl::android::hardware::wifi::IWifiP2pIface;
 using aidl::android::hardware::wifi::IWifiRttController;
 using aidl::android::hardware::wifi::WifiBand;
+using aidl::android::hardware::wifi::WifiChipCapabilities;
 using aidl::android::hardware::wifi::WifiDebugHostWakeReasonStats;
 using aidl::android::hardware::wifi::WifiDebugRingBufferStatus;
 using aidl::android::hardware::wifi::WifiDebugRingBufferVerboseLevel;
@@ -270,6 +274,23 @@
 }
 
 /*
+ * Tests the setAfcChannelAllowance() API.
+ */
+TEST_P(WifiChipAidlTest, SetAfcChannelAllowance) {
+    configureChipForConcurrencyType(IfaceConcurrencyType::STA);
+    int32_t features = getChipFeatureSet(wifi_chip_);
+    AfcChannelAllowance allowance;
+    allowance.availableAfcChannelInfos = std::vector<AvailableAfcChannelInfo>();
+    allowance.availableAfcFrequencyInfos = std::vector<AvailableAfcFrequencyInfo>();
+    auto status = wifi_chip_->setAfcChannelAllowance(allowance);
+    if (features & static_cast<int32_t>(IWifiChip::FeatureSetMask::SET_AFC_CHANNEL_ALLOWANCE)) {
+        EXPECT_TRUE(status.isOk());
+    } else {
+        EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
+    }
+}
+
+/*
  * SetLatencyMode_normal
  * Tests the setLatencyMode() API with Latency mode NORMAL.
  */
@@ -987,6 +1008,29 @@
     EXPECT_EQ(instances.size(), 2);
 }
 
+/*
+ * GetWifiChipCapabilities
+ */
+TEST_P(WifiChipAidlTest, GetWifiChipCapabilities) {
+    WifiChipCapabilities chipCapabilities;
+    auto status = wifi_chip_->getWifiChipCapabilities(&chipCapabilities);
+    if (checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
+        GTEST_SKIP() << "getWifiChipCapabilities() is not supported by vendor.";
+    }
+    EXPECT_TRUE(status.isOk());
+}
+
+/*
+ * SetMloMode
+ */
+TEST_P(WifiChipAidlTest, SetMloMode) {
+    auto status = wifi_chip_->setMloMode(IWifiChip::ChipMloMode::LOW_LATENCY);
+    if (checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
+        GTEST_SKIP() << "setMloMode() is not supported by vendor.";
+    }
+    EXPECT_TRUE(status.isOk());
+}
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiChipAidlTest);
 INSTANTIATE_TEST_SUITE_P(WifiTest, WifiChipAidlTest,
                          testing::ValuesIn(android::getAidlHalInstanceNames(IWifi::descriptor)),
diff --git a/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp
index f659bf6..5e8e21f 100644
--- a/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp
+++ b/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp
@@ -65,6 +65,12 @@
         return features & static_cast<int32_t>(expected);
     }
 
+    bool isTwtSupported() {
+        TwtCapabilities twt_capabilities = {};
+        auto status = wifi_sta_iface_->twtGetCapabilities(&twt_capabilities);
+        return status.isOk() && twt_capabilities.isTwtRequesterSupported;
+    }
+
     ndk::ScopedAStatus createStaIface(std::shared_ptr<IWifiStaIface>* sta_iface) {
         std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(getInstanceName());
         EXPECT_NE(nullptr, wifi_chip.get());
@@ -379,6 +385,9 @@
     }
 }
 
+/**
+ * TwtGetCapabilities
+ */
 TEST_P(WifiStaIfaceAidlTest, TwtGetCapabilities) {
     if (interface_version_ < 2) {
         GTEST_SKIP() << "TwtGetCapabilities is available as of sta_iface V2";
@@ -400,6 +409,9 @@
     EXPECT_GT(twt_capabilities.maxWakeIntervalUs, 0);
 }
 
+/**
+ * TwtSessionSetup
+ */
 TEST_P(WifiStaIfaceAidlTest, TwtSessionSetup) {
     if (interface_version_ < 2) {
         GTEST_SKIP() << "TwtSessionSetup is available as of sta_iface V2";
@@ -424,18 +436,14 @@
     EXPECT_TRUE(wifi_sta_iface_->twtSessionSetup(1, twtRequest).isOk());
 }
 
+/**
+ * TwtSessionGetStats
+ */
 TEST_P(WifiStaIfaceAidlTest, TwtSessionGetStats) {
     if (interface_version_ < 2) {
         GTEST_SKIP() << "TwtSessionGetStats is available as of sta_iface V2";
     }
-
-    TwtCapabilities twt_capabilities = {};
-    auto status = wifi_sta_iface_->twtGetCapabilities(&twt_capabilities);
-    if (checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
-        GTEST_SKIP() << "twtGetCapabilities() is not supported by the vendor";
-    }
-    EXPECT_TRUE(status.isOk());
-    if (!twt_capabilities.isTwtRequesterSupported) {
+    if (!isTwtSupported()) {
         GTEST_SKIP() << "TWT is not supported";
     }
 
@@ -444,26 +452,77 @@
     EXPECT_TRUE(wifi_sta_iface_->twtSessionGetStats(1, 10).isOk());
 }
 
+/**
+ * TwtSessionTeardown
+ */
 TEST_P(WifiStaIfaceAidlTest, TwtSessionTeardown) {
     if (interface_version_ < 2) {
-        GTEST_SKIP() << "TwtSessionTeardown is available as of sta_iface V3";
+        GTEST_SKIP() << "TwtSessionTeardown is available as of sta_iface V2";
     }
-
-    TwtCapabilities twt_capabilities = {};
-    auto status = wifi_sta_iface_->twtGetCapabilities(&twt_capabilities);
-    if (checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
-        GTEST_SKIP() << "twtGetCapabilities() is not supported by the vendor";
-    }
-    EXPECT_TRUE(status.isOk());
-    if (!twt_capabilities.isTwtRequesterSupported) {
+    if (!isTwtSupported()) {
         GTEST_SKIP() << "TWT is not supported";
     }
 
     // Expecting a IWifiStaIfaceEventCallback.onTwtFailure() with INVALID_PARAMS
-    // as  the error code.
+    // as the error code.
     EXPECT_TRUE(wifi_sta_iface_->twtSessionTeardown(1, 10).isOk());
 }
 
+/**
+ * TwtSessionUpdate
+ */
+TEST_P(WifiStaIfaceAidlTest, TwtSessionUpdate) {
+    if (interface_version_ < 2) {
+        GTEST_SKIP() << "TwtSessionUpdate is available as of sta_iface V2";
+    }
+    if (!isTwtSupported()) {
+        GTEST_SKIP() << "TWT is not supported";
+    }
+
+    TwtRequest twtRequest;
+    twtRequest.mloLinkId = 0;
+    twtRequest.minWakeDurationUs = 1000;
+    twtRequest.maxWakeDurationUs = 10000;
+    twtRequest.minWakeIntervalUs = 10000;
+    twtRequest.maxWakeIntervalUs = 100000;
+
+    // Expecting a IWifiStaIfaceEventCallback.onTwtFailure() with INVALID_PARAMS
+    // as the error code.
+    EXPECT_TRUE(wifi_sta_iface_->twtSessionUpdate(1, 10, twtRequest).isOk());
+}
+
+/**
+ * TwtSessionSuspend
+ */
+TEST_P(WifiStaIfaceAidlTest, TwtSessionSuspend) {
+    if (interface_version_ < 2) {
+        GTEST_SKIP() << "TwtSessionSuspend is available as of sta_iface V2";
+    }
+    if (!isTwtSupported()) {
+        GTEST_SKIP() << "TWT is not supported";
+    }
+
+    // Expecting a IWifiStaIfaceEventCallback.onTwtFailure() with INVALID_PARAMS
+    // as the error code.
+    EXPECT_TRUE(wifi_sta_iface_->twtSessionSuspend(1, 10).isOk());
+}
+
+/**
+ * TwtSessionResume
+ */
+TEST_P(WifiStaIfaceAidlTest, TwtSessionResume) {
+    if (interface_version_ < 2) {
+        GTEST_SKIP() << "TwtSessionResume is available as of sta_iface V2";
+    }
+    if (!isTwtSupported()) {
+        GTEST_SKIP() << "TWT is not supported";
+    }
+
+    // Expecting a IWifiStaIfaceEventCallback.onTwtFailure() with INVALID_PARAMS
+    // as the error code.
+    EXPECT_TRUE(wifi_sta_iface_->twtSessionResume(1, 10).isOk());
+}
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiStaIfaceAidlTest);
 INSTANTIATE_TEST_SUITE_P(WifiTest, WifiStaIfaceAidlTest,
                          testing::ValuesIn(android::getAidlHalInstanceNames(IWifi::descriptor)),
diff --git a/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp b/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp
index 590c58b..6723b1f 100644
--- a/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp
+++ b/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp
@@ -86,6 +86,8 @@
         isBridgedSupport = testing::checkSubstringInCommandOutput(
                 "/system/bin/cmd wifi get-softap-supported-features",
                 "wifi_softap_bridged_ap_supported");
+        isMloSupport = testing::checkSubstringInCommandOutput(
+                "/system/bin/cmd wifi get-softap-supported-features", "wifi_softap_mlo_supported");
     }
 
     virtual void TearDown() override {
@@ -100,6 +102,7 @@
     bool isAcsSupport;
     bool isWpa3SaeSupport;
     bool isBridgedSupport;
+    bool isMloSupport;
     int interface_version_;
 
     IfaceParams getIfaceParamsWithoutAcs(std::string iface_name) {
@@ -476,6 +479,34 @@
     EXPECT_TRUE(status.isOk());
 }
 
+/**
+ * AddAccessPointWithMloConfig and remove link should pass
+ */
+TEST_P(HostapdAidl, AddAccessPointWithMloConfigAndRemoveInstance) {
+    if (interface_version_ < 3) {
+        GTEST_SKIP() << "MLO SAP is available in IfaceParams as of Hostapd V3";
+    }
+    if (!isMloSupport) GTEST_SKIP() << "Missing MLO AP support";
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = HostapdAidlTestUtils::setupMloApIface();
+    EXPECT_TRUE(wifi_ap_iface.get() != nullptr);
+    std::string br_name;
+    std::vector<std::string> instances;
+    bool uses_mlo;
+    EXPECT_TRUE(wifi_ap_iface->getName(&br_name).isOk());
+    EXPECT_TRUE(wifi_ap_iface->getBridgedInstances(&instances).isOk());
+    EXPECT_TRUE(wifi_ap_iface->usesMlo(&uses_mlo).isOk());
+    EXPECT_TRUE(uses_mlo);
+
+    IfaceParams iface_params = getIfaceParamsWithBridgedModeACS(br_name);
+    iface_params.instanceIdentities = {instances[0], instances[1]};
+    iface_params.usesMlo = uses_mlo;
+    iface_params.hwModeParams.enable80211AX = true;
+    iface_params.hwModeParams.enable80211BE = true;
+
+    EXPECT_TRUE(hostapd->addAccessPoint(iface_params, getSaeNwParams()).isOk());
+    EXPECT_TRUE(hostapd->removeLinkFromMultipleLinkBridgedApIface(br_name, instances[0]).isOk());
+}
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HostapdAidl);
 INSTANTIATE_TEST_SUITE_P(
     Hostapd, HostapdAidl,
diff --git a/wifi/hostapd/aidl/vts/functional/hostapd_aidl_test_utils.h b/wifi/hostapd/aidl/vts/functional/hostapd_aidl_test_utils.h
index 93540b2..3876998 100644
--- a/wifi/hostapd/aidl/vts/functional/hostapd_aidl_test_utils.h
+++ b/wifi/hostapd/aidl/vts/functional/hostapd_aidl_test_utils.h
@@ -77,4 +77,11 @@
     return ap_iface_name;
 }
 
+std::shared_ptr<IWifiApIface> setupMloApIface() {
+    std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(kWifiInstanceName);
+    EXPECT_TRUE(wifi_chip.get() != nullptr);
+    return getWifiApOrBridgedApIface(
+            wifi_chip, generateApIfaceParams(IfaceConcurrencyType::AP_BRIDGED, true, 0));
+}
+
 }  // namespace HostapdAidlTestUtils
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp b/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp
index 3a01c5b..257607f 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp
@@ -43,10 +43,13 @@
 using aidl::android::hardware::wifi::supplicant::ISupplicantStaIface;
 using aidl::android::hardware::wifi::supplicant::ISupplicantStaNetwork;
 using aidl::android::hardware::wifi::supplicant::KeyMgmtMask;
+using aidl::android::hardware::wifi::supplicant::MloLinksInfo;
 using aidl::android::hardware::wifi::supplicant::MscsParams;
 using aidl::android::hardware::wifi::supplicant::QosCharacteristics;
 using aidl::android::hardware::wifi::supplicant::QosPolicyScsData;
 using aidl::android::hardware::wifi::supplicant::QosPolicyScsRequestStatus;
+using aidl::android::hardware::wifi::supplicant::RxFilterType;
+using aidl::android::hardware::wifi::supplicant::SignalPollResult;
 using aidl::android::hardware::wifi::supplicant::UsdBaseConfig;
 using aidl::android::hardware::wifi::supplicant::UsdCapabilities;
 using aidl::android::hardware::wifi::supplicant::UsdMessageInfo;
@@ -961,6 +964,106 @@
     EXPECT_FALSE(sta_iface_->generateSelfDppConfiguration(ssid, eckey_in).isOk());
 }
 
+/*
+ * getSignalPollResults
+ */
+TEST_P(SupplicantStaIfaceAidlTest, GetSignalPollResults) {
+    if (interface_version_ < 2) {
+        GTEST_SKIP() << "getSignalPollResults is available as of Supplicant V2";
+    }
+
+    std::vector<SignalPollResult> results;
+    EXPECT_TRUE(sta_iface_->getSignalPollResults(&results).isOk());
+}
+
+/*
+ * Test that we can add, remove, start, and stop an RX filter.
+ */
+TEST_P(SupplicantStaIfaceAidlTest, ConfigureRxFilter) {
+    RxFilterType filterType = RxFilterType::V4_MULTICAST;
+    EXPECT_TRUE(sta_iface_->addRxFilter(filterType).isOk());
+    EXPECT_TRUE(sta_iface_->startRxFilter().isOk());
+    EXPECT_TRUE(sta_iface_->stopRxFilter().isOk());
+    EXPECT_TRUE(sta_iface_->removeRxFilter(filterType).isOk());
+}
+
+/*
+ * Test that we can start and cancel all WPS methods.
+ */
+TEST_P(SupplicantStaIfaceAidlTest, StartAndCancelWps) {
+    std::vector<uint8_t> zeroMacAddr = {0, 0, 0, 0, 0, 0};
+    std::string pin = "12345678";
+
+    EXPECT_TRUE(sta_iface_->startWpsPbc(zeroMacAddr).isOk());
+    EXPECT_TRUE(sta_iface_->cancelWps().isOk());
+
+    std::string generatedPin;
+    EXPECT_TRUE(sta_iface_->startWpsPinDisplay(zeroMacAddr, &generatedPin).isOk());
+    EXPECT_TRUE(sta_iface_->cancelWps().isOk());
+
+    EXPECT_TRUE(sta_iface_->startWpsPinKeypad(pin).isOk());
+    EXPECT_TRUE(sta_iface_->cancelWps().isOk());
+
+    EXPECT_TRUE(sta_iface_->startWpsRegistrar(zeroMacAddr, pin).isOk());
+    EXPECT_TRUE(sta_iface_->cancelWps().isOk());
+}
+
+/*
+ * Test that we can add, list, get, and remove a network.
+ */
+TEST_P(SupplicantStaIfaceAidlTest, ManageNetwork) {
+    std::shared_ptr<ISupplicantStaNetwork> network;
+    EXPECT_TRUE(sta_iface_->addNetwork(&network).isOk());
+    EXPECT_NE(network, nullptr);
+
+    std::vector<int32_t> networkList;
+    EXPECT_TRUE(sta_iface_->listNetworks(&networkList).isOk());
+    EXPECT_EQ(networkList.size(), 1);
+
+    int networkId;
+    EXPECT_TRUE(network->getId(&networkId).isOk());
+    EXPECT_EQ(networkId, networkList[0]);
+
+    std::shared_ptr<ISupplicantStaNetwork> retrievedNetwork;
+    EXPECT_TRUE(sta_iface_->getNetwork(networkId, &retrievedNetwork).isOk());
+    EXPECT_NE(retrievedNetwork, nullptr);
+    EXPECT_TRUE(sta_iface_->removeNetwork(networkId).isOk());
+}
+
+/*
+ * EnableAutoReconnect
+ */
+TEST_P(SupplicantStaIfaceAidlTest, EnableAutoReconnect) {
+    EXPECT_TRUE(sta_iface_->enableAutoReconnect(true).isOk());
+    EXPECT_TRUE(sta_iface_->enableAutoReconnect(false).isOk());
+}
+
+/*
+ * SetQosPolicyFeatureEnabled
+ */
+TEST_P(SupplicantStaIfaceAidlTest, SetQosPolicyFeatureEnabled) {
+    EXPECT_TRUE(sta_iface_->setQosPolicyFeatureEnabled(true).isOk());
+    EXPECT_TRUE(sta_iface_->setQosPolicyFeatureEnabled(false).isOk());
+}
+
+/*
+ * GetConnectionMloLinksInfo
+ */
+TEST_P(SupplicantStaIfaceAidlTest, GetConnectionMloLinksInfo) {
+    MloLinksInfo mloInfo;
+    EXPECT_TRUE(sta_iface_->getConnectionMloLinksInfo(&mloInfo).isOk());
+}
+
+/*
+ * StopDppInitiator
+ */
+TEST_P(SupplicantStaIfaceAidlTest, StopDppInitiator) {
+    if (!keyMgmtSupported(sta_iface_, KeyMgmtMask::DPP)) {
+        GTEST_SKIP() << "Missing DPP support";
+    }
+    EXPECT_TRUE(sta_iface_->stopDppInitiator().isOk());
+}
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SupplicantStaIfaceAidlTest);
 INSTANTIATE_TEST_SUITE_P(Supplicant, SupplicantStaIfaceAidlTest,
                          testing::ValuesIn(android::getAidlHalInstanceNames(