Merge "Increase callback waiting time to fix test flakiness." into main
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/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
index ea59771..cef0ea6 100644
--- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
+++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
@@ -77,17 +77,15 @@
 }
 
 ::android::status_t StreamRemoteSubmix::drain(StreamDescriptor::DrainMode) {
-    usleep(1000);
     return ::android::OK;
 }
 
 ::android::status_t StreamRemoteSubmix::flush() {
-    usleep(1000);
-    return ::android::OK;
+    // TODO(b/372951987): consider if this needs to be done from 'StreamInWorkerLogic::cycle'.
+    return mIsInput ? standby() : ::android::OK;
 }
 
 ::android::status_t StreamRemoteSubmix::pause() {
-    usleep(1000);
     return ::android::OK;
 }
 
diff --git a/audio/aidl/default/r_submix/SubmixRoute.cpp b/audio/aidl/default/r_submix/SubmixRoute.cpp
index 325a012..445b1d3 100644
--- a/audio/aidl/default/r_submix/SubmixRoute.cpp
+++ b/audio/aidl/default/r_submix/SubmixRoute.cpp
@@ -134,10 +134,10 @@
 // - the peer input is in standby AFTER having been active.
 // We DO block if:
 // - the input was never activated to avoid discarding first frames in the pipe in case capture
-// start was delayed
+//   start was delayed
 bool SubmixRoute::shouldBlockWrite() {
     std::lock_guard guard(mLock);
-    return (mStreamInOpen || (mStreamInStandby && (mReadCounterFrames != 0)));
+    return mStreamInOpen && (!mStreamInStandby || mReadCounterFrames == 0);
 }
 
 long SubmixRoute::updateReadCounterFrames(size_t frameCount) {
diff --git a/audio/aidl/vts/EffectHelper.h b/audio/aidl/vts/EffectHelper.h
index eedac3d..8ceb56b 100644
--- a/audio/aidl/vts/EffectHelper.h
+++ b/audio/aidl/vts/EffectHelper.h
@@ -47,6 +47,7 @@
 using aidl::android::hardware::audio::effect::getRange;
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::isRangeValid;
+using aidl::android::hardware::audio::effect::kDrainSupportedVersion;
 using aidl::android::hardware::audio::effect::kEffectTypeUuidSpatializer;
 using aidl::android::hardware::audio::effect::kEventFlagDataMqNotEmpty;
 using aidl::android::hardware::audio::effect::kEventFlagDataMqUpdate;
@@ -195,8 +196,11 @@
                 ASSERT_TRUE(expectState(effect, State::PROCESSING));
                 break;
             case CommandId::STOP:
-                ASSERT_TRUE(expectState(effect, State::IDLE) ||
-                            expectState(effect, State::DRAINING));
+                // Enforce the state checking after kDrainSupportedVersion
+                if (getHalVersion(effect) >= kDrainSupportedVersion) {
+                    ASSERT_TRUE(expectState(effect, State::IDLE) ||
+                                expectState(effect, State::DRAINING));
+                }
                 break;
             case CommandId::RESET:
                 ASSERT_TRUE(expectState(effect, State::IDLE));
@@ -518,6 +522,11 @@
         }
     }
 
+    static int getHalVersion(const std::shared_ptr<IEffect>& effect) {
+        int version = 0;
+        return (effect && effect->getInterfaceVersion(&version).isOk()) ? version : 0;
+    }
+
     bool mIsSpatializer;
     Descriptor mDescriptor;
     size_t mInputFrameSize, mOutputFrameSize;
diff --git a/audio/aidl/vts/VtsHalAECTargetTest.cpp b/audio/aidl/vts/VtsHalAECTargetTest.cpp
index 53b6757..c007f18 100644
--- a/audio/aidl/vts/VtsHalAECTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAECTargetTest.cpp
@@ -139,12 +139,12 @@
 };
 
 TEST_P(AECParamTest, SetAndGetEchoDelay) {
-    EXPECT_NO_FATAL_FAILURE(addEchoDelayParam(mEchoDelay));
+    addEchoDelayParam(mEchoDelay);
     SetAndGetParameters();
 }
 
 TEST_P(AECParamTest, SetAndGetMobileMode) {
-    EXPECT_NO_FATAL_FAILURE(addMobileModeParam(mMobileMode));
+    addMobileModeParam(mMobileMode);
     SetAndGetParameters();
 }
 
diff --git a/audio/aidl/vts/VtsHalAGC1TargetTest.cpp b/audio/aidl/vts/VtsHalAGC1TargetTest.cpp
index f14afbc..72a2d5e 100644
--- a/audio/aidl/vts/VtsHalAGC1TargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAGC1TargetTest.cpp
@@ -139,17 +139,17 @@
 };
 
 TEST_P(AGC1ParamTest, SetAndGetTargetPeakLevelParam) {
-    EXPECT_NO_FATAL_FAILURE(addTargetPeakLevelParam(mTargetPeakLevel));
+    addTargetPeakLevelParam(mTargetPeakLevel);
     SetAndGetParameters();
 }
 
 TEST_P(AGC1ParamTest, SetAndGetMaxCompressionGain) {
-    EXPECT_NO_FATAL_FAILURE(addMaxCompressionGainParam(mMaxCompressionGain));
+    addMaxCompressionGainParam(mMaxCompressionGain);
     SetAndGetParameters();
 }
 
 TEST_P(AGC1ParamTest, SetAndGetEnableLimiter) {
-    EXPECT_NO_FATAL_FAILURE(addEnableLimiterParam(mEnableLimiter));
+    addEnableLimiterParam(mEnableLimiter);
     SetAndGetParameters();
 }
 
diff --git a/audio/aidl/vts/VtsHalAGC2TargetTest.cpp b/audio/aidl/vts/VtsHalAGC2TargetTest.cpp
index 048d540..ccac8c5 100644
--- a/audio/aidl/vts/VtsHalAGC2TargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAGC2TargetTest.cpp
@@ -145,17 +145,17 @@
 };
 
 TEST_P(AGC2ParamTest, SetAndGetDigitalGainParam) {
-    EXPECT_NO_FATAL_FAILURE(addDigitalGainParam(mGain));
+    addDigitalGainParam(mGain);
     SetAndGetParameters();
 }
 
 TEST_P(AGC2ParamTest, SetAndGetSaturationMargin) {
-    EXPECT_NO_FATAL_FAILURE(addSaturationMarginParam(mMargin));
+    addSaturationMarginParam(mMargin);
     SetAndGetParameters();
 }
 
 TEST_P(AGC2ParamTest, SetAndGetLevelEstimator) {
-    EXPECT_NO_FATAL_FAILURE(addLevelEstimatorParam(mLevelEstimator));
+    addLevelEstimatorParam(mLevelEstimator);
     SetAndGetParameters();
 }
 
diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
index 93c2a61..750e54d 100644
--- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -938,6 +938,8 @@
         LOG(DEBUG) << __func__;
         return "";
     }
+    const std::vector<int8_t>& getData() const { return mData; }
+    void fillData(int8_t filler) { std::fill(mData.begin(), mData.end(), filler); }
     std::optional<StreamDescriptor::Command> maybeGetNextCommand(int* actualSize = nullptr) {
         TransitionTrigger trigger = mDriver->getNextTrigger(mData.size(), actualSize);
         if (StreamEventReceiver::Event* expEvent =
@@ -1007,6 +1009,8 @@
     StreamReaderLogic(const StreamContext& context, StreamLogicDriver* driver,
                       StreamEventReceiver* eventReceiver)
         : StreamCommonLogic(context, driver, eventReceiver) {}
+    // Should only be called after the worker has joined.
+    const std::vector<int8_t>& getData() const { return StreamCommonLogic::getData(); }
 
   protected:
     Status cycle() override {
@@ -1072,6 +1076,7 @@
         if (const size_t readCount =
                     !isMmapped() ? getDataMQ()->availableToRead() : reply.fmqByteCount;
             readCount > 0) {
+            fillData(-1);
             if (isMmapped() ? readDataFromMmap(readCount) : readDataFromMQ(readCount)) {
                 goto checkAcceptedReply;
             }
@@ -1093,6 +1098,8 @@
     StreamWriterLogic(const StreamContext& context, StreamLogicDriver* driver,
                       StreamEventReceiver* eventReceiver)
         : StreamCommonLogic(context, driver, eventReceiver) {}
+    // Should only be called after the worker has joined.
+    const std::vector<int8_t>& getData() const { return StreamCommonLogic::getData(); }
 
   protected:
     Status cycle() override {
@@ -1109,6 +1116,14 @@
             return Status::ABORT;
         }
         if (actualSize != 0) {
+            if (command.getTag() == StreamDescriptor::Command::burst) {
+                fillData(mBurstIteration);
+                if (mBurstIteration < std::numeric_limits<int8_t>::max()) {
+                    mBurstIteration++;
+                } else {
+                    mBurstIteration = 0;
+                }
+            }
             if (isMmapped() ? !writeDataToMmap() : !writeDataToMQ()) {
                 return Status::ABORT;
             }
@@ -1167,6 +1182,9 @@
         LOG(ERROR) << __func__ << ": unacceptable reply: " << reply.toString();
         return Status::ABORT;
     }
+
+  private:
+    int8_t mBurstIteration = 1;
 };
 using StreamWriter = StreamWorker<StreamWriterLogic>;
 
@@ -2859,10 +2877,12 @@
         ASSERT_NO_FATAL_FAILURE(mStream->SetUpStream(module, getMinimumStreamBufferSizeFrames()));
     }
 
-    void SetUpStreamForDevicePort(IModule* module, ModuleConfig* moduleConfig,
-                                  const AudioPort& devicePort, bool connectedOnly = false) {
-        ASSERT_NO_FATAL_FAILURE(
-                SetUpPortConfigForDevicePort(module, moduleConfig, devicePort, connectedOnly));
+    void SetUpStreamForDevicePort(
+            IModule* module, ModuleConfig* moduleConfig, const AudioPort& devicePort,
+            bool connectedOnly = false,
+            const std::optional<AudioDeviceAddress>& connectionAddress = std::nullopt) {
+        ASSERT_NO_FATAL_FAILURE(SetUpPortConfigForDevicePort(module, moduleConfig, devicePort,
+                                                             connectedOnly, connectionAddress));
         if (!mSkipTestReason.empty()) return;
         ASSERT_NO_FATAL_FAILURE(SetUpStream(module));
     }
@@ -2898,6 +2918,23 @@
         if (!mSkipTestReason.empty()) return;
         ASSERT_NO_FATAL_FAILURE(SetUpStream(module));
     }
+    void SetUpStreamForNewMixPortConfig(IModule* module, ModuleConfig*,
+                                        const AudioPortConfig& existingMixPortConfig,
+                                        const AudioPortConfig& existingDevicePortConfig) {
+        auto mixPortConfig = existingMixPortConfig;
+        mixPortConfig.id = 0;
+        mMixPortConfig = std::make_unique<WithAudioPortConfig>(mixPortConfig);
+        ASSERT_NO_FATAL_FAILURE(mMixPortConfig->SetUp(module));
+        mDevicePortConfig = std::make_unique<WithAudioPortConfig>(existingDevicePortConfig);
+        ASSERT_NO_FATAL_FAILURE(mDevicePortConfig->SetUp(module));
+        mDevice = existingDevicePortConfig.ext.get<AudioPortExt::device>().device;
+        mPatch = std::make_unique<WithAudioPatch>(mIsInput, mMixPortConfig->get(),
+                                                  mDevicePortConfig->get());
+        ASSERT_NO_FATAL_FAILURE(mPatch->SetUp(module));
+        mStream = std::make_unique<WithStream<Stream>>(mMixPortConfig->get());
+        ASSERT_NO_FATAL_FAILURE(mStream->SetUpPortConfig(module));
+        ASSERT_NO_FATAL_FAILURE(SetUpStream(module));
+    }
     void SetUpPatchForMixPortConfig(IModule* module, ModuleConfig* moduleConfig,
                                     const AudioPortConfig& mixPortConfig) {
         constexpr bool connectedOnly = true;
@@ -2929,6 +2966,7 @@
     }
 
     const AudioDevice& getDevice() const { return mDevice; }
+    const AudioPortConfig& getDevicePortConfig() const { return mDevicePortConfig->get(); }
     int32_t getMinimumStreamBufferSizeFrames() const {
         return mPatch->getMinimumStreamBufferSizeFrames();
     }
@@ -2944,7 +2982,8 @@
   private:
     void SetUpDevicePort(IModule* module, ModuleConfig* moduleConfig,
                          const std::set<int32_t>& devicePortIds, bool connectedOnly,
-                         std::optional<AudioPort>* connectedDevicePort) {
+                         std::optional<AudioPort>* connectedDevicePort,
+                         const std::optional<AudioDeviceAddress>& connectionAddress) {
         const auto attachedDevicePorts = moduleConfig->getAttachedDevicePorts();
         if (auto it = findAny<AudioPort>(attachedDevicePorts, devicePortIds);
             it != attachedDevicePorts.end()) {
@@ -2961,7 +3000,12 @@
             const auto externalDevicePorts = moduleConfig->getExternalDevicePorts();
             if (auto it = findAny<AudioPort>(externalDevicePorts, devicePortIds);
                 it != externalDevicePorts.end()) {
-                AudioPort portWithData = GenerateUniqueDeviceAddress(*it);
+                AudioPort portWithData = *it;
+                if (connectionAddress.has_value()) {
+                    portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
+                            *connectionAddress;
+                }
+                portWithData = GenerateUniqueDeviceAddress(portWithData);
                 mPortConnected = std::make_unique<WithDevicePortConnectedState>(portWithData);
                 ASSERT_NO_FATAL_FAILURE(mPortConnected->SetUp(module, moduleConfig));
                 *connectedDevicePort = mPortConnected->get();
@@ -2980,9 +3024,9 @@
             LOG(DEBUG) << __func__ << ": " << mSkipTestReason;
             return;
         };
-        ASSERT_NO_FATAL_FAILURE(SetUpDevicePort(module, moduleConfig,
-                                                extractIds<AudioPort>(devicePorts), connectedOnly,
-                                                connectedDevicePort));
+        ASSERT_NO_FATAL_FAILURE(SetUpDevicePort(
+                module, moduleConfig, extractIds<AudioPort>(devicePorts), connectedOnly,
+                connectedDevicePort, std::nullopt /*connectionAddress*/));
         if (!connectedDevicePort->has_value()) {
             mSkipTestReason = std::string("Unable to find a device port pair for mix port id ")
                                       .append(std::to_string(mixPort.id));
@@ -2990,11 +3034,14 @@
             return;
         }
     }
-    void SetUpPortConfigForDevicePort(IModule* module, ModuleConfig* moduleConfig,
-                                      const AudioPort& devicePort, bool connectedOnly) {
+    void SetUpPortConfigForDevicePort(
+            IModule* module, ModuleConfig* moduleConfig, const AudioPort& devicePort,
+            bool connectedOnly,
+            const std::optional<AudioDeviceAddress>& connectionAddress = std::nullopt) {
         std::optional<AudioPort> connectedDevicePort;
         ASSERT_NO_FATAL_FAILURE(SetUpDevicePort(module, moduleConfig, {devicePort.id},
-                                                connectedOnly, &connectedDevicePort));
+                                                connectedOnly, &connectedDevicePort,
+                                                connectionAddress));
         if (!connectedDevicePort.has_value()) {
             mSkipTestReason = std::string("Device port id ")
                                       .append(std::to_string(devicePort.id))
@@ -3135,7 +3182,8 @@
 };
 
 // Defined later together with state transition sequences.
-std::shared_ptr<StateSequence> makeBurstCommands(bool isSync);
+std::shared_ptr<StateSequence> makeBurstCommands(bool isSync, size_t burstCount = 10,
+                                                 bool standbyInputWhenDone = false);
 
 // Certain types of ports can not be used without special preconditions.
 static bool skipStreamIoTestForMixPortConfig(const AudioPortConfig& portConfig) {
@@ -3160,10 +3208,11 @@
   public:
     explicit StreamFixtureWithWorker(bool isSync) : mIsSync(isSync) {}
 
-    void SetUp(IModule* module, ModuleConfig* moduleConfig, const AudioPort& devicePort) {
+    void SetUp(IModule* module, ModuleConfig* moduleConfig, const AudioPort& devicePort,
+               const std::optional<AudioDeviceAddress>& connectionAddress = std::nullopt) {
         mStream = std::make_unique<StreamFixture<Stream>>();
-        ASSERT_NO_FATAL_FAILURE(
-                mStream->SetUpStreamForDevicePort(module, moduleConfig, devicePort));
+        ASSERT_NO_FATAL_FAILURE(mStream->SetUpStreamForDevicePort(
+                module, moduleConfig, devicePort, false /*connectedOnly*/, connectionAddress));
         MaybeSetSkipTestReason();
     }
 
@@ -3175,26 +3224,42 @@
         MaybeSetSkipTestReason();
     }
 
-    void SendBurstCommands(bool validatePosition = true) {
-        ASSERT_NO_FATAL_FAILURE(StartWorkerToSendBurstCommands());
+    void SetUp(IModule* module, ModuleConfig* moduleConfig,
+               const AudioPortConfig& existingMixPortConfig,
+               const AudioPortConfig& existingDevicePortConfig) {
+        mStream = std::make_unique<StreamFixture<Stream>>();
+        ASSERT_NO_FATAL_FAILURE(mStream->SetUpStreamForNewMixPortConfig(
+                module, moduleConfig, existingMixPortConfig, existingDevicePortConfig));
+        MaybeSetSkipTestReason();
+    }
+
+    void SendBurstCommands(bool validatePosition = true, size_t burstCount = 10,
+                           bool standbyInputWhenDone = false) {
+        ASSERT_NO_FATAL_FAILURE(StartWorkerToSendBurstCommands(burstCount, standbyInputWhenDone));
         ASSERT_NO_FATAL_FAILURE(JoinWorkerAfterBurstCommands(validatePosition));
     }
 
-    void StartWorkerToSendBurstCommands() {
+    void StartWorkerToSendBurstCommands(size_t burstCount = 10, bool standbyInputWhenDone = false) {
+        if (!IOTraits<Stream>::is_input) {
+            ASSERT_FALSE(standbyInputWhenDone) << "Only supported for input";
+        }
         const StreamContext* context = mStream->getStreamContext();
         mWorkerDriver = std::make_unique<StreamLogicDefaultDriver>(
-                makeBurstCommands(mIsSync), context->getFrameSizeBytes(), context->isMmapped());
+                makeBurstCommands(mIsSync, burstCount, standbyInputWhenDone),
+                context->getFrameSizeBytes(), context->isMmapped());
         mWorker = std::make_unique<typename IOTraits<Stream>::Worker>(
                 *context, mWorkerDriver.get(), mStream->getStreamEventReceiver());
         LOG(DEBUG) << __func__ << ": starting " << IOTraits<Stream>::directionStr << " worker...";
         ASSERT_TRUE(mWorker->start());
     }
 
-    void JoinWorkerAfterBurstCommands(bool validatePosition = true) {
-        // Must call 'prepareToClose' before attempting to join because the stream may be stuck.
-        std::shared_ptr<IStreamCommon> common;
-        ASSERT_IS_OK(mStream->getStream()->getStreamCommon(&common));
-        ASSERT_IS_OK(common->prepareToClose());
+    void JoinWorkerAfterBurstCommands(bool validatePosition = true,
+                                      bool callPrepareToClose = true) {
+        if (callPrepareToClose) {
+            std::shared_ptr<IStreamCommon> common;
+            ASSERT_IS_OK(mStream->getStream()->getStreamCommon(&common));
+            ASSERT_IS_OK(common->prepareToClose());
+        }
         LOG(DEBUG) << __func__ << ": joining " << IOTraits<Stream>::directionStr << " worker...";
         mWorker->join();
         EXPECT_FALSE(mWorker->hasError()) << mWorker->getError();
@@ -3205,6 +3270,7 @@
             EXPECT_FALSE(mWorkerDriver->hasObservableRetrogradePosition());
             EXPECT_FALSE(mWorkerDriver->hasHardwareRetrogradePosition());
         }
+        mLastData = mWorker->getData();
         mWorker.reset();
         mWorkerDriver.reset();
     }
@@ -3212,6 +3278,9 @@
     void TeardownPatch() { mStream->TeardownPatch(); }
 
     const AudioDevice& getDevice() const { return mStream->getDevice(); }
+    const AudioPortConfig& getDevicePortConfig() const { return mStream->getDevicePortConfig(); }
+    const std::vector<int8_t>& getLastData() const { return mLastData; }
+    const AudioPortConfig& getPortConfig() const { return mStream->getPortConfig(); }
     Stream* getStream() const { return mStream->getStream(); }
     std::string skipTestReason() const {
         return !mSkipTestReason.empty() ? mSkipTestReason : mStream->skipTestReason();
@@ -3229,6 +3298,7 @@
     std::unique_ptr<StreamFixture<Stream>> mStream;
     std::unique_ptr<StreamLogicDefaultDriver> mWorkerDriver;
     std::unique_ptr<typename IOTraits<Stream>::Worker> mWorker;
+    std::vector<int8_t> mLastData;
 };
 
 template <typename Stream>
@@ -4576,15 +4646,20 @@
 
 // TODO: Add async test cases for input once it is implemented.
 
-std::shared_ptr<StateSequence> makeBurstCommands(bool isSync) {
+std::shared_ptr<StateSequence> makeBurstCommands(bool isSync, size_t burstCount,
+                                                 bool standbyInputWhenDone) {
     using State = StreamDescriptor::State;
     auto d = std::make_unique<StateDag>();
-    StateDag::Node last = d->makeFinalNode(State::ACTIVE);
+    StateDag::Node active = d->makeFinalNode(State::ACTIVE);
+    StateDag::Node paused = d->makeNodes({std::make_pair(State::ACTIVE, kPauseCommand),
+                                          std::make_pair(State::PAUSED, kFlushCommand)},
+                                         State::STANDBY);
+    StateDag::Node& last = standbyInputWhenDone ? paused : active;
     if (isSync) {
         StateDag::Node idle = d->makeNode(
                 State::IDLE, kBurstCommand,
                 // Use several bursts to ensure that the driver starts reporting the position.
-                d->makeNodes(State::ACTIVE, kBurstCommand, 10, last));
+                d->makeNodes(State::ACTIVE, kBurstCommand, burstCount, last));
         d->makeNode(State::STANDBY, kStartCommand, idle);
     } else {
         StateDag::Node active2 = d->makeNode(State::ACTIVE, kBurstCommand, last);
@@ -4949,49 +5024,69 @@
   public:
     WithRemoteSubmix() : mStream(true /*isSync*/) {}
     explicit WithRemoteSubmix(AudioDeviceAddress address)
-        : mStream(true /*isSync*/), mAddress(address) {}
+        : mStream(true /*isSync*/), mAddress(address) {
+        LOG(DEBUG) << __func__ << ": Creating " << IOTraits<Stream>::directionStr
+                   << " stream for: " << mAddress.value_or(AudioDeviceAddress{}).toString();
+    }
     WithRemoteSubmix(const WithRemoteSubmix&) = delete;
     WithRemoteSubmix& operator=(const WithRemoteSubmix&) = delete;
+    ~WithRemoteSubmix() {
+        LOG(DEBUG) << __func__ << ": Deleting " << IOTraits<Stream>::directionStr
+                   << " stream for: " << mAddress.value_or(AudioDeviceAddress{}).toString();
+    }
 
-    static std::optional<AudioPort> getRemoteSubmixAudioPort(
-            ModuleConfig* moduleConfig,
-            const std::optional<AudioDeviceAddress>& address = std::nullopt) {
+    static std::optional<AudioPort> getRemoteSubmixAudioPort(ModuleConfig* moduleConfig) {
         auto ports =
                 moduleConfig->getRemoteSubmixPorts(IOTraits<Stream>::is_input, true /*singlePort*/);
         if (ports.empty()) return {};
-        AudioPort port = ports.front();
-        if (address) {
-            port.ext.template get<AudioPortExt::Tag::device>().device.address = address.value();
-        }
-        return port;
+        return ports.front();
     }
 
     void SetUp(IModule* module, ModuleConfig* moduleConfig) {
-        auto devicePort = getRemoteSubmixAudioPort(moduleConfig, mAddress);
+        auto devicePort = getRemoteSubmixAudioPort(moduleConfig);
         ASSERT_TRUE(devicePort.has_value()) << "Device port for remote submix device not found";
-        ASSERT_NO_FATAL_FAILURE(mStream.SetUp(module, moduleConfig, *devicePort));
+        ASSERT_NO_FATAL_FAILURE(mStream.SetUp(module, moduleConfig, *devicePort, mAddress));
         mAddress = mStream.getDevice().address;
     }
-
-    void StartWorkerToSendBurstCommands() {
-        ASSERT_NO_FATAL_FAILURE(mStream.StartWorkerToSendBurstCommands());
+    void SetUp(IModule* module, ModuleConfig* moduleConfig,
+               const AudioPortConfig& existingMixPortConfig,
+               const AudioPortConfig& existingDevicePortConfig) {
+        ASSERT_NO_FATAL_FAILURE(mStream.SetUp(module, moduleConfig, existingMixPortConfig,
+                                              existingDevicePortConfig));
+        mAddress = mStream.getDevice().address;
+    }
+    void StartWorkerToSendBurstCommands(size_t burstCount = 10, bool standbyInputWhenDone = false) {
+        ASSERT_NO_FATAL_FAILURE(
+                mStream.StartWorkerToSendBurstCommands(burstCount, standbyInputWhenDone));
     }
 
-    void JoinWorkerAfterBurstCommands() {
-        ASSERT_NO_FATAL_FAILURE(mStream.JoinWorkerAfterBurstCommands());
+    void JoinWorkerAfterBurstCommands(bool callPrepareToCloseBeforeJoin) {
+        ASSERT_NO_FATAL_FAILURE(mStream.JoinWorkerAfterBurstCommands(
+                true /*validatePositionIncrease*/, callPrepareToCloseBeforeJoin));
     }
 
-    void SendBurstCommands() {
-        ASSERT_NO_FATAL_FAILURE(mStream.StartWorkerToSendBurstCommands());
-        ASSERT_NO_FATAL_FAILURE(mStream.JoinWorkerAfterBurstCommands());
+    void JoinWorkerAfterBurstCommands(bool validatePositionIncrease,
+                                      bool callPrepareToCloseBeforeJoin) {
+        ASSERT_NO_FATAL_FAILURE(mStream.JoinWorkerAfterBurstCommands(validatePositionIncrease,
+                                                                     callPrepareToCloseBeforeJoin));
+    }
+
+    void SendBurstCommands(bool callPrepareToCloseBeforeJoin, size_t burstCount = 10,
+                           bool standbyInputWhenDone = false) {
+        ASSERT_NO_FATAL_FAILURE(StartWorkerToSendBurstCommands(burstCount, standbyInputWhenDone));
+        // When 'burstCount == 0', there is no "previous" frame count, thus the check for
+        // the position increase fails.
+        ASSERT_NO_FATAL_FAILURE(JoinWorkerAfterBurstCommands(
+                burstCount > 0 /*validatePositionIncrease*/, callPrepareToCloseBeforeJoin));
     }
 
     std::optional<AudioDeviceAddress> getAudioDeviceAddress() const { return mAddress; }
+    const AudioPortConfig& getDevicePortConfig() const { return mStream.getDevicePortConfig(); }
+    int8_t getLastBurstIteration() const { return mStream.getLastData()[0]; }
+    const AudioPortConfig& getPortConfig() const { return mStream.getPortConfig(); }
     std::string skipTestReason() const { return mStream.skipTestReason(); }
 
   private:
-    void SetUp(IModule* module, ModuleConfig* moduleConfig, const AudioPort& devicePort) {}
-
     StreamFixtureWithWorker<Stream> mStream;
     std::optional<AudioDeviceAddress> mAddress;
 };
@@ -5007,77 +5102,130 @@
         }
         ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
     }
+
+    void TearDown() override {
+        streamIn.reset();
+        streamOut.reset();
+    }
+
+    void CreateOutputStream() {
+        streamOut = std::make_unique<WithRemoteSubmix<IStreamOut>>();
+        ASSERT_NO_FATAL_FAILURE(streamOut->SetUp(module.get(), moduleConfig.get()));
+        // Note: any issue with connection attempts is considered as a problem.
+        ASSERT_EQ("", streamOut->skipTestReason());
+        ASSERT_TRUE(streamOut->getAudioDeviceAddress().has_value());
+    }
+
+    void CreateInputStream(const std::optional<AudioDeviceAddress>& address = std::nullopt) {
+        if (address.has_value()) {
+            streamIn = std::make_unique<WithRemoteSubmix<IStreamIn>>(address.value());
+        } else {
+            ASSERT_TRUE(streamOut->getAudioDeviceAddress().has_value());
+            streamIn = std::make_unique<WithRemoteSubmix<IStreamIn>>(
+                    streamOut->getAudioDeviceAddress().value());
+        }
+        ASSERT_NO_FATAL_FAILURE(streamIn->SetUp(module.get(), moduleConfig.get()));
+        ASSERT_EQ("", streamIn->skipTestReason());
+        auto inAddress = streamIn->getAudioDeviceAddress();
+        ASSERT_TRUE(inAddress.has_value());
+        if (address.has_value()) {
+            if (address.value() != AudioDeviceAddress{}) {
+                ASSERT_EQ(address.value(), inAddress.value());
+            }
+        } else {
+            ASSERT_EQ(streamOut->getAudioDeviceAddress().value(), inAddress.value());
+        }
+    }
+
+    std::unique_ptr<WithRemoteSubmix<IStreamOut>> streamOut;
+    std::unique_ptr<WithRemoteSubmix<IStreamIn>> streamIn;
 };
 
 TEST_P(AudioModuleRemoteSubmix, OutputDoesNotBlockWhenNoInput) {
-    WithRemoteSubmix<IStreamOut> streamOut;
-    ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
-    // Note: here and in other tests any issue with connection attempts is considered as a problem.
-    ASSERT_EQ("", streamOut.skipTestReason());
-    ASSERT_NO_FATAL_FAILURE(streamOut.SendBurstCommands());
+    ASSERT_NO_FATAL_FAILURE(CreateOutputStream());
+    ASSERT_NO_FATAL_FAILURE(streamOut->SendBurstCommands(false /*callPrepareToCloseBeforeJoin*/));
 }
 
-TEST_P(AudioModuleRemoteSubmix, OutputDoesNotBlockWhenInputStuck) {
-    WithRemoteSubmix<IStreamOut> streamOut;
-    ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
-    ASSERT_EQ("", streamOut.skipTestReason());
-    auto address = streamOut.getAudioDeviceAddress();
-    ASSERT_TRUE(address.has_value());
+TEST_P(AudioModuleRemoteSubmix, OutputDoesNotBlockWhenInputInStandby) {
+    if (int32_t version; module->getInterfaceVersion(&version).isOk() && version < 3) {
+        GTEST_SKIP() << "Default remote submix implementation <V3 could not pass this test";
+    }
+    ASSERT_NO_FATAL_FAILURE(CreateOutputStream());
+    ASSERT_NO_FATAL_FAILURE(CreateInputStream());
+    ASSERT_NO_FATAL_FAILURE(streamOut->StartWorkerToSendBurstCommands());
+    // Send just 1 burst command. This triggers the condition "input is in standby after
+    // being active." The output must flush the fifo before writing to avoid being blocked.
+    ASSERT_NO_FATAL_FAILURE(
+            streamIn->StartWorkerToSendBurstCommands(1, true /*stanbyInputWhenDone*/));
+    // The output must be able to close without shutting down the pipe first (due to a call
+    // to 'prepareToClose').
+    ASSERT_NO_FATAL_FAILURE(
+            streamOut->JoinWorkerAfterBurstCommands(false /*callPrepareToCloseBeforeJoin*/));
+    ASSERT_NO_FATAL_FAILURE(
+            streamIn->JoinWorkerAfterBurstCommands(false /*callPrepareToCloseBeforeJoin*/));
+}
 
-    WithRemoteSubmix<IStreamIn> streamIn(address.value());
-    ASSERT_NO_FATAL_FAILURE(streamIn.SetUp(module.get(), moduleConfig.get()));
-    ASSERT_EQ("", streamIn.skipTestReason());
+TEST_P(AudioModuleRemoteSubmix, BlockedOutputUnblocksOnClose) {
+    ASSERT_NO_FATAL_FAILURE(CreateOutputStream());
+    ASSERT_NO_FATAL_FAILURE(CreateInputStream());
+    ASSERT_NO_FATAL_FAILURE(streamOut->StartWorkerToSendBurstCommands());
+    // Send just 3 burst command, but do not enter standby. This is a stalled input.
+    ASSERT_NO_FATAL_FAILURE(streamIn->StartWorkerToSendBurstCommands(3));
+    ASSERT_NO_FATAL_FAILURE(
+            streamOut->JoinWorkerAfterBurstCommands(true /*callPrepareToCloseBeforeJoin*/));
+    ASSERT_NO_FATAL_FAILURE(
+            streamIn->JoinWorkerAfterBurstCommands(false /*callPrepareToCloseBeforeJoin*/));
+}
 
-    ASSERT_NO_FATAL_FAILURE(streamOut.SendBurstCommands());
+TEST_P(AudioModuleRemoteSubmix, OutputBlocksUntilInputStarts) {
+    ASSERT_NO_FATAL_FAILURE(CreateOutputStream());
+    ASSERT_NO_FATAL_FAILURE(CreateInputStream());
+    ASSERT_NO_FATAL_FAILURE(streamOut->StartWorkerToSendBurstCommands());
+    // Read the head of the pipe and check that it starts with the first output burst, that is,
+    // the contents of the very first write has not been superseded due to pipe overflow.
+    // The burstCount is '0' because the very first burst is used to exit from the 'IDLE' state,
+    // see 'makeBurstCommands'.
+    ASSERT_NO_FATAL_FAILURE(streamIn->SendBurstCommands(false /*callPrepareToCloseBeforeJoin*/, 0,
+                                                        true /*standbyInputWhenDone*/));
+    EXPECT_EQ(1, streamIn->getLastBurstIteration());
+    ASSERT_NO_FATAL_FAILURE(
+            streamOut->JoinWorkerAfterBurstCommands(true /*callPrepareToCloseBeforeJoin*/));
 }
 
 TEST_P(AudioModuleRemoteSubmix, OutputAndInput) {
-    WithRemoteSubmix<IStreamOut> streamOut;
-    ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
-    ASSERT_EQ("", streamOut.skipTestReason());
-    auto address = streamOut.getAudioDeviceAddress();
-    ASSERT_TRUE(address.has_value());
-
-    WithRemoteSubmix<IStreamIn> streamIn(address.value());
-    ASSERT_NO_FATAL_FAILURE(streamIn.SetUp(module.get(), moduleConfig.get()));
-    ASSERT_EQ("", streamIn.skipTestReason());
-
+    ASSERT_NO_FATAL_FAILURE(CreateOutputStream());
+    ASSERT_NO_FATAL_FAILURE(CreateInputStream());
     // Start writing into the output stream.
-    ASSERT_NO_FATAL_FAILURE(streamOut.StartWorkerToSendBurstCommands());
+    ASSERT_NO_FATAL_FAILURE(streamOut->StartWorkerToSendBurstCommands());
     // Simultaneously, read from the input stream.
-    ASSERT_NO_FATAL_FAILURE(streamIn.SendBurstCommands());
-    ASSERT_NO_FATAL_FAILURE(streamOut.JoinWorkerAfterBurstCommands());
+    ASSERT_NO_FATAL_FAILURE(streamIn->SendBurstCommands(false /*callPrepareToCloseBeforeJoin*/));
+    ASSERT_NO_FATAL_FAILURE(
+            streamOut->JoinWorkerAfterBurstCommands(false /*callPrepareToCloseBeforeJoin*/));
 }
 
 TEST_P(AudioModuleRemoteSubmix, OpenInputMultipleTimes) {
-    WithRemoteSubmix<IStreamOut> streamOut;
-    ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
-    ASSERT_EQ("", streamOut.skipTestReason());
-    auto address = streamOut.getAudioDeviceAddress();
-    ASSERT_TRUE(address.has_value());
-
-    const size_t streamInCount = 3;
-    std::vector<std::unique_ptr<WithRemoteSubmix<IStreamIn>>> streamIns(streamInCount);
-    for (size_t i = 0; i < streamInCount; i++) {
-        streamIns[i] = std::make_unique<WithRemoteSubmix<IStreamIn>>(address.value());
-        ASSERT_NO_FATAL_FAILURE(streamIns[i]->SetUp(module.get(), moduleConfig.get()));
+    ASSERT_NO_FATAL_FAILURE(CreateOutputStream());
+    ASSERT_NO_FATAL_FAILURE(CreateInputStream());
+    ASSERT_NO_FATAL_FAILURE(streamOut->StartWorkerToSendBurstCommands());
+    ASSERT_NO_FATAL_FAILURE(streamIn->SendBurstCommands(false /*callPrepareToCloseBeforeJoin*/, 1,
+                                                        true /*standbyInputWhenDone*/));
+    // For the new stream, only create a new mix port config and a new patch.
+    const size_t extraStreamInCount = 2;
+    std::vector<std::unique_ptr<WithRemoteSubmix<IStreamIn>>> streamIns(extraStreamInCount);
+    for (size_t i = 0; i < extraStreamInCount; i++) {
+        streamIns[i] = std::make_unique<WithRemoteSubmix<IStreamIn>>();
+        ASSERT_NO_FATAL_FAILURE(streamIns[i]->SetUp(module.get(), moduleConfig.get(),
+                                                    streamIn->getPortConfig(),
+                                                    streamIn->getDevicePortConfig()));
         ASSERT_EQ("", streamIns[i]->skipTestReason());
+        const auto inAddress = streamIns[i]->getAudioDeviceAddress();
+        ASSERT_TRUE(inAddress.has_value());
+        ASSERT_EQ(streamOut->getAudioDeviceAddress().value(), inAddress.value());
+        ASSERT_NO_FATAL_FAILURE(streamIns[i]->SendBurstCommands(
+                false /*callPrepareToCloseBeforeJoin*/, 1, true /*standbyInputWhenDone*/));
     }
-    // Start writing into the output stream.
-    ASSERT_NO_FATAL_FAILURE(streamOut.StartWorkerToSendBurstCommands());
-    // Simultaneously, read from input streams.
-    for (size_t i = 0; i < streamInCount; i++) {
-        ASSERT_NO_FATAL_FAILURE(streamIns[i]->StartWorkerToSendBurstCommands());
-    }
-    for (size_t i = 0; i < streamInCount; i++) {
-        ASSERT_NO_FATAL_FAILURE(streamIns[i]->JoinWorkerAfterBurstCommands());
-    }
-    ASSERT_NO_FATAL_FAILURE(streamOut.JoinWorkerAfterBurstCommands());
-    // Clean up input streams in the reverse order because the device connection is owned
-    // by the first one.
-    for (size_t i = streamInCount; i != 0; --i) {
-        streamIns[i - 1].reset();
-    }
+    ASSERT_NO_FATAL_FAILURE(
+            streamOut->JoinWorkerAfterBurstCommands(false /*callPrepareToCloseBeforeJoin*/));
 }
 
 INSTANTIATE_TEST_SUITE_P(AudioModuleRemoteSubmixTest, AudioModuleRemoteSubmix,
diff --git a/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
index 3b1f3d9..37441f0 100644
--- a/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
+++ b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
@@ -542,7 +542,7 @@
 };
 
 TEST_P(DynamicsProcessingTestEngineArchitecture, SetAndGetEngineArch) {
-    EXPECT_NO_FATAL_FAILURE(addEngineConfig(mCfg));
+    addEngineConfig(mCfg);
     ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
 }
 
@@ -594,7 +594,7 @@
 };
 
 TEST_P(DynamicsProcessingTestInputGain, SetAndGetInputGain) {
-    EXPECT_NO_FATAL_FAILURE(addInputGain(mInputGain));
+    addInputGain(mInputGain);
     ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
 }
 
@@ -652,7 +652,7 @@
             mInputGain.push_back(DynamicsProcessing::InputGain(i, gainDb));
         }
         std::vector<float> output(mInput.size());
-        EXPECT_NO_FATAL_FAILURE(addInputGain(mInputGain));
+        addInputGain(mInputGain);
         EXPECT_NO_FATAL_FAILURE(setParamsAndProcess(mInput, output));
         if (!isAllParamsValid()) {
             continue;
@@ -719,8 +719,8 @@
 };
 
 TEST_P(DynamicsProcessingTestLimiterConfig, SetAndGetLimiterConfig) {
-    EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
-    EXPECT_NO_FATAL_FAILURE(addLimiterConfig(mLimiterConfigList));
+    addEngineConfig(mEngineConfigPreset);
+    addLimiterConfig(mLimiterConfigList);
     ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
 }
 
@@ -782,8 +782,8 @@
     }
 
     void setLimiterParamsAndProcess(std::vector<float>& input, std::vector<float>& output) {
-        EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
-        EXPECT_NO_FATAL_FAILURE(addLimiterConfig(mLimiterConfigList));
+        addEngineConfig(mEngineConfigPreset);
+        addLimiterConfig(mLimiterConfigList);
         EXPECT_NO_FATAL_FAILURE(setParamsAndProcess(input, output));
     }
 
@@ -937,20 +937,20 @@
 };
 
 TEST_P(DynamicsProcessingTestChannelConfig, SetAndGetPreEqChannelConfig) {
-    EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
-    EXPECT_NO_FATAL_FAILURE(addPreEqChannelConfig(mCfg));
+    addEngineConfig(mEngineConfigPreset);
+    addPreEqChannelConfig(mCfg);
     ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
 }
 
 TEST_P(DynamicsProcessingTestChannelConfig, SetAndGetPostEqChannelConfig) {
-    EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
-    EXPECT_NO_FATAL_FAILURE(addPostEqChannelConfig(mCfg));
+    addEngineConfig(mEngineConfigPreset);
+    addPostEqChannelConfig(mCfg);
     ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
 }
 
 TEST_P(DynamicsProcessingTestChannelConfig, SetAndGetMbcChannelConfig) {
-    EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
-    EXPECT_NO_FATAL_FAILURE(addMbcChannelConfig(mCfg));
+    addEngineConfig(mEngineConfigPreset);
+    addMbcChannelConfig(mCfg);
     ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
 }
 
@@ -1018,27 +1018,27 @@
 
 TEST_P(DynamicsProcessingTestEqBandConfig, SetAndGetPreEqBandConfig) {
     mEngineConfigPreset.preEqStage.bandCount = mCfgs.size();
-    EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+    addEngineConfig(mEngineConfigPreset);
     std::vector<DynamicsProcessing::ChannelConfig> cfgs(mChannelCount);
     for (int i = 0; i < mChannelCount; i++) {
         cfgs[i].channel = i;
         cfgs[i].enable = true;
     }
-    EXPECT_NO_FATAL_FAILURE(addPreEqChannelConfig(cfgs));
-    EXPECT_NO_FATAL_FAILURE(addPreEqBandConfigs(mCfgs));
+    addPreEqChannelConfig(cfgs);
+    addPreEqBandConfigs(mCfgs);
     ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
 }
 
 TEST_P(DynamicsProcessingTestEqBandConfig, SetAndGetPostEqBandConfig) {
     mEngineConfigPreset.postEqStage.bandCount = mCfgs.size();
-    EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+    addEngineConfig(mEngineConfigPreset);
     std::vector<DynamicsProcessing::ChannelConfig> cfgs(mChannelCount);
     for (int i = 0; i < mChannelCount; i++) {
         cfgs[i].channel = i;
         cfgs[i].enable = true;
     }
-    EXPECT_NO_FATAL_FAILURE(addPostEqChannelConfig(cfgs));
-    EXPECT_NO_FATAL_FAILURE(addPostEqBandConfigs(mCfgs));
+    addPostEqChannelConfig(cfgs);
+    addPostEqBandConfigs(mCfgs);
     ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
 }
 
@@ -1185,14 +1185,14 @@
 
 TEST_P(DynamicsProcessingTestMbcBandConfig, SetAndGetMbcBandConfig) {
     mEngineConfigPreset.mbcStage.bandCount = mCfgs.size();
-    EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+    addEngineConfig(mEngineConfigPreset);
     std::vector<DynamicsProcessing::ChannelConfig> cfgs(mChannelCount);
     for (int i = 0; i < mChannelCount; i++) {
         cfgs[i].channel = i;
         cfgs[i].enable = true;
     }
-    EXPECT_NO_FATAL_FAILURE(addMbcChannelConfig(cfgs));
-    EXPECT_NO_FATAL_FAILURE(addMbcBandConfigs(mCfgs));
+    addMbcChannelConfig(cfgs);
+    addMbcBandConfigs(mCfgs);
     ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
 }
 
diff --git a/audio/aidl/vts/VtsHalNSTargetTest.cpp b/audio/aidl/vts/VtsHalNSTargetTest.cpp
index a50e1b4..c5a9bad 100644
--- a/audio/aidl/vts/VtsHalNSTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalNSTargetTest.cpp
@@ -140,12 +140,12 @@
 };
 
 TEST_P(NSParamTest, SetAndGetLevel) {
-    EXPECT_NO_FATAL_FAILURE(addLevelParam(mLevel));
+    addLevelParam(mLevel);
     SetAndGetParameters();
 }
 
 TEST_P(NSParamTest, SetAndGetType) {
-    EXPECT_NO_FATAL_FAILURE(addLevelParam(mLevel));
+    addLevelParam(mLevel);
     SetAndGetParameters();
 }
 
diff --git a/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
index a942521..3b07809 100644
--- a/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
@@ -189,22 +189,22 @@
 };
 
 TEST_P(VisualizerParamTest, SetAndGetCaptureSize) {
-    ASSERT_NO_FATAL_FAILURE(addCaptureSizeParam(mCaptureSize));
+    addCaptureSizeParam(mCaptureSize);
     ASSERT_NO_FATAL_FAILURE(SetAndGetParameters());
 }
 
 TEST_P(VisualizerParamTest, SetAndGetScalingMode) {
-    ASSERT_NO_FATAL_FAILURE(addScalingModeParam(mScalingMode));
+    addScalingModeParam(mScalingMode);
     ASSERT_NO_FATAL_FAILURE(SetAndGetParameters());
 }
 
 TEST_P(VisualizerParamTest, SetAndGetMeasurementMode) {
-    ASSERT_NO_FATAL_FAILURE(addMeasurementModeParam(mMeasurementMode));
+    addMeasurementModeParam(mMeasurementMode);
     ASSERT_NO_FATAL_FAILURE(SetAndGetParameters());
 }
 
 TEST_P(VisualizerParamTest, SetAndGetLatency) {
-    ASSERT_NO_FATAL_FAILURE(addLatencyParam(mLatency));
+    addLatencyParam(mLatency);
     ASSERT_NO_FATAL_FAILURE(SetAndGetParameters());
 }
 
@@ -212,10 +212,10 @@
     SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
 
     bool allParamsValid = true;
-    ASSERT_NO_FATAL_FAILURE(addCaptureSizeParam(mCaptureSize));
-    ASSERT_NO_FATAL_FAILURE(addScalingModeParam(mScalingMode));
-    ASSERT_NO_FATAL_FAILURE(addMeasurementModeParam(mMeasurementMode));
-    ASSERT_NO_FATAL_FAILURE(addLatencyParam(mLatency));
+    addCaptureSizeParam(mCaptureSize);
+    addScalingModeParam(mScalingMode);
+    addMeasurementModeParam(mMeasurementMode);
+    addLatencyParam(mLatency);
     ASSERT_NO_FATAL_FAILURE(SetAndGetParameters(&allParamsValid));
 
     Parameter getParam;
@@ -276,9 +276,9 @@
 
     for (float maxAudioSampleValue : testMaxAudioSampleValueList) {
         bool allParamsValid = true;
-        ASSERT_NO_FATAL_FAILURE(addCaptureSizeParam(mCaptureSize));
-        ASSERT_NO_FATAL_FAILURE(addScalingModeParam(mScalingMode));
-        ASSERT_NO_FATAL_FAILURE(addLatencyParam(mLatency));
+        addCaptureSizeParam(mCaptureSize);
+        addScalingModeParam(mScalingMode);
+        addLatencyParam(mLatency);
         ASSERT_NO_FATAL_FAILURE(SetAndGetParameters(&allParamsValid));
 
         generateSineWave(std::vector<int>{1000}, mInputBuffer, maxAudioSampleValue,
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/android/hardware/automotive/vehicle/IVehicle.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/IVehicle.aidl
index 220b1da..cdf9066 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/IVehicle.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/IVehicle.aidl
@@ -237,6 +237,8 @@
      * {@link StatusCode#INVALID_ARG}. If a specified propId was not subscribed
      * before, this method must ignore that propId.
      *
+     * Unsubscribe a not-subscribed property ID must do nothing.
+     *
      * If error is returned, some of the properties failed to unsubscribe.
      * Caller is safe to try again, since unsubscribing an already unsubscribed
      * property is okay.
@@ -267,6 +269,9 @@
     /**
      * Gets the supported values lists for [propId, areaId]s.
      *
+     * This is only supported for [propId, areaId]s that have non-null
+     * {@code hasSupportedValueInfo} for their {@code VehicleAreaConfig}.
+     *
      * For a specific [propId, areaId], if the hardware currently specifies
      * a list of supported values for it, then it is returned through the
      * {@code supportedValuesList} field inside
@@ -304,6 +309,9 @@
     /**
      * Gets the min/max supported values for [propId, areaId]s.
      *
+     * This is only supported for [propId, areaId]s that have non-null
+     * {@code hasSupportedValueInfo} for their {@code VehicleAreaConfig}.
+     *
      * For a specific [propId, areaId], if the hardware currently specifies
      * min/max supported value for it, then it is returned through the
      * {@code minSupportedValue} or {@code maxSupportedValue} field inside
@@ -342,6 +350,9 @@
     /**
      * Registers the supported value change callback.
      *
+     * This is only supported for [propId, areaId]s that have non-null
+     * {@code hasSupportedValueInfo} for their {@code VehicleAreaConfig}.
+     *
      * For the specified [propId, areaId]s,
      * {@code callback.onSupportedValueChange} must be invoked if change
      * happens.
@@ -360,6 +371,9 @@
     /**
      * Unregisters the supported value change callback.
      *
+     * This is only supported for [propId, areaId]s that have non-null
+     * {@code hasSupportedValueInfo} for their {@code VehicleAreaConfig}.
+     *
      * @param callback The callback to unregister.
      * @param propIdAreaIds A list of [propId, areaId]s to unregister.
      */
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/MinMaxSupportedValueResult.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/MinMaxSupportedValueResult.aidl
index f85ad3a..a3508ee 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/MinMaxSupportedValueResult.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/MinMaxSupportedValueResult.aidl
@@ -43,6 +43,8 @@
      *
      * If the [propId, areaId] does not specify a max supported value, this
      * is {@code null}.
+     *
+     * This must be ignored if status is not {@code StatusCode.OK}.
      */
     @nullable RawPropValues maxSupportedValue;
 }
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SupportedValuesListResult.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SupportedValuesListResult.aidl
index 4524f4f..8800b0b 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SupportedValuesListResult.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SupportedValuesListResult.aidl
@@ -36,6 +36,8 @@
      *
      * If the [propId, areaId] does not specify a supported values list, this
      * is {@code null}.
+     *
+     * This must be ignored if status is not {@code StatusCode.OK}.
      */
     @nullable List<RawPropValues> supportedValuesList;
 }
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
index 62d7e21..c6b8cd1 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
@@ -230,10 +230,17 @@
     boolean supportVariableUpdateRate;
 
     /**
-     * For VHAL implementation >= V4, this must not be {@code null}. This specifies whether
-     * this property may have min/max supported value or supported values list.
+     * This specifies whether this property may have min/max supported value or supported values
+     * list for [propId, areaId] that supports new supported values APIs.
      *
-     * For VHAL implementation < V4, this is always {@code null} and is not accessed.
+     * If this is not {@code null}. The client may use {@code getMinMaxSupportedValue},
+     * {@code getSupportedValuesLists}, {@code subscribeSupportedValueChange},
+     * {@code unsubscribeSupportedValueChange}.
+     *
+     * If this is {@code null} for legacy properties, the APIs mentioned before are not supported.
+     * Client must fallback to use static supported value information in {@code VehicleAreaConfig}.
+     *
+     * For VHAL implementation < V4, this is always {@code null}.
      */
     @nullable HasSupportedValueInfo hasSupportedValueInfo;
 }
diff --git a/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json b/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json
index b774580..da73b03 100644
--- a/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json
+++ b/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json
@@ -218,7 +218,7 @@
             {
                 "name": "Tire pressure",
                 "value": 392168201,
-                "description": "Tire pressure\nEach tire is identified by its areaConfig.areaId config and its minFloatValue\/maxFloatValue are used to store OEM recommended pressure range.\nThe minFloatValue and maxFloatValue in VehicleAreaConfig must be defined.\nThe minFloatValue in the areaConfig data represents the lower bound of the recommended tire pressure.\nThe maxFloatValue in the areaConfig data represents the upper bound of the recommended tire pressure.\nFor example:\nThe following areaConfig indicates the recommended tire pressure of the left_front tire is from 200.0 KILOPASCAL to 240.0 KILOPASCAL. .areaConfigs = { VehicleAreaConfig { .areaId = VehicleAreaWheel::LEFT_FRONT, .minFloatValue = 200.0, .maxFloatValue = 240.0, } }\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:\n{@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.\n{@code MinMaxSupportedValueResult.minSupportedValue} represents the lower bound of the recommended tire pressure for the tire at the specified area ID.\n{@code MinMaxSupportedValueResult.maxSupportedValue} represents the upper bound of the recommended tire pressure for the tire at the specified area ID.\nFor example, if the recommended tire pressure of left_front tire is from 200.0 KILOPASCAL to 240.0 KILOPASCAL, {@code getMinMaxSupportedValue} for [propId=TIRE_PRESSURE, areaId=VehicleAreaWheel::LEFT_FRONT] must return a {@code MinMaxSupportedValueResult} with OK status, 200.0 as minSupportedValue, 240.0 as maxSupportedValue.\nAt boot, minFloatValue is equal to minSupportedValue, maxFloatValue is equal to maxSupportedValue."
+                "description": "Tire pressure\nEach tire is identified by its areaConfig.areaId config and its minFloatValue\/maxFloatValue are used to store OEM recommended pressure range.\nThe minFloatValue and maxFloatValue in VehicleAreaConfig must be defined.\nThe minFloatValue in the areaConfig data represents the lower bound of the recommended tire pressure.\nThe maxFloatValue in the areaConfig data represents the upper bound of the recommended tire pressure.\nFor example:\nThe following areaConfig indicates the recommended tire pressure of the left_front tire is from 200.0 KILOPASCAL to 240.0 KILOPASCAL. .areaConfigs = { VehicleAreaConfig { .areaId = VehicleAreaWheel::LEFT_FRONT, .minFloatValue = 200.0, .maxFloatValue = 240.0, } }\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minFloatValue. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxFloatValue. For example, if the recommended tire pressure of left_front tire is from 200.0 KILOPASCAL to 240.0 KILOPASCAL, {@code getMinMaxSupportedValue} for [propId=TIRE_PRESSURE, areaId=VehicleAreaWheel::LEFT_FRONT] must return a {@code MinMaxSupportedValueResult} with OK status, 200.0 as minSupportedValue, 240.0 as maxSupportedValue. At boot, minFloatValue is equal to minSupportedValue, maxFloatValue is equal to maxSupportedValue."
             },
             {
                 "name": "Critically low tire pressure",
@@ -262,7 +262,7 @@
                     "ImpactSensorLocation"
                 ],
                 "data_enum": "ImpactSensorLocation",
-                "description": "Impact detected.\nBit flag property to relay information on whether an impact has occurred on a particular side of the vehicle as described through the ImpactSensorLocation enum. As a bit flag property, this property can be set to multiple ORed together values of the enum when necessary.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all bit flags of ImpactSensorLocation are supported.\nIf {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0):\n{@code getSupportedValuesList} must return a {@code SupportedValuesListResult} that contains supported values unless all bit flags of ImpactSensorLocation are supported.\nAt boot, supportedEnumValues is equal to the supported values list."
+                "description": "Impact detected.\nBit flag property to relay information on whether an impact has occurred on a particular side of the vehicle as described through the ImpactSensorLocation enum. As a bit flag property, this property can be set to multiple ORed together values of the enum when necessary.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all bit flags of ImpactSensorLocation are supported.\nIf {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0): {@code getSupportedValuesList} must return a {@code SupportedValuesListResult} that contains supported values unless all bit flags of ImpactSensorLocation are supported. At boot, supportedEnumValues is equal to the supported values list."
             },
             {
                 "name": "Vehicle horn engaged.",
@@ -276,7 +276,7 @@
                     "VehicleGear"
                 ],
                 "data_enum": "VehicleGear",
-                "description": "Currently selected gear\nThis is the gear selected by the user.\nValues in the config array must represent the list of supported gears for this vehicle at boot time. For example, config array for an automatic transmission must contain {GEAR_NEUTRAL, GEAR_REVERSE, GEAR_PARK, GEAR_DRIVE, GEAR_1, GEAR_2,...} and for manual transmission the list must contain {GEAR_NEUTRAL, GEAR_REVERSE, GEAR_1, GEAR_2,...}\nIn the case of an automatic transmission vehicle that allows the driver to select specific gears on demand (i.e. \"manual mode\"), GEAR_SELECTION's value must be set to the specific gear selected by the driver instead of simply GEAR_DRIVE.\nIf {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0):\n{@code VehicleAreaConfig.HasSupportedValueInfo.hasSupportedValuesList} for the global area ID (0) must be {@code true}.\n{@code getSupportedValuesList} for [GEAR_SELECTION, areaId=0] must return a {@code SupportedValuesListResult} that contains non-null {@code supportedValuesList}.\nThe supportedValues must represent the list of supported gears for this vehicle. For example, for an automatic transmission, the list can be {GEAR_NEUTRAL, GEAR_REVERSE, GEAR_PARK, GEAR_DRIVE, GEAR_1, GEAR_2,...} and for manual transmission it can be {GEAR_NEUTRAL, GEAR_REVERSE, GEAR_1, GEAR_2,...}.\nIn the case of an automatic transmission vehicle that allows the driver to select specific gears on demand (i.e. \"manual mode\"), the GEAR_SELECTION property value must be set to the specific gear selected by the driver instead of simply GEAR_DRIVE.\nAt boot, the config array's values are equal to the supported values list."
+                "description": "Currently selected gear\nThis is the gear selected by the user.\nValues in the config array must represent the list of supported gears for this vehicle at boot time. For example, config array for an automatic transmission must contain {GEAR_NEUTRAL, GEAR_REVERSE, GEAR_PARK, GEAR_DRIVE, GEAR_1, GEAR_2,...} and for manual transmission the list must contain {GEAR_NEUTRAL, GEAR_REVERSE, GEAR_1, GEAR_2,...}\nIn the case of an automatic transmission vehicle that allows the driver to select specific gears on demand (i.e. \"manual mode\"), GEAR_SELECTION's value must be set to the specific gear selected by the driver instead of simply GEAR_DRIVE.\nIf {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0): {@code VehicleAreaConfig.HasSupportedValueInfo.hasSupportedValuesList} for the global area ID (0) must be {@code true}. {@code getSupportedValuesList} for [GEAR_SELECTION, areaId=0] must return a {@code SupportedValuesListResult} that contains non-null {@code supportedValuesList}. The supportedValues must represent the list of supported gears for this vehicle. For example, for an automatic transmission, the list can be {GEAR_NEUTRAL, GEAR_REVERSE, GEAR_PARK, GEAR_DRIVE, GEAR_1, GEAR_2,...} and for manual transmission it can be {GEAR_NEUTRAL, GEAR_REVERSE, GEAR_1, GEAR_2,...}. In the case of an automatic transmission vehicle that allows the driver to select specific gears on demand (i.e. \"manual mode\"), the GEAR_SELECTION property value must be set to the specific gear selected by the driver instead of simply GEAR_DRIVE. At boot, the config array's values are equal to the supported values list."
             },
             {
                 "name": "CURRENT_GEAR",
@@ -285,7 +285,7 @@
                     "VehicleGear"
                 ],
                 "data_enum": "VehicleGear",
-                "description": "Current gear. In non-manual case, selected gear may not match the current gear. For example, if the selected gear is GEAR_DRIVE, the current gear will be one of GEAR_1, GEAR_2 etc, which reflects the actual gear the transmission is currently running in.\nValues in the config array must represent the list of supported gears for this vehicle at boot time.  For example, config array for an automatic transmission must contain {GEAR_NEUTRAL, GEAR_REVERSE, GEAR_PARK, GEAR_1, GEAR_2,...} and for manual transmission the list must contain {GEAR_NEUTRAL, GEAR_REVERSE, GEAR_1, GEAR_2,...}. This list need not be the same as that of the supported gears reported in GEAR_SELECTION.\nIf {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0):\n{@code VehicleAreaConfig.HasSupportedValueInfo.hasSupportedValuesList} for the global area ID (0) must be {@code true}.\n{@code getSupportedValuesList} for [GEAR_SELECTION, areaId=0] must return a {@code SupportedValuesListResult} that contains non-null {@code supportedValuesList}.\nThe supported values list must represent the list of supported gears for this vehicle.  For example, for an automatic transmission, this list can be {GEAR_NEUTRAL, GEAR_REVERSE, GEAR_PARK, GEAR_1, GEAR_2,...} and for manual transmission the list can be {GEAR_NEUTRAL, GEAR_REVERSE, GEAR_1, GEAR_2,...}. This list need not be the same as that of the supported gears reported in GEAR_SELECTION.\nAt boot, the config array's values are equal to the supported values list."
+                "description": "Current gear. In non-manual case, selected gear may not match the current gear. For example, if the selected gear is GEAR_DRIVE, the current gear will be one of GEAR_1, GEAR_2 etc, which reflects the actual gear the transmission is currently running in.\nValues in the config array must represent the list of supported gears for this vehicle at boot time.  For example, config array for an automatic transmission must contain {GEAR_NEUTRAL, GEAR_REVERSE, GEAR_PARK, GEAR_1, GEAR_2,...} and for manual transmission the list must contain {GEAR_NEUTRAL, GEAR_REVERSE, GEAR_1, GEAR_2,...}. This list need not be the same as that of the supported gears reported in GEAR_SELECTION.\nIf {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0): {@code VehicleAreaConfig.HasSupportedValueInfo.hasSupportedValuesList} for the global area ID (0) must be {@code true}. {@code getSupportedValuesList} for [GEAR_SELECTION, areaId=0] must return a {@code SupportedValuesListResult} that contains non-null {@code supportedValuesList}. The supported values list must represent the list of supported gears for this vehicle.  For example, for an automatic transmission, this list can be {GEAR_NEUTRAL, GEAR_REVERSE, GEAR_PARK, GEAR_1, GEAR_2,...} and for manual transmission the list can be {GEAR_NEUTRAL, GEAR_REVERSE, GEAR_1, GEAR_2,...}. This list need not be the same as that of the supported gears reported in GEAR_SELECTION. At boot, the config array's values are equal to the supported values list."
             },
             {
                 "name": "Parking brake state.",
@@ -300,7 +300,7 @@
             {
                 "name": "EV_BRAKE_REGENERATION_LEVEL",
                 "value": 289408012,
-                "description": "Regenerative braking level of a electronic vehicle\nThe minInt32Value and maxInt32Value in VehicleAreaConfig must be defined. All values between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the setting for no regenerative braking, must be 0.\nThe maxInt32Value indicates the setting for the maximum amount of energy regenerated from braking.\nAll values between min and max supported value must be supported.\nIf {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0):\n{@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for global area ID(0)\n{@code MinMaxSupportedValueResult.minSupportedValue} must be 0.\n{@code MinMaxSupportedValueResult.maxSupportedValue} indicates the setting for the maximum amount of energy regenerated from braking. The minSupportedValue indicates the setting for no regenerative braking.\nAt boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\n\nThis property is a more granular form of EV_REGENERATIVE_BRAKING_STATE. It allows the user to set a more specific level of regenerative braking if the states in EvRegenerativeBrakingState are not granular enough for the OEM.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Regenerative braking level of a electronic vehicle\nThe minInt32Value and maxInt32Value in VehicleAreaConfig must be defined. All values between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the setting for no regenerative braking, must be 0.\nThe maxInt32Value indicates the setting for the maximum amount of energy regenerated from braking.\nAll values between min and max supported value must be supported.\nIf {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0): {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for global area ID(0) {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is a more granular form of EV_REGENERATIVE_BRAKING_STATE. It allows the user to set a more specific level of regenerative braking if the states in EvRegenerativeBrakingState are not granular enough for the OEM.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Warning for fuel low level.",
@@ -347,7 +347,7 @@
                     "EvStoppingMode"
                 ],
                 "data_enum": "EvStoppingMode",
-                "description": "Represents property for the current stopping mode of the vehicle.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues must be defined unless all enum values of EvStoppingMode are supported.\nIf {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0):\nFor the global area ID (0), {@code getSupportedValuesList} must return a {@code SupportedValuesListResult} that contains supported values unless all enum values of EvStoppingMode are supported.\nAt boot, supportedEnumValues is equal to the supported values list.\n\nThe EvStoppingMode enum may be extended to include more states in the future.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Represents property for the current stopping mode of the vehicle.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues must be defined unless all enum values of EvStoppingMode are supported.\nIf {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0): For the global area ID (0), {@code getSupportedValuesList} must return a {@code SupportedValuesListResult} that contains supported values unless all enum values of EvStoppingMode are supported. At boot, supportedEnumValues is equal to the supported values list.\nThe EvStoppingMode enum may be extended to include more states in the future.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "ELECTRONIC_STABILITY_CONTROL_ENABLED",
@@ -362,7 +362,7 @@
                     "ErrorState"
                 ],
                 "data_enum": "ElectronicStabilityControlState",
-                "description": "Electronic Stability Control (ESC) state.\nReturns the current state of ESC. This property must always return a valid state defined in ElectronicStabilityControlState or ErrorState. It must not surface errors through StatusCode and must use the supported error states instead.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both ElectronicStabilityControlState (including OTHER, which is not recommended) and ErrorState are supported.\nIf {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0):\nFor the global area ID (0), {@code getSupportedValuesList} must return a {@code SupportedValuesListResult} that contains supported values unless all states of both ElectronicStabilityControlState (including OTHER, which is not recommended) and ErrorState are supported.\nAt boot, supportedEnumValues is equal to the supported values list."
+                "description": "Electronic Stability Control (ESC) state.\nReturns the current state of ESC. This property must always return a valid state defined in ElectronicStabilityControlState or ErrorState. It must not surface errors through StatusCode and must use the supported error states instead.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both ElectronicStabilityControlState (including OTHER, which is not recommended) and ErrorState are supported.\nIf {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0): For the global area ID (0), {@code getSupportedValuesList} must return a {@code SupportedValuesListResult} that contains supported values unless all states of both ElectronicStabilityControlState (including OTHER, which is not recommended) and ErrorState are supported. At boot, supportedEnumValues is equal to the supported values list."
             },
             {
                 "name": "Turn signal light state.",
@@ -385,7 +385,7 @@
             {
                 "name": "Fan speed setting",
                 "value": 356517120,
-                "description": "Fan speed setting\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the lowest fan speed. The maxInt32Value indicates the highest fan speed.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:\n{@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the specific area ID.\n{@code MinMaxSupportedValueResult.minSupportedValue} indicates the lowest fan speed.\n{@code MinMaxSupportedValueResult.maxSupportedValue} indicates the highest fan speed.\nAll integers between minSupportedValue and maxSupportedValue must be supported.\nAt boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\n\nThis property is not in any particular unit but in a specified range of relative speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Fan speed setting\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the lowest fan speed.\nThe maxInt32Value indicates the highest fan speed.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the specific area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Fan direction setting",
@@ -404,7 +404,7 @@
             {
                 "name": "HVAC_TEMPERATURE_SET",
                 "value": 358614275,
-                "description": "HVAC target temperature set in Celsius.\nThe minFloatValue and maxFloatValue in VehicleAreaConfig must be defined.\nThe minFloatValue indicates the minimum temperature setting in Celsius. The maxFloatValue indicates the maximum temperature setting in Celsius.\nIf all the values between minFloatValue and maxFloatValue are not supported, the configArray can be used to list the valid temperature values that can be set. It also describes a lookup table to convert the temperature from Celsius to Fahrenheit and vice versa for this vehicle. The configArray must be defined if standard unit conversion is not supported on this vehicle.\nThe configArray is set as follows: configArray[0] = [the lower bound of the supported temperature in Celsius] * 10. configArray[1] = [the upper bound of the supported temperature in Celsius] * 10. configArray[2] = [the increment in Celsius] * 10. configArray[3] = [the lower bound of the supported temperature in Fahrenheit] * 10. configArray[4] = [the upper bound of the supported temperature in Fahrenheit] * 10. configArray[5] = [the increment in Fahrenheit] * 10.\nThe minFloatValue and maxFloatValue in VehicleAreaConfig must be equal to configArray[0] and configArray[1] respectively.\nFor example, if the vehicle supports temperature values as: [16.0, 16.5, 17.0 ,..., 28.0] in Celsius [60.5, 61.5, 62.5 ,..., 84.5] in Fahrenheit The configArray should be configArray = {160, 280, 5, 605, 845, 10}.\nIdeally, the ratio of the Celsius increment to the Fahrenheit increment should be as close to the actual ratio of 1 degree Celsius to 1.8 degrees Fahrenheit.\nThere must be a one to one mapping of all Celsius values to Fahrenheit values defined by the configArray. The configArray will be used by clients to convert this property's temperature from Celsius to Fahrenheit. Also, it will let clients know what Celsius value to set the property to achieve their desired Fahreneheit value for the system. If the ECU does not have a one to one mapping of all Celsius values to Fahrenheit values, then the config array should only define the list of Celsius and Fahrenheit values that do have a one to one mapping.\nFor example, if the ECU supports Celsius values from 16 to 28 and Fahrenheit values from 60 to 85 both with an increment of 1, then one possible configArray would be {160, 280, 10, 600, 840, 20}. In this case, 85 would not be a supported temperature.\nAny value set in between a valid value should be rounded to the closest valid value.\nIt is highly recommended that the OEM also implement the HVAC_TEMPERATURE_VALUE_SUGGESTION vehicle property because it provides applications a simple method for determining temperature values that can be set for this vehicle and for converting values between Celsius and Fahrenheit.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "HVAC target temperature set in Celsius.\nThe minFloatValue and maxFloatValue in VehicleAreaConfig must be defined.\nThe minFloatValue indicates the minimum temperature setting in Celsius.\nThe maxFloatValue indicates the maximum temperature setting in Celsius.\nIf all the values between minFloatValue and maxFloatValue are not supported, the configArray can be used to list the valid temperature values that can be set. It also describes a lookup table to convert the temperature from Celsius to Fahrenheit and vice versa for this vehicle. The configArray must be defined if standard unit conversion is not supported on this vehicle.\nThe configArray is set as follows: configArray[0] = [the lower bound of the supported temperature in Celsius] * 10. configArray[1] = [the upper bound of the supported temperature in Celsius] * 10. configArray[2] = [the increment in Celsius] * 10. configArray[3] = [the lower bound of the supported temperature in Fahrenheit] * 10. configArray[4] = [the upper bound of the supported temperature in Fahrenheit] * 10. configArray[5] = [the increment in Fahrenheit] * 10.\nThe minFloatValue and maxFloatValue in VehicleAreaConfig must be equal to configArray[0] and configArray[1] respectively.\nFor example, if the vehicle supports temperature values as: [16.0, 16.5, 17.0 ,..., 28.0] in Celsius [60.5, 61.5, 62.5 ,..., 84.5] in Fahrenheit The configArray should be configArray = {160, 280, 5, 605, 845, 10}.\nIdeally, the ratio of the Celsius increment to the Fahrenheit increment should be as close to the actual ratio of 1 degree Celsius to 1.8 degrees Fahrenheit.\nThere must be a one to one mapping of all Celsius values to Fahrenheit values defined by the configArray. The configArray will be used by clients to convert this property's temperature from Celsius to Fahrenheit. Also, it will let clients know what Celsius value to set the property to achieve their desired Fahreneheit value for the system. If the ECU does not have a one to one mapping of all Celsius values to Fahrenheit values, then the config array should only define the list of Celsius and Fahrenheit values that do have a one to one mapping.\nFor example, if the ECU supports Celsius values from 16 to 28 and Fahrenheit values from 60 to 85 both with an increment of 1, then one possible configArray would be {160, 280, 10, 600, 840, 20}. In this case, 85 would not be a supported temperature.\nAny value set in between a valid value should be rounded to the closest valid value.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the specific area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minFloatValue. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxFloatValue. If not all the values between minSupportedValue and maxSupportedValue are supported, {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} for the specified area ID. At boot, supportedValuesList must be equal to what is described in config array. At boot, minFloatValue is equal to minSupportedValue, maxFloatValue is equal to maxSupportedValue.\nIt is highly recommended that the OEM also implement the HVAC_TEMPERATURE_VALUE_SUGGESTION vehicle property because it provides applications a simple method for determining temperature values that can be set for this vehicle and for converting values between Celsius and Fahrenheit.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "HVAC_DEFROSTER",
@@ -444,17 +444,17 @@
             {
                 "name": "Seat heating\/cooling",
                 "value": 356517131,
-                "description": "Seat heating\/cooling\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value indicates the maximum seat temperature heating setting. The minInt32Value must be 0, unless the vehicle supports seat cooling as well. In this case, minInt32Value indicates the maximum seat temperature cooling setting.\nThis property is not in any particular unit, but in a specified range of relative temperature settings.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Seat heating\/cooling\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value must be 0, unless the vehicle supports seat cooling as well. In this case, minInt32Value indicates the maximum seat temperature cooling setting.\nThe maxInt32Value indicates the maximum seat temperature heating setting.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the specified area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit, but in a specified range of relative temperature settings.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Side Mirror Heat",
                 "value": 339739916,
-                "description": "Side Mirror Heat\nIncreasing values denote higher heating levels for side mirrors.\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value in the config data represents the maximum heating level. The minInt32Value in the config data MUST be zero and indicates no heating.\nThis property is not in any particular unit but in a specified range of relative heating settings.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Side Mirror Heat\nIncreasing values denote higher heating levels for side mirrors.\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value in the config data MUST be zero and indicates no heating.\nThe maxInt32Value in the config data represents the maximum heating level.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the specified area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative heating settings.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Steering Wheel Heating\/Cooling",
                 "value": 289408269,
-                "description": "Steering Wheel Heating\/Cooling\nSets the amount of heating\/cooling for the steering wheel.\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value indicates the maximum steering wheel heating setting. The minInt32Value should be 0, unless the vehicle supports steering wheel cooling as well. In such a case, the minInt32Value indicates the maximum steering wheel cooling setting.\nThis property is not in any particular unit but in a specified range of heating settings.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Steering Wheel Heating\/Cooling\nSets the amount of heating\/cooling for the steering wheel.\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value should be 0, unless the vehicle supports steering wheel cooling as well. In such a case, the minInt32Value indicates the maximum steering wheel cooling setting.\nThe maxInt32Value indicates the maximum steering wheel heating setting.\nIf {@code HasSupportedValueInfo} is not null for the global area ID (0): {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true}. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of heating settings.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Temperature units for display",
@@ -463,7 +463,7 @@
                     "VehicleUnit"
                 ],
                 "data_enum": "VehicleUnit",
-                "description": "Temperature units for display\nIndicates whether the vehicle is displaying temperature to the user as Celsius or Fahrenheit. VehiclePropConfig.configArray is used to indicate the supported temperature display units. For example: configArray[0] = CELSIUS configArray[1] = FAHRENHEIT\nThis parameter MAY be used for displaying any HVAC temperature in the system. Values must be one of VehicleUnit.CELSIUS or VehicleUnit.FAHRENHEIT Note that internally, all temperatures are represented in floating point Celsius.\nIf updating HVAC_TEMPERATURE_DISPLAY_UNITS affects the values of other *_DISPLAY_UNITS properties, then their values must be updated and communicated to the AAOS framework as well.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Temperature units for display\nIndicates whether the vehicle is displaying temperature to the user as Celsius or Fahrenheit.\nVehiclePropConfig.configArray is used to indicate the supported temperature display units.\nFor example: configArray[0] = CELSIUS configArray[1] = FAHRENHEIT\nIf {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0): {@code VehicleAreaConfig.HasSupportedValueInfo.hasSupportedValuesList} for the global area ID (0) must be {@code true}. {@code getSupportedValuesLists} for [HVAC_TEMPERATURE_DISPLAY_UNITS, areaId=0] must return a {@code SupportedValuesListResult} that contains non-null {@code supportedValuesList}, e.g. [CELSIUS, FAHRENHEIT]. At boot, the values in the config array are equal to the supported values list.\nThis parameter MAY be used for displaying any HVAC temperature in the system. Values must be one of VehicleUnit.CELSIUS or VehicleUnit.FAHRENHEIT Note that internally, all temperatures are represented in floating point Celsius.\nIf updating HVAC_TEMPERATURE_DISPLAY_UNITS affects the values of other *_DISPLAY_UNITS properties, then their values must be updated and communicated to the AAOS framework as well.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Actual fan speed",
@@ -492,7 +492,7 @@
             {
                 "name": "Seat ventilation",
                 "value": 356517139,
-                "description": "Seat ventilation\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value must be 0. The maxInt32Value indicates the maximum ventilation setting available for the seat.\nThis property is not in any particular unit but in the specified range of ventilation settings.\nUsed by HVAC apps and Assistant to enable, change, or read state of seat ventilation.  This is different than seating cooling. It can be on at the same time as cooling, or not.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Seat ventilation\nThe minInt32Value and maxInt32Value in VehicleAreaConfig must be defined.\nAll integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value must be 0.\nThe maxInt32Value indicates the maximum ventilation setting available for the seat.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the specified area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in the specified range of ventilation settings.\nUsed by HVAC apps and Assistant to enable, change, or read state of seat ventilation.  This is different than seating cooling. It can be on at the same time as cooling, or not.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Electric defrosters' status",
@@ -511,7 +511,7 @@
                     "VehicleUnit"
                 ],
                 "data_enum": "VehicleUnit",
-                "description": "Distance units for display\nIndicates which units the car is using to display distances to the user. Eg. Mile, Meter Kilometer.\nDistance units are defined in VehicleUnit. VehiclePropConfig.configArray is used to indicate the supported distance display units. For example: configArray[0] = METER configArray[1] = KILOMETER configArray[2] = MILE\nIf updating DISTANCE_DISPLAY_UNITS affects the values of other *_DISPLAY_UNITS properties, then their values must be updated and communicated to the AAOS framework as well.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Distance units for display\nIndicates which units the car is using to display distances to the user. Eg. Mile, Meter Kilometer.\nDistance units are defined in VehicleUnit. VehiclePropConfig.configArray is used to indicate the supported distance display units. For example: configArray[0] = METER configArray[1] = KILOMETER configArray[2] = MILE\nIf {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0): {@code VehicleAreaConfig.HasSupportedValueInfo.hasSupportedValuesList} for the global area ID (0) must be {@code true}. {@code getSupportedValuesLists} for [DISTANCE_DISPLAY_UNITS, areaId=0] must returns a {@code SupportedValuesListResult} that contains non-null {@code supportedValuesList}, e.g. [METER, KILOMETER, MILE]. At boot, the values in the config array are equal to the supported values list.\nIf updating DISTANCE_DISPLAY_UNITS affects the values of other *_DISPLAY_UNITS properties, then their values must be updated and communicated to the AAOS framework as well.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Fuel volume units for display",
@@ -520,7 +520,7 @@
                     "VehicleUnit"
                 ],
                 "data_enum": "VehicleUnit",
-                "description": "Fuel volume units for display\nIndicates which units the car is using to display fuel volume to the user. Eg. Liter or Gallon.\nVehiclePropConfig.configArray is used to indicate the supported fuel volume display units. Volume units are defined in VehicleUnit. For example: configArray[0] = LITER configArray[1] = GALLON\nIf updating FUEL_VOLUME_DISPLAY_UNITS affects the values of other *_DISPLAY_UNITS properties, then their values must be updated and communicated to the AAOS framework as well.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Fuel volume units for display\nIndicates which units the car is using to display fuel volume to the user. Eg. Liter or Gallon.\nVehiclePropConfig.configArray is used to indicate the supported fuel volume display units. Volume units are defined in VehicleUnit. For example: configArray[0] = LITER configArray[1] = GALLON\nIf {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0): {@code VehicleAreaConfig.HasSupportedValueInfo.hasSupportedValuesList} for the global area ID (0) must be {@code true}. {@code getSupportedValuesLists} for [FUEL_VOLUME_DISPLAY_UNITS, areaId=0] must return a {@code SupportedValuesListResult} that contains non-null {@code supportedValuesList}, e.g. [LITER, GALLON]. At boot, the values in the config array are equal to the supported values list.\nIf updating FUEL_VOLUME_DISPLAY_UNITS affects the values of other *_DISPLAY_UNITS properties, then their values must be updated and communicated to the AAOS framework as well.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "TIRE_PRESSURE_DISPLAY_UNITS",
@@ -529,7 +529,7 @@
                     "VehicleUnit"
                 ],
                 "data_enum": "VehicleUnit",
-                "description": "Tire pressure units for display\nIndicates which units the car is using to display tire pressure to the user. Eg. PSI, Bar or Kilopascal.\nVehiclePropConfig.configArray is used to indicate the supported pressure display units. Pressure units are defined in VehicleUnit. For example: configArray[0] = KILOPASCAL configArray[1] = PSI configArray[2] = BAR\nIf updating TIRE_PRESSURE_DISPLAY_UNITS affects the values of other *_DISPLAY_UNITS properties, then their values must be updated and communicated to the AAOS framework as well.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Tire pressure units for display\nIndicates which units the car is using to display tire pressure to the user. Eg. PSI, Bar or Kilopascal.\nVehiclePropConfig.configArray is used to indicate the supported pressure display units. Pressure units are defined in VehicleUnit. For example: configArray[0] = KILOPASCAL configArray[1] = PSI configArray[2] = BAR\nIf {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0): {@code VehicleAreaConfig.HasSupportedValueInfo.hasSupportedValuesList} for the global area ID (0) must be {@code true}. {@code getSupportedValuesLists} for [TIRE_PRESSURE_DISPLAY_UNITS, areaId=0] must return a {@code SupportedValuesListResult} that contains non-null {@code supportedValuesList}, e.g. [KILOPASCAL, PSI, BAR]. At boot, the values in the config array are equal to the supported values list.\nIf updating TIRE_PRESSURE_DISPLAY_UNITS affects the values of other *_DISPLAY_UNITS properties, then their values must be updated and communicated to the AAOS framework as well.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "EV battery units for display",
@@ -538,7 +538,7 @@
                     "VehicleUnit"
                 ],
                 "data_enum": "VehicleUnit",
-                "description": "EV battery units for display\nIndicates which units the car is using to display EV battery information to the user. Eg. watt-hours(Wh), kilowatt-hours(kWh) or ampere-hours(Ah).\nVehiclePropConfig.configArray is used to indicate the supported electrical energy units. Electrical energy units are defined in VehicleUnit. For example: configArray[0] = WATT_HOUR configArray[1] = AMPERE_HOURS configArray[2] = KILOWATT_HOUR\nIf updating EV_BATTERY_DISPLAY_UNITS affects the values of other *_DISPLAY_UNITS properties, then their values must be updated and communicated to the AAOS framework as well.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "EV battery units for display\nIndicates which units the car is using to display EV battery information to the user. Eg. watt-hours(Wh), kilowatt-hours(kWh) or ampere-hours(Ah).\nVehiclePropConfig.configArray is used to indicate the supported electrical energy units. Electrical energy units are defined in VehicleUnit. For example: configArray[0] = WATT_HOUR configArray[1] = AMPERE_HOURS configArray[2] = KILOWATT_HOUR\nIf {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0): {@code VehicleAreaConfig.HasSupportedValueInfo.hasSupportedValuesList} for the global area ID (0) must be {@code true}. {@code getSupportedValuesLists} for [EV_BATTERY_DISPLAY_UNITS, areaId=0] must return a {@code SupportedValuesListResult} that contains non-null {@code supportedValuesList}, e.g. [WATT_HOUR, AMPERE_HOURS, KILOWATT_HOUR]. At boot, the values in the config array are equal to the supported values list.\nIf updating EV_BATTERY_DISPLAY_UNITS affects the values of other *_DISPLAY_UNITS properties, then their values must be updated and communicated to the AAOS framework as well.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME",
@@ -552,7 +552,7 @@
                     "VehicleUnit"
                 ],
                 "data_enum": "VehicleUnit",
-                "description": "Speed units for display\nIndicates type of units the car is using to display speed to user. Eg. m\/s, km\/h, or mph.\nVehiclePropConfig.configArray is used to indicate the supported speed display units. Pressure units are defined in VehicleUnit. For example: configArray[0] = METER_PER_SEC configArray[1] = MILES_PER_HOUR configArray[2] = KILOMETERS_PER_HOUR\nIf {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0):\n{@code VehicleAreaConfig.HasSupportedValueInfo.hasSupportedValuesList} for the global area ID (0) must be {@code true}.\n{@code getSupportedValuesLists} for [VEHICLE_SPEED_DISPLAY_UNITS, areaId=0] must return a {@code SupportedValuesListResult} that contains non-null {@code supportedValuesList}, e.g. [METER_PER_SEC, MILES_PER_HOUR, KILOMETERS_PER_HOUR].\nAt boot, the values in the config array are equal to the supported values list.\n\nIf updating VEHICLE_SPEED_DISPLAY_UNITS affects the values of other *_DISPLAY_UNITS properties, then their values must be updated and communicated to the AAOS framework as well.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Speed units for display\nIndicates type of units the car is using to display speed to user. Eg. m\/s, km\/h, or mph.\nVehiclePropConfig.configArray is used to indicate the supported speed display units. Pressure units are defined in VehicleUnit. For example: configArray[0] = METER_PER_SEC configArray[1] = MILES_PER_HOUR configArray[2] = KILOMETERS_PER_HOUR\nIf {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0): {@code VehicleAreaConfig.HasSupportedValueInfo.hasSupportedValuesList} for the global area ID (0) must be {@code true}. {@code getSupportedValuesLists} for [VEHICLE_SPEED_DISPLAY_UNITS, areaId=0] must return a {@code SupportedValuesListResult} that contains non-null {@code supportedValuesList}, e.g. [METER_PER_SEC, MILES_PER_HOUR, KILOMETERS_PER_HOUR]. At boot, the values in the config array are equal to the supported values list.\nIf updating VEHICLE_SPEED_DISPLAY_UNITS affects the values of other *_DISPLAY_UNITS properties, then their values must be updated and communicated to the AAOS framework as well.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "EXTERNAL_CAR_TIME",
@@ -645,12 +645,12 @@
             {
                 "name": "Door position",
                 "value": 373295872,
-                "description": "Door position\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the door is closed. The minInt32Value must be 0. The maxInt32Value indicates the door is fully open.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the closed and fully open positions.\nThis property is not in any particular unit but in a specified range of relative positions.\nSome vehicles (minivans) can open the door electronically. Hence, the ability to write this property.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Door position\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the door is closed. The minInt32Value must be 0.\nThe maxInt32Value indicates the door is fully open.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the closed and fully open positions.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative positions.\nSome vehicles (minivans) can open the door electronically. Hence, the ability to write this property.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Door move",
                 "value": 373295873,
-                "description": "Door move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value represents the maximum movement speed of the door while opening. The minInt32Value represents the maximum movement speed of the door while closing.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the door reaches the positional limit, the value must reset to 0. If DOOR_MOVE's value is currently 0, then that means there is no movement currently occurring.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Door move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value represents the maximum movement speed of the door while closing.\nThe maxInt32Value represents the maximum movement speed of the door while opening.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the door reaches the positional limit, the value must reset to 0. If DOOR_MOVE's value is currently 0, then that means there is no movement currently occurring.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Door lock",
@@ -665,22 +665,22 @@
             {
                 "name": "Mirror Z Position",
                 "value": 339741504,
-                "description": "Mirror Z Position\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the mirror is tilted completely downwards. This must be a non-positive value. The maxInt32Value indicates the mirror is tilted completely upwards. This must be a non-negative value. 0 indicates the mirror is not tilted in either direction.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the fully downward and fully upwards positions.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Mirror Z Position\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the mirror is tilted completely downwards. This must be a non-positive value.\nThe maxInt32Value indicates the mirror is tilted completely upwards. This must be a non-negative value.\n0 indicates the mirror is not tilted in either direction.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the fully downward and fully upwards positions.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. Values in between minSupportedValue and maxSupportedValue indicate a transition state between the fully downward and fully upwards positions. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Mirror Z Move",
                 "value": 339741505,
-                "description": "Mirror Z Move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value represents the maximum movement speed of the mirror while tilting upwards. The minInt32Value represents the maximum movement speed of the mirror while tilting downwards.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the mirror reaches the positional limit, the value must reset to 0. If MIRROR_Z_MOVE's value is currently 0, then that means there is no movement currently occurring.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Mirror Z Move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value represents the maximum movement speed of the mirror while tilting downwards.\nThe maxInt32Value represents the maximum movement speed of the mirror while tilting upwards.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the mirror reaches the positional limit, the value must reset to 0. If MIRROR_Z_MOVE's value is currently 0, then that means there is no movement currently occurring.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Mirror Y Position",
                 "value": 339741506,
-                "description": "Mirror Y Position\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the mirror is tilted completely to the left. This must be a non-positive value. The maxInt32Value indicates the mirror is tilted completely to the right. This must be a non-negative value. 0 indicates the mirror is not tilted in either direction.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the left extreme and right extreme positions.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Mirror Y Position\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the mirror is tilted completely to the left. This must be a non-positive value.\nThe maxInt32Value indicates the mirror is tilted completely to the right. This must be a non-negative value.\n0 indicates the mirror is not tilted in either direction.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the left extreme and right extreme positions.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. Values in between minSupportedValue and maxSupportedValue indicate a transition state between the fully downward and fully upwards positions. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Mirror Y Move",
                 "value": 339741507,
-                "description": "Mirror Y Move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value represents the maximum movement speed of the mirror while tilting right. The minInt32Value represents the maximum movement speed of the mirror while tilting left.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the mirror reaches the positional limit, the value must reset to 0. If MIRROR_Y_MOVE's value is currently 0, then that means there is no movement currently occurring.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Mirror Y Move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value represents the maximum movement speed of the mirror while tilting left.\nThe maxInt32Value represents the maximum movement speed of the mirror while tilting right.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the mirror reaches the positional limit, the value must reset to 0. If MIRROR_Y_MOVE's value is currently 0, then that means there is no movement currently occurring.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Mirror Lock",
@@ -705,12 +705,12 @@
             {
                 "name": "Seat memory select",
                 "value": 356518784,
-                "description": "Seat memory select\nThis parameter selects the memory preset to use to select the seat position. The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported. The minInt32Value is always 0, and the maxInt32Value determines the number of seat preset memory slots available (i.e. numSeatPresets - 1).\nFor instance, if the driver's seat has 3 memory presets, the maxInt32Value will be 2. When the user wants to select a preset, the desired preset number (0, 1, or 2) is set."
+                "description": "Seat memory select\nThis parameter selects the memory preset to use to select the seat position.\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined.\nAll integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value is always 0, and the maxInt32Value determines the number of seat preset memory slots available (i.e. numSeatPresets - 1).\nFor instance, if the driver's seat has 3 memory presets, the maxInt32Value will be 2. When the user wants to select a preset, the desired preset number (0, 1, or 2) is set.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue."
             },
             {
                 "name": "Seat memory set",
                 "value": 356518785,
-                "description": "Seat memory set\nThis setting allows the user to save the current seat position settings into the selected preset slot. The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. The minInt32Value must be 0, and the maxInt32Value for each seat position must match the maxInt32Value for SEAT_MEMORY_SELECT."
+                "description": "Seat memory set\nThis setting allows the user to save the current seat position settings into the selected preset slot.\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined.\nThe minInt32Value must be 0, and the maxInt32Value for each seat position must match the maxInt32Value for SEAT_MEMORY_SELECT.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue."
             },
             {
                 "name": "Seatbelt buckled",
@@ -720,92 +720,92 @@
             {
                 "name": "Seatbelt height position",
                 "value": 356518787,
-                "description": "Seatbelt height position\nAdjusts the shoulder belt anchor point.\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the seat belt's shoulder anchor is at its lowest position. The maxInt32Value indicates the seat belt's shoulder anchor is at its highest position.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the lowest and highest positions.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Seatbelt height position\nAdjusts the shoulder belt anchor point.\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the seat belt's shoulder anchor is at its lowest position.\nThe maxInt32Value indicates the seat belt's shoulder anchor is at its highest position.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the lowest and highest positions.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. Values in between minSupportedValue and maxSupportedValue indicate a transition state between the lowest and highest positions. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Seatbelt height move",
                 "value": 356518788,
-                "description": "Seatbelt height move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value represents the maximum movement speed of the seat belt's shoulder anchor while moving upwards. The minInt32Value represents the maximum movement speed of the seat belt's shoulder anchor while moving downwards.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat belt reaches the positional limit, the value must reset to 0. If SEAT_BELT_HEIGHT_MOVE's value is currently 0, then that means there is no movement currently occurring.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Seatbelt height move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value represents the maximum movement speed of the seat belt's shoulder anchor while moving downwards.\nThe maxInt32Value represents the maximum movement speed of the seat belt's shoulder anchor while moving upwards.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat belt reaches the positional limit, the value must reset to 0. If SEAT_BELT_HEIGHT_MOVE's value is currently 0, then that means there is no movement currently occurring.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Seat fore\/aft position",
                 "value": 356518789,
-                "description": "Seat fore\/aft position\nSets the seat position forward and backwards.\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the seat is at its rearward-most linear position. The maxInt32Value indicates the seat is at its forward-most linear position.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the closest and farthest positions.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Seat fore\/aft position\nSets the seat position forward and backwards.\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the seat is at its rearward-most linear position.\nThe maxInt32Value indicates the seat is at its forward-most linear position.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the closest and farthest positions.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Seat fore\/aft move",
                 "value": 356518790,
-                "description": "Seat fore\/aft move\nThis property moves the entire seat forward\/backward in the direction that it is facing.\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value represents the maximum movement speed of the seat while moving forward. The minInt32Value represents the maximum movement speed of the seat while moving backward.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat reaches the positional limit, the value must reset to 0. If SEAT_FORE_AFT_MOVE's value is currently 0, then that means there is no movement currently occurring.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Seat fore\/aft move\nThis property moves the entire seat forward\/backward in the direction that it is facing.\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value represents the maximum movement speed of the seat while moving backward.\nThe maxInt32Value represents the maximum movement speed of the seat while moving forward.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat reaches the positional limit, the value must reset to 0. If SEAT_FORE_AFT_MOVE's value is currently 0, then that means there is no movement currently occurring.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Seat backrest angle 1 position",
                 "value": 356518791,
-                "description": "Seat backrest angle 1 position\nBackrest angle 1 is the actuator closest to the bottom of the seat.\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the seat backrest's full recline position w.r.t the actuator at the bottom of the seat. The maxInt32Value indicates the seat backrest's most upright\/forward position w.r.t the actuator at the bottom of the seat.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the full recline and upright\/forward positions.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Seat backrest angle 1 position\nBackrest angle 1 is the actuator closest to the bottom of the seat.\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the seat backrest's full recline position w.r.t the actuator at the bottom of the seat.\nThe maxInt32Value indicates the seat backrest's most upright\/forward position w.r.t the actuator at the bottom of the seat.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the full recline and upright\/forward positions.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. Values in between minSupportedValue and maxSupportedValue indicate a transition state between the full recline and upright\/forward positions. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Seat backrest angle 1 move",
                 "value": 356518792,
-                "description": "Seat backrest angle 1 move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value represents the maximum movement speed of the seat backrest while angling forward. The minInt32Value represents the maximum movement speed of the seat backrest while reclining.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat backrest reaches the positional limit, the value must reset to 0. If SEAT_BACKREST_ANGLE_1_MOVE's value is currently 0, then that means there is no movement currently occurring.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Seat backrest angle 1 move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value represents the maximum movement speed of the seat backrest while reclining.\nThe maxInt32Value represents the maximum movement speed of the seat backrest while angling forward.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat backrest reaches the positional limit, the value must reset to 0. If SEAT_BACKREST_ANGLE_1_MOVE's value is currently 0, then that means there is no movement currently occurring.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Seat backrest angle 2 position",
                 "value": 356518793,
-                "description": "Seat backrest angle 2 position\nBackrest angle 2 is the next actuator up from the bottom of the seat.\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the seat backrest's full recline position w.r.t the next actuator in the backrest from the one at the bottom of the seat (see SEAT_BACKREST_ANGLE_1_POS for additional details). The maxInt32Value indicates the seat backrest's most upright\/forward position w.r.t the next actuator in the backrest from the one at the bottom of the seat(see SEAT_BACKREST_ANGLE_1_POS for additional details).\nValues in between minInt32Value and maxInt32Value indicate a transition state between the full recline and upright\/forward positions.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Seat backrest angle 2 position\nBackrest angle 2 is the next actuator up from the bottom of the seat.\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the seat backrest's full recline position w.r.t the next actuator in the backrest from the one at the bottom of the seat (see SEAT_BACKREST_ANGLE_1_POS for additional details).\nThe maxInt32Value indicates the seat backrest's most upright\/forward position w.r.t the next actuator in the backrest from the one at the bottom of the seat(see SEAT_BACKREST_ANGLE_1_POS for additional details).\nValues in between minInt32Value and maxInt32Value indicate a transition state between the full recline and upright\/forward positions.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} ihas the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. Values in between minSupportedValue and maxSupportedValue indicate a transition state between the full recline and upright\/forward positions. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Seat backrest angle 2 move",
                 "value": 356518794,
-                "description": "Seat backrest angle 2 move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value represents the maximum movement speed of the seat backrest while angling forward. The minInt32Value represents the maximum movement speed of the seat backrest while reclining.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat backrest reaches the positional limit, the value must reset to 0. If SEAT_BACKREST_ANGLE_2_MOVE's value is currently 0, then that means there is no movement currently occurring.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Seat backrest angle 2 move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value represents the maximum movement speed of the seat backrest while reclining.\nThe maxInt32Value represents the maximum movement speed of the seat backrest while angling forward.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat backrest reaches the positional limit, the value must reset to 0. If SEAT_BACKREST_ANGLE_2_MOVE's value is currently 0, then that means there is no movement currently occurring.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Seat height position",
                 "value": 356518795,
-                "description": "Seat height position\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the seat is in its lowest position. The maxInt32Value indicates the seat is in its highest position.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the lowest and highest positions.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Seat height position\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the seat is in its lowest position.\nThe maxInt32Value indicates the seat is in its highest position.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the lowest and highest positions.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. position. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Seat height move",
                 "value": 356518796,
-                "description": "Seat height move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value represents the maximum movement speed of the seat while moving upward. The minInt32Value represents the maximum movement speed of the seat while moving downward.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat reaches the positional limit, the value must reset to 0. If SEAT_HEIGHT_MOVE's value is currently 0, then that means there is no movement currently occurring.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Seat height move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value represents the maximum movement speed of the seat while moving downward.\nThe maxInt32Value represents the maximum movement speed of the seat while moving upward.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat reaches the positional limit, the value must reset to 0. If SEAT_HEIGHT_MOVE's value is currently 0, then that means there is no movement currently occurring.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Seat depth position",
                 "value": 356518797,
-                "description": "Seat depth position\nSets the seat depth, distance from back rest to front edge of seat.\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the seat is in its shallowest position (i.e. the position with the smallest distance between the front edge of the seat cushion and the rear end of the seat). The maxInt32Value indicates the seat is in its deepest position (i.e. the position with the largest distance between the front edge of the seat cushion and the rear end of the seat).\nValues in between minInt32Value and maxInt32Value indicate a transition state between the shallowest and deepest positions.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Seat depth position\nSets the seat depth, distance from back rest to front edge of seat.\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the seat is in its shallowest position (i.e. the position with the smallest distance between the front edge of the seat cushion and the rear end of the seat).\nThe maxInt32Value indicates the seat is in its deepest position (i.e. the position with the largest distance between the front edge of the seat cushion and the rear end of the seat).\nValues in between minInt32Value and maxInt32Value indicate a transition state between the shallowest and deepest positions.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Seat depth move",
                 "value": 356518798,
-                "description": "Seat depth move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value represents the maximum movement speed of the seat while getting deeper The minInt32Value represents the maximum movement speed of the seat while getting shallower.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat backrest reaches the positional limit, the value must reset to 0. If SEAT_DEPTH_MOVE's value is currently 0, then that means there is no movement currently occurring.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Seat depth move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value represents the maximum movement speed of the seat while getting shallower.\nThe maxInt32Value represents the maximum movement speed of the seat while getting deeper.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat backrest reaches the positional limit, the value must reset to 0. If SEAT_DEPTH_MOVE's value is currently 0, then that means there is no movement currently occurring.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Seat tilt position",
                 "value": 356518799,
-                "description": "Seat tilt position\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the seat bottom is angled at its lowest angular position. This corresponds to the seat's front edge at its lowest possible position relative to the rear end of the seat. The maxInt32Value indicates the seat bottom is angled at its highest angular position. This corresponds to the seat's front edge at its highest possible position relative to the rear end of the seat.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the lowest and highest positions.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Seat tilt position\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the seat bottom is angled at its lowest angular position. This corresponds to the seat's front edge at its lowest possible position relative to the rear end of the seat.\nThe maxInt32Value indicates the seat bottom is angled at its highest angular position. This corresponds to the seat's front edge at its highest possible position relative to the rear end of the seat.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the lowest and highest positions.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Seat tilt move",
                 "value": 356518800,
-                "description": "Seat tilt move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value represents the maximum movement speed of the front edge of the seat while moving upward. The minInt32Value represents the maximum movement speed of the front edge of the seat while moving downward.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat bottom reaches the positional limit, the value must reset to 0. If SEAT_TILT_MOVE's value is currently 0, then that means there is no movement currently occurring.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Seat tilt move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value represents the maximum movement speed of the front edge of the seat while moving downward.\nThe maxInt32Value represents the maximum movement speed of the front edge of the seat while moving upward.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat bottom reaches the positional limit, the value must reset to 0. If SEAT_TILT_MOVE's value is currently 0, then that means there is no movement currently occurring.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Lumber fore\/aft position",
                 "value": 356518801,
-                "description": "Lumber fore\/aft position\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the lumbar support is in its rearward most position (i.e. least supportive position). The maxInt32Value indicates the lumbar support is in its forward most position (i.e. most supportive position).\nValues in between minInt32Value and maxInt32Value indicate a transition state between the forward and rearward positions.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Lumber fore\/aft position\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the lumbar support is in its rearward most position (i.e. least supportive position).\nThe maxInt32Value indicates the lumbar support is in its forward most position (i.e. most supportive position).\nValues in between minInt32Value and maxInt32Value indicate a transition state between the forward and rearward positions.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Lumbar fore\/aft move",
                 "value": 356518802,
-                "description": "Lumbar fore\/aft move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value represents the maximum movement speed of the seat's lumbar support while moving forward. The minInt32Value represents the maximum movement speed of the seat's lumbar support while moving backward.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat's lumbar support reaches the positional limit, the value must reset to 0. If SEAT_LUMBAR_FORE_AFT_MOVE's value is currently 0, then that means there is no movement currently occurring.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Lumbar fore\/aft move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value represents the maximum movement speed of the seat's lumbar support while moving backward.\nThe maxInt32Value represents the maximum movement speed of the seat's lumbar support while moving forward.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat's lumbar support reaches the positional limit, the value must reset to 0. If SEAT_LUMBAR_FORE_AFT_MOVE's value is currently 0, then that means there is no movement currently occurring.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Lumbar side support position",
                 "value": 356518803,
-                "description": "Lumbar side support position\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the lumbar side support is in its thinnest position (i.e. most support). The maxInt32Value indicates the lumbar side support is in its widest position (i.e. least support).\nValues in between minInt32Value and maxInt32Value indicate a transition state between the thinnest and widest positions.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Lumbar side support position\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the lumbar side support is in its thinnest position (i.e. most support).\nThe maxInt32Value indicates the lumbar side support is in its widest position (i.e. least support).\nValues in between minInt32Value and maxInt32Value indicate a transition state between the thinnest and widest positions.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Lumbar side support move",
                 "value": 356518804,
-                "description": "Lumbar side support move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value represents the maximum movement speed of the seat's lumbar side support while getting wider. The minInt32Value represents the maximum movement speed of the seat's lumbar side support while getting thinner.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat's lumbar side support reaches the positional limit, the value must reset to 0. If SEAT_LUMBAR_SIDE_SUPPORT_MOVE's value is currently 0, then that means there is no movement currently occurring.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Lumbar side support move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value represents the maximum movement speed of the seat's lumbar side support while getting thinner.\nThe maxInt32Value represents the maximum movement speed of the seat's lumbar side support while getting wider.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat's lumbar side support reaches the positional limit, the value must reset to 0. If SEAT_LUMBAR_SIDE_SUPPORT_MOVE's value is currently 0, then that means there is no movement currently occurring.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "SEAT_HEADREST_HEIGHT_POS",
@@ -815,32 +815,32 @@
             {
                 "name": "Headrest height position",
                 "value": 356518820,
-                "description": "Headrest height position\nSets the headrest height for supported seats. VehiclePropConfig.areaConfigs specifies which seats are supported.\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the headrest is in its lowest position. The maxInt32Value indicates the headrest is in its highest position.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the lowest and highest positions.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Headrest height position\nSets the headrest height for supported seats. VehiclePropConfig.areaConfigs specifies which seats are supported.\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the headrest is in its lowest position.\nThe maxInt32Value indicates the headrest is in its highest position.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the lowest and highest positions.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Headrest height move",
                 "value": 356518806,
-                "description": "Headrest height move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value represents the maximum movement speed of the seat's headrest while moving up. The minInt32Value represents the maximum movement speed of the seat's headrest while moving down.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat's headrest reaches the positional limit, the value must reset to 0. If SEAT_HEADREST_HEIGHT_MOVE's value is currently 0, then that means there is no movement currently occurring.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Headrest height move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value represents the maximum movement speed of the seat's headrest while moving down.\nThe maxInt32Value represents the maximum movement speed of the seat's headrest while moving up.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat's headrest reaches the positional limit, the value must reset to 0. If SEAT_HEADREST_HEIGHT_MOVE's value is currently 0, then that means there is no movement currently occurring.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Headrest angle position",
                 "value": 356518807,
-                "description": "Headrest angle position\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the headrest is in its full recline position. The maxInt32Value indicates the headrest is in its most upright\/forward position.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the full recline and most upright\/forward positions.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Headrest angle position\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the headrest is in its full recline position.\nThe maxInt32Value indicates the headrest is in its most upright\/forward position.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the full recline and most upright\/forward positions.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Headrest angle move",
                 "value": 356518808,
-                "description": "Headrest angle move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value represents the maximum movement speed of the seat's headrest while moving into an upright\/forward position. The minInt32Value represents the maximum movement speed of the seat's headrest while moving into a shallow position.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat's headrest reaches the positional limit, the value must reset to 0. If SEAT_HEADREST_ANGLE_MOVE's value is currently 0, then that means there is no movement currently occurring.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Headrest angle move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value represents the maximum movement speed of the seat's headrest while moving into a shallow position.\nThe maxInt32Value represents the maximum movement speed of the seat's headrest while moving into an upright\/forward position.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat's headrest reaches the positional limit, the value must reset to 0. If SEAT_HEADREST_ANGLE_MOVE's value is currently 0, then that means there is no movement currently occurring.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Headrest fore\/aft position",
                 "value": 356518809,
-                "description": "Headrest fore\/aft position\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the headrest is in its rearward-most linear position. The maxInt32Value indicates the headrest is in its forward-most linear position.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the forward and rearward positions.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Headrest fore\/aft position\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the headrest is in its rearward-most linear position.\nThe maxInt32Value indicates the headrest is in its forward-most linear position.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the forward and rearward positions.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Headrest fore\/aft move",
                 "value": 356518810,
-                "description": "Headrest fore\/aft move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value represents the maximum movement speed of the seat's headrest while moving forward. The minInt32Value represents the maximum movement speed of the seat's headrest while moving backward.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat's headrest reaches the positional limit, the value must reset to 0. If SEAT_HEADREST_FORE_AFT_MOVE's value is currently 0, then that means there is no movement currently occurring.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Headrest fore\/aft move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value represents the maximum movement speed of the seat's headrest while moving backward.\nThe maxInt32Value represents the maximum movement speed of the seat's headrest while moving forward.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat's headrest reaches the positional limit, the value must reset to 0. If SEAT_HEADREST_FORE_AFT_MOVE's value is currently 0, then that means there is no movement currently occurring.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "SEAT_FOOTWELL_LIGHTS_STATE",
@@ -849,7 +849,7 @@
                     "VehicleLightState"
                 ],
                 "data_enum": "VehicleLightState",
-                "description": "Represents property for the seat footwell lights state.\nSEAT_FOOTWELL_LIGHTS_STATE reflects the current state of the lights at any point in time. This is different from the function of SEAT_FOOTWELL_LIGHTS_SWITCH which represents the position of the switch controlling the lights. Therefore, SEAT_FOOTWELL_LIGHTS_STATE may not match the value of SEAT_FOOTWELL_LIGHTS_SWITCH (e.g. SEAT_FOOTWELL_LIGHTS_SWITCH=AUTOMATIC and SEAT_FOOTWELL_LIGHTS_STATE=ON).\nThis property should only be implemented if SEAT_FOOTWELL_LIGHTS_STATE's value may be different from that of CABIN_LIGHTS_STATE.\nFor each supported area ID, the VehicleAreaConfig#supportedEnumValues must be defined unless all enum values of VehicleLightState are supported."
+                "description": "Represents property for the seat footwell lights state.\nSEAT_FOOTWELL_LIGHTS_STATE reflects the current state of the lights at any point in time. This is different from the function of SEAT_FOOTWELL_LIGHTS_SWITCH which represents the position of the switch controlling the lights. Therefore, SEAT_FOOTWELL_LIGHTS_STATE may not match the value of SEAT_FOOTWELL_LIGHTS_SWITCH (e.g. SEAT_FOOTWELL_LIGHTS_SWITCH=AUTOMATIC and SEAT_FOOTWELL_LIGHTS_STATE=ON).\nThis property should only be implemented if SEAT_FOOTWELL_LIGHTS_STATE's value may be different from that of CABIN_LIGHTS_STATE.\nFor each supported area ID, the VehicleAreaConfig#supportedEnumValues must be defined unless all enum values of VehicleLightState are supported.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} for the area ID unless all enum values of VehicleLightState are supported. At boot, the supported values list is the same as supportedEnumValues."
             },
             {
                 "name": "SEAT_FOOTWELL_LIGHTS_SWITCH",
@@ -858,7 +858,7 @@
                     "VehicleLightSwitch"
                 ],
                 "data_enum": "VehicleLightSwitch",
-                "description": "Represents property for the seat footwell lights switch.\nSEAT_FOOTWELL_LIGHTS_SWITCH represents the position of the switch controlling the lights. This is different from the function of SEAT_FOOTWELL_LIGHTS_STATE which reflects the current state of the lights at any point in time. Therefore, SEAT_FOOTWELL_LIGHTS_SWITCH may not match the value of SEAT_FOOTWELL_LIGHTS_STATE (e.g. SEAT_FOOTWELL_LIGHTS_SWITCH=AUTOMATIC and SEAT_FOOTWELL_LIGHTS_STATE=ON).\nThis property should only be implemented if SEAT_FOOTWELL_LIGHTS_SWITCH's value may be different from that of CABIN_LIGHTS_SWITCH.\nFor each supported area ID, the VehicleAreaConfig#supportedEnumValues must be defined unless all enum values of VehicleLightSwitch are supported.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Represents property for the seat footwell lights switch.\nSEAT_FOOTWELL_LIGHTS_SWITCH represents the position of the switch controlling the lights. This is different from the function of SEAT_FOOTWELL_LIGHTS_STATE which reflects the current state of the lights at any point in time. Therefore, SEAT_FOOTWELL_LIGHTS_SWITCH may not match the value of SEAT_FOOTWELL_LIGHTS_STATE (e.g. SEAT_FOOTWELL_LIGHTS_SWITCH=AUTOMATIC and SEAT_FOOTWELL_LIGHTS_STATE=ON).\nThis property should only be implemented if SEAT_FOOTWELL_LIGHTS_SWITCH's value may be different from that of CABIN_LIGHTS_SWITCH.\nFor each supported area ID, the VehicleAreaConfig#supportedEnumValues must be defined unless all enum values of VehicleLightSwitch are supported.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} for the area ID unless all enum values of VehicleLightSwitch are supported. At boot, the supported values list is the same as supportedEnumValues.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "SEAT_EASY_ACCESS_ENABLED",
@@ -877,32 +877,32 @@
                     "VehicleAirbagLocation"
                 ],
                 "data_enum": "VehicleAirbagLocation",
-                "description": "Seat airbags deployed\nBit flag property to relay information on which airbags have been deployed in the vehicle at each seat, vs which ones are currently still armed. If SEAT_AIRBAG_ENABLED is set to false at a particular areaId, this property should return status code UNAVAILABLE at that areaId.\nEnums apply to each seat, not the global vehicle. For example, VehicleAirbagsLocation#CURTAIN at the driver seat areaId represents whether the driver side curtain airbag has been deployed. Multiple bit flags can be set to indicate that multiple different airbags have been deployed for the seat.\nFor each seat area ID, the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of VehicleAirbagLocation are supported (including OTHER, which is not recommended)."
+                "description": "Seat airbags deployed\nBit flag property to relay information on which airbags have been deployed in the vehicle at each seat, vs which ones are currently still armed. If SEAT_AIRBAG_ENABLED is set to false at a particular areaId, this property should return status code UNAVAILABLE at that areaId.\nEnums apply to each seat, not the global vehicle. For example, VehicleAirbagsLocation#CURTAIN at the driver seat areaId represents whether the driver side curtain airbag has been deployed. Multiple bit flags can be set to indicate that multiple different airbags have been deployed for the seat.\nFor each seat area ID, the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of VehicleAirbagLocation are supported (including OTHER, which is not recommended).\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} for the area ID unless all states of VehicleAirbagLocation are supported (including OTHER, which is not recommended). At boot, the supported values list is the same as supportedEnumValues."
             },
             {
                 "name": "SEAT_CUSHION_SIDE_SUPPORT_POS",
                 "value": 356518815,
-                "description": "Represents property for seat’s hipside (bottom cushion’s side) support position.\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value indicates the seat cushion side support is in its widest position (i.e. least support). The minInt32Value indicates the seat cushion side support is in its thinnest position (i.e. most support).\nValues in between minInt32Value and maxInt32Value indicate a transition state between the thinnest and widest positions.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Represents property for seat’s hipside (bottom cushion’s side) support position.\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the seat cushion side support is in its thinnest position (i.e. most support).\nThe maxInt32Value indicates the seat cushion side support is in its widest position (i.e. least support).\nValues in between minInt32Value and maxInt32Value indicate a transition state between the thinnest and widest positions.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "SEAT_CUSHION_SIDE_SUPPORT_MOVE",
                 "value": 356518816,
-                "description": "Represents property for movement direction and speed of seat cushion side support.\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value represents the maximum movement speed of the seat cushion side support when growing wider (i.e. support is decreasing). The minInt32Value represents the maximum movement speed of the seat cushion side support when growing thinner (i.e. support is increasing).\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat cushion side support reaches the positional limit, the value must reset to 0. If SEAT_CUSHION_SIDE_SUPPORT_MOVE's value is currently 0, then that means there is no movement currently occurring.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Represents property for movement direction and speed of seat cushion side support.\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value represents the maximum movement speed of the seat cushion side support when growing thinner (i.e. support is increasing).\nThe maxInt32Value represents the maximum movement speed of the seat cushion side support when growing wider (i.e. support is decreasing).\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat cushion side support reaches the positional limit, the value must reset to 0. If SEAT_CUSHION_SIDE_SUPPORT_MOVE's value is currently 0, then that means there is no movement currently occurring.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "SEAT_LUMBAR_VERTICAL_POS",
                 "value": 356518817,
-                "description": "Represents property for seat’s lumbar support vertical position.\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value indicates the lumbar support's highest position. The minInt32Value indicates the lumbar support's lowest position.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the lowest and highest positions.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Represents property for seat’s lumbar support vertical position.\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the lumbar support's lowest position.\nThe maxInt32Value indicates the lumbar support's highest position.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the lowest and highest positions.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "SEAT_LUMBAR_VERTICAL_MOVE",
                 "value": 356518818,
-                "description": "Represents property for vertical movement direction and speed of seat lumbar support.\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value indicates the lumbar support is moving at the fastest upward speed. The minInt32Value indicates the lumbar support is moving at the fastest downward speed.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat cushion side support reaches the positional limit, the value must reset to 0. If SEAT_LUMBAR_VERTICAL_MOVE's value is currently 0, then that means there is no movement currently occurring.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Represents property for vertical movement direction and speed of seat lumbar support.\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the lumbar support is moving at the fastest downward speed.\nThe maxInt32Value indicates the lumbar support is moving at the fastest upward speed.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the seat cushion side support reaches the positional limit, the value must reset to 0. If SEAT_LUMBAR_VERTICAL_MOVE's value is currently 0, then that means there is no movement currently occurring.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "SEAT_WALK_IN_POS",
                 "value": 356518819,
-                "description": "Represents property that indicates the current walk-in position of the seat.\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the normal seat position. The minInt32Value must be 0. The maxInt32Value indicates the seat is in the full walk-in position.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the normal and walk-in positions.\nThis property is not in any particular unit but in a specified range of relative positions.\nThe area ID must match the seat that actually moves when the walk-in feature activates, not the intended seat the passengers will sit in.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Represents property that indicates the current walk-in position of the seat.\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the normal seat position. The minInt32Value must be 0.\nThe maxInt32Value indicates the seat is in the full walk-in position.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the normal and walk-in positions.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative positions.\nThe area ID must match the seat that actually moves when the walk-in feature activates, not the intended seat the passengers will sit in.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "SEAT_BELT_PRETENSIONER_DEPLOYED",
@@ -921,12 +921,12 @@
             {
                 "name": "Window Position",
                 "value": 322964416,
-                "description": "Window Position\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the window is closed\/fully open out of plane. If the window cannot open out of plane, then minInt32Value is the position of the window when fully closed and must be 0. If the window can open out of plane, the minInt32Value indicates the window is fully open in its position out of plane and will be a negative value. See the example below for a more detailed explanation. The maxInt32Value indicates the window is fully open.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the closed\/fully open out-of-plane and fully open positions.\nThis property is not in any particular unit but in a specified range of relative positions.\nFor example, this is how the property should work for a window that can move out of plane: For a window that may open out of plane (i.e. vent mode of sunroof) this parameter will work with negative values as follows: Max = sunroof completely open 0 = sunroof closed. Min = sunroof vent completely open\nNote that in this mode, 0 indicates the window is closed.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Window Position\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined.\nAll integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the window is closed\/fully open out of plane. If the window cannot open out of plane, then minInt32Value is the position of the window when fully closed and must be 0. If the window can open out of plane, the minInt32Value indicates the window is fully open in its position out of plane and will be a negative value. See the example below for a more detailed explanation.\nThe maxInt32Value indicates the window is fully open.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the closed\/fully open out-of-plane and fully open positions.\nThis property is not in any particular unit but in a specified range of relative positions.\nFor example, this is how the property should work for a window that can move out of plane: For a window that may open out of plane (i.e. vent mode of sunroof) this parameter will work with negative values as follows: Max = sunroof completely open 0 = sunroof closed. Min = sunroof vent completely open\nNote that in this mode, 0 indicates the window is closed.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Window Move",
                 "value": 322964417,
-                "description": "Window Move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value indicates the window is opening in plane\/closing in the out of plane direction at the fastest speed. The minInt32Value indicates the window is closing in plane\/opening in the out of plane direction at the fastest speed.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the window reaches the positional limit, the value must reset to 0. If WINDOW_MOVE's value is currently 0, then that means there is no movement currently occurring.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nFor a window that may open out of plane (i.e. vent mode of sunroof) this parameter will work as follows:\nIf sunroof is open: Max = open the sunroof further, automatically stop when fully open. Min = close the sunroof, automatically stop when sunroof is closed.\nIf vent is open: Max = close the vent, automatically stop when vent is closed. Min = open the vent further, automatically stop when vent is fully open.\nIf sunroof is in the closed position: Max = open the sunroof, automatically stop when sunroof is fully open. Min = open the vent, automatically stop when vent is fully open.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Window Move\nThe maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the window is closing in plane\/opening in the out of plane direction at the fastest speed.\nThe maxInt32Value indicates the window is opening in plane\/closing in the out of plane direction at the fastest speed.\nLarger absolute values, either positive or negative, indicate a faster movement speed. Once the window reaches the positional limit, the value must reset to 0. If WINDOW_MOVE's value is currently 0, then that means there is no movement currently occurring.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nFor a window that may open out of plane (i.e. vent mode of sunroof) this parameter will work as follows:\nIf sunroof is open: Max = open the sunroof further, automatically stop when fully open. Min = close the sunroof, automatically stop when sunroof is closed.\nIf vent is open: Max = close the vent, automatically stop when vent is closed. Min = open the vent further, automatically stop when vent is fully open.\nIf sunroof is in the closed position: Max = open the sunroof, automatically stop when sunroof is fully open. Min = open the vent, automatically stop when vent is fully open.\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Window Child Lock",
@@ -936,7 +936,7 @@
             {
                 "name": "WINDSHIELD_WIPERS_PERIOD",
                 "value": 322964421,
-                "description": "Windshield wipers period (milliseconds).\nReturns the instantaneous time period for 1 full cycle of the windshield wipers in milliseconds. A full cycle is defined as a wiper moving from and returning to its rest position.\nWhen an intermittent wiper setting is selected, this property value must be set to 0 during the \"pause\" period of the intermittent wiping.\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. The maxInt32Value for each area ID must specify the longest wiper period. The minInt32Value must be set to 0 for each area ID."
+                "description": "Windshield wipers period (milliseconds).\nReturns the instantaneous time period for 1 full cycle of the windshield wipers in milliseconds. A full cycle is defined as a wiper moving from and returning to its rest position.\nWhen an intermittent wiper setting is selected, this property value must be set to 0 during the \"pause\" period of the intermittent wiping.\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined.\nThe minInt32Value must be set to 0 for each area ID.\nThe maxInt32Value for each area ID must specify the longest wiper period.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true}. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue."
             },
             {
                 "name": "Windshield wipers state.",
@@ -945,7 +945,7 @@
                     "WindshieldWipersState"
                 ],
                 "data_enum": "WindshieldWipersState",
-                "description": "Windshield wipers state.\nReturns the current state of the windshield wipers. The value of WINDSHIELD_WIPERS_STATE may not match the value of WINDSHIELD_WIPERS_SWITCH. (e.g. WINDSHIELD_WIPERS_STATE = ON and WINDSHIELD_WIPERS_SWITCH = WindshieldWipersSwitch#AUTO).\nIf WINDSHIELD_WIPERS_STATE = ON and WINDSHIELD_WIPERS_PERIOD is implemented, then WINDSHIELD_WIPERS_PERIOD must reflect the time period of 1 full cycle of the wipers.\nFor each supported area ID, the VehicleAreaConfig#supportedEnumValues array must be defined unless all states in WindshieldWipersState are supported (including OTHER, which is not recommended)."
+                "description": "Windshield wipers state.\nReturns the current state of the windshield wipers. The value of WINDSHIELD_WIPERS_STATE may not match the value of WINDSHIELD_WIPERS_SWITCH. (e.g. WINDSHIELD_WIPERS_STATE = ON and WINDSHIELD_WIPERS_SWITCH = WindshieldWipersSwitch#AUTO).\nIf WINDSHIELD_WIPERS_STATE = ON and WINDSHIELD_WIPERS_PERIOD is implemented, then WINDSHIELD_WIPERS_PERIOD must reflect the time period of 1 full cycle of the wipers.\nFor each supported area ID, the VehicleAreaConfig#supportedEnumValues array must be defined unless all states in WindshieldWipersState are supported (including OTHER, which is not recommended).\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} for the area ID unless all states in WindshieldWipersState are supported (including OTHER, which is not recommended). At boot, the supported values list is the same as supportedEnumValues."
             },
             {
                 "name": "Windshield wipers switch.",
@@ -954,27 +954,27 @@
                     "WindshieldWipersSwitch"
                 ],
                 "data_enum": "WindshieldWipersSwitch",
-                "description": "Windshield wipers switch.\nRepresents the position of the switch controlling the windshield wipers. The value of WINDSHIELD_WIPERS_SWITCH may not match the value of WINDSHIELD_WIPERS_STATE (e.g. WINDSHIELD_WIPERS_SWITCH = AUTO and WINDSHIELD_WIPERS_STATE = WindshieldWipersState#ON).\nFor each supported area ID, the VehicleAreaConfig#supportedEnumValues array must be defined unless all states in WindshieldWipersSwitch are supported (including OTHER, which is not recommended).\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only.\nIf this property is implemented as VehiclePropertyAccess.READ_WRITE and the OTHER state is listed in the VehicleAreaConfig#supportedEnumValues array, then OTHER is not a supported value for writing. It is only a supported value for reading."
+                "description": "Windshield wipers switch.\nRepresents the position of the switch controlling the windshield wipers. The value of WINDSHIELD_WIPERS_SWITCH may not match the value of WINDSHIELD_WIPERS_STATE (e.g. WINDSHIELD_WIPERS_SWITCH = AUTO and WINDSHIELD_WIPERS_STATE = WindshieldWipersState#ON).\nFor each supported area ID, the VehicleAreaConfig#supportedEnumValues array must be defined unless all states in WindshieldWipersSwitch are supported (including OTHER, which is not recommended).\nIf {@code HasSupportedValueInfo} for a specific area ID is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} for the area ID unless all states in WindshieldWipersSwitch are supported (including OTHER, which is not recommended). At boot, the supported values list is the same as supportedEnumValues.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only.\nIf this property is implemented as VehiclePropertyAccess.READ_WRITE and the OTHER state is listed in the VehicleAreaConfig#supportedEnumValues array, then OTHER is not a supported value for writing. It is only a supported value for reading."
             },
             {
                 "name": "Steering wheel depth position",
                 "value": 289410016,
-                "description": "Steering wheel depth position\nAll steering wheel properties' unique ids start from 0x0BE0.\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value indicates the steering wheel position furthest from the driver. The minInt32Value indicates the steering wheel position closest to the driver.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the closest and furthest positions.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Steering wheel depth position\nAll steering wheel properties' unique ids start from 0x0BE0.\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the steering wheel position closest to the driver.\nThe maxInt32Value indicates the steering wheel position furthest from the driver.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the closest and furthest positions.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true}. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Steering wheel depth movement",
                 "value": 289410017,
-                "description": "Steering wheel depth movement\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value indicates the steering wheel moving away from the driver. The minInt32Value indicates the steering wheel moving towards the driver.\nLarger integers, either positive or negative, indicate a faster movement speed. Once the steering wheel reaches the positional limit, the value must reset to 0. If STEERING_WHEEL_DEPTH_MOVE's value is currently 0, then that means there is no movement currently occurring.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Steering wheel depth movement\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the steering wheel moving towards the driver.\nThe maxInt32Value indicates the steering wheel moving away from the driver.\nLarger integers, either positive or negative, indicate a faster movement speed. Once the steering wheel reaches the positional limit, the value must reset to 0. If STEERING_WHEEL_DEPTH_MOVE's value is currently 0, then that means there is no movement currently occurring.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true}. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Steering wheel height position",
                 "value": 289410018,
-                "description": "Steering wheel height position\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value indicates the steering wheel being in the highest position. The minInt32Value indicates the steering wheel being in the lowest position.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the lowest and highest positions.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Steering wheel height position\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the steering wheel being in the lowest position.\nThe maxInt32Value indicates the steering wheel being in the highest position.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the lowest and highest positions.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true}. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative positions.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Steering wheel height movement",
                 "value": 289410019,
-                "description": "Steering wheel height movement\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between minInt32Value and maxInt32Value must be supported.\nThe maxInt32Value indicates the steering wheel moving upwards. The minInt32Value indicates the steering wheel moving downwards.\nLarger integers, either positive or negative, indicate a faster movement speed. Once the steering wheel reaches the positional limit, the value must reset to 0. If STEERING_WHEEL_HEIGHT_MOVE's value is currently 0, then that means there is no movement currently occurring.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Steering wheel height movement\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates the steering wheel moving downwards.\nThe maxInt32Value indicates the steering wheel moving upwards.\nLarger integers, either positive or negative, indicate a faster movement speed. Once the steering wheel reaches the positional limit, the value must reset to 0. If STEERING_WHEEL_HEIGHT_MOVE's value is currently 0, then that means there is no movement currently occurring.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true}. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative movement speeds.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "STEERING_WHEEL_THEFT_LOCK_ENABLED",
@@ -994,7 +994,7 @@
             {
                 "name": "GLOVE_BOX_DOOR_POS",
                 "value": 356518896,
-                "description": "Property that represents the current position of the glove box door.\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates that the glove box door is closed. The minInt32Value must be 0. The maxInt32Value indicates that the glove box door is in the fully open position.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the closed and fully open positions.\nThis property is not in any particular unit but in a specified range of relative positions.\nThe area ID must match the seat by which the glove box is intended to be used  (e.g. if the front right dashboard has a glove box embedded in it, then the area ID should be SEAT_1_RIGHT).\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Property that represents the current position of the glove box door.\nThe maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between minInt32Value and maxInt32Value must be supported.\nThe minInt32Value indicates that the glove box door is closed. The minInt32Value must be 0.\nThe maxInt32Value indicates that the glove box door is in the fully open position.\nValues in between minInt32Value and maxInt32Value indicate a transition state between the closed and fully open positions.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasMinSupportedValue} and {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true}. {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value. {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value. All integers between minSupportedValue and maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to maxSupportedValue.\nThis property is not in any particular unit but in a specified range of relative positions.\nThe area ID must match the seat by which the glove box is intended to be used  (e.g. if the front right dashboard has a glove box embedded in it, then the area ID should be SEAT_1_RIGHT).\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "Lock or unlock the glove box.",
@@ -1176,7 +1176,7 @@
                     "VehicleLightState"
                 ],
                 "data_enum": "VehicleLightState",
-                "description": "Steering wheel lights state\nRepresents the current state of the steering wheel lights. This is different from STEERING_WHEEL_LIGHTS_SWITCH which represents the position of the switch controlling the lights. Therefore, STEERING_WHEEL_LIGHTS_STATE may not match the value of STEERING_WHEEL_LIGHTS_SWITCH (e.g. STEERING_WHEEL_LIGHTS_SWITCH=AUTOMATIC and STEERING_WHEEL_LIGHTS_STATE=ON).\nThis property should only be implemented if STEERING_WHEEL_LIGHTS_STATE's value may be different from that of CABIN_LIGHTS_STATE.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues must be defined unless all enum values of VehicleLightState are supported."
+                "description": "Steering wheel lights state\nRepresents the current state of the steering wheel lights. This is different from STEERING_WHEEL_LIGHTS_SWITCH which represents the position of the switch controlling the lights. Therefore, STEERING_WHEEL_LIGHTS_STATE may not match the value of STEERING_WHEEL_LIGHTS_SWITCH (e.g. STEERING_WHEEL_LIGHTS_SWITCH=AUTOMATIC and STEERING_WHEEL_LIGHTS_STATE=ON).\nThis property should only be implemented if STEERING_WHEEL_LIGHTS_STATE's value may be different from that of CABIN_LIGHTS_STATE.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues must be defined unless all enum values of VehicleLightState are supported.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} unless all enum values of VehicleLightState are supported. At boot, the supported values list is the same as supportedEnumValues."
             },
             {
                 "name": "Steering wheel lights switch",
@@ -1185,7 +1185,7 @@
                     "VehicleLightSwitch"
                 ],
                 "data_enum": "VehicleLightSwitch",
-                "description": "Steering wheel lights switch\nRepresents the position of the switch controlling the steering wheel lights. This is different from STEERING_WHEEL_LIGHTS_STATE which represents the current state of the steering wheel lights. Therefore, STEERING_WHEEL_LIGHTS_SWITCH may not match the value of STEERING_WHEEL_LIGHTS_STATE (e.g. STEERING_WHEEL_LIGHTS_SWITCH=AUTOMATIC and STEERING_WHEEL_LIGHTS_STATE=ON).\nThis property should only be implemented if STEERING_WHEEL_LIGHTS_SWITCH's value may be different from that of CABIN_LIGHTS_SWITCH.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues must be defined unless all enum values of VehicleLightSwitch are supported.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Steering wheel lights switch\nRepresents the position of the switch controlling the steering wheel lights. This is different from STEERING_WHEEL_LIGHTS_STATE which represents the current state of the steering wheel lights. Therefore, STEERING_WHEEL_LIGHTS_SWITCH may not match the value of STEERING_WHEEL_LIGHTS_STATE (e.g. STEERING_WHEEL_LIGHTS_SWITCH=AUTOMATIC and STEERING_WHEEL_LIGHTS_STATE=ON).\nThis property should only be implemented if STEERING_WHEEL_LIGHTS_SWITCH's value may be different from that of CABIN_LIGHTS_SWITCH.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues must be defined unless all enum values of VehicleLightSwitch are supported.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} unless all enum values of VehicleLightSwitch are supported. At boot, the supported values list is the same as supportedEnumValues.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "SUPPORT_CUSTOMIZE_VENDOR_PERMISSION",
@@ -1428,7 +1428,7 @@
                     "VehicleAutonomousState"
                 ],
                 "data_enum": "VehicleAutonomousState",
-                "description": "Current state of vehicle autonomy.\nDefines the level of autonomy currently engaged in the vehicle from the J3016_202104 revision of the SAE standard levels 0-5, with 0 representing no autonomy and 5 representing full driving automation.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of VehicleAutonomousState are supported."
+                "description": "Current state of vehicle autonomy.\nDefines the level of autonomy currently engaged in the vehicle from the J3016_202104 revision of the SAE standard levels 0-5, with 0 representing no autonomy and 5 representing full driving automation.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of VehicleAutonomousState are supported.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} unless all enum values of VehicleAutonomousState are supported. At boot, the supported values list is the same as supportedEnumValues."
             },
             {
                 "name": "VEHICLE_DRIVING_AUTOMATION_TARGET_LEVEL",
@@ -1466,7 +1466,7 @@
                     "ErrorState"
                 ],
                 "data_enum": "AutomaticEmergencyBrakingState",
-                "description": "Automatic Emergency Braking (AEB) state.\nReturns the current state of AEB. This property must always return a valid state defined in AutomaticEmergencyBrakingState or ErrorState. It must not surface errors through StatusCode and must use the supported error states instead. This property should apply for higher speed applications only. For representing the state of the low speed automatic emergency braking system, LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE should be used.\nIf AEB includes forward collision warnings before activating the brakes, those warnings must be surfaced through the Forward Collision Warning (FCW) properties.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both AutomaticEmergencyBrakingState (including OTHER, which is not recommended) and ErrorState are supported."
+                "description": "Automatic Emergency Braking (AEB) state.\nReturns the current state of AEB. This property must always return a valid state defined in AutomaticEmergencyBrakingState or ErrorState. It must not surface errors through StatusCode and must use the supported error states instead. This property should apply for higher speed applications only. For representing the state of the low speed automatic emergency braking system, LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE should be used.\nIf AEB includes forward collision warnings before activating the brakes, those warnings must be surfaced through the Forward Collision Warning (FCW) properties.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both AutomaticEmergencyBrakingState (including OTHER, which is not recommended) and ErrorState are supported.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} unless all states of both AutomaticEmergencyBrakingState (including OTHER, which is not recommended) and ErrorState are supported. At boot, the supported values list is the same as supportedEnumValues."
             },
             {
                 "name": "FORWARD_COLLISION_WARNING_ENABLED",
@@ -1481,7 +1481,7 @@
                     "ErrorState"
                 ],
                 "data_enum": "ForwardCollisionWarningState",
-                "description": "Forward Collision Warning (FCW) state.\nReturns the current state of FCW. This property must always return a valid state defined in ForwardCollisionWarningState or ErrorState. It must not surface errors through StatusCode and must use the supported error states instead.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both ForwardCollisionWarningState (including OTHER, which is not recommended) and ErrorState are supported."
+                "description": "Forward Collision Warning (FCW) state.\nReturns the current state of FCW. This property must always return a valid state defined in ForwardCollisionWarningState or ErrorState. It must not surface errors through StatusCode and must use the supported error states instead.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both ForwardCollisionWarningState (including OTHER, which is not recommended) and ErrorState are supported.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} unless all states of both ForwardCollisionWarningState (including OTHER, which is not recommended) and ErrorState are supported. At boot, the supported values list is the same as supportedEnumValues."
             },
             {
                 "name": "BLIND_SPOT_WARNING_ENABLED",
@@ -1496,7 +1496,7 @@
                     "ErrorState"
                 ],
                 "data_enum": "BlindSpotWarningState",
-                "description": "Blind Spot Warning (BSW) state.\nReturns the current state of BSW. This property must always return a valid state defined in BlindSpotWarningState or ErrorState. It must not surface errors through StatusCode and must use the supported error states instead.\nFor each supported area ID, the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both BlindSpotWarningState (including OTHER, which is not recommended) and ErrorState are supported."
+                "description": "Blind Spot Warning (BSW) state.\nReturns the current state of BSW. This property must always return a valid state defined in BlindSpotWarningState or ErrorState. It must not surface errors through StatusCode and must use the supported error states instead.\nFor each supported area ID, the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both BlindSpotWarningState (including OTHER, which is not recommended) and ErrorState are supported.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} unless all states of both BlindSpotWarningState (including OTHER, which is not recommended) and ErrorState are supported. At boot, the supported values list is the same as supportedEnumValues."
             },
             {
                 "name": "LANE_DEPARTURE_WARNING_ENABLED",
@@ -1511,7 +1511,7 @@
                     "ErrorState"
                 ],
                 "data_enum": "LaneDepartureWarningState",
-                "description": "Lane Departure Warning (LDW) state.\nReturns the current state of LDW. This property must always return a valid state defined in LaneDepartureWarningState or ErrorState. It must not surface errors through StatusCode and must use the supported error states instead.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both LaneDepartureWarningState (including OTHER, which is not recommended) and ErrorState are supported."
+                "description": "Lane Departure Warning (LDW) state.\nReturns the current state of LDW. This property must always return a valid state defined in LaneDepartureWarningState or ErrorState. It must not surface errors through StatusCode and must use the supported error states instead.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both LaneDepartureWarningState (including OTHER, which is not recommended) and ErrorState are supported.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} unless all states of both LaneDepartureWarningState (including OTHER, which is not recommended) and ErrorState are supported. At boot, the supported values list is the same as supportedEnumValues."
             },
             {
                 "name": "LANE_KEEP_ASSIST_ENABLED",
@@ -1526,7 +1526,7 @@
                     "ErrorState"
                 ],
                 "data_enum": "LaneKeepAssistState",
-                "description": "Lane Keep Assist (LKA) state.\nReturns the current state of LKA. This property must always return a valid state defined in LaneKeepAssistState or ErrorState. It must not surface errors through StatusCode and must use the supported error states instead.\nIf LKA includes lane departure warnings before applying steering corrections, those warnings must be surfaced through the Lane Departure Warning (LDW) properties.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both LaneKeepAssistState (including OTHER, which is not recommended) and ErrorState are supported."
+                "description": "Lane Keep Assist (LKA) state.\nReturns the current state of LKA. This property must always return a valid state defined in LaneKeepAssistState or ErrorState. It must not surface errors through StatusCode and must use the supported error states instead.\nIf LKA includes lane departure warnings before applying steering corrections, those warnings must be surfaced through the Lane Departure Warning (LDW) properties.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both LaneKeepAssistState (including OTHER, which is not recommended) and ErrorState are supported.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} unless all states of both LaneKeepAssistState (including OTHER, which is not recommended) and ErrorState are supported. At boot, the supported values list is the same as supportedEnumValues."
             },
             {
                 "name": "LANE_CENTERING_ASSIST_ENABLED",
@@ -1540,7 +1540,7 @@
                     "LaneCenteringAssistCommand"
                 ],
                 "data_enum": "LaneCenteringAssistCommand",
-                "description": "Lane Centering Assist (LCA) commands.\nCommands to activate and suspend LCA.\nWhen the command ACTIVATE from LaneCenteringAssistCommand is sent, LANE_CENTERING_ASSIST_STATE must be set to LaneCenteringAssistState#ACTIVATION_REQUESTED. When the ACTIVATE command succeeds, LANE_CENTERING_ASSIST_STATE must be set to LaneCenteringAssistState#ACTIVATED. When the command DEACTIVATE from LaneCenteringAssistCommand succeeds, LANE_CENTERING_ASSIST_STATE must be set to LaneCenteringAssistState#ENABLED.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues must be defined unless all enum values of LaneCenteringAssistCommand are supported.\nWhen this property is not available because LCA is disabled (i.e. LANE_CENTERING_ASSIST_ENABLED is false), this property must return StatusCode#NOT_AVAILABLE_DISABLED. If LANE_CENTERING_ASSIST_STATE is implemented and the state is set to an ErrorState value, then this property must return a StatusCode that aligns with the ErrorState value. For example, if LANE_CENTERING_ASSIST_STATE is set to ErrorState#NOT_AVAILABLE_SPEED_LOW, then this property must return StatusCode#NOT_AVAILABLE_SPEED_LOW."
+                "description": "Lane Centering Assist (LCA) commands.\nCommands to activate and suspend LCA.\nWhen the command ACTIVATE from LaneCenteringAssistCommand is sent, LANE_CENTERING_ASSIST_STATE must be set to LaneCenteringAssistState#ACTIVATION_REQUESTED. When the ACTIVATE command succeeds, LANE_CENTERING_ASSIST_STATE must be set to LaneCenteringAssistState#ACTIVATED. When the command DEACTIVATE from LaneCenteringAssistCommand succeeds, LANE_CENTERING_ASSIST_STATE must be set to LaneCenteringAssistState#ENABLED.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues must be defined unless all enum values of LaneCenteringAssistCommand are supported.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} unless all enum values of LaneCenteringAssistCommand are supported. At boot, the supported values list is the same as supportedEnumValues.\nWhen this property is not available because LCA is disabled (i.e. LANE_CENTERING_ASSIST_ENABLED is false), this property must return StatusCode#NOT_AVAILABLE_DISABLED. If LANE_CENTERING_ASSIST_STATE is implemented and the state is set to an ErrorState value, then this property must return a StatusCode that aligns with the ErrorState value. For example, if LANE_CENTERING_ASSIST_STATE is set to ErrorState#NOT_AVAILABLE_SPEED_LOW, then this property must return StatusCode#NOT_AVAILABLE_SPEED_LOW."
             },
             {
                 "name": "LANE_CENTERING_ASSIST_STATE",
@@ -1550,7 +1550,7 @@
                     "ErrorState"
                 ],
                 "data_enum": "LaneCenteringAssistState",
-                "description": "Lane Centering Assist (LCA) state.\nReturns the current state of LCA. This property must always return a valid state defined in LaneCenteringAssistState or ErrorState. It must not surface errors through StatusCode and must use the supported error states instead.\nIf LCA includes lane departure warnings, those warnings must be surfaced through the Lane Departure Warning (LDW) properties.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both LaneCenteringAssistState (including OTHER, which is not recommended) and ErrorState are supported."
+                "description": "Lane Centering Assist (LCA) state.\nReturns the current state of LCA. This property must always return a valid state defined in LaneCenteringAssistState or ErrorState. It must not surface errors through StatusCode and must use the supported error states instead.\nIf LCA includes lane departure warnings, those warnings must be surfaced through the Lane Departure Warning (LDW) properties.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both LaneCenteringAssistState (including OTHER, which is not recommended) and ErrorState are supported.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} unless all states of both LaneCenteringAssistState (including OTHER, which is not recommended) and ErrorState are supported. At boot, the supported values list is the same as supportedEnumValues."
             },
             {
                 "name": "EMERGENCY_LANE_KEEP_ASSIST_ENABLED",
@@ -1565,7 +1565,7 @@
                     "ErrorState"
                 ],
                 "data_enum": "EmergencyLaneKeepAssistState",
-                "description": "Emergency Lane Keep Assist (ELKA) state.\nReturns the current state of ELKA. Generally, this property should return a valid state defined in the EmergencyLaneKeepAssistState or ErrorState. For example, if the feature is not available due to some temporary state, that information should be conveyed through ErrorState.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of EmergencyLaneKeepAssistState (including OTHER, which is not recommended) and ErrorState are supported."
+                "description": "Emergency Lane Keep Assist (ELKA) state.\nReturns the current state of ELKA. Generally, this property should return a valid state defined in the EmergencyLaneKeepAssistState or ErrorState. For example, if the feature is not available due to some temporary state, that information should be conveyed through ErrorState.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of EmergencyLaneKeepAssistState (including OTHER, which is not recommended) and ErrorState are supported.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} unless all states of EmergencyLaneKeepAssistState (including OTHER, which is not recommended) and ErrorState are supported. At boot, the supported values list is the same as supportedEnumValues."
             },
             {
                 "name": "CRUISE_CONTROL_ENABLED",
@@ -1580,7 +1580,7 @@
                     "ErrorState"
                 ],
                 "data_enum": "CruiseControlType",
-                "description": "Current type of Cruise Control (CC).\nWhen CRUISE_CONTROL_ENABLED is true, this property returns the type of CC that is currently enabled (for example, standard CC, adaptive CC, predictive CC, etc.). Generally, this property should return a valid state defined in the CruiseControlType or ErrorState. For example, if the feature is not available due to some temporary state, that information should be conveyed through ErrorState.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of CruiseControlType (including OTHER, which is not recommended) and ErrorState are supported.\nTrying to write CruiseControlType#OTHER or an ErrorState to this property will throw an IllegalArgumentException.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
+                "description": "Current type of Cruise Control (CC).\nWhen CRUISE_CONTROL_ENABLED is true, this property returns the type of CC that is currently enabled (for example, standard CC, adaptive CC, predictive CC, etc.). Generally, this property should return a valid state defined in the CruiseControlType or ErrorState. For example, if the feature is not available due to some temporary state, that information should be conveyed through ErrorState.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of CruiseControlType (including OTHER, which is not recommended) and ErrorState are supported.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} unless all states of CruiseControlType (including OTHER, which is not recommended) and ErrorState are supported. At boot, the supported values list is the same as supportedEnumValues.\nTrying to write CruiseControlType#OTHER or an ErrorState to this property will throw an IllegalArgumentException.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
             },
             {
                 "name": "CRUISE_CONTROL_STATE",
@@ -1590,7 +1590,7 @@
                     "ErrorState"
                 ],
                 "data_enum": "CruiseControlState",
-                "description": "Current state of Cruise Control (CC).\nThis property returns the current state of CC. Generally, this property should return a valid state defined in the CruiseControlState or ErrorState. For example, if the feature is not available due to some temporary state, that information should be conveyed through ErrorState.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of CruiseControlState (including OTHER, which is not recommended) and ErrorState are supported."
+                "description": "Current state of Cruise Control (CC).\nThis property returns the current state of CC. Generally, this property should return a valid state defined in the CruiseControlState or ErrorState. For example, if the feature is not available due to some temporary state, that information should be conveyed through ErrorState.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of CruiseControlState (including OTHER, which is not recommended) and ErrorState are supported.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} unless all states of CruiseControlState (including OTHER, which is not recommended) and ErrorState are supported. At boot, the supported values list is the same as supportedEnumValues."
             },
             {
                 "name": "CRUISE_CONTROL_COMMAND",
@@ -1599,7 +1599,7 @@
                     "CruiseControlCommand"
                 ],
                 "data_enum": "CruiseControlCommand",
-                "description": "Write Cruise Control (CC) commands.\nSee CruiseControlCommand for the details about each supported command.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of CruiseControlState are supported. Any unsupported commands sent through this property must return StatusCode#INVALID_ARG.\nWhen this property is not available because CC is disabled (i.e. CRUISE_CONTROL_ENABLED is false), this property must return StatusCode#NOT_AVAILABLE_DISABLED. If CRUISE_CONTROL_STATE is implemented and the state is set to an ErrorState value, then this property must return a StatusCode that aligns with the ErrorState value. For example, if CRUISE_CONTROL_STATE is set to ErrorState#NOT_AVAILABLE_SPEED_LOW, then this property must return StatusCode#NOT_AVAILABLE_SPEED_LOW."
+                "description": "Write Cruise Control (CC) commands.\nSee CruiseControlCommand for the details about each supported command.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of CruiseControlState are supported. Any unsupported commands sent through this property must return StatusCode#INVALID_ARG.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} unless all states of CruiseControlState are supported. At boot, the supported values list is the same as supportedEnumValues.\nWhen this property is not available because CC is disabled (i.e. CRUISE_CONTROL_ENABLED is false), this property must return StatusCode#NOT_AVAILABLE_DISABLED. If CRUISE_CONTROL_STATE is implemented and the state is set to an ErrorState value, then this property must return a StatusCode that aligns with the ErrorState value. For example, if CRUISE_CONTROL_STATE is set to ErrorState#NOT_AVAILABLE_SPEED_LOW, then this property must return StatusCode#NOT_AVAILABLE_SPEED_LOW."
             },
             {
                 "name": "CRUISE_CONTROL_TARGET_SPEED",
@@ -1629,7 +1629,7 @@
                     "ErrorState"
                 ],
                 "data_enum": "HandsOnDetectionDriverState",
-                "description": "Hands On Detection (HOD) driver state.\nReturns whether the driver's hands are on the steering wheel. Generally, this property should return a valid state defined in the HandsOnDetectionDriverState or ErrorState. For example, if the feature is not available due to some temporary state, that information should be conveyed through ErrorState.\nIf the vehicle wants to send a warning to the user because the driver's hands have been off the steering wheel for too long, the warning should be surfaced through HANDS_ON_DETECTION_WARNING.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both HandsOnDetectionDriverState (including OTHER, which is not recommended) and ErrorState are supported."
+                "description": "Hands On Detection (HOD) driver state.\nReturns whether the driver's hands are on the steering wheel. Generally, this property should return a valid state defined in the HandsOnDetectionDriverState or ErrorState. For example, if the feature is not available due to some temporary state, that information should be conveyed through ErrorState.\nIf the vehicle wants to send a warning to the user because the driver's hands have been off the steering wheel for too long, the warning should be surfaced through HANDS_ON_DETECTION_WARNING.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both HandsOnDetectionDriverState (including OTHER, which is not recommended) and ErrorState are supported.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} unless all states of both HandsOnDetectionDriverState (including OTHER, which is not recommended) and ErrorState are supported. At boot, the supported values list is the same as supportedEnumValues."
             },
             {
                 "name": "HANDS_ON_DETECTION_WARNING",
@@ -1639,7 +1639,7 @@
                     "ErrorState"
                 ],
                 "data_enum": "HandsOnDetectionWarning",
-                "description": "Hands On Detection (HOD) warning.\nReturns whether a warning is being sent to the driver for having their hands off the wheel for too long a duration.\nGenerally, this property should return a valid state defined in HandsOnDetectionWarning or ErrorState. For example, if the feature is not available due to some temporary state, that information should be conveyed through an ErrorState.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both HandsOnDetectionWarning (including OTHER, which is not recommended) and ErrorState are supported."
+                "description": "Hands On Detection (HOD) warning.\nReturns whether a warning is being sent to the driver for having their hands off the wheel for too long a duration.\nGenerally, this property should return a valid state defined in HandsOnDetectionWarning or ErrorState. For example, if the feature is not available due to some temporary state, that information should be conveyed through an ErrorState.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both HandsOnDetectionWarning (including OTHER, which is not recommended) and ErrorState are supported.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} unless all states of both HandsOnDetectionWarning (including OTHER, which is not recommended) and ErrorState are supported. At boot, the supported values list is the same as supportedEnumValues."
             },
             {
                 "name": "DRIVER_DROWSINESS_ATTENTION_SYSTEM_ENABLED",
@@ -1654,7 +1654,7 @@
                     "ErrorState"
                 ],
                 "data_enum": "DriverDrowsinessAttentionState",
-                "description": "Driver drowsiness and attention level state.\nReturns the current detected state of driver drowiness and attention level based on the Karolinska Sleepiness scale. If alternative measurement methods are used, the value should be translated to the Karolinska Sleepiness Scale equivalent.\nGenerally, this property should return a valid state defined in the DriverDrowsinessAttentionState or ErrorState. For example, if the feature is not available due to some temporary state, that information should be conveyed through ErrorState.\nIf the vehicle is sending a warning to the user because the driver is too drowsy, the warning should be surfaced through {@link #DRIVER_DROWSINESS_ATTENTION_WARNING}.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both DriverDrowsinessAttentionState (including OTHER, which is not recommended) and ErrorState are supported."
+                "description": "Driver drowsiness and attention level state.\nReturns the current detected state of driver drowiness and attention level based on the Karolinska Sleepiness scale. If alternative measurement methods are used, the value should be translated to the Karolinska Sleepiness Scale equivalent.\nGenerally, this property should return a valid state defined in the DriverDrowsinessAttentionState or ErrorState. For example, if the feature is not available due to some temporary state, that information should be conveyed through ErrorState.\nIf the vehicle is sending a warning to the user because the driver is too drowsy, the warning should be surfaced through {@link #DRIVER_DROWSINESS_ATTENTION_WARNING}.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both DriverDrowsinessAttentionState (including OTHER, which is not recommended) and ErrorState are supported.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} unless all states of both DriverDrowsinessAttentionState (including OTHER, which is not recommended) and ErrorState are supported. At boot, the supported values list is the same as supportedEnumValues."
             },
             {
                 "name": "DRIVER_DROWSINESS_ATTENTION_WARNING_ENABLED",
@@ -1669,7 +1669,7 @@
                     "ErrorState"
                 ],
                 "data_enum": "DriverDrowsinessAttentionWarning",
-                "description": "Driver drowsiness and attention warning.\nReturns whether a warning is being sent to the driver for being drowsy or not attentive.\nGenerally, this property should return a valid state defined in DriverDrowsinessAttentionWarning or ErrorState. For example, if the feature is not available due to some temporary state, that information should be conveyed through an ErrorState.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both DriverDrowsinessAttentionWarning (including OTHER, which is not recommended) and ErrorState are supported."
+                "description": "Driver drowsiness and attention warning.\nReturns whether a warning is being sent to the driver for being drowsy or not attentive.\nGenerally, this property should return a valid state defined in DriverDrowsinessAttentionWarning or ErrorState. For example, if the feature is not available due to some temporary state, that information should be conveyed through an ErrorState.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both DriverDrowsinessAttentionWarning (including OTHER, which is not recommended) and ErrorState are supported.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} unless all states of both DriverDrowsinessAttentionWarning (including OTHER, which is not recommended) and ErrorState are supported. At boot, the supported values list is the same as supportedEnumValues."
             },
             {
                 "name": "DRIVER_DISTRACTION_SYSTEM_ENABLED",
@@ -1684,7 +1684,7 @@
                     "ErrorState"
                 ],
                 "data_enum": "DriverDistractionState",
-                "description": "Driver distraction state.\nReturns the current detected driver distraction state.\nGenerally, this property should return a valid state defined in the DriverDistractionState or ErrorState. For example, if the feature is not available due to some temporary state, that information should be conveyed through ErrorState.\nIf the vehicle is sending a warning to the user because the driver is too distracted, the warning should be surfaced through {@link #DRIVER_DISTRACTION_WARNING}.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both DriverDistractionState (including OTHER, which is not recommended) and ErrorState are supported."
+                "description": "Driver distraction state.\nReturns the current detected driver distraction state.\nGenerally, this property should return a valid state defined in the DriverDistractionState or ErrorState. For example, if the feature is not available due to some temporary state, that information should be conveyed through ErrorState.\nIf the vehicle is sending a warning to the user because the driver is too distracted, the warning should be surfaced through {@link #DRIVER_DISTRACTION_WARNING}.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both DriverDistractionState (including OTHER, which is not recommended) and ErrorState are supported.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} unless all states of both DriverDistractionState (including OTHER, which is not recommended) and ErrorState are supported. At boot, the supported values list is the same as supportedEnumValues."
             },
             {
                 "name": "DRIVER_DISTRACTION_WARNING_ENABLED",
@@ -1699,7 +1699,7 @@
                     "ErrorState"
                 ],
                 "data_enum": "DriverDistractionWarning",
-                "description": "Driver distraction warning.\nReturns whether a warning is being sent to the driver for being distracted.\nGenerally, this property should return a valid state defined in DriverDistractionWarning or ErrorState. For example, if the feature is not available due to some temporary state, that information should be conveyed through an ErrorState.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both DriverDistractionWarning (including OTHER, which is not recommended) and ErrorState are supported."
+                "description": "Driver distraction warning.\nReturns whether a warning is being sent to the driver for being distracted.\nGenerally, this property should return a valid state defined in DriverDistractionWarning or ErrorState. For example, if the feature is not available due to some temporary state, that information should be conveyed through an ErrorState.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both DriverDistractionWarning (including OTHER, which is not recommended) and ErrorState are supported.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} unless all states of both DriverDistractionWarning (including OTHER, which is not recommended) and ErrorState are supported. At boot, the supported values list is the same as supportedEnumValues."
             },
             {
                 "name": "LOW_SPEED_COLLISION_WARNING_ENABLED",
@@ -1714,7 +1714,7 @@
                     "ErrorState"
                 ],
                 "data_enum": "LowSpeedCollisionWarningState",
-                "description": "Low Speed Collision Warning state.\nReturns the current state of Low Speed Collision Warning. This property must always return a valid state defined in LowSpeedCollisionWarningState or ErrorState. It must not surface errors through StatusCode and must use the supported error states instead. This property is different from the pre-existing FORWARD_COLLISION_WARNING_STATE, which should apply to higher speed applications only. If the vehicle doesn't have a separate collision detection system for low speed environments, this property should not be implemented.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both LowSpeedCollisionWarningState (including OTHER, which is not recommended) and ErrorState are supported."
+                "description": "Low Speed Collision Warning state.\nReturns the current state of Low Speed Collision Warning. This property must always return a valid state defined in LowSpeedCollisionWarningState or ErrorState. It must not surface errors through StatusCode and must use the supported error states instead. This property is different from the pre-existing FORWARD_COLLISION_WARNING_STATE, which should apply to higher speed applications only. If the vehicle doesn't have a separate collision detection system for low speed environments, this property should not be implemented.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both LowSpeedCollisionWarningState (including OTHER, which is not recommended) and ErrorState are supported.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} unless all states of both LowSpeedCollisionWarningState (including OTHER, which is not recommended) and ErrorState are supported. At boot, the supported values list is the same as supportedEnumValues."
             },
             {
                 "name": "CROSS_TRAFFIC_MONITORING_ENABLED",
@@ -1729,7 +1729,7 @@
                     "ErrorState"
                 ],
                 "data_enum": "CrossTrafficMonitoringWarningState",
-                "description": "Cross Traffic Monitoring warning state.\nReturns the current state of Cross Traffic Monitoring Warning. This property must always return a valid state defined in CrossTrafficMonitoringWarningState or ErrorState. It must not surface errors through StatusCode and must use the supported error states instead.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both CrossTrafficMonitoringWarningState (including OTHER, which is not recommended) and ErrorState are supported."
+                "description": "Cross Traffic Monitoring warning state.\nReturns the current state of Cross Traffic Monitoring Warning. This property must always return a valid state defined in CrossTrafficMonitoringWarningState or ErrorState. It must not surface errors through StatusCode and must use the supported error states instead.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both CrossTrafficMonitoringWarningState (including OTHER, which is not recommended) and ErrorState are supported.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} unless all states of both CrossTrafficMonitoringWarningState (including OTHER, which is not recommended) and ErrorState are supported. At boot, the supported values list is the same as supportedEnumValues."
             },
             {
                 "name": "LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED",
@@ -1744,7 +1744,7 @@
                     "ErrorState"
                 ],
                 "data_enum": "LowSpeedAutomaticEmergencyBrakingState",
-                "description": "Low Speed Automatic Emergency Braking state.\nReturns the current state of Low Speed Automatic Emergency Braking. This property must always return a valid state defined in LowSpeedAutomaticEmergencyBrakingState or ErrorState. It must not surface errors through StatusCode and must use the supported error states instead. This property is different from the pre-existing AUTOMATIC_EMERGENCY_BRAKING_STATE, which should apply to higher speed applications only. If the vehicle doesn't have a separate collision avoidance system for low speed environments, this property should not be implemented.\nIf Low Speed Automatic Emergency Braking includes collision warnings before activating the brakes, those warnings must be surfaced through use of LOW_SPEED_COLLISION_WARNING_ENABLED and LOW_SPEED_COLLISION_WARNING_STATE.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both LowSpeedAutomaticEmergencyBrakingState (including OTHER, which is not recommended) and ErrorState are supported."
+                "description": "Low Speed Automatic Emergency Braking state.\nReturns the current state of Low Speed Automatic Emergency Braking. This property must always return a valid state defined in LowSpeedAutomaticEmergencyBrakingState or ErrorState. It must not surface errors through StatusCode and must use the supported error states instead. This property is different from the pre-existing AUTOMATIC_EMERGENCY_BRAKING_STATE, which should apply to higher speed applications only. If the vehicle doesn't have a separate collision avoidance system for low speed environments, this property should not be implemented.\nIf Low Speed Automatic Emergency Braking includes collision warnings before activating the brakes, those warnings must be surfaced through use of LOW_SPEED_COLLISION_WARNING_ENABLED and LOW_SPEED_COLLISION_WARNING_STATE.\nFor the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined unless all states of both LowSpeedAutomaticEmergencyBrakingState (including OTHER, which is not recommended) and ErrorState are supported.\nIf {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}: {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} unless all states of both LowSpeedAutomaticEmergencyBrakingState (including OTHER, which is not recommended) and ErrorState are supported. At boot, the supported values list is the same as supportedEnumValues."
             }
         ]
     },
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/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp b/automotive/vehicle/aidl/impl/current/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
index 7a1f0e0..f910beb 100644
--- a/automotive/vehicle/aidl/impl/current/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
+++ b/automotive/vehicle/aidl/impl/current/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
@@ -58,6 +58,7 @@
 using ::aidl::android::hardware::automotive::vehicle::GsrComplianceRequirementType;
 using ::aidl::android::hardware::automotive::vehicle::HandsOnDetectionDriverState;
 using ::aidl::android::hardware::automotive::vehicle::HandsOnDetectionWarning;
+using ::aidl::android::hardware::automotive::vehicle::HasSupportedValueInfo;
 using ::aidl::android::hardware::automotive::vehicle::ImpactSensorLocation;
 using ::aidl::android::hardware::automotive::vehicle::LaneCenteringAssistCommand;
 using ::aidl::android::hardware::automotive::vehicle::LaneCenteringAssistState;
@@ -600,6 +601,22 @@
         if (!supportedEnumValues.empty()) {
             areaConfig.supportedEnumValues = std::move(supportedEnumValues);
         }
+
+        if (jsonAreaConfig.isMember("hasSupportedValueInfo")) {
+            HasSupportedValueInfo hasSupportedValueInfo = HasSupportedValueInfo{};
+            const Json::Value& jsonHasSupportedValueInfo = jsonAreaConfig["hasSupportedValueInfo"];
+            tryParseJsonValueToVariable(jsonHasSupportedValueInfo, "hasMinSupportedValue",
+                                        /*optional=*/true,
+                                        &hasSupportedValueInfo.hasMinSupportedValue, errors);
+            tryParseJsonValueToVariable(jsonHasSupportedValueInfo, "hasMaxSupportedValue",
+                                        /*optional=*/true,
+                                        &hasSupportedValueInfo.hasMaxSupportedValue, errors);
+            tryParseJsonValueToVariable(jsonHasSupportedValueInfo, "hasSupportedValuesList",
+                                        /*optional=*/true,
+                                        &hasSupportedValueInfo.hasSupportedValuesList, errors);
+            areaConfig.hasSupportedValueInfo = std::move(hasSupportedValueInfo);
+        }
+
         config->config.areaConfigs.push_back(std::move(areaConfig));
 
         RawPropValues areaValue = {};
diff --git a/automotive/vehicle/aidl/impl/current/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp b/automotive/vehicle/aidl/impl/current/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp
index 54afbd4..595c2ed 100644
--- a/automotive/vehicle/aidl/impl/current/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp
+++ b/automotive/vehicle/aidl/impl/current/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp
@@ -26,6 +26,7 @@
 namespace automotive {
 namespace vehicle {
 
+using ::aidl::android::hardware::automotive::vehicle::HasSupportedValueInfo;
 using ::aidl::android::hardware::automotive::vehicle::RawPropValues;
 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
@@ -803,6 +804,108 @@
     ASSERT_EQ(areaConfig2.areaId, 1);
 }
 
+TEST_F(JsonConfigLoaderUnitTest, testHasSupportedValueInfo_allTrue) {
+    std::istringstream iss(R"(
+    {
+        "properties": [{
+            "property": "VehicleProperty::CABIN_LIGHTS_SWITCH",
+            "areas": [{
+                "access": "VehiclePropertyAccess::WRITE",
+                "areaId": 0,
+                "hasSupportedValueInfo": {
+                    "hasMinSupportedValue": true,
+                    "hasMaxSupportedValue": true,
+                    "hasSupportedValuesList": true
+                }
+            }],
+            "access": "VehiclePropertyAccess::READ",
+        }]
+    }
+    )");
+
+    auto result = mLoader.loadPropConfig(iss);
+    ASSERT_TRUE(result.ok());
+
+    auto configs = result.value();
+    ASSERT_EQ(configs.size(), 1u);
+
+    const VehiclePropConfig& config = configs.begin()->second.config;
+    ASSERT_EQ(config.access, VehiclePropertyAccess::READ);
+    ASSERT_EQ(config.areaConfigs.size(), 1u);
+
+    const VehicleAreaConfig& areaConfig = config.areaConfigs[0];
+    ASSERT_EQ(areaConfig.hasSupportedValueInfo, HasSupportedValueInfo({
+                                                        .hasMinSupportedValue = true,
+                                                        .hasMaxSupportedValue = true,
+                                                        .hasSupportedValuesList = true,
+                                                }));
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testHasSupportedValueInfo_allFalse) {
+    std::istringstream iss(R"(
+    {
+        "properties": [{
+            "property": "VehicleProperty::CABIN_LIGHTS_SWITCH",
+            "areas": [{
+                "access": "VehiclePropertyAccess::WRITE",
+                "areaId": 0,
+                "hasSupportedValueInfo": {
+                    "hasMinSupportedValue": false,
+                    "hasMaxSupportedValue": false,
+                    "hasSupportedValuesList": false
+                }
+            }],
+            "access": "VehiclePropertyAccess::READ",
+        }]
+    }
+    )");
+
+    auto result = mLoader.loadPropConfig(iss);
+    ASSERT_TRUE(result.ok());
+
+    auto configs = result.value();
+    ASSERT_EQ(configs.size(), 1u);
+
+    const VehiclePropConfig& config = configs.begin()->second.config;
+    ASSERT_EQ(config.access, VehiclePropertyAccess::READ);
+    ASSERT_EQ(config.areaConfigs.size(), 1u);
+
+    const VehicleAreaConfig& areaConfig = config.areaConfigs[0];
+    ASSERT_EQ(areaConfig.hasSupportedValueInfo, HasSupportedValueInfo({
+                                                        .hasMinSupportedValue = false,
+                                                        .hasMaxSupportedValue = false,
+                                                        .hasSupportedValuesList = false,
+                                                }));
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testHasSupportedValueInfo_unspecified) {
+    std::istringstream iss(R"(
+    {
+        "properties": [{
+            "property": "VehicleProperty::CABIN_LIGHTS_SWITCH",
+            "areas": [{
+                "access": "VehiclePropertyAccess::WRITE",
+                "areaId": 0
+            }],
+            "access": "VehiclePropertyAccess::READ",
+        }]
+    }
+    )");
+
+    auto result = mLoader.loadPropConfig(iss);
+    ASSERT_TRUE(result.ok());
+
+    auto configs = result.value();
+    ASSERT_EQ(configs.size(), 1u);
+
+    const VehiclePropConfig& config = configs.begin()->second.config;
+    ASSERT_EQ(config.access, VehiclePropertyAccess::READ);
+    ASSERT_EQ(config.areaConfigs.size(), 1u);
+
+    const VehicleAreaConfig& areaConfig = config.areaConfigs[0];
+    ASSERT_EQ(areaConfig.hasSupportedValueInfo, std::nullopt);
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/current/default_config/config/TestProperties.json b/automotive/vehicle/aidl/impl/current/default_config/config/TestProperties.json
index 73e4d44..83debf7 100644
--- a/automotive/vehicle/aidl/impl/current/default_config/config/TestProperties.json
+++ b/automotive/vehicle/aidl/impl/current/default_config/config/TestProperties.json
@@ -99,12 +99,15 @@
                 {
                     "defaultValue": {
                         "int32Values": [
-                            1
+                            2
                         ]
                     },
                     "areaId": "VehicleAreaWindow::FRONT_WINDSHIELD",
-                    "minInt32Value": -100,
-                    "maxInt32Value": 100
+                    "hasSupportedValueInfo": {
+                        "hasMinSupportedValue": true,
+                        "hasMaxSupportedValue": true,
+                        "hasSupportedValuesList": true
+                    }
                 },
                 {
                     "defaultValue": {
diff --git a/automotive/vehicle/aidl/impl/current/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/current/fake_impl/hardware/include/FakeVehicleHardware.h
index 5916307..b7ada62 100644
--- a/automotive/vehicle/aidl/impl/current/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/current/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -108,6 +108,12 @@
     aidl::android::hardware::automotive::vehicle::StatusCode unsubscribe(int32_t propId,
                                                                          int32_t areaId) override;
 
+    std::vector<aidlvhal::MinMaxSupportedValueResult> getMinMaxSupportedValues(
+            const std::vector<PropIdAreaId>& propIdAreaIds) override;
+
+    std::vector<aidlvhal::SupportedValuesListResult> getSupportedValuesLists(
+            const std::vector<PropIdAreaId>& propIdAreaIds) override;
+
   protected:
     // mValuePool is also used in mServerSidePropStore.
     const std::shared_ptr<VehiclePropValuePool> mValuePool;
diff --git a/automotive/vehicle/aidl/impl/current/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/current/fake_impl/hardware/src/FakeVehicleHardware.cpp
index 52daf68..f1aaefc 100644
--- a/automotive/vehicle/aidl/impl/current/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/current/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -62,11 +62,13 @@
 using ::aidl::android::hardware::automotive::vehicle::ErrorState;
 using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
 using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::MinMaxSupportedValueResult;
 using ::aidl::android::hardware::automotive::vehicle::RawPropValues;
 using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
 using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
 using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
+using ::aidl::android::hardware::automotive::vehicle::SupportedValuesListResult;
 using ::aidl::android::hardware::automotive::vehicle::toString;
 using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReport;
 using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq;
@@ -2299,6 +2301,62 @@
     return StatusCode::OK;
 }
 
+std::vector<MinMaxSupportedValueResult> FakeVehicleHardware::getMinMaxSupportedValues(
+        const std::vector<PropIdAreaId>& propIdAreaIds) {
+    std::vector<MinMaxSupportedValueResult> results;
+    // We only support VENDOR_EXTENSION_INT_PROPERTY
+    for (const auto& propIdAreaId : propIdAreaIds) {
+        int propId = propIdAreaId.propId;
+        int areaId = propIdAreaId.areaId;
+        if (propId != toInt(TestVendorProperty::VENDOR_EXTENSION_INT_PROPERTY)) {
+            results.push_back(MinMaxSupportedValueResult{
+                    .status = StatusCode::INVALID_ARG,
+            });
+            continue;
+        }
+        results.push_back(MinMaxSupportedValueResult{
+                .status = StatusCode::OK,
+                .minSupportedValue =
+                        RawPropValues{
+                                .int32Values = {0},
+                        },
+                .maxSupportedValue =
+                        RawPropValues{
+                                .int32Values = {10},
+                        },
+        });
+    }
+    return results;
+}
+
+std::vector<SupportedValuesListResult> FakeVehicleHardware::getSupportedValuesLists(
+        const std::vector<PropIdAreaId>& propIdAreaIds) {
+    std::vector<SupportedValuesListResult> results;
+    // We only support VENDOR_EXTENSION_INT_PROPERTY
+    for (const auto& propIdAreaId : propIdAreaIds) {
+        int propId = propIdAreaId.propId;
+        int areaId = propIdAreaId.areaId;
+        if (propId != toInt(TestVendorProperty::VENDOR_EXTENSION_INT_PROPERTY)) {
+            results.push_back(SupportedValuesListResult{
+                    .status = StatusCode::INVALID_ARG,
+            });
+            continue;
+        }
+        results.push_back(SupportedValuesListResult{
+                .status = StatusCode::OK,
+                .supportedValuesList = std::vector<std::optional<RawPropValues>>({
+                        RawPropValues{.int32Values = {0}},
+                        RawPropValues{.int32Values = {2}},
+                        RawPropValues{.int32Values = {4}},
+                        RawPropValues{.int32Values = {6}},
+                        RawPropValues{.int32Values = {8}},
+                        RawPropValues{.int32Values = {10}},
+                }),
+        });
+    }
+    return results;
+}
+
 bool FakeVehicleHardware::isVariableUpdateRateSupported(const VehiclePropConfig& vehiclePropConfig,
                                                         int32_t areaId) {
     for (size_t i = 0; i < vehiclePropConfig.areaConfigs.size(); i++) {
diff --git a/automotive/vehicle/aidl/impl/current/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/current/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
index f6098ca..29a690b 100644
--- a/automotive/vehicle/aidl/impl/current/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/current/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -3884,6 +3884,44 @@
     }
 }
 
+TEST_F(FakeVehicleHardwareTest, testGetMinMaxSupportedValues) {
+    auto results = getHardware()->getMinMaxSupportedValues({
+            PropIdAreaId{.propId = toInt(TestVendorProperty::VENDOR_EXTENSION_INT_PROPERTY),
+                         .areaId = 0},
+            PropIdAreaId{.propId = toInt(VehicleProperty::HVAC_TEMPERATURE_SET), .areaId = 0},
+    });
+
+    ASSERT_EQ(results.size(), 2u);
+    EXPECT_EQ(results[0].status, StatusCode::OK);
+    EXPECT_NE(results[0].minSupportedValue, std::nullopt);
+    EXPECT_EQ(results[0].minSupportedValue.value(), RawPropValues{.int32Values = {0}});
+    EXPECT_NE(results[0].maxSupportedValue, std::nullopt);
+    EXPECT_EQ(results[0].maxSupportedValue.value(), RawPropValues{.int32Values = {10}});
+    EXPECT_EQ(results[1].status, StatusCode::INVALID_ARG);
+}
+
+TEST_F(FakeVehicleHardwareTest, testGetSupportedValuesLists) {
+    auto results = getHardware()->getSupportedValuesLists({
+            PropIdAreaId{.propId = toInt(TestVendorProperty::VENDOR_EXTENSION_INT_PROPERTY),
+                         .areaId = 0},
+            PropIdAreaId{.propId = toInt(VehicleProperty::HVAC_TEMPERATURE_SET), .areaId = 0},
+    });
+
+    ASSERT_EQ(results.size(), 2u);
+    EXPECT_EQ(results[0].status, StatusCode::OK);
+    EXPECT_NE(results[0].supportedValuesList, std::nullopt);
+    EXPECT_NE((results[0].supportedValuesList)->size(), 0u);
+    EXPECT_EQ(results[0].supportedValuesList.value(), std::vector<std::optional<RawPropValues>>({
+                                                              RawPropValues{.int32Values = {0}},
+                                                              RawPropValues{.int32Values = {2}},
+                                                              RawPropValues{.int32Values = {4}},
+                                                              RawPropValues{.int32Values = {6}},
+                                                              RawPropValues{.int32Values = {8}},
+                                                              RawPropValues{.int32Values = {10}},
+                                                      }));
+    EXPECT_EQ(results[1].status, StatusCode::INVALID_ARG);
+}
+
 }  // namespace fake
 }  // namespace vehicle
 }  // namespace automotive
diff --git a/automotive/vehicle/aidl/impl/current/hardware/include/IVehicleHardware.h b/automotive/vehicle/aidl/impl/current/hardware/include/IVehicleHardware.h
index 0684655..9122955 100644
--- a/automotive/vehicle/aidl/impl/current/hardware/include/IVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/current/hardware/include/IVehicleHardware.h
@@ -18,9 +18,11 @@
 #define android_hardware_automotive_vehicle_aidl_impl_hardware_include_IVehicleHardware_H_
 
 #include <VehicleHalTypes.h>
+#include <VehicleUtils.h>
 
 #include <memory>
 #include <optional>
+#include <unordered_set>
 #include <vector>
 
 namespace android {
@@ -59,10 +61,23 @@
     using GetValuesCallback = std::function<void(std::vector<aidlvhal::GetValueResult>)>;
     using PropertyChangeCallback = std::function<void(std::vector<aidlvhal::VehiclePropValue>)>;
     using PropertySetErrorCallback = std::function<void(std::vector<SetValueErrorEvent>)>;
+    using SupportedValueChangeCallback = std::function<void(std::vector<PropIdAreaId>)>;
 
     virtual ~IVehicleHardware() = default;
 
     // Get all the property configs.
+    //
+    // Note that {@code VehicleAreaConfig.HasSupportedValueInfo} field is newly introduced in VHAL
+    // V4 to specify whether the [propertyId, areaId] has specified min/max supported value or
+    // supported values list.
+    //
+    // Since IVehicleHardware is designed to be backward compatible, this field can be set to null.
+    // If this field is set to null, VHAL client should fallback to use min/max supported value
+    // information in {@code VehicleAreaConfig} and {@code supportedEnumVaules} for enum properties.
+    //
+    // It is highly recommended to specify {@code VehicleAreaConfig.HasSupportedValueInfo} for new
+    // property implementations, even if the property does not specify supported values or the
+    // supported values are static.
     virtual std::vector<aidlvhal::VehiclePropConfig> getAllPropertyConfigs() const = 0;
 
     // Get the property configs for the specified propId. This is used for early-boot
@@ -240,6 +255,78 @@
                                                   [[maybe_unused]] float sampleRate) {
         return aidlvhal::StatusCode::OK;
     }
+
+    // Gets the min/max supported values for each of the specified [propId, areaId]s.
+    //
+    // The returned result may change dynamically.
+    //
+    // This is only called for [propId, areaId] that has
+    // {@code HasSupportedValueInfo.hasMinSupportedValue} or
+    // {@code HasSupportedValueInfo.hasMinSupportedValue} set to true.
+    //
+    // Client must implement (override) this function if at least one [propId, areaId]'s
+    // {@code HasSupportedValueInfo} is not null.
+    virtual std::vector<aidlvhal::MinMaxSupportedValueResult> getMinMaxSupportedValues(
+            [[maybe_unused]] const std::vector<PropIdAreaId>& propIdAreaIds) {
+        return {};
+    }
+
+    // Gets the supported values list for each of the specified [propId, areaId]s.
+    //
+    // The returned result may change dynamically.
+    //
+    // This is only called for [propId, areaId] that has
+    // {@code HasSupportedValueInfo.hasSupportedValuesList} set to true.
+    //
+    // Client must implement (override) this function if at least one [propId, areaId]'s
+    // {@code HasSupportedValueInfo} is not null.
+    virtual std::vector<aidlvhal::SupportedValuesListResult> getSupportedValuesLists(
+            [[maybe_unused]] const std::vector<PropIdAreaId>& propIdAreaIds) {
+        return {};
+    }
+
+    // Register a callback that would be called when the min/max supported value or supported
+    // values list change dynamically for propertyID returned from
+    // getPropertyIdsThatImplementGetSupportedValue
+    //
+    // This function must only be called once during initialization.
+    //
+    // Client must implement (override) this function if at least one [propId, areaId]'s
+    // {@code HasSupportedValueInfo} is not null.
+    virtual void registerSupportedValueChangeCallback(
+            [[maybe_unused]] std::unique_ptr<const SupportedValueChangeCallback> callback) {
+        // Do nothing.
+    }
+
+    // Subscribes to the min/max supported value or supported values list change for the specified
+    // [propId, areaId]s.
+    //
+    // If the propertyId's supported values are static, then must do nothing.
+    //
+    // If some of the [propId, areaId]s are already subscribed, then do nothing.
+    //
+    // This is only called for [propId, areaId] that has non-null {@code HasSupportedValueInfo}.
+    //
+    // Client must implement (override) this function if at least one [propId, areaId]'s
+    // {@code HasSupportedValueInfo} is not null.
+    virtual aidlvhal::StatusCode subscribeSupportedValueChange(
+            [[maybe_unused]] const std::vector<PropIdAreaId>& propIdAreaIds) {
+        return aidlvhal::StatusCode::OK;
+    }
+
+    // Unsubscrbies to the min/max supported value or supported values list change.
+    //
+    // Must do nothing if the [propId, areaId] was not previously subscribed to for supported
+    // values change.
+    //
+    // This is only called for [propId, areaId] that has non-null {@code HasSupportedValueInfo}.
+    //
+    // Client must implement (override) this function if at least one [propId, areaId]'s
+    // {@code HasSupportedValueInfo} is not null.
+    virtual aidlvhal::StatusCode unsubscribeSupportedValueChange(
+            [[maybe_unused]] const std::vector<PropIdAreaId>& propIdAreaIds) {
+        return aidlvhal::StatusCode::OK;
+    }
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/current/utils/common/include/VehicleHalTypes.h b/automotive/vehicle/aidl/impl/current/utils/common/include/VehicleHalTypes.h
index 4fa0a06..fcc006b 100644
--- a/automotive/vehicle/aidl/impl/current/utils/common/include/VehicleHalTypes.h
+++ b/automotive/vehicle/aidl/impl/current/utils/common/include/VehicleHalTypes.h
@@ -53,6 +53,8 @@
 #include <aidl/android/hardware/automotive/vehicle/LocationCharacterization.h>
 #include <aidl/android/hardware/automotive/vehicle/LowSpeedAutomaticEmergencyBrakingState.h>
 #include <aidl/android/hardware/automotive/vehicle/LowSpeedCollisionWarningState.h>
+#include <aidl/android/hardware/automotive/vehicle/MinMaxSupportedValueResult.h>
+#include <aidl/android/hardware/automotive/vehicle/MinMaxSupportedValueResults.h>
 #include <aidl/android/hardware/automotive/vehicle/Obd2CommonIgnitionMonitors.h>
 #include <aidl/android/hardware/automotive/vehicle/Obd2FuelSystemStatus.h>
 #include <aidl/android/hardware/automotive/vehicle/Obd2FuelType.h>
@@ -65,6 +67,8 @@
 #include <aidl/android/hardware/automotive/vehicle/SetValueResults.h>
 #include <aidl/android/hardware/automotive/vehicle/StatusCode.h>
 #include <aidl/android/hardware/automotive/vehicle/SubscribeOptions.h>
+#include <aidl/android/hardware/automotive/vehicle/SupportedValuesListResult.h>
+#include <aidl/android/hardware/automotive/vehicle/SupportedValuesListResults.h>
 #include <aidl/android/hardware/automotive/vehicle/VehicleAirbagLocation.h>
 #include <aidl/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.h>
 #include <aidl/android/hardware/automotive/vehicle/VehicleApPowerStateReport.h>
diff --git a/automotive/vehicle/aidl/impl/current/utils/common/include/VehicleUtils.h b/automotive/vehicle/aidl/impl/current/utils/common/include/VehicleUtils.h
index 90a7c46..5b19100 100644
--- a/automotive/vehicle/aidl/impl/current/utils/common/include/VehicleUtils.h
+++ b/automotive/vehicle/aidl/impl/current/utils/common/include/VehicleUtils.h
@@ -310,6 +310,12 @@
     return toScopedAStatus(result, getErrorCode(result), additionalErrorMsg);
 }
 
+// This is for debug purpose only.
+inline std::string propIdToString(int32_t propId) {
+    return toString(
+            static_cast<aidl::android::hardware::automotive::vehicle::VehicleProperty>(propId));
+}
+
 struct PropIdAreaId {
     int32_t propId;
     int32_t areaId;
@@ -317,6 +323,11 @@
     inline bool operator==(const PropIdAreaId& other) const {
         return areaId == other.areaId && propId == other.propId;
     }
+
+    // This is for debug purpose only.
+    inline std::string toString() const {
+        return fmt::format("{{propId: {}, areaId: {}}}", propIdToString(propId), areaId);
+    }
 };
 
 struct PropIdAreaIdHash {
@@ -329,12 +340,6 @@
 };
 
 // This is for debug purpose only.
-inline std::string propIdToString(int32_t propId) {
-    return toString(
-            static_cast<aidl::android::hardware::automotive::vehicle::VehicleProperty>(propId));
-}
-
-// This is for debug purpose only.
 android::base::Result<int32_t> stringToPropId(const std::string& propName);
 
 // This is for debug purpose only. Converts an area's name to its enum definition.
@@ -362,4 +367,21 @@
 }  // namespace hardware
 }  // namespace android
 
+// Formatter must not be defined inside our namespace.
+template <>
+struct fmt::formatter<android::hardware::automotive::vehicle::PropIdAreaId> {
+    template <typename ParseContext>
+    constexpr auto parse(ParseContext& ctx) {
+        return ctx.begin();
+    }
+
+    template <typename FormatContext>
+    auto format(const android::hardware::automotive::vehicle::PropIdAreaId& p,
+                FormatContext& ctx) const {
+        return fmt::format_to(ctx.out(), "{{propId: {}, areaId: {}}}",
+                              android::hardware::automotive::vehicle::propIdToString(p.propId),
+                              p.areaId);
+    }
+};
+
 #endif  // android_hardware_automotive_vehicle_aidl_impl_utils_common_include_VehicleUtils_H_
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/common/test/VehicleUtilsTest.cpp b/automotive/vehicle/aidl/impl/current/utils/common/test/VehicleUtilsTest.cpp
index 1048877..8278376 100644
--- a/automotive/vehicle/aidl/impl/current/utils/common/test/VehicleUtilsTest.cpp
+++ b/automotive/vehicle/aidl/impl/current/utils/common/test/VehicleUtilsTest.cpp
@@ -787,6 +787,29 @@
     ASSERT_FALSE(result.ok());
 }
 
+TEST(VehicleUtilsTest, testPropIdAreaIdToString) {
+    PropIdAreaId propIdAreaId = {
+            .propId = toInt(VehicleProperty::PERF_VEHICLE_SPEED),
+            .areaId = 0,
+    };
+
+    ASSERT_EQ(propIdAreaId.toString(), "{propId: PERF_VEHICLE_SPEED, areaId: 0}");
+}
+
+TEST(VehicleUtilsTest, testPropIdAreaIdFormatter) {
+    PropIdAreaId propIdAreaId1 = {
+            .propId = toInt(VehicleProperty::PERF_VEHICLE_SPEED),
+            .areaId = 0,
+    };
+    PropIdAreaId propIdAreaId2 = {
+            .propId = toInt(VehicleProperty::HVAC_FAN_SPEED),
+            .areaId = 1,
+    };
+
+    ASSERT_EQ(fmt::format("{}", std::vector<PropIdAreaId>{propIdAreaId1, propIdAreaId2}),
+              "[{propId: PERF_VEHICLE_SPEED, areaId: 0}, {propId: HVAC_FAN_SPEED, areaId: 1}]");
+}
+
 class InvalidPropValueTest : public testing::TestWithParam<InvalidPropValueTestCase> {};
 
 INSTANTIATE_TEST_SUITE_P(InvalidPropValueTests, InvalidPropValueTest,
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 5d64e6f..d360be0 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/include/DefaultVehicleHal.h
+++ b/automotive/vehicle/aidl/impl/current/vhal/include/DefaultVehicleHal.h
@@ -219,7 +219,7 @@
     // mBinderEvents.
     void onBinderDiedUnlinkedHandler();
 
-    size_t countSubscribeClients();
+    size_t countClients();
 
     // Handles the property change events in batch.
     void handleBatchedPropertyEvents(std::vector<aidlvhal::VehiclePropValue>&& batchedEvents);
@@ -233,6 +233,10 @@
             std::function<void(const std::unordered_map<int32_t, aidlvhal::VehiclePropConfig>&)>
                     callback) const EXCLUDES(mConfigLock);
 
+    android::base::Result<aidlvhal::VehicleAreaConfig> getAreaConfigForPropIdAreaId(
+            int32_t propId, int32_t areaId) const;
+    android::base::Result<aidlvhal::HasSupportedValueInfo> getHasSupportedValueInfo(
+            int32_t propId, int32_t areaId) const;
     // Puts the property change events into a queue so that they can handled in batch.
     static void batchPropertyChangeEvent(
             const std::weak_ptr<ConcurrentQueue<aidlvhal::VehiclePropValue>>& batchedEventQueue,
@@ -251,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 2f16fca..f4e6ced 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/include/SubscriptionManager.h
+++ b/automotive/vehicle/aidl/impl/current/vhal/include/SubscriptionManager.h
@@ -95,15 +95,14 @@
             bool isContinuousProperty);
 
     // Unsubscribes from the properties for the client.
-    // Returns error if the client was not subscribed before, or one of the given property was not
-    // subscribed, or one of the property failed to unsubscribe. Caller is safe to retry since
+    // Returns error if one of the property failed to unsubscribe. Caller is safe to retry since
     // unsubscribing to an already unsubscribed property is okay (it would be ignored).
     // Returns ok if all the requested properties for the client are unsubscribed.
     VhalResult<void> unsubscribe(ClientIdType client, const std::vector<int32_t>& propIds);
 
     // Unsubscribes from all the properties for the client.
-    // Returns error if the client was not subscribed before or one of the subscribed properties
-    // for the client failed to unsubscribe. Caller is safe to retry.
+    // Returns error one of the subscribed properties for the client failed to unsubscribe.
+    // Caller is safe to retry.
     // Returns ok if all the properties for the client are unsubscribed.
     VhalResult<void> unsubscribe(ClientIdType client);
 
@@ -119,8 +118,24 @@
                        std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropError>>
     getSubscribedClientsForErrorEvents(const std::vector<SetValueErrorEvent>& errorEvents);
 
-    // Returns the number of subscribed clients.
-    size_t countClients();
+    // 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);
+
+    // Unsubscribes to supported values change.
+    VhalResult<void> unsubscribeSupportedValueChange(
+            ClientIdType client, const std::vector<PropIdAreaId>& propIdAreaIds);
+
+    // Returns the number of subscribed property change clients.
+    size_t countPropertyChangeClients();
+
+    // Returns the number of subscribed supported value change clients.
+    size_t countSupportedValueChangeClients();
 
     // Checks whether the sample rate is valid.
     static bool checkSampleRateHz(float sampleRateHz);
@@ -131,6 +146,7 @@
   private:
     // Friend class for testing.
     friend class DefaultVehicleHalTest;
+    friend class SubscriptionManagerTest;
 
     IVehicleHardware* mVehicleHardware;
 
@@ -161,6 +177,11 @@
                        std::unordered_set<VehiclePropValue, VehiclePropValueHashPropIdAreaId,
                                           VehiclePropValueEqualPropIdAreaId>>
             mContSubValuesByCallback GUARDED_BY(mLock);
+    std::unordered_map<PropIdAreaId, std::unordered_map<ClientIdType, CallbackType>,
+                       PropIdAreaIdHash>
+            mSupportedValueChangeClientsByPropIdAreaId GUARDED_BY(mLock);
+    std::unordered_map<ClientIdType, std::unordered_set<PropIdAreaId, PropIdAreaIdHash>>
+            mSupportedValueChangePropIdAreaIdsByClient GUARDED_BY(mLock);
 
     VhalResult<void> addContinuousSubscriberLocked(const ClientIdType& clientId,
                                                    const PropIdAreaId& propIdAreaId,
@@ -181,6 +202,9 @@
     VhalResult<void> unsubscribePropIdAreaIdLocked(SubscriptionManager::ClientIdType clientId,
                                                    const PropIdAreaId& propIdAreaId)
             REQUIRES(mLock);
+    VhalResult<void> unsubscribeSupportedValueChangeLocked(
+            SubscriptionManager::ClientIdType clientId,
+            const std::vector<PropIdAreaId>& propIdAreaIds) REQUIRES(mLock);
 
     // Checks whether the manager is empty. For testing purpose.
     bool isEmpty();
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 1e55a1a..ea0c215 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/current/vhal/src/DefaultVehicleHal.cpp
@@ -49,7 +49,9 @@
 using ::aidl::android::hardware::automotive::vehicle::GetValueRequests;
 using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
 using ::aidl::android::hardware::automotive::vehicle::GetValueResults;
+using ::aidl::android::hardware::automotive::vehicle::HasSupportedValueInfo;
 using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
+using ::aidl::android::hardware::automotive::vehicle::MinMaxSupportedValueResult;
 using ::aidl::android::hardware::automotive::vehicle::MinMaxSupportedValueResults;
 using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
 using ::aidl::android::hardware::automotive::vehicle::SetValueRequests;
@@ -57,6 +59,7 @@
 using ::aidl::android::hardware::automotive::vehicle::SetValueResults;
 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
 using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
+using ::aidl::android::hardware::automotive::vehicle::SupportedValuesListResult;
 using ::aidl::android::hardware::automotive::vehicle::SupportedValuesListResults;
 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
@@ -77,6 +80,8 @@
 using ::ndk::ScopedAStatus;
 using ::ndk::ScopedFileDescriptor;
 
+using VhalPropIdAreaId = ::aidl::android::hardware::automotive::vehicle::PropIdAreaId;
+
 std::string toString(const std::unordered_set<int64_t>& values) {
     std::string str = "";
     for (auto it = values.begin(); it != values.end(); it++) {
@@ -155,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()>>(
@@ -202,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));
@@ -218,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));
@@ -232,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);
@@ -241,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,
@@ -926,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,
@@ -964,32 +993,233 @@
     return ScopedAStatus::ok();
 }
 
+Result<VehicleAreaConfig> DefaultVehicleHal::getAreaConfigForPropIdAreaId(int32_t propId,
+                                                                          int32_t areaId) const {
+    auto result = getConfig(propId);
+    if (!result.ok()) {
+        return Error() << "Failed to get property config for propertyId: " << propIdToString(propId)
+                       << ", error: " << result.error();
+    }
+    const VehiclePropConfig& config = result.value();
+    const VehicleAreaConfig* areaConfig = getAreaConfig(propId, areaId, config);
+    if (areaConfig == nullptr) {
+        return Error() << "AreaId config not found for propertyId: " << propIdToString(propId)
+                       << ", areaId: " << areaId;
+    }
+    return *areaConfig;
+}
+
+Result<HasSupportedValueInfo> DefaultVehicleHal::getHasSupportedValueInfo(int32_t propId,
+                                                                          int32_t areaId) const {
+    Result<VehicleAreaConfig> propIdAreaIdConfigResult =
+            getAreaConfigForPropIdAreaId(propId, areaId);
+    if (!isGlobalProp(propId) && !propIdAreaIdConfigResult.ok()) {
+        // For global property, it is possible that no config exists.
+        return Error() << propIdAreaIdConfigResult.error();
+    }
+    if (propIdAreaIdConfigResult.has_value()) {
+        auto areaConfig = propIdAreaIdConfigResult.value();
+        if (areaConfig.hasSupportedValueInfo.has_value()) {
+            return areaConfig.hasSupportedValueInfo.value();
+        }
+    }
+    return Error() << "property: " << propIdToString(propId) << ", areaId: " << areaId
+                   << " does not support this operation because hasSupportedValueInfo is null";
+}
+
 ScopedAStatus DefaultVehicleHal::getSupportedValuesLists(
-        const std::vector<::aidl::android::hardware::automotive::vehicle::PropIdAreaId>&,
-        SupportedValuesListResults*) {
-    // TODO(b/381020465): Add relevant implementation.
-    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+        const std::vector<VhalPropIdAreaId>& vhalPropIdAreaIds,
+        SupportedValuesListResults* supportedValuesListResults) {
+    std::vector<size_t> toHardwareRequestCounters;
+    std::vector<PropIdAreaId> toHardwarePropIdAreaIds;
+    std::vector<SupportedValuesListResult> results;
+    results.resize(vhalPropIdAreaIds.size());
+    for (size_t requestCounter = 0; requestCounter < vhalPropIdAreaIds.size(); requestCounter++) {
+        const auto& vhalPropIdAreaId = vhalPropIdAreaIds.at(requestCounter);
+        int32_t propId = vhalPropIdAreaId.propId;
+        int32_t areaId = vhalPropIdAreaId.areaId;
+        auto hasSupportedValueInfoResult = getHasSupportedValueInfo(propId, areaId);
+        if (!hasSupportedValueInfoResult.ok()) {
+            ALOGE("getSupportedValuesLists: %s",
+                  hasSupportedValueInfoResult.error().message().c_str());
+            results[requestCounter] = SupportedValuesListResult{
+                    .status = StatusCode::INVALID_ARG, .supportedValuesList = std::nullopt};
+            continue;
+        }
+
+        const auto& hasSupportedValueInfo = hasSupportedValueInfoResult.value();
+        if (hasSupportedValueInfo.hasSupportedValuesList) {
+            toHardwarePropIdAreaIds.push_back(PropIdAreaId{.propId = propId, .areaId = areaId});
+            toHardwareRequestCounters.push_back(requestCounter);
+        } else {
+            results[requestCounter] = SupportedValuesListResult{
+                    .status = StatusCode::OK, .supportedValuesList = std::nullopt};
+            continue;
+        }
+    }
+    if (toHardwarePropIdAreaIds.size() != 0) {
+        std::vector<SupportedValuesListResult> resultsFromHardware =
+                mVehicleHardware->getSupportedValuesLists(toHardwarePropIdAreaIds);
+        // It is guaranteed that toHardwarePropIdAreaIds, toHardwareRequestCounters,
+        // resultsFromHardware have the same size.
+        if (resultsFromHardware.size() != toHardwareRequestCounters.size()) {
+            return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                    toInt(StatusCode::INTERNAL_ERROR),
+                    fmt::format(
+                            "getSupportedValuesLists: Unexpected results size from IVehicleHardware"
+                            ", got: {}, expect: {}",
+                            resultsFromHardware.size(), toHardwareRequestCounters.size())
+                            .c_str());
+        }
+        for (size_t i = 0; i < toHardwareRequestCounters.size(); i++) {
+            results[toHardwareRequestCounters[i]] = resultsFromHardware[i];
+        }
+    }
+    ScopedAStatus status =
+            vectorToStableLargeParcelable(std::move(results), supportedValuesListResults);
+    if (!status.isOk()) {
+        int statusCode = status.getServiceSpecificError();
+        ALOGE("getSupportedValuesLists: failed to marshal result into large parcelable, error: "
+              "%s, code: %d",
+              status.getMessage(), statusCode);
+        return status;
+    }
+    return ScopedAStatus::ok();
 }
 
 ScopedAStatus DefaultVehicleHal::getMinMaxSupportedValue(
-        const std::vector<::aidl::android::hardware::automotive::vehicle::PropIdAreaId>&,
-        MinMaxSupportedValueResults*) {
-    // TODO(b/381020465): Add relevant implementation.
-    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+        const std::vector<VhalPropIdAreaId>& vhalPropIdAreaIds,
+        MinMaxSupportedValueResults* minMaxSupportedValueResults) {
+    std::vector<size_t> toHardwareRequestCounters;
+    std::vector<PropIdAreaId> toHardwarePropIdAreaIds;
+    std::vector<MinMaxSupportedValueResult> results;
+    results.resize(vhalPropIdAreaIds.size());
+    for (size_t requestCounter = 0; requestCounter < vhalPropIdAreaIds.size(); requestCounter++) {
+        const auto& vhalPropIdAreaId = vhalPropIdAreaIds.at(requestCounter);
+        int32_t propId = vhalPropIdAreaId.propId;
+        int32_t areaId = vhalPropIdAreaId.areaId;
+        auto hasSupportedValueInfoResult = getHasSupportedValueInfo(propId, areaId);
+        if (!hasSupportedValueInfoResult.ok()) {
+            ALOGE("getMinMaxSupportedValue: %s",
+                  hasSupportedValueInfoResult.error().message().c_str());
+            results[requestCounter] = MinMaxSupportedValueResult{.status = StatusCode::INVALID_ARG,
+                                                                 .minSupportedValue = std::nullopt,
+                                                                 .maxSupportedValue = std::nullopt};
+            continue;
+        }
+
+        const auto& hasSupportedValueInfo = hasSupportedValueInfoResult.value();
+        if (hasSupportedValueInfo.hasMinSupportedValue ||
+            hasSupportedValueInfo.hasMaxSupportedValue) {
+            toHardwarePropIdAreaIds.push_back(PropIdAreaId{.propId = propId, .areaId = areaId});
+            toHardwareRequestCounters.push_back(requestCounter);
+        } else {
+            results[requestCounter] = MinMaxSupportedValueResult{.status = StatusCode::OK,
+                                                                 .minSupportedValue = std::nullopt,
+                                                                 .maxSupportedValue = std::nullopt};
+            continue;
+        }
+    }
+    if (toHardwarePropIdAreaIds.size() != 0) {
+        std::vector<MinMaxSupportedValueResult> resultsFromHardware =
+                mVehicleHardware->getMinMaxSupportedValues(toHardwarePropIdAreaIds);
+        // It is guaranteed that toHardwarePropIdAreaIds, toHardwareRequestCounters,
+        // resultsFromHardware have the same size.
+        if (resultsFromHardware.size() != toHardwareRequestCounters.size()) {
+            return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                    toInt(StatusCode::INTERNAL_ERROR),
+                    fmt::format(
+                            "getMinMaxSupportedValue: Unexpected results size from IVehicleHardware"
+                            ", got: {}, expect: {}",
+                            resultsFromHardware.size(), toHardwareRequestCounters.size())
+                            .c_str());
+        }
+        for (size_t i = 0; i < toHardwareRequestCounters.size(); i++) {
+            results[toHardwareRequestCounters[i]] = resultsFromHardware[i];
+        }
+    }
+    ScopedAStatus status =
+            vectorToStableLargeParcelable(std::move(results), minMaxSupportedValueResults);
+    if (!status.isOk()) {
+        int statusCode = status.getServiceSpecificError();
+        ALOGE("getMinMaxSupportedValue: failed to marshal result into large parcelable, error: "
+              "%s, code: %d",
+              status.getMessage(), statusCode);
+        return status;
+    }
+    return ScopedAStatus::ok();
 }
 
 ScopedAStatus DefaultVehicleHal::registerSupportedValueChangeCallback(
-        const std::shared_ptr<IVehicleCallback>&,
-        const std::vector<::aidl::android::hardware::automotive::vehicle::PropIdAreaId>&) {
-    // TODO(b/381020465): Add relevant implementation.
-    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+        const std::shared_ptr<IVehicleCallback>& callback,
+        const std::vector<VhalPropIdAreaId>& vhalPropIdAreaIds) {
+    std::vector<PropIdAreaId> propIdAreaIdsToSubscribe;
+    for (size_t i = 0; i < vhalPropIdAreaIds.size(); i++) {
+        const auto& vhalPropIdAreaId = vhalPropIdAreaIds.at(i);
+        int32_t propId = vhalPropIdAreaId.propId;
+        int32_t areaId = vhalPropIdAreaId.areaId;
+        auto hasSupportedValueInfoResult = getHasSupportedValueInfo(propId, areaId);
+        if (!hasSupportedValueInfoResult.ok()) {
+            ALOGE("registerSupportedValueChangeCallback not supported: %s",
+                  hasSupportedValueInfoResult.error().message().c_str());
+            return toScopedAStatus(hasSupportedValueInfoResult, StatusCode::INVALID_ARG);
+        }
+        const auto& hasSupportedValueInfo = hasSupportedValueInfoResult.value();
+        if (!hasSupportedValueInfo.hasMinSupportedValue &&
+            !hasSupportedValueInfo.hasMaxSupportedValue &&
+            !hasSupportedValueInfo.hasSupportedValuesList) {
+            ALOGW("registerSupportedValueChangeCallback: do nothing for property: %s, "
+                  "areaId: %" PRId32
+                  ", no min/max supported values or supported values list"
+                  " specified",
+                  propIdToString(propId).c_str(), areaId);
+            continue;
+        }
+        propIdAreaIdsToSubscribe.push_back(PropIdAreaId{.propId = propId, .areaId = areaId});
+    }
+    if (propIdAreaIdsToSubscribe.empty()) {
+        return ScopedAStatus::ok();
+    }
+    {
+        // 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();
 }
 
 ScopedAStatus DefaultVehicleHal::unregisterSupportedValueChangeCallback(
-        const std::shared_ptr<IVehicleCallback>&,
-        const std::vector<::aidl::android::hardware::automotive::vehicle::PropIdAreaId>&) {
-    // TODO(b/381020465): Add relevant implementation.
-    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+        const std::shared_ptr<IVehicleCallback>& callback,
+        const std::vector<VhalPropIdAreaId>& vhalPropIdAreaIds) {
+    std::vector<PropIdAreaId> propIdAreaIds;
+    for (const auto& vhalPropIdAreaId : vhalPropIdAreaIds) {
+        propIdAreaIds.push_back(
+                PropIdAreaId{.propId = vhalPropIdAreaId.propId, .areaId = vhalPropIdAreaId.areaId});
+    }
+
+    auto result = mSubscriptionManager->unsubscribeSupportedValueChange(callback->asBinder().get(),
+                                                                        propIdAreaIds);
+    if (!result.ok()) {
+        ALOGW("unregisterSupportedValueChangeCallback: failed to unsubscribe supported value change"
+              " for %s, error: %s",
+              fmt::format("{}", propIdAreaIds).c_str(), result.error().message().c_str());
+        return toScopedAStatus(result);
+    }
+    return ScopedAStatus::ok();
 }
 
 IVehicleHardware* DefaultVehicleHal::getHardware() {
@@ -1106,13 +1336,19 @@
         dprintf(fd, "Containing %zu property configs\n", configsByPropIdCopy.size());
         dprintf(fd, "Currently have %zu getValues clients\n", mGetValuesClients.size());
         dprintf(fd, "Currently have %zu setValues clients\n", mSetValuesClients.size());
-        dprintf(fd, "Currently have %zu subscribe clients\n", countSubscribeClients());
+        dprintf(fd, "Currently have %zu subscribe clients\n",
+                mSubscriptionManager->countPropertyChangeClients());
+        dprintf(fd, "Currently have %zu supported values change subscribe clients\n",
+                mSubscriptionManager->countSupportedValueChangeClients());
     }
     return STATUS_OK;
 }
 
-size_t DefaultVehicleHal::countSubscribeClients() {
-    return mSubscriptionManager->countClients();
+size_t DefaultVehicleHal::countClients() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return mGetValuesClients.size() + mSetValuesClients.size() +
+           mSubscriptionManager->countPropertyChangeClients() +
+           mSubscriptionManager->countSupportedValueChangeClients();
 }
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/current/vhal/src/SubscriptionManager.cpp b/automotive/vehicle/aidl/impl/current/vhal/src/SubscriptionManager.cpp
index 14ee707..64c46c9 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/src/SubscriptionManager.cpp
+++ b/automotive/vehicle/aidl/impl/current/vhal/src/SubscriptionManager.cpp
@@ -17,6 +17,7 @@
 #include "SubscriptionManager.h"
 
 #include <VehicleUtils.h>
+#include <android-base/format.h>
 #include <android-base/stringprintf.h>
 #include <utils/Log.h>
 #include <utils/SystemClock.h>
@@ -65,6 +66,8 @@
 
     mClientsByPropIdAreaId.clear();
     mSubscribedPropsByClient.clear();
+    mSupportedValueChangeClientsByPropIdAreaId.clear();
+    mSupportedValueChangePropIdAreaIdsByClient.clear();
 }
 
 bool SubscriptionManager::checkSampleRateHz(float sampleRateHz) {
@@ -166,8 +169,7 @@
                                     /*enableVur*/ false));
         status != StatusCode::OK) {
         return StatusError(status)
-               << StringPrintf("failed subscribe for prop: %s, areaId: %" PRId32,
-                               propIdToString(propId).c_str(), areaId);
+               << fmt::format("failed subscribe for propIdAreaId: {}", propIdAreaId);
     }
     return {};
 }
@@ -345,8 +347,8 @@
     std::scoped_lock<std::mutex> lockGuard(mLock);
 
     if (mSubscribedPropsByClient.find(clientId) == mSubscribedPropsByClient.end()) {
-        return StatusError(StatusCode::INVALID_ARG)
-               << "No property was subscribed for the callback";
+        ALOGW("No property was subscribed for the callback, unsubscribe does nothing");
+        return {};
     }
 
     std::vector<PropIdAreaId> propIdAreaIdsToUnsubscribe;
@@ -378,16 +380,112 @@
     std::scoped_lock<std::mutex> lockGuard(mLock);
 
     if (mSubscribedPropsByClient.find(clientId) == mSubscribedPropsByClient.end()) {
-        return StatusError(StatusCode::INVALID_ARG) << "No property was subscribed for this client";
+        ALOGW("No property was subscribed for this client, unsubscribe does nothing");
+    } else {
+        auto& propIdAreaIds = mSubscribedPropsByClient[clientId];
+        for (auto const& propIdAreaId : propIdAreaIds) {
+            if (auto result = unsubscribePropIdAreaIdLocked(clientId, propIdAreaId); !result.ok()) {
+                return result;
+            }
+        }
+        mSubscribedPropsByClient.erase(clientId);
     }
 
-    auto& subscriptions = mSubscribedPropsByClient[clientId];
-    for (auto const& propIdAreaId : subscriptions) {
-        if (auto result = unsubscribePropIdAreaIdLocked(clientId, propIdAreaId); !result.ok()) {
+    if (mSupportedValueChangePropIdAreaIdsByClient.find(clientId) ==
+        mSupportedValueChangePropIdAreaIdsByClient.end()) {
+        ALOGW("No supported value change was subscribed for this client, unsubscribe does nothing");
+    } else {
+        const auto& propIdAreaIds = mSupportedValueChangePropIdAreaIdsByClient[clientId];
+        if (auto result = unsubscribeSupportedValueChangeLocked(
+                    clientId,
+                    std::vector<PropIdAreaId>(propIdAreaIds.begin(), propIdAreaIds.end()));
+            !result.ok()) {
             return result;
         }
     }
-    mSubscribedPropsByClient.erase(clientId);
+    return {};
+}
+
+VhalResult<void> SubscriptionManager::subscribeSupportedValueChange(
+        const std::shared_ptr<IVehicleCallback>& callback,
+        const std::vector<PropIdAreaId>& propIdAreaIds) {
+    // Need to make sure this whole operation is guarded by a lock so that our internal state is
+    // consistent with IVehicleHardware state.
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+
+    ClientIdType clientId = callback->asBinder().get();
+
+    // It is possible that some of the [propId, areaId]s are already subscribed, IVehicleHardware
+    // will ignore them.
+    if (auto status = mVehicleHardware->subscribeSupportedValueChange(propIdAreaIds);
+        status != StatusCode::OK) {
+        return StatusError(status)
+               << fmt::format("failed to call subscribeSupportedValueChange for propIdAreaIds: {}",
+                              propIdAreaIds);
+    }
+    for (const auto& propIdAreaId : propIdAreaIds) {
+        mSupportedValueChangeClientsByPropIdAreaId[propIdAreaId][clientId] = callback;
+        // mSupportedValueChangePropIdAreaIdsByClient[clientId] is a set so this will ignore
+        // duplicate [propId, areaId].
+        mSupportedValueChangePropIdAreaIdsByClient[clientId].insert(propIdAreaId);
+    }
+    return {};
+}
+
+VhalResult<void> SubscriptionManager::unsubscribeSupportedValueChange(
+        SubscriptionManager::ClientIdType clientId,
+        const std::vector<PropIdAreaId>& propIdAreaIds) {
+    // Need to make sure this whole operation is guarded by a lock so that our internal state is
+    // consistent with IVehicleHardware state.
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+
+    return unsubscribeSupportedValueChangeLocked(clientId, propIdAreaIds);
+}
+
+VhalResult<void> SubscriptionManager::unsubscribeSupportedValueChangeLocked(
+        SubscriptionManager::ClientIdType clientId,
+        const std::vector<PropIdAreaId>& propIdAreaIds) {
+    std::vector<PropIdAreaId> propIdAreaIdsToUnsubscribe;
+
+    // Check which [propId, areaId] needs to be unsubscribed from the hardware.
+    for (const auto& propIdAreaId : propIdAreaIds) {
+        auto it = mSupportedValueChangeClientsByPropIdAreaId.find(propIdAreaId);
+        if (it != mSupportedValueChangeClientsByPropIdAreaId.end()) {
+            const auto& clients = it->second;
+            if (clients.size() == 1 && clients.find(clientId) != clients.end()) {
+                // This callback is the only client registered for [propId, areaId].
+                // Unregister it should unregister the [propId, areaId].
+                propIdAreaIdsToUnsubscribe.push_back(propIdAreaId);
+            }
+        }
+    }
+
+    // Send the unsubscribe request.
+    if (!propIdAreaIdsToUnsubscribe.empty()) {
+        if (auto status =
+                    mVehicleHardware->unsubscribeSupportedValueChange(propIdAreaIdsToUnsubscribe);
+            status != StatusCode::OK) {
+            return StatusError(status) << fmt::format(
+                           "failed to call unsubscribeSupportedValueChange for "
+                           "propIdAreaIds: {}",
+                           propIdAreaIdsToUnsubscribe);
+        }
+    }
+
+    // Remove internal book-keeping.
+    for (const auto& propIdAreaId : propIdAreaIds) {
+        if (mSupportedValueChangeClientsByPropIdAreaId.find(propIdAreaId) !=
+            mSupportedValueChangeClientsByPropIdAreaId.end()) {
+            mSupportedValueChangeClientsByPropIdAreaId[propIdAreaId].erase(clientId);
+        }
+        if (mSupportedValueChangeClientsByPropIdAreaId[propIdAreaId].empty()) {
+            mSupportedValueChangeClientsByPropIdAreaId.erase(propIdAreaId);
+        }
+        mSupportedValueChangePropIdAreaIdsByClient[clientId].erase(propIdAreaId);
+        if (mSupportedValueChangePropIdAreaIdsByClient[clientId].empty()) {
+            mSupportedValueChangePropIdAreaIdsByClient.erase(clientId);
+        }
+    }
     return {};
 }
 
@@ -483,16 +581,42 @@
     return clients;
 }
 
-bool SubscriptionManager::isEmpty() {
+std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<PropIdAreaId>>
+SubscriptionManager::getSubscribedClientsForSupportedValueChange(
+        const std::vector<PropIdAreaId>& propIdAreaIds) {
     std::scoped_lock<std::mutex> lockGuard(mLock);
-    return mSubscribedPropsByClient.empty() && mClientsByPropIdAreaId.empty();
+    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;
 }
 
-size_t SubscriptionManager::countClients() {
+bool SubscriptionManager::isEmpty() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return mSubscribedPropsByClient.empty() && mClientsByPropIdAreaId.empty() &&
+           mSupportedValueChangeClientsByPropIdAreaId.empty() &&
+           mSupportedValueChangePropIdAreaIdsByClient.empty();
+}
+
+size_t SubscriptionManager::countPropertyChangeClients() {
     std::scoped_lock<std::mutex> lockGuard(mLock);
     return mSubscribedPropsByClient.size();
 }
 
+size_t SubscriptionManager::countSupportedValueChangeClients() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return mSupportedValueChangePropIdAreaIdsByClient.size();
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/current/vhal/test/DefaultVehicleHalTest.cpp b/automotive/vehicle/aidl/impl/current/vhal/test/DefaultVehicleHalTest.cpp
index 0af9a9a..3b89e5f 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/test/DefaultVehicleHalTest.cpp
+++ b/automotive/vehicle/aidl/impl/current/vhal/test/DefaultVehicleHalTest.cpp
@@ -21,6 +21,7 @@
 
 #include <IVehicleHardware.h>
 #include <LargeParcelableBase.h>
+#include <aidl/android/hardware/automotive/vehicle/HasSupportedValueInfo.h>
 #include <aidl/android/hardware/automotive/vehicle/IVehicle.h>
 #include <aidl/android/hardware/automotive/vehicle/IVehicleCallback.h>
 
@@ -51,14 +52,20 @@
 using ::aidl::android::hardware::automotive::vehicle::GetValueRequests;
 using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
 using ::aidl::android::hardware::automotive::vehicle::GetValueResults;
+using ::aidl::android::hardware::automotive::vehicle::HasSupportedValueInfo;
 using ::aidl::android::hardware::automotive::vehicle::IVehicle;
 using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
+using ::aidl::android::hardware::automotive::vehicle::MinMaxSupportedValueResult;
+using ::aidl::android::hardware::automotive::vehicle::MinMaxSupportedValueResults;
+using ::aidl::android::hardware::automotive::vehicle::RawPropValues;
 using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
 using ::aidl::android::hardware::automotive::vehicle::SetValueRequests;
 using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
 using ::aidl::android::hardware::automotive::vehicle::SetValueResults;
 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
 using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
+using ::aidl::android::hardware::automotive::vehicle::SupportedValuesListResult;
+using ::aidl::android::hardware::automotive::vehicle::SupportedValuesListResults;
 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaWindow;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
@@ -85,6 +92,8 @@
 using ::testing::UnorderedElementsAreArray;
 using ::testing::WhenSortedBy;
 
+using VhalPropIdAreaId = ::aidl::android::hardware::automotive::vehicle::PropIdAreaId;
+
 constexpr int32_t INVALID_PROP_ID = 0;
 // VehiclePropertyGroup:VENDOR,VehicleArea:WINDOW,VehiclePropertyType:INT32
 constexpr int32_t INT32_WINDOW_PROP = 10001 + 0x20000000 + 0x03000000 + 0x00400000;
@@ -112,6 +121,11 @@
     return static_cast<int32_t>(i) + 0x20000000 + 0x01000000 + 0x00410000;
 }
 
+int32_t testInt32VecWindowProp(size_t i) {
+    // VehiclePropertyGroup:VENDOR,VehicleArea:WINDOW,VehiclePropertyType:INT32_VEC
+    return static_cast<int32_t>(i) + 0x20000000 + 0x03000000 + 0x00410000;
+}
+
 std::string toString(const std::vector<SubscribeOptions>& options) {
     std::string optionsStr;
     for (const auto& option : options) {
@@ -258,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{
@@ -406,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 {
@@ -437,11 +445,7 @@
 
     size_t countPendingRequests() { return mVhal->mPendingRequestPool->countPendingRequests(); }
 
-    size_t countClients() {
-        std::scoped_lock<std::mutex> lockGuard(mVhal->mLock);
-        return mVhal->mGetValuesClients.size() + mVhal->mSetValuesClients.size() +
-               mVhal->countSubscribeClients();
-    }
+    size_t countClients() { return mVhal->countClients(); }
 
     std::shared_ptr<PendingRequestPool> getPool() { return mVhal->mPendingRequestPool; }
 
@@ -534,6 +538,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:
@@ -574,11 +605,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)));
@@ -595,11 +625,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());
@@ -623,12 +652,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{
@@ -652,15 +679,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) {
@@ -675,11 +701,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);
 
@@ -1828,12 +1853,11 @@
     ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::ACCESS_DENIED));
 }
 
-TEST_F(DefaultVehicleHalTest, testUnsubscribeFailure) {
+TEST_F(DefaultVehicleHalTest, testUnsubscribeNotSubscribedProperty) {
     auto status = getClient()->unsubscribe(getCallbackClient(),
                                            std::vector<int32_t>({GLOBAL_ON_CHANGE_PROP}));
 
-    ASSERT_FALSE(status.isOk()) << "unsubscribe to a not-subscribed property must fail";
-    ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::INVALID_ARG));
+    ASSERT_TRUE(status.isOk()) << "unsubscribe to a not-subscribed property must do nothing";
 }
 
 TEST_F(DefaultVehicleHalTest, testHeartbeatEvent) {
@@ -2121,6 +2145,742 @@
     }
 }
 
+TEST_F(DefaultVehicleHalTest, testGetSupportedValuesLists) {
+    auto testConfigs = std::vector<VehiclePropConfig>(
+            {// This ia valid request, but no supported values are specified.
+             VehiclePropConfig{
+                     .prop = testInt32VecProp(1),
+                     .areaConfigs =
+                             {
+                                     {.areaId = 0,
+                                      .hasSupportedValueInfo =
+                                              HasSupportedValueInfo{
+                                                      .hasSupportedValuesList = false,
+                                              }},
+                             },
+             },
+             // This is an invalid request since hasSupportedValueInfo is null. This is not
+             // supported.
+             VehiclePropConfig{
+                     .prop = testInt32VecWindowProp(2),
+                     .areaConfigs =
+                             {
+                                     {
+                                             .areaId = 2,
+                                     },
+                             },
+             },
+             // This is an invalid request for global property.
+             VehiclePropConfig{
+                     .prop = testInt32VecProp(3),
+             },
+             // This is a normal request.
+             VehiclePropConfig{
+                     .prop = testInt32VecWindowProp(4),
+                     .areaConfigs =
+                             {
+                                     {.areaId = 4,
+                                      .hasSupportedValueInfo =
+                                              HasSupportedValueInfo{
+                                                      .hasSupportedValuesList = true,
+                                              }},
+                             },
+             }});
+
+    auto hardware = std::make_unique<MockVehicleHardware>();
+    MockVehicleHardware* hardwarePtr = hardware.get();
+    hardware->setPropertyConfigs(testConfigs);
+
+    SupportedValuesListResult resultFromHardware = {
+            .status = StatusCode::OK,
+            .supportedValuesList =
+                    std::vector<std::optional<RawPropValues>>{RawPropValues{.int32Values = {1}}}};
+    auto response = std::vector<SupportedValuesListResult>({resultFromHardware});
+    hardware->setSupportedValuesListResponse(response);
+
+    setHardware(std::move(hardware));
+
+    SupportedValuesListResults results;
+
+    auto propIdAreaId1 = VhalPropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
+    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 = getClient()->getSupportedValuesLists(
+            std::vector<VhalPropIdAreaId>{propIdAreaId1, propIdAreaId2, propIdAreaId3,
+                                          propIdAreaId4},
+            &results);
+
+    ASSERT_TRUE(status.isOk()) << "Get non-okay status from getSupportedValuesLists"
+                               << status.getMessage();
+    ASSERT_THAT(getHardware()->getSupportedValuesListRequest(),
+                ElementsAre(PropIdAreaId{.propId = testInt32VecWindowProp(4), .areaId = 4}))
+            << "Only valid request 4 should get to hardware";
+
+    ASSERT_EQ(results.payloads.size(), 4u);
+    SupportedValuesListResult result = results.payloads[0];
+    ASSERT_EQ(result.status, StatusCode::OK)
+            << "Must return OK even if the supported values list is not specified";
+    ASSERT_FALSE(result.supportedValuesList.has_value())
+            << "Must return an empty supported values list if not specified";
+
+    result = results.payloads[1];
+    ASSERT_EQ(result.status, StatusCode::INVALID_ARG)
+            << "PropId, areaId that set hasSupportedValueInfo to null must not be supported";
+    ASSERT_FALSE(result.supportedValuesList.has_value());
+
+    result = results.payloads[2];
+    ASSERT_EQ(result.status, StatusCode::INVALID_ARG)
+            << "Must return INVALID_ARG for global property without area config";
+    ASSERT_FALSE(result.supportedValuesList.has_value());
+
+    result = results.payloads[3];
+    ASSERT_EQ(result.status, StatusCode::OK);
+    ASSERT_TRUE(result.supportedValuesList.has_value());
+    ASSERT_EQ(result.supportedValuesList.value().size(), 1u);
+    ASSERT_EQ(result.supportedValuesList.value()[0]->int32Values.size(), 1u);
+    ASSERT_EQ((result.supportedValuesList.value())[0]->int32Values[0], 1);
+}
+
+TEST_F(DefaultVehicleHalTest, testGetSupportedValuesLists_propIdAreaIdNotFound) {
+    auto testConfigs = std::vector<VehiclePropConfig>({
+            VehiclePropConfig{
+                    .prop = testInt32VecWindowProp(1),
+                    .areaConfigs =
+                            {
+                                    {.areaId = 1,
+                                     .hasSupportedValueInfo =
+                                             HasSupportedValueInfo{
+                                                     .hasSupportedValuesList = true,
+                                             }},
+                            },
+            },
+    });
+
+    auto hardware = std::make_unique<MockVehicleHardware>();
+    hardware->setPropertyConfigs(testConfigs);
+
+    setHardware(std::move(hardware));
+
+    SupportedValuesListResults results;
+
+    // propId not valid.
+    auto propIdAreaId1 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 1};
+    // areaId not valid.
+    auto propIdAreaId2 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(1), .areaId = 2};
+
+    auto status = getClient()->getSupportedValuesLists(
+            std::vector<VhalPropIdAreaId>{propIdAreaId1, propIdAreaId2}, &results);
+
+    ASSERT_TRUE(status.isOk()) << "Get non-okay status from getSupportedValuesLists"
+                               << status.getMessage();
+    ASSERT_EQ(results.payloads.size(), 2u);
+    SupportedValuesListResult result = results.payloads[0];
+    ASSERT_EQ(result.status, StatusCode::INVALID_ARG);
+    result = results.payloads[1];
+    ASSERT_EQ(result.status, StatusCode::INVALID_ARG);
+}
+
+TEST_F(DefaultVehicleHalTest, testGetMinMaxSupportedValue) {
+    auto testConfigs = std::vector<VehiclePropConfig>(
+            {// This ia valid request, but no supported values are specified.
+             VehiclePropConfig{
+                     .prop = testInt32VecProp(1),
+                     .areaConfigs =
+                             {
+                                     {.areaId = 0,
+                                      .hasSupportedValueInfo =
+                                              HasSupportedValueInfo{
+                                                      .hasMinSupportedValue = false,
+                                                      .hasMaxSupportedValue = false,
+                                              }},
+                             },
+             },
+             // This is an invalid request since hasSupportedValueInfo is null. This is not
+             // supported.
+             VehiclePropConfig{
+                     .prop = testInt32VecWindowProp(2),
+                     .areaConfigs =
+                             {
+                                     {
+                                             .areaId = 2,
+                                     },
+                             },
+             },
+             // This is an invalid request for global property.
+             VehiclePropConfig{
+                     .prop = testInt32VecProp(3),
+             },
+             // This is a normal request.
+             VehiclePropConfig{
+                     .prop = testInt32VecWindowProp(4),
+                     .areaConfigs =
+                             {
+                                     {.areaId = 4,
+                                      .hasSupportedValueInfo =
+                                              HasSupportedValueInfo{
+                                                      .hasMinSupportedValue = true,
+                                                      .hasMaxSupportedValue = false,
+                                              }},
+                             },
+             }});
+
+    auto hardware = std::make_unique<MockVehicleHardware>();
+    MockVehicleHardware* hardwarePtr = hardware.get();
+    hardware->setPropertyConfigs(testConfigs);
+
+    MinMaxSupportedValueResult resultFromHardware = {
+            .status = StatusCode::OK,
+            .minSupportedValue = std::optional<RawPropValues>{RawPropValues{.int32Values = {1}}},
+            .maxSupportedValue = std::nullopt,
+    };
+    auto response = std::vector<MinMaxSupportedValueResult>({resultFromHardware});
+    hardware->setMinMaxSupportedValueResponse(response);
+
+    setHardware(std::move(hardware));
+
+    MinMaxSupportedValueResults results;
+
+    auto propIdAreaId1 = VhalPropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
+    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 = getClient()->getMinMaxSupportedValue(
+            std::vector<VhalPropIdAreaId>{propIdAreaId1, propIdAreaId2, propIdAreaId3,
+                                          propIdAreaId4},
+            &results);
+
+    ASSERT_TRUE(status.isOk()) << "Get non-okay status from getMinMaxSupportedValue"
+                               << status.getMessage();
+    ASSERT_THAT(getHardware()->getMinMaxSupportedValueRequest(),
+                ElementsAre(PropIdAreaId{.propId = testInt32VecWindowProp(4), .areaId = 4}))
+            << "Only valid request 4 should get to hardware";
+
+    ASSERT_EQ(results.payloads.size(), 4u);
+    MinMaxSupportedValueResult result = results.payloads[0];
+    ASSERT_EQ(result.status, StatusCode::OK)
+            << "Must return OK even if the min/max supported values are not specified";
+    ASSERT_FALSE(result.minSupportedValue.has_value())
+            << "Must return null min supported value if not specified";
+    ASSERT_FALSE(result.maxSupportedValue.has_value())
+            << "Must return null max supported value if not specified";
+
+    result = results.payloads[1];
+    ASSERT_EQ(result.status, StatusCode::INVALID_ARG)
+            << "PropId, areaId that set hasSupportedValueInfo to null must not be supported";
+    ASSERT_FALSE(result.minSupportedValue.has_value());
+    ASSERT_FALSE(result.maxSupportedValue.has_value());
+
+    result = results.payloads[2];
+    ASSERT_EQ(result.status, StatusCode::INVALID_ARG)
+            << "Must return INVALID_ARG for global property without area config";
+    ASSERT_FALSE(result.minSupportedValue.has_value());
+    ASSERT_FALSE(result.maxSupportedValue.has_value());
+
+    result = results.payloads[3];
+    ASSERT_EQ(result.status, StatusCode::OK);
+    ASSERT_TRUE(result.minSupportedValue.has_value());
+    ASSERT_EQ(result.minSupportedValue->int32Values.size(), 1u);
+    ASSERT_EQ(result.minSupportedValue->int32Values[0], 1);
+    ASSERT_FALSE(result.maxSupportedValue.has_value());
+}
+
+TEST_F(DefaultVehicleHalTest, testGetMinMaxSupportedValue_propIdAreaIdNotFound) {
+    auto testConfigs = std::vector<VehiclePropConfig>({
+            VehiclePropConfig{
+                    .prop = testInt32VecWindowProp(1),
+                    .areaConfigs =
+                            {
+                                    {.areaId = 1,
+                                     .hasSupportedValueInfo =
+                                             HasSupportedValueInfo{
+                                                     .hasMinSupportedValue = true,
+                                                     .hasMaxSupportedValue = true,
+                                             }},
+                            },
+            },
+    });
+
+    auto hardware = std::make_unique<MockVehicleHardware>();
+    hardware->setPropertyConfigs(testConfigs);
+
+    setHardware(std::move(hardware));
+
+    MinMaxSupportedValueResults results;
+
+    // propId not valid.
+    auto propIdAreaId1 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 1};
+    // areaId not valid.
+    auto propIdAreaId2 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(1), .areaId = 2};
+
+    auto status = getClient()->getMinMaxSupportedValue(
+            std::vector<VhalPropIdAreaId>{propIdAreaId1, propIdAreaId2}, &results);
+
+    ASSERT_TRUE(status.isOk()) << "Get non-okay status from getMinMaxSupportedValue"
+                               << status.getMessage();
+    ASSERT_EQ(results.payloads.size(), 2u);
+    MinMaxSupportedValueResult result = results.payloads[0];
+    ASSERT_EQ(result.status, StatusCode::INVALID_ARG);
+    result = results.payloads[1];
+    ASSERT_EQ(result.status, StatusCode::INVALID_ARG);
+}
+
+TEST_F(DefaultVehicleHalTest, testRegisterSupportedValueChangeCallback) {
+    auto testConfigs = std::vector<VehiclePropConfig>(
+            {VehiclePropConfig{
+                     .prop = testInt32VecProp(1),
+                     .areaConfigs =
+                             {
+                                     {.areaId = 0,
+                                      .hasSupportedValueInfo =
+                                              HasSupportedValueInfo{
+                                                      .hasMinSupportedValue = false,
+                                                      .hasMaxSupportedValue = false,
+                                                      .hasSupportedValuesList = false,
+                                              }},
+                             },
+             },
+             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));
+
+    // 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 = getClient()->registerSupportedValueChangeCallback(
+            getCallbackClient(), std::vector<VhalPropIdAreaId>{propIdAreaId1, propIdAreaId2});
+
+    ASSERT_TRUE(status.isOk()) << "Get non-okay status from registerSupportedValueChangeCallback"
+                               << status.getMessage();
+    ASSERT_THAT(
+            getHardware()->getSubscribedSupportedValueChangePropIdAreaIds(),
+            UnorderedElementsAre(PropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2}));
+}
+
+TEST_F(DefaultVehicleHalTest, testRegisterSupportedValueChangeCallback_invalidRequest) {
+    auto testConfigs = std::vector<VehiclePropConfig>({VehiclePropConfig{
+            .prop = testInt32VecProp(1),
+            .areaConfigs =
+                    {
+                            {.areaId = 0, .hasSupportedValueInfo = std::nullopt},
+                    },
+    }});
+    auto hardware = std::make_unique<MockVehicleHardware>();
+    hardware->setPropertyConfigs(testConfigs);
+
+    setHardware(std::move(hardware));
+
+    auto propIdAreaId1 = VhalPropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
+    auto status = getClient()->registerSupportedValueChangeCallback(
+            getCallbackClient(), std::vector<VhalPropIdAreaId>{propIdAreaId1});
+
+    ASSERT_FALSE(status.isOk()) << "registerSupportedValueChangeCallback must return error if one "
+                                   "of the requested [propId, areaId]"
+                                   " does not have supportedValueInfo";
+}
+
+TEST_F(DefaultVehicleHalTest, testRegisterSupportedValueChangeCallback_errorStatusFromHardware) {
+    auto testConfigs = std::vector<VehiclePropConfig>({VehiclePropConfig{
+            .prop = testInt32VecWindowProp(2),
+            .areaConfigs =
+                    {
+                            {.areaId = 2,
+                             .hasSupportedValueInfo =
+                                     HasSupportedValueInfo{
+                                             .hasMinSupportedValue = true,
+                                             .hasMaxSupportedValue = false,
+                                             .hasSupportedValuesList = false,
+                                     }},
+                    },
+    }});
+
+    auto hardware = std::make_unique<MockVehicleHardware>();
+    hardware->setStatus("subscribeSupportedValueChange", StatusCode::INTERNAL_ERROR);
+    hardware->setPropertyConfigs(testConfigs);
+
+    setHardware(std::move(hardware));
+
+    auto propIdAreaId = VhalPropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
+    auto status = getClient()->registerSupportedValueChangeCallback(
+            getCallbackClient(), std::vector<VhalPropIdAreaId>{propIdAreaId});
+
+    ASSERT_FALSE(status.isOk()) << "registerSupportedValueChangeCallback must return error if "
+                                   "VehicleHardware returns error";
+}
+
+TEST_F(DefaultVehicleHalTest, testUnregisterSupportedValueChangeCallback) {
+    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 propIdAreaId1 = VhalPropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
+    auto propIdAreaId2 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
+    auto status = getClient()->registerSupportedValueChangeCallback(
+            getCallbackClient(), std::vector<VhalPropIdAreaId>{propIdAreaId1, propIdAreaId2});
+
+    ASSERT_TRUE(status.isOk()) << "Get non-okay status from registerSupportedValueChangeCallback"
+                               << status.getMessage();
+
+    status = getClient()->unregisterSupportedValueChangeCallback(
+            getCallbackClient(), std::vector<VhalPropIdAreaId>{propIdAreaId1, propIdAreaId2});
+
+    ASSERT_TRUE(status.isOk()) << "Get non-okay status from unregisterSupportedValueChangeCallback"
+                               << status.getMessage();
+
+    EXPECT_TRUE(getHardware()->getSubscribedSupportedValueChangePropIdAreaIds().empty())
+            << "All registered [propId, areaId]s must be unregistered";
+    EXPECT_EQ(countClients(), static_cast<size_t>(0)) << "subscribe clients must be cleared";
+    EXPECT_TRUE(hasNoSubscriptions()) << "subscribe clients must be cleared";
+}
+
+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{
+                     .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 propIdAreaId1 = VhalPropIdAreaId{.propId = testInt32VecProp(1), .areaId = 0};
+    auto propIdAreaId2 = VhalPropIdAreaId{.propId = testInt32VecWindowProp(2), .areaId = 2};
+    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 e796ce5..197e99d 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleHardware.cpp
@@ -26,10 +26,12 @@
 
 using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
 using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::MinMaxSupportedValueResult;
 using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
 using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
 using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
+using ::aidl::android::hardware::automotive::vehicle::SupportedValuesListResult;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 
@@ -200,6 +202,20 @@
     return propIdAreaIds;
 }
 
+std::vector<SupportedValuesListResult> MockVehicleHardware::getSupportedValuesLists(
+        const std::vector<PropIdAreaId>& propIdAreaIds) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    mSupportedValuesListRequest = propIdAreaIds;
+    return mSupportedValuesListResponse;
+}
+
+std::vector<MinMaxSupportedValueResult> MockVehicleHardware::getMinMaxSupportedValues(
+        const std::vector<PropIdAreaId>& propIdAreaIds) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    mMinMaxSupportedValueRequest = propIdAreaIds;
+    return mMinMaxSupportedValueResponse;
+}
+
 void MockVehicleHardware::registerOnPropertyChangeEvent(
         std::unique_ptr<const PropertyChangeCallback> callback) {
     std::scoped_lock<std::mutex> lockGuard(mLock);
@@ -212,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;
@@ -267,11 +289,67 @@
     mEventBatchingWindow = window;
 }
 
+void MockVehicleHardware::setSupportedValuesListResponse(
+        const std::vector<SupportedValuesListResult>& response) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    mSupportedValuesListResponse = response;
+}
+
+void MockVehicleHardware::setMinMaxSupportedValueResponse(
+        const std::vector<MinMaxSupportedValueResult>& response) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    mMinMaxSupportedValueResponse = response;
+}
+
+std::vector<PropIdAreaId> MockVehicleHardware::getSupportedValuesListRequest() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return mSupportedValuesListRequest;
+}
+
+std::vector<PropIdAreaId> MockVehicleHardware::getMinMaxSupportedValueRequest() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return mMinMaxSupportedValueRequest;
+}
+
 std::chrono::nanoseconds MockVehicleHardware::getPropertyOnChangeEventBatchingWindow() {
     std::scoped_lock<std::mutex> lockGuard(mLock);
     return mEventBatchingWindow;
 }
 
+StatusCode MockVehicleHardware::subscribeSupportedValueChange(
+        const std::vector<PropIdAreaId>& propIdAreaIds) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    if (auto it = mStatusByFunctions.find(__func__); it != mStatusByFunctions.end()) {
+        if (StatusCode status = it->second; status != StatusCode::OK) {
+            return status;
+        }
+    }
+    for (const auto& propIdAreaId : propIdAreaIds) {
+        mSubscribedSupportedValueChangePropIdAreaIds.insert(propIdAreaId);
+    }
+    return StatusCode::OK;
+}
+
+StatusCode MockVehicleHardware::unsubscribeSupportedValueChange(
+        const std::vector<PropIdAreaId>& propIdAreaIds) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    if (auto it = mStatusByFunctions.find(__func__); it != mStatusByFunctions.end()) {
+        if (StatusCode status = it->second; status != StatusCode::OK) {
+            return status;
+        }
+    }
+    for (const auto& propIdAreaId : propIdAreaIds) {
+        mSubscribedSupportedValueChangePropIdAreaIds.erase(propIdAreaId);
+    }
+    return StatusCode::OK;
+}
+
+std::unordered_set<PropIdAreaId, PropIdAreaIdHash>
+MockVehicleHardware::getSubscribedSupportedValueChangePropIdAreaIds() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return mSubscribedSupportedValueChangePropIdAreaIds;
+}
+
 template <class ResultType>
 StatusCode MockVehicleHardware::returnResponse(
         std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
@@ -347,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 06e01a8..444166b 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/current/vhal/test/MockVehicleHardware.h
@@ -62,11 +62,21 @@
     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,
                                                                          int32_t areaId) override;
     std::chrono::nanoseconds getPropertyOnChangeEventBatchingWindow() override;
+    std::vector<aidl::android::hardware::automotive::vehicle::SupportedValuesListResult>
+    getSupportedValuesLists(const std::vector<PropIdAreaId>& propIdAreaIds) override;
+    std::vector<aidl::android::hardware::automotive::vehicle::MinMaxSupportedValueResult>
+    getMinMaxSupportedValues(const std::vector<PropIdAreaId>& propIdAreaIds) override;
+    aidl::android::hardware::automotive::vehicle::StatusCode subscribeSupportedValueChange(
+            const std::vector<PropIdAreaId>& propIdAreaIds) override;
+    aidl::android::hardware::automotive::vehicle::StatusCode unsubscribeSupportedValueChange(
+            const std::vector<PropIdAreaId>& propIdAreaIds) override;
 
     // Test functions.
     void setPropertyConfigs(
@@ -78,6 +88,14 @@
     void addSetValueResponses(
             const std::vector<aidl::android::hardware::automotive::vehicle::SetValueResult>&
                     responses);
+    void setSupportedValuesListResponse(
+            const std::vector<
+                    aidl::android::hardware::automotive::vehicle::SupportedValuesListResult>&
+                    response);
+    void setMinMaxSupportedValueResponse(
+            const std::vector<
+                    aidl::android::hardware::automotive::vehicle::MinMaxSupportedValueResult>&
+                    response);
     void setGetValueResponder(
             std::function<aidl::android::hardware::automotive::vehicle::StatusCode(
                     std::shared_ptr<const GetValuesCallback>,
@@ -88,22 +106,28 @@
     nextGetValueRequests();
     std::vector<aidl::android::hardware::automotive::vehicle::SetValueRequest>
     nextSetValueRequests();
+    std::vector<PropIdAreaId> getSupportedValuesListRequest();
+    std::vector<PropIdAreaId> getMinMaxSupportedValueRequest();
     void setStatus(const char* functionName,
                    aidl::android::hardware::automotive::vehicle::StatusCode status);
     void setSleepTime(int64_t timeInNano);
     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();
     std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions>
     getSubscribeOptions();
     void clearSubscribeOptions();
-    // Whether getAllPropertyConfigs() has been called, which blocks all all property configs
+    // Whether getAllPropertyConfigs() has been called, which blocks on all property configs
     // being ready.
     bool getAllPropertyConfigsCalled();
 
+    std::unordered_set<PropIdAreaId, PropIdAreaIdHash>
+    getSubscribedSupportedValueChangePropIdAreaIds();
+
   private:
     mutable std::mutex mLock;
     mutable std::condition_variable mCv;
@@ -118,11 +142,19 @@
             mSetValueRequests GUARDED_BY(mLock);
     mutable std::list<std::vector<aidl::android::hardware::automotive::vehicle::SetValueResult>>
             mSetValueResponses GUARDED_BY(mLock);
+    mutable std::vector<PropIdAreaId> mSupportedValuesListRequest GUARDED_BY(mLock);
+    mutable std::vector<PropIdAreaId> mMinMaxSupportedValueRequest GUARDED_BY(mLock);
+    mutable std::vector<aidl::android::hardware::automotive::vehicle::SupportedValuesListResult>
+            mSupportedValuesListResponse GUARDED_BY(mLock);
+    mutable std::vector<aidl::android::hardware::automotive::vehicle::MinMaxSupportedValueResult>
+            mMinMaxSupportedValueResponse GUARDED_BY(mLock);
     std::unordered_map<const char*, aidl::android::hardware::automotive::vehicle::StatusCode>
             mStatusByFunctions GUARDED_BY(mLock);
     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>&)>
@@ -154,6 +186,9 @@
     std::shared_ptr<RecurrentTimer> mRecurrentTimer;
     std::unordered_map<int32_t, std::unordered_map<int32_t, std::shared_ptr<std::function<void()>>>>
             mRecurrentActions GUARDED_BY(mLock);
+
+    std::unordered_set<PropIdAreaId, PropIdAreaIdHash> mSubscribedSupportedValueChangePropIdAreaIds
+            GUARDED_BY(mLock);
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/current/vhal/test/SubscriptionManagerTest.cpp b/automotive/vehicle/aidl/impl/current/vhal/test/SubscriptionManagerTest.cpp
index 5d58de5..d624cce 100644
--- a/automotive/vehicle/aidl/impl/current/vhal/test/SubscriptionManagerTest.cpp
+++ b/automotive/vehicle/aidl/impl/current/vhal/test/SubscriptionManagerTest.cpp
@@ -124,6 +124,8 @@
 
     std::shared_ptr<MockVehicleHardware> getHardware() { return mHardware; }
 
+    bool isEmpty() { return mManager->isEmpty(); }
+
   private:
     std::unique_ptr<SubscriptionManager> mManager;
     std::shared_ptr<PropertyCallback> mCallback;
@@ -351,6 +353,10 @@
                                        std::vector<int32_t>({0, 1, 2}));
     ASSERT_TRUE(result.ok()) << "unsubscribe an unsubscribed property must do nothing";
 
+    result = getManager()->unsubscribe(getCallbackClient()->asBinder().get(),
+                                       std::vector<int32_t>({0, 1, 2}));
+    ASSERT_TRUE(result.ok()) << "retry an unsubscribe operation must not throw error";
+
     std::vector<VehiclePropValue> updatedValues = {
             {
                     .prop = 0,
@@ -883,6 +889,80 @@
             << "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";
+
+    result = getManager()->unsubscribeSupportedValueChange(binder2.get(), {propIdAreaId2});
+
+    ASSERT_TRUE(result.ok()) << "failed to call unsubscribeSupportedValueChange"
+                             << result.error().message();
+
+    result = getManager()->unsubscribeSupportedValueChange(binder1.get(), {propIdAreaId1});
+
+    ASSERT_TRUE(result.ok()) << "failed to call unsubscribeSupportedValueChange"
+                             << result.error().message();
+
+    EXPECT_EQ(getManager()->countSupportedValueChangeClients(), 0u) << "All clients cleared";
+    EXPECT_TRUE(isEmpty()) << "All clients cleared";
+}
+
 }  // 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 797be73..856d38c 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 {
     /**
@@ -620,22 +621,15 @@
      * }
      *
      * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
-     *
      * {@code HasSupportedValueInfo.hasMinSupportedValue} and
      * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
-     *
-     * {@code MinMaxSupportedValueResult.minSupportedValue} represents the lower bound of the
-     * recommended tire pressure for the tire at the specified area ID.
-     *
-     * {@code MinMaxSupportedValueResult.maxSupportedValue} represents the upper bound of the
-     * recommended tire pressure for the tire at the specified area ID.
-     *
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minFloatValue.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxFloatValue.
      * For example, if the recommended tire pressure of left_front tire is from 200.0 KILOPASCAL to
      * 240.0 KILOPASCAL, {@code getMinMaxSupportedValue} for
      * [propId=TIRE_PRESSURE, areaId=VehicleAreaWheel::LEFT_FRONT] must return a
      * {@code MinMaxSupportedValueResult} with OK status, 200.0 as minSupportedValue, 240.0 as
      * maxSupportedValue.
-     *
      * At boot, minFloatValue is equal to minSupportedValue, maxFloatValue is equal to
      * maxSupportedValue.
      *
@@ -784,10 +778,8 @@
      * unless all bit flags of ImpactSensorLocation are supported.
      *
      * If {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0):
-     *
      * {@code getSupportedValuesList} must return a {@code SupportedValuesListResult} that contains
      * supported values unless all bit flags of ImpactSensorLocation are supported.
-     *
      * At boot, supportedEnumValues is equal to the supported values list.
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
@@ -825,22 +817,17 @@
      * selected by the driver instead of simply GEAR_DRIVE.
      *
      * If {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0):
-     *
      * {@code VehicleAreaConfig.HasSupportedValueInfo.hasSupportedValuesList} for the global area ID
      * (0) must be {@code true}.
-     *
      * {@code getSupportedValuesList} for [GEAR_SELECTION, areaId=0] must return a
      * {@code SupportedValuesListResult} that contains non-null {@code supportedValuesList}.
-     *
      * The supportedValues must represent the list of supported gears for this vehicle. For example,
      * for an automatic transmission, the list can be {GEAR_NEUTRAL, GEAR_REVERSE, GEAR_PARK,
      * GEAR_DRIVE, GEAR_1, GEAR_2,...} and for manual transmission it can be {GEAR_NEUTRAL,
      * GEAR_REVERSE, GEAR_1, GEAR_2,...}.
-     *
      * In the case of an automatic transmission vehicle that allows the driver to select specific
      * gears on demand (i.e. "manual mode"), the GEAR_SELECTION property value must be set to the
      * specific gear selected by the driver instead of simply GEAR_DRIVE.
-     *
      * At boot, the config array's values are equal to the supported values list.
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
@@ -866,20 +853,16 @@
      * same as that of the supported gears reported in GEAR_SELECTION.
      *
      * If {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0):
-     *
      * {@code VehicleAreaConfig.HasSupportedValueInfo.hasSupportedValuesList} for the global area ID
      * (0) must be {@code true}.
-     *
      * {@code getSupportedValuesList} for [GEAR_SELECTION, areaId=0] must return a
      * {@code SupportedValuesListResult} that contains non-null {@code supportedValuesList}.
-     *
      * The supported values list must represent the list of supported gears
      * for this vehicle.  For example, for an automatic transmission, this list can be
      * {GEAR_NEUTRAL, GEAR_REVERSE, GEAR_PARK, GEAR_1, GEAR_2,...}
      * and for manual transmission the list can be
      * {GEAR_NEUTRAL, GEAR_REVERSE, GEAR_1, GEAR_2,...}. This list need not be the
      * same as that of the supported gears reported in GEAR_SELECTION.
-     *
      * At boot, the config array's values are equal to the supported values list.
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
@@ -935,20 +918,13 @@
      * All values between min and max supported value must be supported.
      *
      * If {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0):
-     *
      * {@code HasSupportedValueInfo.hasMinSupportedValue} and
      * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for global area ID(0)
-     *
-     * {@code MinMaxSupportedValueResult.minSupportedValue} must be 0.
-     *
-     * {@code MinMaxSupportedValueResult.maxSupportedValue} indicates the setting for the maximum
-     * amount of energy regenerated from braking. The minSupportedValue indicates the setting for no
-     * regenerative braking.
-     *
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
      * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
      * maxSupportedValue.
      *
-     *
      * This property is a more granular form of EV_REGENERATIVE_BRAKING_STATE. It allows the user to
      * set a more specific level of regenerative braking if the states in EvRegenerativeBrakingState
      * are not granular enough for the OEM.
@@ -1054,14 +1030,11 @@
      * all enum values of EvStoppingMode are supported.
      *
      * If {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0):
-     *
      * For the global area ID (0), {@code getSupportedValuesList}
      * must return a {@code SupportedValuesListResult} that contains supported values unless all
      * enum values of EvStoppingMode are supported.
-     *
      * At boot, supportedEnumValues is equal to the supported values list.
      *
-     *
      * The EvStoppingMode enum may be extended to include more states in the future.
      *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
@@ -1109,12 +1082,10 @@
      * recommended) and ErrorState are supported.
      *
      * If {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0):
-     *
      * For the global area ID (0), {@code getSupportedValuesList}
      * must return a {@code SupportedValuesListResult} that contains supported values unless all
      * states of both ElectronicStabilityControlState (including OTHER, which is not
      * recommended) and ErrorState are supported.
-     *
      * At boot, supportedEnumValues is equal to the supported values list.
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
@@ -1232,24 +1203,19 @@
      * All integers between minInt32Value and maxInt32Value must be supported.
      *
      * The minInt32Value indicates the lowest fan speed.
+     *
      * The maxInt32Value indicates the highest fan speed.
      *
      * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
-     *
      * {@code HasSupportedValueInfo.hasMinSupportedValue} and
      * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the specific
      * area ID.
-     *
-     * {@code MinMaxSupportedValueResult.minSupportedValue} indicates the lowest fan speed.
-     *
-     * {@code MinMaxSupportedValueResult.maxSupportedValue} indicates the highest fan speed.
-     *
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
      * All integers between minSupportedValue and maxSupportedValue must be supported.
-     *
      * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
      * maxSupportedValue.
      *
-     *
      * This property is not in any particular unit but in a specified range of relative speeds.
      *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
@@ -1297,6 +1263,7 @@
      * The minFloatValue and maxFloatValue in VehicleAreaConfig must be defined.
      *
      * The minFloatValue indicates the minimum temperature setting in Celsius.
+     *
      * The maxFloatValue indicates the maximum temperature setting in Celsius.
      *
      * If all the values between minFloatValue and maxFloatValue are not supported, the configArray
@@ -1336,6 +1303,19 @@
      *
      * Any value set in between a valid value should be rounded to the closest valid value.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the specific
+     * area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minFloatValue.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxFloatValue.
+     * If not all the values between minSupportedValue and maxSupportedValue are supported,
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} for the
+     * specified area ID. At boot, supportedValuesList must be equal to what is described in
+     * config array.
+     * At boot, minFloatValue is equal to minSupportedValue, maxFloatValue is equal to
+     * maxSupportedValue.
+     *
      * It is highly recommended that the OEM also implement the HVAC_TEMPERATURE_VALUE_SUGGESTION
      * vehicle property because it provides applications a simple method for determining temperature
      * values that can be set for this vehicle and for converting values between Celsius and
@@ -1348,6 +1328,7 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit.CELSIUS
+     * @require_min_max_supported_value
      * @version 2
      */
     HVAC_TEMPERATURE_SET = 0x0503 + 0x10000000 + 0x05000000
@@ -1508,10 +1489,21 @@
      * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined.
      * All integers between minInt32Value and maxInt32Value must be supported.
      *
-     * The maxInt32Value indicates the maximum seat temperature heating setting.
      * The minInt32Value must be 0, unless the vehicle supports seat cooling as well. In this case,
      * minInt32Value indicates the maximum seat temperature cooling setting.
      *
+     * The maxInt32Value indicates the maximum seat temperature heating setting.
+     *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the specified
+     * area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit, but in a specified range of relative temperature
      * settings.
      *
@@ -1521,6 +1513,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     HVAC_SEAT_TEMPERATURE = 0x050B + 0x10000000 + 0x05000000
@@ -1533,9 +1526,20 @@
      * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined.
      * All integers between minInt32Value and maxInt32Value must be supported.
      *
-     * The maxInt32Value in the config data represents the maximum heating level.
      * The minInt32Value in the config data MUST be zero and indicates no heating.
      *
+     * The maxInt32Value in the config data represents the maximum heating level.
+     *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the specified
+     * area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative heating
      * settings.
      *
@@ -1545,6 +1549,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     HVAC_SIDE_MIRROR_HEAT = 0x050C + 0x10000000 + 0x04000000
@@ -1557,10 +1562,20 @@
      * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined.
      * All integers between minInt32Value and maxInt32Value must be supported.
      *
-     * The maxInt32Value indicates the maximum steering wheel heating setting.
      * The minInt32Value should be 0, unless the vehicle supports steering wheel cooling as well. In
      * such a case, the minInt32Value indicates the maximum steering wheel cooling setting.
      *
+     * The maxInt32Value indicates the maximum steering wheel heating setting.
+     *
+     * If {@code HasSupportedValueInfo} is not null for the global area ID (0):
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true}.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of heating settings.
      *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
@@ -1569,6 +1584,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     HVAC_STEERING_WHEEL_HEAT = 0x050D + 0x10000000 + 0x01000000
@@ -1576,12 +1592,21 @@
     /**
      * Temperature units for display
      *
-     * Indicates whether the vehicle is displaying temperature to the user as
-     * Celsius or Fahrenheit.
+     * Indicates whether the vehicle is displaying temperature to the user as Celsius or Fahrenheit.
+     *
      * VehiclePropConfig.configArray is used to indicate the supported temperature display units.
+     *
      * For example: configArray[0] = CELSIUS
      *              configArray[1] = FAHRENHEIT
      *
+     * If {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0):
+     * {@code VehicleAreaConfig.HasSupportedValueInfo.hasSupportedValuesList} for the global area ID
+     * (0) must be {@code true}.
+     * {@code getSupportedValuesLists} for [HVAC_TEMPERATURE_DISPLAY_UNITS, areaId=0] must return a
+     * {@code SupportedValuesListResult} that contains non-null {@code supportedValuesList},
+     * e.g. [CELSIUS, FAHRENHEIT].
+     * At boot, the values in the config array are equal to the supported values list.
+     *
      * This parameter MAY be used for displaying any HVAC temperature in the system.
      * Values must be one of VehicleUnit.CELSIUS or VehicleUnit.FAHRENHEIT
      * Note that internally, all temperatures are represented in floating point Celsius.
@@ -1596,6 +1621,8 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleUnit
+     * @require_supported_values_list
+     * @legacy_supported_values_in_config
      * @version 2
      */
     HVAC_TEMPERATURE_DISPLAY_UNITS = 0x050E + 0x10000000 + 0x01000000
@@ -1696,12 +1723,24 @@
     /**
      * Seat ventilation
      *
-     * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined.
+     * The minInt32Value and maxInt32Value in VehicleAreaConfig must be defined.
+     *
      * All integers between minInt32Value and maxInt32Value must be supported.
      *
      * The minInt32Value must be 0.
+     *
      * The maxInt32Value indicates the maximum ventilation setting available for the seat.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the specified
+     * area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in the specified range of ventilation
      * settings.
      *
@@ -1715,6 +1754,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     HVAC_SEAT_VENTILATION = 0x0513 + 0x10000000 + 0x05000000
@@ -1800,6 +1840,14 @@
      *              configArray[1] = KILOMETER
      *              configArray[2] = MILE
      *
+     * If {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0):
+     * {@code VehicleAreaConfig.HasSupportedValueInfo.hasSupportedValuesList} for the global area ID
+     * (0) must be {@code true}.
+     * {@code getSupportedValuesLists} for [DISTANCE_DISPLAY_UNITS, areaId=0] must returns a
+     * {@code SupportedValuesListResult} that contains non-null {@code supportedValuesList},
+     * e.g. [METER, KILOMETER, MILE].
+     * At boot, the values in the config array are equal to the supported values list.
+     *
      * If updating DISTANCE_DISPLAY_UNITS affects the values of other *_DISPLAY_UNITS properties,
      * then their values must be updated and communicated to the AAOS framework as well.
      *
@@ -1810,6 +1858,8 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleUnit
+     * @require_supported_values_list
+     * @legacy_supported_values_in_config
      * @version 2
      */
     DISTANCE_DISPLAY_UNITS = 0x0600 + 0x10000000 + 0x01000000
@@ -1825,6 +1875,14 @@
      * For example: configArray[0] = LITER
      *              configArray[1] = GALLON
      *
+     * If {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0):
+     * {@code VehicleAreaConfig.HasSupportedValueInfo.hasSupportedValuesList} for the global area ID
+     * (0) must be {@code true}.
+     * {@code getSupportedValuesLists} for [FUEL_VOLUME_DISPLAY_UNITS, areaId=0] must return a
+     * {@code SupportedValuesListResult} that contains non-null {@code supportedValuesList},
+     * e.g. [LITER, GALLON].
+     * At boot, the values in the config array are equal to the supported values list.
+     *
      * If updating FUEL_VOLUME_DISPLAY_UNITS affects the values of other *_DISPLAY_UNITS properties,
      * then their values must be updated and communicated to the AAOS framework as well.
      *
@@ -1835,6 +1893,8 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleUnit
+     * @require_supported_values_list
+     * @legacy_supported_values_in_config
      * @version 2
      */
     FUEL_VOLUME_DISPLAY_UNITS = 0x0601 + 0x10000000 + 0x01000000
@@ -1851,6 +1911,14 @@
      *              configArray[1] = PSI
      *              configArray[2] = BAR
      *
+     * If {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0):
+     * {@code VehicleAreaConfig.HasSupportedValueInfo.hasSupportedValuesList} for the global area ID
+     * (0) must be {@code true}.
+     * {@code getSupportedValuesLists} for [TIRE_PRESSURE_DISPLAY_UNITS, areaId=0] must return a
+     * {@code SupportedValuesListResult} that contains non-null {@code supportedValuesList},
+     * e.g. [KILOPASCAL, PSI, BAR].
+     * At boot, the values in the config array are equal to the supported values list.
+     *
      * If updating TIRE_PRESSURE_DISPLAY_UNITS affects the values of other *_DISPLAY_UNITS
      * properties, then their values must be updated and communicated to the AAOS framework as well.
      *
@@ -1861,6 +1929,8 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleUnit
+     * @require_supported_values_list
+     * @legacy_supported_values_in_config
      * @version 2
      */
     TIRE_PRESSURE_DISPLAY_UNITS = 0x0602 + 0x10000000 + 0x01000000
@@ -1877,6 +1947,14 @@
      *              configArray[1] = AMPERE_HOURS
      *              configArray[2] = KILOWATT_HOUR
      *
+     * If {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0):
+     * {@code VehicleAreaConfig.HasSupportedValueInfo.hasSupportedValuesList} for the global area ID
+     * (0) must be {@code true}.
+     * {@code getSupportedValuesLists} for [EV_BATTERY_DISPLAY_UNITS, areaId=0] must return a
+     * {@code SupportedValuesListResult} that contains non-null {@code supportedValuesList},
+     * e.g. [WATT_HOUR, AMPERE_HOURS, KILOWATT_HOUR].
+     * At boot, the values in the config array are equal to the supported values list.
+     *
      * If updating EV_BATTERY_DISPLAY_UNITS affects the values of other *_DISPLAY_UNITS properties,
      * then their values must be updated and communicated to the AAOS framework as well.
      *
@@ -1887,6 +1965,8 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleUnit
+     * @require_supported_values_list
+     * @legacy_supported_values_in_config
      * @version 2
      */
     EV_BATTERY_DISPLAY_UNITS = 0x0603 + 0x10000000 + 0x01000000
@@ -1920,17 +2000,13 @@
      *              configArray[2] = KILOMETERS_PER_HOUR
      *
      * If {@code HasSupportedValueInfo} is not {@code null} for the global area ID (0):
-     *
      * {@code VehicleAreaConfig.HasSupportedValueInfo.hasSupportedValuesList} for the global area ID
      * (0) must be {@code true}.
-     *
      * {@code getSupportedValuesLists} for [VEHICLE_SPEED_DISPLAY_UNITS, areaId=0] must return a
      * {@code SupportedValuesListResult} that contains non-null {@code supportedValuesList},
      * e.g. [METER_PER_SEC, MILES_PER_HOUR, KILOMETERS_PER_HOUR].
-     *
      * At boot, the values in the config array are equal to the supported values list.
      *
-     *
      * If updating VEHICLE_SPEED_DISPLAY_UNITS affects the values of other *_DISPLAY_UNITS
      * properties, then their values must be updated and communicated to the AAOS framework as well.
      *
@@ -2357,11 +2433,21 @@
      * All integers between minInt32Value and maxInt32Value must be supported.
      *
      * The minInt32Value indicates the door is closed. The minInt32Value must be 0.
+     *
      * The maxInt32Value indicates the door is fully open.
      *
      * Values in between minInt32Value and maxInt32Value indicate a transition state between the
      * closed and fully open positions.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative positions.
      *
      * Some vehicles (minivans) can open the door electronically. Hence, the
@@ -2373,6 +2459,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     DOOR_POS = 0x0B00 + 0x10000000 + 0x06000000
@@ -2383,13 +2470,23 @@
      * The maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers
      * between minInt32Value and maxInt32Value must be supported.
      *
-     * The maxInt32Value represents the maximum movement speed of the door while opening.
      * The minInt32Value represents the maximum movement speed of the door while closing.
      *
+     * The maxInt32Value represents the maximum movement speed of the door while opening.
+     *
      * Larger absolute values, either positive or negative, indicate a faster movement speed. Once
      * the door reaches the positional limit, the value must reset to 0. If DOOR_MOVE's value is
      * currently 0, then that means there is no movement currently occurring.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative movement
      * speeds.
      *
@@ -2399,6 +2496,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     DOOR_MOVE = 0x0B01 + 0x10000000 + 0x06000000
@@ -2443,13 +2541,26 @@
      *
      * The minInt32Value indicates the mirror is tilted completely downwards. This must be a
      * non-positive value.
+     *
      * The maxInt32Value indicates the mirror is tilted completely upwards. This must be a
      * non-negative value.
+     *
      * 0 indicates the mirror is not tilted in either direction.
      *
      * Values in between minInt32Value and maxInt32Value indicate a transition state between the
      * fully downward and fully upwards positions.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * Values in between minSupportedValue and maxSupportedValue indicate a transition state between
+     * the fully downward and fully upwards positions.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative positions.
      *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
@@ -2458,6 +2569,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     MIRROR_Z_POS = 0x0B40 + 0x10000000 + 0x04000000
@@ -2468,14 +2580,24 @@
      * The maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers
      * between minInt32Value and maxInt32Value must be supported.
      *
-     * The maxInt32Value represents the maximum movement speed of the mirror while tilting upwards.
      * The minInt32Value represents the maximum movement speed of the mirror while tilting
      * downwards.
      *
+     * The maxInt32Value represents the maximum movement speed of the mirror while tilting upwards.
+     *
      * Larger absolute values, either positive or negative, indicate a faster movement speed. Once
      * the mirror reaches the positional limit, the value must reset to 0. If MIRROR_Z_MOVE's value
      * is currently 0, then that means there is no movement currently occurring.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative movement
      * speeds.
      *
@@ -2485,6 +2607,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     MIRROR_Z_MOVE = 0x0B41 + 0x10000000 + 0x04000000
@@ -2497,13 +2620,26 @@
      *
      * The minInt32Value indicates the mirror is tilted completely to the left. This must be a
      * non-positive value.
+     *
      * The maxInt32Value indicates the mirror is tilted completely to the right. This must be a
      * non-negative value.
+     *
      * 0 indicates the mirror is not tilted in either direction.
      *
      * Values in between minInt32Value and maxInt32Value indicate a transition state between the
      * left extreme and right extreme positions.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * Values in between minSupportedValue and maxSupportedValue indicate a transition state between
+     * the fully downward and fully upwards positions.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative positions.
      *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
@@ -2512,6 +2648,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     MIRROR_Y_POS = 0x0B42 + 0x10000000 + 0x04000000
@@ -2522,13 +2659,23 @@
      * The maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers
      * between minInt32Value and maxInt32Value must be supported.
      *
-     * The maxInt32Value represents the maximum movement speed of the mirror while tilting right.
      * The minInt32Value represents the maximum movement speed of the mirror while tilting left.
      *
+     * The maxInt32Value represents the maximum movement speed of the mirror while tilting right.
+     *
      * Larger absolute values, either positive or negative, indicate a faster movement speed. Once
      * the mirror reaches the positional limit, the value must reset to 0. If MIRROR_Y_MOVE's value
      * is currently 0, then that means there is no movement currently occurring.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative movement
      * speeds.
      *
@@ -2538,6 +2685,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     MIRROR_Y_MOVE = 0x0B43 + 0x10000000 + 0x04000000
@@ -2614,17 +2762,30 @@
     /**
      * Seat memory select
      *
-     * This parameter selects the memory preset to use to select the seat position. The
-     * maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers between
-     * minInt32Value and maxInt32Value must be supported. The minInt32Value is always 0, and the
-     * maxInt32Value determines the number of seat preset memory slots available (i.e.
-     * numSeatPresets - 1).
+     * This parameter selects the memory preset to use to select the seat position.
+     *
+     * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined.
+     *
+     * All integers between minInt32Value and maxInt32Value must be supported.
+     *
+     * The minInt32Value is always 0, and the maxInt32Value determines the number of seat preset
+     * memory slots available (i.e. numSeatPresets - 1).
      *
      * For instance, if the driver's seat has 3 memory presets, the maxInt32Value will be 2. When
      * the user wants to select a preset, the desired preset number (0, 1, or 2) is set.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_MEMORY_SELECT = 0x0B80 + 0x10000000 + 0x05000000
@@ -2633,12 +2794,24 @@
      * Seat memory set
      *
      * This setting allows the user to save the current seat position settings into the selected
-     * preset slot. The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. The
-     * minInt32Value must be 0, and the maxInt32Value for each seat position must match the
+     * preset slot.
+     *
+     * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined.
+     *
+     * The minInt32Value must be 0, and the maxInt32Value for each seat position must match the
      * maxInt32Value for SEAT_MEMORY_SELECT.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_MEMORY_SET = 0x0B81 + 0x10000000 + 0x05000000
@@ -2670,11 +2843,22 @@
      * All integers between minInt32Value and maxInt32Value must be supported.
      *
      * The minInt32Value indicates the seat belt's shoulder anchor is at its lowest position.
+     *
      * The maxInt32Value indicates the seat belt's shoulder anchor is at its highest position.
      *
      * Values in between minInt32Value and maxInt32Value indicate a transition state between the
      * lowest and highest positions.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * Values in between minSupportedValue and maxSupportedValue indicate a transition state between
+     * the lowest and highest positions. All integers between minSupportedValue and
+     * maxSupportedValue must be supported. At boot, minInt32Value is equal to minSupportedValue,
+     * maxInt32Value is equal to maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative positions.
      *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
@@ -2683,6 +2867,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_BELT_HEIGHT_POS = 0x0B83 + 0x10000000 + 0x05000000
@@ -2693,16 +2878,26 @@
      * The maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers
      * between minInt32Value and maxInt32Value must be supported.
      *
-     * The maxInt32Value represents the maximum movement speed of the seat belt's shoulder anchor
-     * while moving upwards.
      * The minInt32Value represents the maximum movement speed of the seat belt's shoulder anchor
      * while moving downwards.
      *
+     * The maxInt32Value represents the maximum movement speed of the seat belt's shoulder anchor
+     * while moving upwards.
+     *
      * Larger absolute values, either positive or negative, indicate a faster movement speed. Once
      * the seat belt reaches the positional limit, the value must reset to 0. If
      * SEAT_BELT_HEIGHT_MOVE's value is currently 0, then that means there is no movement currently
      * occurring.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative movement
      * speeds.
      *
@@ -2712,6 +2907,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_BELT_HEIGHT_MOVE = 0x0B84 + 0x10000000 + 0x05000000
@@ -2725,11 +2921,21 @@
      * All integers between minInt32Value and maxInt32Value must be supported.
      *
      * The minInt32Value indicates the seat is at its rearward-most linear position.
+     *
      * The maxInt32Value indicates the seat is at its forward-most linear position.
      *
      * Values in between minInt32Value and maxInt32Value indicate a transition state between the
      * closest and farthest positions.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative positions.
      *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
@@ -2738,6 +2944,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_FORE_AFT_POS = 0x0B85 + 0x10000000 + 0x05000000
@@ -2750,13 +2957,23 @@
      * The maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers
      * between minInt32Value and maxInt32Value must be supported.
      *
-     * The maxInt32Value represents the maximum movement speed of the seat while moving forward.
      * The minInt32Value represents the maximum movement speed of the seat while moving backward.
      *
+     * The maxInt32Value represents the maximum movement speed of the seat while moving forward.
+     *
      * Larger absolute values, either positive or negative, indicate a faster movement speed. Once
      * the seat reaches the positional limit, the value must reset to 0. If SEAT_FORE_AFT_MOVE's
      * value is currently 0, then that means there is no movement currently occurring.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative movement
      * speeds.
      *
@@ -2766,6 +2983,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_FORE_AFT_MOVE = 0x0B86 + 0x10000000 + 0x05000000
@@ -2780,12 +2998,24 @@
      *
      * The minInt32Value indicates the seat backrest's full recline position w.r.t the
      * actuator at the bottom of the seat.
+     *
      * The maxInt32Value indicates the seat backrest's most upright/forward position w.r.t the
      * actuator at the bottom of the seat.
      *
      * Values in between minInt32Value and maxInt32Value indicate a transition state between the
      * full recline and upright/forward positions.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * Values in between minSupportedValue and maxSupportedValue indicate a transition state between
+     * the full recline and upright/forward positions.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative positions.
      *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
@@ -2794,6 +3024,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_BACKREST_ANGLE_1_POS = 0x0B87 + 0x10000000 + 0x05000000
@@ -2804,15 +3035,25 @@
      * The maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers
      * between minInt32Value and maxInt32Value must be supported.
      *
+     * The minInt32Value represents the maximum movement speed of the seat backrest while reclining.
+     *
      * The maxInt32Value represents the maximum movement speed of the seat backrest while angling
      * forward.
-     * The minInt32Value represents the maximum movement speed of the seat backrest while reclining.
      *
      * Larger absolute values, either positive or negative, indicate a faster movement speed. Once
      * the seat backrest reaches the positional limit, the value must reset to 0. If
      * SEAT_BACKREST_ANGLE_1_MOVE's value is currently 0, then that means there is no movement
      * currently occurring.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative movement
      * speeds.
      *
@@ -2822,6 +3063,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_BACKREST_ANGLE_1_MOVE = 0x0B88 + 0x10000000 + 0x05000000
@@ -2837,6 +3079,7 @@
      * The minInt32Value indicates the seat backrest's full recline position w.r.t the next
      * actuator in the backrest from the one at the bottom of the seat (see
      * SEAT_BACKREST_ANGLE_1_POS for additional details).
+     *
      * The maxInt32Value indicates the seat backrest's most upright/forward position w.r.t the
      * next actuator in the backrest from the one at the bottom of the seat(see
      * SEAT_BACKREST_ANGLE_1_POS for additional details).
@@ -2844,6 +3087,17 @@
      * Values in between minInt32Value and maxInt32Value indicate a transition state between the
      * full recline and upright/forward positions.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} ihas the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * Values in between minSupportedValue and maxSupportedValue indicate a transition state between
+     * the full recline and upright/forward positions.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative positions.
      *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
@@ -2852,6 +3106,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_BACKREST_ANGLE_2_POS = 0x0B89 + 0x10000000 + 0x05000000
@@ -2862,15 +3117,25 @@
      * The maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers
      * between minInt32Value and maxInt32Value must be supported.
      *
+     * The minInt32Value represents the maximum movement speed of the seat backrest while reclining.
+     *
      * The maxInt32Value represents the maximum movement speed of the seat backrest while angling
      * forward.
-     * The minInt32Value represents the maximum movement speed of the seat backrest while reclining.
      *
      * Larger absolute values, either positive or negative, indicate a faster movement speed. Once
      * the seat backrest reaches the positional limit, the value must reset to 0. If
      * SEAT_BACKREST_ANGLE_2_MOVE's value is currently 0, then that means there is no movement
      * currently occurring.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative movement
      * speeds.
      *
@@ -2880,6 +3145,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_BACKREST_ANGLE_2_MOVE = 0x0B8A + 0x10000000 + 0x05000000
@@ -2891,11 +3157,22 @@
      * All integers between minInt32Value and maxInt32Value must be supported.
      *
      * The minInt32Value indicates the seat is in its lowest position.
+     *
      * The maxInt32Value indicates the seat is in its highest position.
      *
      * Values in between minInt32Value and maxInt32Value indicate a transition state between the
      * lowest and highest positions.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * position.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative positions.
      *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
@@ -2904,6 +3181,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_HEIGHT_POS = 0x0B8B + 0x10000000 + 0x05000000
@@ -2914,13 +3192,23 @@
      * The maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers
      * between minInt32Value and maxInt32Value must be supported.
      *
-     * The maxInt32Value represents the maximum movement speed of the seat while moving upward.
      * The minInt32Value represents the maximum movement speed of the seat while moving downward.
      *
+     * The maxInt32Value represents the maximum movement speed of the seat while moving upward.
+     *
      * Larger absolute values, either positive or negative, indicate a faster movement speed. Once
      * the seat reaches the positional limit, the value must reset to 0. If SEAT_HEIGHT_MOVE's value
      * is currently 0, then that means there is no movement currently occurring.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative movement
      * speeds.
      *
@@ -2930,6 +3218,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_HEIGHT_MOVE = 0x0B8C + 0x10000000 + 0x05000000
@@ -2945,12 +3234,22 @@
      * The minInt32Value indicates the seat is in its shallowest position (i.e. the position with
      * the smallest distance between the front edge of the seat cushion and the rear end of the
      * seat).
+     *
      * The maxInt32Value indicates the seat is in its deepest position (i.e. the position with the
      * largest distance between the front edge of the seat cushion and the rear end of the seat).
      *
      * Values in between minInt32Value and maxInt32Value indicate a transition state between the
      * shallowest and deepest positions.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative positions.
      *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
@@ -2959,6 +3258,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_DEPTH_POS = 0x0B8D + 0x10000000 + 0x05000000
@@ -2969,14 +3269,24 @@
      * The maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers
      * between minInt32Value and maxInt32Value must be supported.
      *
-     * The maxInt32Value represents the maximum movement speed of the seat while getting deeper
      * The minInt32Value represents the maximum movement speed of the seat while getting shallower.
      *
+     * The maxInt32Value represents the maximum movement speed of the seat while getting deeper.
+     *
      * Larger absolute values, either positive or negative, indicate a faster movement speed. Once
      * the seat backrest reaches the positional limit, the value must reset to 0. If
      * SEAT_DEPTH_MOVE's value is currently 0, then that means there is no movement currently
      * occurring.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative movement
      * speeds.
      *
@@ -2986,6 +3296,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_DEPTH_MOVE = 0x0B8E + 0x10000000 + 0x05000000
@@ -2999,6 +3310,7 @@
      * The minInt32Value indicates the seat bottom is angled at its lowest angular position. This
      * corresponds to the seat's front edge at its lowest possible position relative to the rear
      * end of the seat.
+     *
      * The maxInt32Value indicates the seat bottom is angled at its highest angular position. This
      * corresponds to the seat's front edge at its highest possible position relative to the rear
      * end of the seat.
@@ -3006,6 +3318,15 @@
      * Values in between minInt32Value and maxInt32Value indicate a transition state between the
      * lowest and highest positions.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative positions.
      *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
@@ -3014,6 +3335,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_TILT_POS = 0x0B8F + 0x10000000 + 0x05000000
@@ -3024,15 +3346,25 @@
      * The maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers
      * between minInt32Value and maxInt32Value must be supported.
      *
-     * The maxInt32Value represents the maximum movement speed of the front edge of the seat while
-     * moving upward.
      * The minInt32Value represents the maximum movement speed of the front edge of the seat while
      * moving downward.
      *
+     * The maxInt32Value represents the maximum movement speed of the front edge of the seat while
+     * moving upward.
+     *
      * Larger absolute values, either positive or negative, indicate a faster movement speed. Once
      * the seat bottom reaches the positional limit, the value must reset to 0. If SEAT_TILT_MOVE's
      * value is currently 0, then that means there is no movement currently occurring.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative movement
      * speeds.
      *
@@ -3042,6 +3374,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_TILT_MOVE = 0x0B90 + 0x10000000 + 0x05000000
@@ -3054,12 +3387,22 @@
      *
      * The minInt32Value indicates the lumbar support is in its rearward most position (i.e. least
      * supportive position).
+     *
      * The maxInt32Value indicates the lumbar support is in its forward most position (i.e. most
      * supportive position).
      *
      * Values in between minInt32Value and maxInt32Value indicate a transition state between the
      * forward and rearward positions.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative positions.
      *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
@@ -3068,6 +3411,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_LUMBAR_FORE_AFT_POS = 0x0B91 + 0x10000000 + 0x05000000
@@ -3078,16 +3422,26 @@
      * The maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers
      * between minInt32Value and maxInt32Value must be supported.
      *
-     * The maxInt32Value represents the maximum movement speed of the seat's lumbar support while
-     * moving forward.
      * The minInt32Value represents the maximum movement speed of the seat's lumbar support while
      * moving backward.
      *
+     * The maxInt32Value represents the maximum movement speed of the seat's lumbar support while
+     * moving forward.
+     *
      * Larger absolute values, either positive or negative, indicate a faster movement speed. Once
      * the seat's lumbar support reaches the positional limit, the value must reset to 0. If
      * SEAT_LUMBAR_FORE_AFT_MOVE's value is currently 0, then that means there is no movement
      * currently occurring.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative movement
      * speeds.
      *
@@ -3097,6 +3451,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_LUMBAR_FORE_AFT_MOVE = 0x0B92 + 0x10000000 + 0x05000000
@@ -3109,12 +3464,22 @@
      *
      * The minInt32Value indicates the lumbar side support is in its thinnest position (i.e.
      * most support).
+     *
      * The maxInt32Value indicates the lumbar side support is in its widest position (i.e.
      * least support).
      *
      * Values in between minInt32Value and maxInt32Value indicate a transition state between the
      * thinnest and widest positions.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative positions.
      *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
@@ -3123,6 +3488,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_LUMBAR_SIDE_SUPPORT_POS = 0x0B93 + 0x10000000 + 0x05000000
@@ -3133,16 +3499,26 @@
      * The maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers
      * between minInt32Value and maxInt32Value must be supported.
      *
-     * The maxInt32Value represents the maximum movement speed of the seat's lumbar side support
-     * while getting wider.
      * The minInt32Value represents the maximum movement speed of the seat's lumbar side support
      * while getting thinner.
      *
+     * The maxInt32Value represents the maximum movement speed of the seat's lumbar side support
+     * while getting wider.
+     *
      * Larger absolute values, either positive or negative, indicate a faster movement speed. Once
      * the seat's lumbar side support reaches the positional limit, the value must reset to 0. If
      * SEAT_LUMBAR_SIDE_SUPPORT_MOVE's value is currently 0, then that means there is no movement
      * currently occurring.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative movement
      * speeds.
      *
@@ -3152,6 +3528,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 0x0B94 + 0x10000000 + 0x05000000
@@ -3188,11 +3565,21 @@
      * All integers between minInt32Value and maxInt32Value must be supported.
      *
      * The minInt32Value indicates the headrest is in its lowest position.
+     *
      * The maxInt32Value indicates the headrest is in its highest position.
      *
      * Values in between minInt32Value and maxInt32Value indicate a transition state between the
      * lowest and highest positions.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative positions.
      *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
@@ -3201,6 +3588,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_HEADREST_HEIGHT_POS_V2 =
@@ -3212,16 +3600,26 @@
      * The maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers
      * between minInt32Value and maxInt32Value must be supported.
      *
-     * The maxInt32Value represents the maximum movement speed of the seat's headrest while moving
-     * up.
      * The minInt32Value represents the maximum movement speed of the seat's headrest while moving
      * down.
      *
+     * The maxInt32Value represents the maximum movement speed of the seat's headrest while moving
+     * up.
+     *
      * Larger absolute values, either positive or negative, indicate a faster movement speed. Once
      * the seat's headrest reaches the positional limit, the value must reset to 0. If
      * SEAT_HEADREST_HEIGHT_MOVE's value is currently 0, then that means there is no movement
      * currently occurring.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative movement
      * speeds.
      *
@@ -3231,6 +3629,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_HEADREST_HEIGHT_MOVE = 0x0B96 + 0x10000000 + 0x05000000
@@ -3242,11 +3641,21 @@
      * All integers between minInt32Value and maxInt32Value must be supported.
      *
      * The minInt32Value indicates the headrest is in its full recline position.
+     *
      * The maxInt32Value indicates the headrest is in its most upright/forward position.
      *
      * Values in between minInt32Value and maxInt32Value indicate a transition state between the
      * full recline and most upright/forward positions.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative positions.
      *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
@@ -3255,6 +3664,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_HEADREST_ANGLE_POS = 0x0B97 + 0x10000000 + 0x05000000
@@ -3265,16 +3675,26 @@
      * The maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers
      * between minInt32Value and maxInt32Value must be supported.
      *
-     * The maxInt32Value represents the maximum movement speed of the seat's headrest while moving
-     * into an upright/forward position.
      * The minInt32Value represents the maximum movement speed of the seat's headrest while moving
      * into a shallow position.
      *
+     * The maxInt32Value represents the maximum movement speed of the seat's headrest while moving
+     * into an upright/forward position.
+     *
      * Larger absolute values, either positive or negative, indicate a faster movement speed. Once
      * the seat's headrest reaches the positional limit, the value must reset to 0. If
      * SEAT_HEADREST_ANGLE_MOVE's value is currently 0, then that means there is no movement
      * currently occurring.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative movement
      * speeds.
      *
@@ -3284,6 +3704,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_HEADREST_ANGLE_MOVE = 0x0B98 + 0x10000000 + 0x05000000
@@ -3295,11 +3716,21 @@
      * All integers between minInt32Value and maxInt32Value must be supported.
      *
      * The minInt32Value indicates the headrest is in its rearward-most linear position.
+     *
      * The maxInt32Value indicates the headrest is in its forward-most linear position.
      *
      * Values in between minInt32Value and maxInt32Value indicate a transition state between the
      * forward and rearward positions.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative positions.
      *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
@@ -3308,6 +3739,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_HEADREST_FORE_AFT_POS = 0x0B99 + 0x10000000 + 0x05000000
@@ -3318,16 +3750,26 @@
      * The maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers
      * between minInt32Value and maxInt32Value must be supported.
      *
-     * The maxInt32Value represents the maximum movement speed of the seat's headrest while moving
-     * forward.
      * The minInt32Value represents the maximum movement speed of the seat's headrest while moving
      * backward.
      *
+     * The maxInt32Value represents the maximum movement speed of the seat's headrest while moving
+     * forward.
+     *
      * Larger absolute values, either positive or negative, indicate a faster movement speed. Once
      * the seat's headrest reaches the positional limit, the value must reset to 0. If
      * SEAT_HEADREST_FORE_AFT_MOVE's value is currently 0, then that means there is no movement
      * currently occurring.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative movement
      * speeds.
      *
@@ -3337,6 +3779,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_HEADREST_FORE_AFT_MOVE = 0x0B9A + 0x10000000 + 0x05000000
@@ -3356,6 +3799,11 @@
      * For each supported area ID, the VehicleAreaConfig#supportedEnumValues must be defined unless
      * all enum values of VehicleLightState are supported.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} for the area ID
+     * unless all enum values of VehicleLightState are supported.
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightState
@@ -3378,6 +3826,11 @@
      * For each supported area ID, the VehicleAreaConfig#supportedEnumValues must be defined unless
      * all enum values of VehicleLightSwitch are supported.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} for the area ID
+     * unless all enum values of VehicleLightSwitch are supported.
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
      * implement it as VehiclePropertyAccess.READ only.
      *
@@ -3443,6 +3896,12 @@
      * all states of VehicleAirbagLocation are supported (including OTHER, which is not
      * recommended).
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} for the area ID
+     * unless all states of VehicleAirbagLocation are supported (including OTHER, which is not
+     * recommended).
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleAirbagLocation
@@ -3456,14 +3915,24 @@
      * The maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers
      * between minInt32Value and maxInt32Value must be supported.
      *
-     * The maxInt32Value indicates the seat cushion side support is in its widest position (i.e.
-     * least support).
      * The minInt32Value indicates the seat cushion side support is in its thinnest position (i.e.
      * most support).
      *
+     * The maxInt32Value indicates the seat cushion side support is in its widest position (i.e.
+     * least support).
+     *
      * Values in between minInt32Value and maxInt32Value indicate a transition state between the
      * thinnest and widest positions.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative positions.
      *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
@@ -3472,6 +3941,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_CUSHION_SIDE_SUPPORT_POS =
@@ -3482,16 +3952,26 @@
      * The maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers
      * between minInt32Value and maxInt32Value must be supported.
      *
-     * The maxInt32Value represents the maximum movement speed of the seat cushion side support when
-     * growing wider (i.e. support is decreasing).
      * The minInt32Value represents the maximum movement speed of the seat cushion side support when
      * growing thinner (i.e. support is increasing).
      *
+     * The maxInt32Value represents the maximum movement speed of the seat cushion side support when
+     * growing wider (i.e. support is decreasing).
+     *
      * Larger absolute values, either positive or negative, indicate a faster movement speed. Once
      * the seat cushion side support reaches the positional limit, the value must reset to 0. If
      * SEAT_CUSHION_SIDE_SUPPORT_MOVE's value is currently 0, then that means there is no movement
      * currently occurring.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative movement
      * speeds.
      *
@@ -3501,6 +3981,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_CUSHION_SIDE_SUPPORT_MOVE =
@@ -3511,12 +3992,22 @@
      * The maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers
      * between minInt32Value and maxInt32Value must be supported.
      *
-     * The maxInt32Value indicates the lumbar support's highest position.
      * The minInt32Value indicates the lumbar support's lowest position.
      *
+     * The maxInt32Value indicates the lumbar support's highest position.
+     *
      * Values in between minInt32Value and maxInt32Value indicate a transition state between the
      * lowest and highest positions.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative positions.
      *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
@@ -3525,6 +4016,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_LUMBAR_VERTICAL_POS =
@@ -3535,14 +4027,24 @@
      * The maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers
      * between minInt32Value and maxInt32Value must be supported.
      *
-     * The maxInt32Value indicates the lumbar support is moving at the fastest upward speed.
      * The minInt32Value indicates the lumbar support is moving at the fastest downward speed.
      *
+     * The maxInt32Value indicates the lumbar support is moving at the fastest upward speed.
+     *
      * Larger absolute values, either positive or negative, indicate a faster movement speed. Once
      * the seat cushion side support reaches the positional limit, the value must reset to 0. If
      * SEAT_LUMBAR_VERTICAL_MOVE's value is currently 0, then that means there is no movement
      * currently occurring.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative movement
      * speeds.
      *
@@ -3552,6 +4054,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_LUMBAR_VERTICAL_MOVE =
@@ -3563,11 +4066,21 @@
      * All integers between minInt32Value and maxInt32Value must be supported.
      *
      * The minInt32Value indicates the normal seat position. The minInt32Value must be 0.
+     *
      * The maxInt32Value indicates the seat is in the full walk-in position.
      *
      * Values in between minInt32Value and maxInt32Value indicate a transition state between the
      * normal and walk-in positions.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative positions.
      *
      * The area ID must match the seat that actually moves when the walk-in feature activates, not
@@ -3579,6 +4092,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     SEAT_WALK_IN_POS =
@@ -3619,6 +4133,7 @@
      * Window Position
      *
      * The maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined.
+     *
      * All integers between minInt32Value and maxInt32Value must be supported.
      *
      * The minInt32Value indicates the window is closed/fully open out of plane. If the window
@@ -3626,6 +4141,7 @@
      * and must be 0. If the window can open out of plane, the minInt32Value indicates the window
      * is fully open in its position out of plane and will be a negative value. See the example
      * below for a more detailed explanation.
+     *
      * The maxInt32Value indicates the window is fully open.
      *
      * Values in between minInt32Value and maxInt32Value indicate a transition state between the
@@ -3642,12 +4158,22 @@
      *
      *    Note that in this mode, 0 indicates the window is closed.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
      * implement it as VehiclePropertyAccess.READ only.
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     WINDOW_POS = 0x0BC0 + 0x10000000 + 0x03000000
@@ -3658,11 +4184,12 @@
      * The maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers
      * between minInt32Value and maxInt32Value must be supported.
      *
-     * The maxInt32Value indicates the window is opening in plane/closing in the out of plane
-     * direction at the fastest speed.
      * The minInt32Value indicates the window is closing in plane/opening in the out of plane
      * direction at the fastest speed.
      *
+     * The maxInt32Value indicates the window is opening in plane/closing in the out of plane
+     * direction at the fastest speed.
+     *
      * Larger absolute values, either positive or negative, indicate a faster movement speed. Once
      * the window reaches the positional limit, the value must reset to 0. If WINDOW_MOVE's value is
      * currently 0, then that means there is no movement currently occurring.
@@ -3685,12 +4212,22 @@
      *   Max = open the sunroof, automatically stop when sunroof is fully open.
      *   Min = open the vent, automatically stop when vent is fully open.
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true} for the area ID.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
      * implement it as VehiclePropertyAccess.READ only.
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     WINDOW_MOVE = 0x0BC1 + 0x10000000 + 0x03000000
@@ -3720,13 +4257,25 @@
      * When an intermittent wiper setting is selected, this property value must be set to 0 during
      * the "pause" period of the intermittent wiping.
      *
-     * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. The maxInt32Value
-     * for each area ID must specify the longest wiper period. The minInt32Value must be set to 0
-     * for each area ID.
+     * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined.
+     *
+     * The minInt32Value must be set to 0 for each area ID.
+     *
+     * The maxInt32Value for each area ID must specify the longest wiper period.
+     *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true}.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit.MILLI_SECS
+     * @require_min_max_supported_value
      * @version 2
      */
     WINDSHIELD_WIPERS_PERIOD =
@@ -3746,6 +4295,12 @@
      * unless all states in WindshieldWipersState are supported (including OTHER, which is not
      * recommended).
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} for the area ID
+     * unless all states in WindshieldWipersState are supported (including OTHER, which is not
+     * recommended).
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum WindshieldWipersState
@@ -3765,6 +4320,12 @@
      * unless all states in WindshieldWipersSwitch are supported (including OTHER, which is not
      * recommended).
      *
+     * If {@code HasSupportedValueInfo} for a specific area ID is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true} for the area ID
+     * unless all states in WindshieldWipersSwitch are supported (including OTHER, which is not
+     * recommended).
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
      * implement it as VehiclePropertyAccess.READ only.
      *
@@ -3789,12 +4350,22 @@
      * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between
      * minInt32Value and maxInt32Value must be supported.
      *
-     * The maxInt32Value indicates the steering wheel position furthest from the driver.
      * The minInt32Value indicates the steering wheel position closest to the driver.
      *
+     * The maxInt32Value indicates the steering wheel position furthest from the driver.
+     *
      * Values in between minInt32Value and maxInt32Value indicate a transition state between the
      * closest and furthest positions.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true}.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative positions.
      *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
@@ -3803,6 +4374,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     STEERING_WHEEL_DEPTH_POS =
@@ -3813,14 +4385,24 @@
      * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between
      * minInt32Value and maxInt32Value must be supported.
      *
-     * The maxInt32Value indicates the steering wheel moving away from the driver.
      * The minInt32Value indicates the steering wheel moving towards the driver.
      *
+     * The maxInt32Value indicates the steering wheel moving away from the driver.
+     *
      * Larger integers, either positive or negative, indicate a faster movement speed. Once the
      * steering wheel reaches the positional limit, the value must reset to 0. If
      * STEERING_WHEEL_DEPTH_MOVE's value is currently 0, then that means there is no movement
      * currently occurring.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true}.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative movement
      * speeds.
      *
@@ -3830,6 +4412,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     STEERING_WHEEL_DEPTH_MOVE =
@@ -3840,12 +4423,22 @@
      * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between
      * minInt32Value and maxInt32Value must be supported.
      *
-     * The maxInt32Value indicates the steering wheel being in the highest position.
      * The minInt32Value indicates the steering wheel being in the lowest position.
      *
+     * The maxInt32Value indicates the steering wheel being in the highest position.
+     *
      * Values in between minInt32Value and maxInt32Value indicate a transition state between the
      * lowest and highest positions.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true}.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative positions.
      *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
@@ -3854,6 +4447,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     STEERING_WHEEL_HEIGHT_POS =
@@ -3864,14 +4458,24 @@
      * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between
      * minInt32Value and maxInt32Value must be supported.
      *
-     * The maxInt32Value indicates the steering wheel moving upwards.
      * The minInt32Value indicates the steering wheel moving downwards.
      *
+     * The maxInt32Value indicates the steering wheel moving upwards.
+     *
      * Larger integers, either positive or negative, indicate a faster movement speed. Once the
      * steering wheel reaches the positional limit, the value must reset to 0. If
      * STEERING_WHEEL_HEIGHT_MOVE's value is currently 0, then that means there is no movement
      * currently occurring.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true}.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative movement
      * speeds.
      *
@@ -3881,6 +4485,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     STEERING_WHEEL_HEIGHT_MOVE =
@@ -3939,11 +4544,21 @@
      * All integers between minInt32Value and maxInt32Value must be supported.
      *
      * The minInt32Value indicates that the glove box door is closed. The minInt32Value must be 0.
+     *
      * The maxInt32Value indicates that the glove box door is in the fully open position.
      *
      * Values in between minInt32Value and maxInt32Value indicate a transition state between the
      * closed and fully open positions.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasMinSupportedValue} and
+     * {@code HasSupportedValueInfo.hasMaxSupportedValue} must be {@code true}.
+     * {@code MinMaxSupportedValueResult.minSupportedValue} has the same meaning as minInt32Value.
+     * {@code MinMaxSupportedValueResult.maxSupportedValue} has the same meaning as maxInt32Value.
+     * All integers between minSupportedValue and maxSupportedValue must be supported.
+     * At boot, minInt32Value is equal to minSupportedValue, maxInt32Value is equal to
+     * maxSupportedValue.
+     *
      * This property is not in any particular unit but in a specified range of relative positions.
      *
      * The area ID must match the seat by which the glove box is intended to be used  (e.g. if the
@@ -3956,6 +4571,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @require_min_max_supported_value
      * @version 2
      */
     GLOVE_BOX_DOOR_POS =
@@ -4530,6 +5146,11 @@
      * For the global area ID (0), the VehicleAreaConfig#supportedEnumValues must be defined unless
      * all enum values of VehicleLightState are supported.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true}
+     * unless all enum values of VehicleLightState are supported.
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightState
@@ -4552,6 +5173,11 @@
      * For the global area ID (0), the VehicleAreaConfig#supportedEnumValues must be defined unless
      * all enum values of VehicleLightSwitch are supported.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true}
+     * unless all enum values of VehicleLightSwitch are supported.
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
      * implement it as VehiclePropertyAccess.READ only.
      *
@@ -5576,6 +6202,11 @@
      * For the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined
      * unless all states of VehicleAutonomousState are supported.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true}
+     * unless all enum values of VehicleAutonomousState are supported.
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleAutonomousState
@@ -5703,6 +6334,12 @@
      * unless all states of both AutomaticEmergencyBrakingState (including OTHER, which is not
      * recommended) and ErrorState are supported.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true}
+     * unless all states of both AutomaticEmergencyBrakingState (including OTHER, which is not
+     * recommended) and ErrorState are supported.
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum AutomaticEmergencyBrakingState
@@ -5745,6 +6382,12 @@
      * unless all states of both ForwardCollisionWarningState (including OTHER, which is not
      * recommended) and ErrorState are supported.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true}
+     * unless all states of both ForwardCollisionWarningState (including OTHER, which is not
+     * recommended) and ErrorState are supported.
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum ForwardCollisionWarningState
@@ -5787,6 +6430,12 @@
      * unless all states of both BlindSpotWarningState (including OTHER, which is not
      * recommended) and ErrorState are supported.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true}
+     * unless all states of both BlindSpotWarningState (including OTHER, which is not
+     * recommended) and ErrorState are supported.
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum BlindSpotWarningState
@@ -5830,6 +6479,12 @@
      * unless all states of both LaneDepartureWarningState (including OTHER, which is not
      * recommended) and ErrorState are supported.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true}
+     * unless all states of both LaneDepartureWarningState (including OTHER, which is not
+     * recommended) and ErrorState are supported.
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum LaneDepartureWarningState
@@ -5880,6 +6535,12 @@
      * unless all states of both LaneKeepAssistState (including OTHER, which is not
      * recommended) and ErrorState are supported.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true}
+     * unless all states of both LaneKeepAssistState (including OTHER, which is not
+     * recommended) and ErrorState are supported.
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum LaneKeepAssistState
@@ -5932,6 +6593,11 @@
      * For the global area ID (0), the VehicleAreaConfig#supportedEnumValues must be defined unless
      * all enum values of LaneCenteringAssistCommand are supported.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true}
+     * unless all enum values of LaneCenteringAssistCommand are supported.
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * When this property is not available because LCA is disabled (i.e.
      * LANE_CENTERING_ASSIST_ENABLED is false), this property must return
      * StatusCode#NOT_AVAILABLE_DISABLED. If LANE_CENTERING_ASSIST_STATE is implemented and the
@@ -5962,6 +6628,12 @@
      * unless all states of both LaneCenteringAssistState (including OTHER, which is not
      * recommended) and ErrorState are supported.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true}
+     * unless all states of both LaneCenteringAssistState (including OTHER, which is not
+     * recommended) and ErrorState are supported.
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum LaneCenteringAssistState
@@ -6007,6 +6679,12 @@
      * unless all states of EmergencyLaneKeepAssistState (including OTHER, which is not recommended)
      * and ErrorState are supported.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true}
+     * unless all states of EmergencyLaneKeepAssistState (including OTHER, which is not recommended)
+     * and ErrorState are supported.
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum EmergencyLaneKeepAssistState
@@ -6054,6 +6732,12 @@
      * unless all states of CruiseControlType (including OTHER, which is not recommended) and
      * ErrorState are supported.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true}
+     * unless all states of CruiseControlType (including OTHER, which is not recommended) and
+     * ErrorState are supported.
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * Trying to write CruiseControlType#OTHER or an ErrorState to this property will throw an
      * IllegalArgumentException.
      *
@@ -6082,6 +6766,12 @@
      * unless all states of CruiseControlState (including OTHER, which is not recommended) and
      * ErrorState are supported.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true}
+     * unless all states of CruiseControlState (including OTHER, which is not recommended) and
+     * ErrorState are supported.
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum CruiseControlState
@@ -6100,6 +6790,11 @@
      * unless all states of CruiseControlState are supported. Any unsupported commands sent through
      * this property must return StatusCode#INVALID_ARG.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true}
+     * unless all states of CruiseControlState are supported.
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * When this property is not available because CC is disabled (i.e. CRUISE_CONTROL_ENABLED is
      * false), this property must return StatusCode#NOT_AVAILABLE_DISABLED. If CRUISE_CONTROL_STATE
      * is implemented and the state is set to an ErrorState value, then this property must return a
@@ -6240,6 +6935,12 @@
      * unless all states of both HandsOnDetectionDriverState (including OTHER, which is not
      * recommended) and ErrorState are supported.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true}
+     * unless all states of both HandsOnDetectionDriverState (including OTHER, which is not
+     * recommended) and ErrorState are supported.
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum HandsOnDetectionDriverState
@@ -6263,6 +6964,12 @@
      * unless all states of both HandsOnDetectionWarning (including OTHER, which is not recommended)
      * and ErrorState are supported.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true}
+     * unless all states of both HandsOnDetectionWarning (including OTHER, which is not recommended)
+     * and ErrorState are supported.
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum HandsOnDetectionWarning
@@ -6313,6 +7020,12 @@
      * unless all states of both DriverDrowsinessAttentionState (including OTHER, which is not
      * recommended) and ErrorState are supported.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true}
+     * unless all states of both DriverDrowsinessAttentionState (including OTHER, which is not
+     * recommended) and ErrorState are supported.
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum DriverDrowsinessAttentionState
@@ -6360,6 +7073,12 @@
      * unless all states of both DriverDrowsinessAttentionWarning (including OTHER, which is not
      * recommended) and ErrorState are supported.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true}
+     * unless all states of both DriverDrowsinessAttentionWarning (including OTHER, which is not
+     * recommended) and ErrorState are supported.
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum DriverDrowsinessAttentionWarning
@@ -6408,6 +7127,12 @@
      * unless all states of both DriverDistractionState (including OTHER, which is not
      * recommended) and ErrorState are supported.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true}
+     * unless all states of both DriverDistractionState (including OTHER, which is not
+     * recommended) and ErrorState are supported.
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum DriverDistractionState
@@ -6454,6 +7179,12 @@
      * unless all states of both DriverDistractionWarning (including OTHER, which is not
      * recommended) and ErrorState are supported.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true}
+     * unless all states of both DriverDistractionWarning (including OTHER, which is not
+     * recommended) and ErrorState are supported.
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum DriverDistractionWarning
@@ -6503,6 +7234,12 @@
      * unless all states of both LowSpeedCollisionWarningState (including OTHER, which is not
      * recommended) and ErrorState are supported.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true}
+     * unless all states of both LowSpeedCollisionWarningState (including OTHER, which is not
+     * recommended) and ErrorState are supported.
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum LowSpeedCollisionWarningState
@@ -6546,6 +7283,12 @@
      * unless all states of both CrossTrafficMonitoringWarningState (including OTHER, which is not
      * recommended) and ErrorState are supported.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true}
+     * unless all states of both CrossTrafficMonitoringWarningState (including OTHER, which is not
+     * recommended) and ErrorState are supported.
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum CrossTrafficMonitoringWarningState
@@ -6600,6 +7343,12 @@
      * unless all states of both LowSpeedAutomaticEmergencyBrakingState (including OTHER, which is
      * not recommended) and ErrorState are supported.
      *
+     * If {@code HasSupportedValueInfo} for the global area ID (0) is not {@code null}:
+     * {@code HasSupportedValueInfo.hasSupportedValuesList} must be {@code true}
+     * unless all states of both LowSpeedAutomaticEmergencyBrakingState (including OTHER, which is
+     * not recommended) and ErrorState are supported.
+     * At boot, the supported values list is the same as supportedEnumValues.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum LowSpeedAutomaticEmergencyBrakingState
diff --git a/bluetooth/OWNERS b/bluetooth/OWNERS
index f401b8c..df250c8 100644
--- a/bluetooth/OWNERS
+++ b/bluetooth/OWNERS
@@ -1,5 +1,5 @@
 # Bug component: 27441
 
+asoulier@google.com
 henrichataing@google.com
-mylesgw@google.com
 siyuanh@google.com
diff --git a/boot/aidl/default/Android.bp b/boot/aidl/default/Android.bp
index c1d3c57..2fd2dad 100644
--- a/boot/aidl/default/Android.bp
+++ b/boot/aidl/default/Android.bp
@@ -57,7 +57,7 @@
     name: "android.hardware.boot-service.default_recovery",
     defaults: ["android.hardware.boot-service_common"],
     init_rc: ["android.hardware.boot-service.default_recovery.rc"],
-    vintf_fragments: ["android.hardware.boot-service.default.xml"],
+    vintf_fragment_modules: ["android.hardware.boot-service.default.xml.recovery"],
     recovery: true,
 
     shared_libs: [
@@ -77,11 +77,16 @@
     installable: false,
 }
 
-prebuilt_etc {
+vintf_fragment {
+    name: "android.hardware.boot-service.default.xml.recovery",
+    src: "android.hardware.boot-service.default.xml",
+    recovery: true,
+}
+
+vintf_fragment {
     name: "android.hardware.boot-service.default.xml",
     src: "android.hardware.boot-service.default.xml",
-    sub_dir: "vintf",
-    installable: false,
+    vendor: true,
 }
 
 apex {
@@ -98,6 +103,8 @@
     ],
     prebuilts: [
         "android.hardware.boot-service.default.rc",
+    ],
+    vintf_fragment_modules: [
         "android.hardware.boot-service.default.xml",
     ],
 }
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
index 2646d15..2940745 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
@@ -51,14 +51,6 @@
   void sendMessageDeliveryStatusToHub(in int contextHubId, in android.hardware.contexthub.MessageDeliveryStatus messageDeliveryStatus);
   List<android.hardware.contexthub.HubInfo> getHubs();
   List<android.hardware.contexthub.EndpointInfo> getEndpoints();
-  void registerEndpoint(in android.hardware.contexthub.EndpointInfo endpoint);
-  void unregisterEndpoint(in android.hardware.contexthub.EndpointInfo endpoint);
-  void registerEndpointCallback(in android.hardware.contexthub.IEndpointCallback callback);
-  int[2] requestSessionIdRange(int size);
-  void openEndpointSession(int sessionId, in android.hardware.contexthub.EndpointId destination, in android.hardware.contexthub.EndpointId initiator, in @nullable String serviceDescriptor);
-  void sendMessageToEndpoint(int sessionId, in android.hardware.contexthub.Message msg);
-  void sendMessageDeliveryStatusToEndpoint(int sessionId, in android.hardware.contexthub.MessageDeliveryStatus msgStatus);
-  void closeEndpointSession(int sessionId, in android.hardware.contexthub.Reason reason);
-  void endpointSessionOpenComplete(int sessionId);
+  @PropagateAllowBlocking android.hardware.contexthub.IEndpointCommunication registerEndpointHub(in android.hardware.contexthub.IEndpointCallback callback, in android.hardware.contexthub.HubInfo hubInfo);
   const int EX_CONTEXT_HUB_UNSPECIFIED = (-1) /* -1 */;
 }
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IEndpointCommunication.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IEndpointCommunication.aidl
new file mode 100644
index 0000000..8742415
--- /dev/null
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IEndpointCommunication.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.contexthub;
+@VintfStability
+interface IEndpointCommunication {
+  void registerEndpoint(in android.hardware.contexthub.EndpointInfo endpoint);
+  void unregisterEndpoint(in android.hardware.contexthub.EndpointInfo endpoint);
+  int[2] requestSessionIdRange(int size);
+  void openEndpointSession(int sessionId, in android.hardware.contexthub.EndpointId destination, in android.hardware.contexthub.EndpointId initiator, in @nullable String serviceDescriptor);
+  void sendMessageToEndpoint(int sessionId, in android.hardware.contexthub.Message msg);
+  void sendMessageDeliveryStatusToEndpoint(int sessionId, in android.hardware.contexthub.MessageDeliveryStatus msgStatus);
+  void closeEndpointSession(int sessionId, in android.hardware.contexthub.Reason reason);
+  void endpointSessionOpenComplete(int sessionId);
+  void unregister();
+}
diff --git a/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl b/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
index eb6d051..3fb452c 100644
--- a/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
@@ -18,19 +18,16 @@
 
 import android.hardware.contexthub.ContextHubInfo;
 import android.hardware.contexthub.ContextHubMessage;
-import android.hardware.contexthub.EndpointId;
 import android.hardware.contexthub.EndpointInfo;
 import android.hardware.contexthub.HostEndpointInfo;
 import android.hardware.contexthub.HubInfo;
 import android.hardware.contexthub.IContextHubCallback;
 import android.hardware.contexthub.IEndpointCallback;
-import android.hardware.contexthub.Message;
+import android.hardware.contexthub.IEndpointCommunication;
 import android.hardware.contexthub.MessageDeliveryStatus;
 import android.hardware.contexthub.NanSessionStateUpdate;
 import android.hardware.contexthub.NanoappBinary;
 import android.hardware.contexthub.NanoappInfo;
-import android.hardware.contexthub.Reason;
-import android.hardware.contexthub.Service;
 import android.hardware.contexthub.Setting;
 
 @VintfStability
@@ -271,125 +268,22 @@
     List<EndpointInfo> getEndpoints();
 
     /**
-     * Publishes an endpoint from the calling side (e.g. Android). Endpoints must be registered
-     * prior to starting a session.
+     * Registers a new hub for endpoint communication which will receive events for its endpoints
+     * over the given callback. Returns an interface for the hub to register endpoints, start
+     * sessions, and send messages.
+     *
+     * It is valid for the same callback to be registered for multiple hubs, as the
+     * IEndpointCallback events provide sufficient information to determine which hub the event is
+     * intended for:
+     * * session ids are allocated to a specific hub and are unique
+     * * endpoints are identified by hub and endpoint id
+     *
+     * @param callback Interface to send endpoint events targeting the caller
+     * @param hubInfo Details of the hub being registered
+     * @return Interface for the hub to interact with other endpoint hubs
+     *
+     * @throws EX_ILLEGAL_STATE if hubInfo.hubId has already been registered
      */
-    void registerEndpoint(in EndpointInfo endpoint);
-
-    /**
-     * Teardown an endpoint from the calling side (e.g. Android). This endpoint must have already
-     * been published via registerEndpoint().
-     */
-    void unregisterEndpoint(in EndpointInfo endpoint);
-
-    /**
-     * Attaches a callback interface to receive events targeted at endpoints registered by the
-     * caller.
-     */
-    void registerEndpointCallback(in IEndpointCallback callback);
-
-    /**
-     * Request a range of session IDs for the caller to use when initiating sessions. This may be
-     * called more than once, but typical usage is to request a large enough range to accommodate
-     * the maximum expected number of concurrent sessions, but not overly large as to limit other
-     * clients.
-     *
-     * @param size The number of sessionId reserved for host-initiated sessions. This number should
-     *         be less than or equal to 1024.
-     *
-     * @return An array with two elements representing the smallest and largest possible session id
-     *         available for host.
-     *
-     * @throws EX_ILLEGAL_ARGUMENT if the size is invalid.
-     * @throws EX_SERVICE_SPECIFIC if the id range requested cannot be allocated.
-     */
-    int[2] requestSessionIdRange(int size);
-
-    /**
-     * Request to open a session for communication between an endpoint previously registered by the
-     * caller and a target endpoint found in getEndpoints(), optionally scoped to a service
-     * published by the target endpoint.
-     *
-     * Upon returning from this function, the session is in pending state, and the final result will
-     * be given by an asynchronous call to onEndpointSessionOpenComplete() on success, or
-     * onCloseEndpointSession() on failure.
-     *
-     * @param sessionId Caller-allocated session identifier, which must be unique across all active
-     *         sessions, and must fall in a range allocated via requestSessionIdRange().
-     * @param destination The EndpointId representing the destination side of the session.
-     * @param initiator The EndpointId representing the initiating side of the session, which
-     *         must've already been published through registerEndpoint().
-     * @param serviceDescriptor Descriptor for the service specification for scoping this session
-     *         (nullable). Null indicates a fully custom marshalling scheme. The value should match
-     *         a published descriptor for both destination and initiator.
-     *
-     * @throws EX_ILLEGAL_ARGUMENT if any of the arguments are invalid, or the combination of the
-     *         arguments is invalid.
-     * @throws EX_SERVICE_SPECIFIC on other errors
-     *         - EX_CONTEXT_HUB_UNSPECIFIED if the request failed for other reasons.
-     */
-    void openEndpointSession(int sessionId, in EndpointId destination, in EndpointId initiator,
-            in @nullable String serviceDescriptor);
-
-    /**
-     * Send a message from one endpoint to another on the (currently open) session.
-     *
-     * @param sessionId The integer representing the communication session, previously set in
-     *         openEndpointSession() or onEndpointSessionOpenRequest().
-     * @param msg The Message object representing a message to endpoint from the endpoint on host.
-     *
-     * @throws EX_ILLEGAL_ARGUMENT if any of the arguments are invalid, or the combination of the
-     *         arguments is invalid.
-     * @throws EX_SERVICE_SPECIFIC on other errors
-     *         - EX_CONTEXT_HUB_UNSPECIFIED if the request failed for other reasons.
-     */
-    void sendMessageToEndpoint(int sessionId, in Message msg);
-
-    /**
-     * Sends a message delivery status to the endpoint in response to receiving a Message with flag
-     * FLAG_REQUIRES_DELIVERY_STATUS. Each message with the flag should have a MessageDeliveryStatus
-     * response. This method sends the message delivery status back to the remote endpoint for a
-     * session.
-     *
-     * @param sessionId The integer representing the communication session, previously set in
-     *         openEndpointSession() or onEndpointSessionOpenRequest().
-     * @param msgStatus The MessageDeliveryStatus object representing the delivery status for a
-     *         specific message (identified by the sequenceNumber) within the session.
-     *
-     * @throws EX_UNSUPPORTED_OPERATION if ContextHubInfo.supportsReliableMessages is false for
-     *          the hub involved in this session.
-     */
-    void sendMessageDeliveryStatusToEndpoint(int sessionId, in MessageDeliveryStatus msgStatus);
-
-    /**
-     * Closes a session previously opened by openEndpointSession() or requested via
-     * onEndpointSessionOpenRequest(). Processing of session closure must be ordered/synchronized
-     * with message delivery, such that if this session was open, any messages previously passed to
-     * sendMessageToEndpoint() that are still in-flight must still be delivered before the session
-     * is closed. Any in-flight messages to the endpoint that requested to close the session will
-     * not be delivered.
-     *
-     * @param sessionId The integer representing the communication session, previously set in
-     *         openEndpointSession() or onEndpointSessionOpenRequest().
-     * @param reason The reason for this close endpoint session request.
-     *
-     * @throws EX_ILLEGAL_ARGUMENT if any of the arguments are invalid, or the combination of the
-     *         arguments is invalid.
-     * @throws EX_SERVICE_SPECIFIC on other errors
-     *         - EX_CONTEXT_HUB_UNSPECIFIED if the request failed for other reasons.
-     */
-    void closeEndpointSession(int sessionId, in Reason reason);
-
-    /**
-     * Notifies the HAL that the session requested by onEndpointSessionOpenRequest is ready to use.
-     *
-     * @param sessionId The integer representing the communication session, previously set in
-     *         onEndpointSessionOpenRequest(). This id is assigned by the HAL.
-     *
-     * @throws EX_ILLEGAL_ARGUMENT if any of the arguments are invalid, or the combination of the
-     *         arguments is invalid.
-     * @throws EX_SERVICE_SPECIFIC on other errors
-     *         - EX_CONTEXT_HUB_UNSPECIFIED if the request failed for other reasons.
-     */
-    void endpointSessionOpenComplete(int sessionId);
+    @PropagateAllowBlocking
+    IEndpointCommunication registerEndpointHub(in IEndpointCallback callback, in HubInfo hubInfo);
 }
diff --git a/contexthub/aidl/android/hardware/contexthub/IEndpointCommunication.aidl b/contexthub/aidl/android/hardware/contexthub/IEndpointCommunication.aidl
new file mode 100644
index 0000000..e5045ba
--- /dev/null
+++ b/contexthub/aidl/android/hardware/contexthub/IEndpointCommunication.aidl
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.contexthub;
+
+import android.hardware.contexthub.EndpointId;
+import android.hardware.contexthub.EndpointInfo;
+import android.hardware.contexthub.IEndpointCallback;
+import android.hardware.contexthub.Message;
+import android.hardware.contexthub.MessageDeliveryStatus;
+import android.hardware.contexthub.Reason;
+import android.hardware.contexthub.Service;
+
+@VintfStability
+interface IEndpointCommunication {
+    /**
+     * Publishes an endpoint from the calling side (e.g. Android). Endpoints must be registered
+     * prior to starting a session.
+     */
+    void registerEndpoint(in EndpointInfo endpoint);
+
+    /**
+     * Teardown an endpoint from the calling side (e.g. Android). This endpoint must have already
+     * been published via registerEndpoint().
+     */
+    void unregisterEndpoint(in EndpointInfo endpoint);
+
+    /**
+     * Request a range of session IDs for the caller to use when initiating sessions. This may be
+     * called more than once, but typical usage is to request a large enough range to accommodate
+     * the maximum expected number of concurrent sessions, but not overly large as to limit other
+     * clients.
+     *
+     * @param size The number of sessionId reserved for host-initiated sessions. This number should
+     *         be less than or equal to 1024.
+     *
+     * @return An array with two elements representing the smallest and largest possible session id
+     *         available for host.
+     *
+     * @throws EX_ILLEGAL_ARGUMENT if the size is invalid.
+     * @throws EX_SERVICE_SPECIFIC if the id range requested cannot be allocated.
+     */
+    int[2] requestSessionIdRange(int size);
+
+    /**
+     * Request to open a session for communication between an endpoint previously registered by the
+     * caller and a target endpoint found in getEndpoints(), optionally scoped to a service
+     * published by the target endpoint.
+     *
+     * Upon returning from this function, the session is in pending state, and the final result will
+     * be given by an asynchronous call to onEndpointSessionOpenComplete() on success, or
+     * onCloseEndpointSession() on failure.
+     *
+     * @param sessionId Caller-allocated session identifier, which must be unique across all active
+     *         sessions, and must fall in a range allocated via requestSessionIdRange().
+     * @param destination The EndpointId representing the destination side of the session.
+     * @param initiator The EndpointId representing the initiating side of the session, which
+     *         must've already been published through registerEndpoint().
+     * @param serviceDescriptor Descriptor for the service specification for scoping this session
+     *         (nullable). Null indicates a fully custom marshalling scheme. The value should match
+     *         a published descriptor for both destination and initiator.
+     *
+     * @throws EX_ILLEGAL_ARGUMENT if any of the arguments are invalid, or the combination of the
+     *         arguments is invalid.
+     * @throws EX_SERVICE_SPECIFIC on other errors
+     *         - EX_CONTEXT_HUB_UNSPECIFIED if the request failed for other reasons.
+     */
+    void openEndpointSession(int sessionId, in EndpointId destination, in EndpointId initiator,
+            in @nullable String serviceDescriptor);
+
+    /**
+     * Send a message from one endpoint to another on the (currently open) session.
+     *
+     * @param sessionId The integer representing the communication session, previously set in
+     *         openEndpointSession() or onEndpointSessionOpenRequest().
+     * @param msg The Message object representing a message to endpoint from the endpoint on host.
+     *
+     * @throws EX_ILLEGAL_ARGUMENT if any of the arguments are invalid, or the combination of the
+     *         arguments is invalid.
+     * @throws EX_SERVICE_SPECIFIC on other errors
+     *         - EX_CONTEXT_HUB_UNSPECIFIED if the request failed for other reasons.
+     */
+    void sendMessageToEndpoint(int sessionId, in Message msg);
+
+    /**
+     * Sends a message delivery status to the endpoint in response to receiving a Message with flag
+     * FLAG_REQUIRES_DELIVERY_STATUS. Each message with the flag should have a MessageDeliveryStatus
+     * response. This method sends the message delivery status back to the remote endpoint for a
+     * session.
+     *
+     * @param sessionId The integer representing the communication session, previously set in
+     *         openEndpointSession() or onEndpointSessionOpenRequest().
+     * @param msgStatus The MessageDeliveryStatus object representing the delivery status for a
+     *         specific message (identified by the sequenceNumber) within the session.
+     *
+     * @throws EX_UNSUPPORTED_OPERATION if ContextHubInfo.supportsReliableMessages is false for
+     *          the hub involved in this session.
+     */
+    void sendMessageDeliveryStatusToEndpoint(int sessionId, in MessageDeliveryStatus msgStatus);
+
+    /**
+     * Closes a session previously opened by openEndpointSession() or requested via
+     * onEndpointSessionOpenRequest(). Processing of session closure must be ordered/synchronized
+     * with message delivery, such that if this session was open, any messages previously passed to
+     * sendMessageToEndpoint() that are still in-flight must still be delivered before the session
+     * is closed. Any in-flight messages to the endpoint that requested to close the session will
+     * not be delivered.
+     *
+     * @param sessionId The integer representing the communication session, previously set in
+     *         openEndpointSession() or onEndpointSessionOpenRequest().
+     * @param reason The reason for this close endpoint session request.
+     *
+     * @throws EX_ILLEGAL_ARGUMENT if any of the arguments are invalid, or the combination of the
+     *         arguments is invalid.
+     * @throws EX_SERVICE_SPECIFIC on other errors
+     *         - EX_CONTEXT_HUB_UNSPECIFIED if the request failed for other reasons.
+     */
+    void closeEndpointSession(int sessionId, in Reason reason);
+
+    /**
+     * Notifies the HAL that the session requested by onEndpointSessionOpenRequest is ready to use.
+     *
+     * @param sessionId The integer representing the communication session, previously set in
+     *         onEndpointSessionOpenRequest(). This id is assigned by the HAL.
+     *
+     * @throws EX_ILLEGAL_ARGUMENT if any of the arguments are invalid, or the combination of the
+     *         arguments is invalid.
+     * @throws EX_SERVICE_SPECIFIC on other errors
+     *         - EX_CONTEXT_HUB_UNSPECIFIED if the request failed for other reasons.
+     */
+    void endpointSessionOpenComplete(int sessionId);
+
+    /**
+     * Unregisters this hub. Subsequent calls on this interface will fail.
+     *
+     * @throws EX_ILLEGAL_STATE if this interface was already unregistered.
+     */
+    void unregister();
+}
diff --git a/contexthub/aidl/default/ContextHub.cpp b/contexthub/aidl/default/ContextHub.cpp
index 19d9639..433617e 100644
--- a/contexthub/aidl/default/ContextHub.cpp
+++ b/contexthub/aidl/default/ContextHub.cpp
@@ -150,10 +150,11 @@
 
 ScopedAStatus ContextHub::setTestMode(bool enable) {
     if (enable) {
-        std::unique_lock<std::mutex> lock(mEndpointMutex);
-        mEndpoints.clear();
-        mEndpointSessions.clear();
-        mEndpointCallback = nullptr;
+        std::lock_guard lock(mHostHubsLock);
+        for (auto& [id, hub] : mIdToHostHub) {
+            hub->mActive = false;
+        }
+        mIdToHostHub.clear();
     }
     return ScopedAStatus::ok();
 }
@@ -227,7 +228,23 @@
     return ScopedAStatus::ok();
 };
 
-ScopedAStatus ContextHub::registerEndpoint(const EndpointInfo& in_endpoint) {
+ScopedAStatus ContextHub::registerEndpointHub(
+        const std::shared_ptr<IEndpointCallback>& in_callback, const HubInfo& in_hubInfo,
+        std::shared_ptr<IEndpointCommunication>* _aidl_return) {
+    std::lock_guard lock(mHostHubsLock);
+    if (mIdToHostHub.count(in_hubInfo.hubId)) {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    auto hub = ndk::SharedRefBase::make<HubInterface>(*this, in_callback, in_hubInfo);
+    mIdToHostHub.insert({in_hubInfo.hubId, hub});
+    *_aidl_return = std::move(hub);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus ContextHub::HubInterface::registerEndpoint(const EndpointInfo& in_endpoint) {
+    if (!mActive) {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
     std::unique_lock<std::mutex> lock(mEndpointMutex);
 
     for (const EndpointInfo& endpoint : mEndpoints) {
@@ -240,7 +257,10 @@
     return ScopedAStatus::ok();
 };
 
-ScopedAStatus ContextHub::unregisterEndpoint(const EndpointInfo& in_endpoint) {
+ScopedAStatus ContextHub::HubInterface::unregisterEndpoint(const EndpointInfo& in_endpoint) {
+    if (!mActive) {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
     std::unique_lock<std::mutex> lock(mEndpointMutex);
 
     for (auto it = mEndpoints.begin(); it != mEndpoints.end(); ++it) {
@@ -252,41 +272,47 @@
     return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
 };
 
-ScopedAStatus ContextHub::registerEndpointCallback(
-        const std::shared_ptr<IEndpointCallback>& in_callback) {
-    std::unique_lock<std::mutex> lock(mEndpointMutex);
-
-    mEndpointCallback = in_callback;
-    return ScopedAStatus::ok();
-};
-
-ScopedAStatus ContextHub::requestSessionIdRange(int32_t in_size,
-                                                std::array<int32_t, 2>* _aidl_return) {
+ScopedAStatus ContextHub::HubInterface::requestSessionIdRange(
+        int32_t in_size, std::array<int32_t, 2>* _aidl_return) {
+    if (!mActive) {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
     constexpr int32_t kMaxSize = 1024;
     if (in_size > kMaxSize || _aidl_return == nullptr) {
         return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
 
+    uint16_t base = 0;
     {
-        std::lock_guard<std::mutex> lock(mEndpointMutex);
-        mMaxValidSessionId = in_size;
+        std::lock_guard lock(mHal.mHostHubsLock);
+        if (static_cast<int32_t>(USHRT_MAX) - mHal.mNextSessionIdBase + 1 < in_size) {
+            return ScopedAStatus::fromServiceSpecificError(EX_CONTEXT_HUB_UNSPECIFIED);
+        }
+        base = mHal.mNextSessionIdBase;
+        mHal.mNextSessionIdBase += in_size;
     }
 
-    (*_aidl_return)[0] = 0;
-    (*_aidl_return)[1] = in_size;
+    {
+        std::lock_guard<std::mutex> lock(mEndpointMutex);
+        (*_aidl_return)[0] = mBaseSessionId = base;
+        (*_aidl_return)[1] = mMaxSessionId = base + (in_size - 1);
+    }
     return ScopedAStatus::ok();
 };
 
-ScopedAStatus ContextHub::openEndpointSession(
+ScopedAStatus ContextHub::HubInterface::openEndpointSession(
         int32_t in_sessionId, const EndpointId& in_destination, const EndpointId& in_initiator,
         const std::optional<std::string>& in_serviceDescriptor) {
+    if (!mActive) {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
     // We are not calling onCloseEndpointSession on failure because the remote endpoints (our
     // mock endpoints) always accept the session.
 
     std::weak_ptr<IEndpointCallback> callback;
     {
         std::unique_lock<std::mutex> lock(mEndpointMutex);
-        if (in_sessionId > mMaxValidSessionId) {
+        if (in_sessionId < mBaseSessionId || in_sessionId > mMaxSessionId) {
             ALOGE("openEndpointSession: session ID %" PRId32 " is invalid", in_sessionId);
             return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
         }
@@ -346,7 +372,11 @@
     return ScopedAStatus::ok();
 };
 
-ScopedAStatus ContextHub::sendMessageToEndpoint(int32_t in_sessionId, const Message& in_msg) {
+ScopedAStatus ContextHub::HubInterface::sendMessageToEndpoint(int32_t in_sessionId,
+                                                              const Message& in_msg) {
+    if (!mActive) {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
     std::weak_ptr<IEndpointCallback> callback;
     {
         std::unique_lock<std::mutex> lock(mEndpointMutex);
@@ -393,12 +423,19 @@
     return ScopedAStatus::ok();
 };
 
-ScopedAStatus ContextHub::sendMessageDeliveryStatusToEndpoint(
+ScopedAStatus ContextHub::HubInterface::sendMessageDeliveryStatusToEndpoint(
         int32_t /* in_sessionId */, const MessageDeliveryStatus& /* in_msgStatus */) {
+    if (!mActive) {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
     return ScopedAStatus::ok();
 };
 
-ScopedAStatus ContextHub::closeEndpointSession(int32_t in_sessionId, Reason /* in_reason */) {
+ScopedAStatus ContextHub::HubInterface::closeEndpointSession(int32_t in_sessionId,
+                                                             Reason /* in_reason */) {
+    if (!mActive) {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
     std::unique_lock<std::mutex> lock(mEndpointMutex);
 
     for (auto it = mEndpointSessions.begin(); it != mEndpointSessions.end(); ++it) {
@@ -411,8 +448,20 @@
     return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
 };
 
-ScopedAStatus ContextHub::endpointSessionOpenComplete(int32_t /* in_sessionId */) {
+ScopedAStatus ContextHub::HubInterface::endpointSessionOpenComplete(int32_t /* in_sessionId */) {
+    if (!mActive) {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
     return ScopedAStatus::ok();
 };
 
+ScopedAStatus ContextHub::HubInterface::unregister() {
+    if (!mActive.exchange(false)) {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    std::lock_guard lock(mHal.mHostHubsLock);
+    mHal.mIdToHostHub.erase(kInfo.hubId);
+    return ScopedAStatus::ok();
+}
+
 }  // namespace aidl::android::hardware::contexthub
diff --git a/contexthub/aidl/default/include/contexthub-impl/ContextHub.h b/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
index 6da8bf2..65e84bb 100644
--- a/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
+++ b/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
@@ -17,7 +17,9 @@
 #pragma once
 
 #include <aidl/android/hardware/contexthub/BnContextHub.h>
+#include <aidl/android/hardware/contexthub/BnEndpointCommunication.h>
 
+#include <atomic>
 #include <mutex>
 #include <unordered_set>
 #include <vector>
@@ -56,54 +58,79 @@
 
     ::ndk::ScopedAStatus getHubs(std::vector<HubInfo>* _aidl_return) override;
     ::ndk::ScopedAStatus getEndpoints(std::vector<EndpointInfo>* _aidl_return) override;
-    ::ndk::ScopedAStatus registerEndpoint(const EndpointInfo& in_endpoint) override;
-    ::ndk::ScopedAStatus unregisterEndpoint(const EndpointInfo& in_endpoint) override;
-    ::ndk::ScopedAStatus registerEndpointCallback(
-            const std::shared_ptr<IEndpointCallback>& in_callback) override;
-    ::ndk::ScopedAStatus requestSessionIdRange(int32_t in_size,
-                                               std::array<int32_t, 2>* _aidl_return) override;
-    ::ndk::ScopedAStatus openEndpointSession(
-            int32_t in_sessionId, const EndpointId& in_destination, const EndpointId& in_initiator,
-            const std::optional<std::string>& in_serviceDescriptor) override;
-    ::ndk::ScopedAStatus sendMessageToEndpoint(int32_t in_sessionId,
-                                               const Message& in_msg) override;
-    ::ndk::ScopedAStatus sendMessageDeliveryStatusToEndpoint(
-            int32_t in_sessionId, const MessageDeliveryStatus& in_msgStatus) override;
-    ::ndk::ScopedAStatus closeEndpointSession(int32_t in_sessionId, Reason in_reason) override;
-    ::ndk::ScopedAStatus endpointSessionOpenComplete(int32_t in_sessionId) override;
+    ::ndk::ScopedAStatus registerEndpointHub(
+            const std::shared_ptr<IEndpointCallback>& in_callback, const HubInfo& in_hubInfo,
+            std::shared_ptr<IEndpointCommunication>* _aidl_return) override;
 
   private:
-    struct EndpointSession {
-        int32_t sessionId;
-        EndpointId initiator;
-        EndpointId peer;
-        std::optional<std::string> serviceDescriptor;
+    class HubInterface : public BnEndpointCommunication {
+      public:
+        HubInterface(ContextHub& hal, const std::shared_ptr<IEndpointCallback>& in_callback,
+                     const HubInfo& in_hubInfo)
+            : mHal(hal), mEndpointCallback(in_callback), kInfo(in_hubInfo) {}
+        ~HubInterface() = default;
+
+        ::ndk::ScopedAStatus registerEndpoint(const EndpointInfo& in_endpoint) override;
+        ::ndk::ScopedAStatus unregisterEndpoint(const EndpointInfo& in_endpoint) override;
+        ::ndk::ScopedAStatus requestSessionIdRange(int32_t in_size,
+                                                   std::array<int32_t, 2>* _aidl_return) override;
+        ::ndk::ScopedAStatus openEndpointSession(
+                int32_t in_sessionId, const EndpointId& in_destination,
+                const EndpointId& in_initiator,
+                const std::optional<std::string>& in_serviceDescriptor) override;
+        ::ndk::ScopedAStatus sendMessageToEndpoint(int32_t in_sessionId,
+                                                   const Message& in_msg) override;
+        ::ndk::ScopedAStatus sendMessageDeliveryStatusToEndpoint(
+                int32_t in_sessionId, const MessageDeliveryStatus& in_msgStatus) override;
+        ::ndk::ScopedAStatus closeEndpointSession(int32_t in_sessionId, Reason in_reason) override;
+        ::ndk::ScopedAStatus endpointSessionOpenComplete(int32_t in_sessionId) override;
+        ::ndk::ScopedAStatus unregister() override;
+
+      private:
+        friend class ContextHub;
+
+        struct EndpointSession {
+            int32_t sessionId;
+            EndpointId initiator;
+            EndpointId peer;
+            std::optional<std::string> serviceDescriptor;
+        };
+
+        //! Finds an endpoint in the range defined by the endpoints
+        //! @return whether the endpoint was found
+        template <typename Iter>
+        bool findEndpoint(const EndpointId& target, const Iter& begin, const Iter& end) {
+            for (auto iter = begin; iter != end; ++iter) {
+                if (iter->id.id == target.id && iter->id.hubId == target.hubId) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        //! Endpoint storage and information
+        ContextHub& mHal;
+        std::shared_ptr<IEndpointCallback> mEndpointCallback;
+        const HubInfo kInfo;
+
+        std::atomic<bool> mActive = true;
+
+        std::mutex mEndpointMutex;
+        std::vector<EndpointInfo> mEndpoints;
+        std::vector<EndpointSession> mEndpointSessions;
+        uint16_t mBaseSessionId;
+        uint16_t mMaxSessionId;
     };
 
     static constexpr uint32_t kMockHubId = 0;
 
-    //! Finds an endpoint in the range defined by the endpoints
-    //! @return whether the endpoint was found
-    template <typename Iter>
-    bool findEndpoint(const EndpointId& target, const Iter& begin, const Iter& end) {
-        for (auto iter = begin; iter != end; ++iter) {
-            if (iter->id.id == target.id && iter->id.hubId == target.hubId) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     std::shared_ptr<IContextHubCallback> mCallback;
 
     std::unordered_set<char16_t> mConnectedHostEndpoints;
 
-    //! Endpoint storage and information
-    std::mutex mEndpointMutex;
-    std::vector<EndpointInfo> mEndpoints;
-    std::vector<EndpointSession> mEndpointSessions;
-    std::shared_ptr<IEndpointCallback> mEndpointCallback;
-    int32_t mMaxValidSessionId = 0;
+    std::mutex mHostHubsLock;
+    std::unordered_map<int64_t, std::shared_ptr<HubInterface>> mIdToHostHub;
+    int32_t mNextSessionIdBase = 0;
 };
 
 }  // namespace contexthub
diff --git a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
index aa611ce..d7859d9 100644
--- a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
+++ b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
@@ -24,6 +24,7 @@
 #include <android/hardware/contexthub/IContextHub.h>
 #include <android/hardware/contexthub/IContextHubCallback.h>
 #include <android/hardware/contexthub/IEndpointCallback.h>
+#include <android/hardware/contexthub/IEndpointCommunication.h>
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
 #include <log/log.h>
@@ -46,6 +47,7 @@
 using ::android::hardware::contexthub::HubInfo;
 using ::android::hardware::contexthub::IContextHub;
 using ::android::hardware::contexthub::IContextHubCallbackDefault;
+using ::android::hardware::contexthub::IEndpointCommunication;
 using ::android::hardware::contexthub::Message;
 using ::android::hardware::contexthub::MessageDeliveryStatus;
 using ::android::hardware::contexthub::NanoappBinary;
@@ -62,34 +64,71 @@
 // 6612b522-b717-41c8-b48d-c0b1cc64e142
 constexpr std::array<uint8_t, 16> kUuid = {0x66, 0x12, 0xb5, 0x22, 0xb7, 0x17, 0x41, 0xc8,
                                            0xb4, 0x8d, 0xc0, 0xb1, 0xcc, 0x64, 0xe1, 0x42};
+
 const String16 kName{"VtsAidlHalContextHubTargetTest"};
 
 const String16 kEchoServiceName{"android.hardware.contexthub.test.EchoService"};
 
+constexpr int64_t kDefaultHubId = 1;
+
+class TestEndpointCallback;
 class ContextHubAidl : public testing::TestWithParam<std::tuple<std::string, int32_t>> {
   public:
-    virtual void SetUp() override {
-        contextHub = android::waitForDeclaredService<IContextHub>(
+    void SetUp() override {
+        mContextHub = android::waitForDeclaredService<IContextHub>(
                 String16(std::get<0>(GetParam()).c_str()));
-        ASSERT_NE(contextHub, nullptr);
-
-        // Best effort enable test mode - this may not be supported on older HALS, so we
-        // ignore the return value.
-        contextHub->setTestMode(/* enable= */ true);
+        ASSERT_NE(mContextHub, nullptr);
+        mEndpointCb = sp<TestEndpointCallback>::make();
     }
 
-    virtual void TearDown() override { contextHub->setTestMode(/* enable= */ false); }
-
     uint32_t getHubId() { return std::get<1>(GetParam()); }
 
+    Status registerHub(int64_t id, sp<IEndpointCommunication>* hubInterface) {
+        HubInfo info;
+        info.hubId = id;
+        return mContextHub->registerEndpointHub(mEndpointCb, info, hubInterface);
+    }
+
+    bool registerDefaultHub() {
+        Status status = registerHub(kDefaultHubId, &mHubInterface);
+        if (status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
+            status.transactionError() == android::UNKNOWN_TRANSACTION) {
+            return false;
+        }
+        EXPECT_TRUE(status.isOk());
+        EXPECT_NE(mHubInterface, nullptr);
+        if (!mHubInterface) {
+            return false;
+        }
+        return true;
+    }
+
     void testSettingChanged(Setting setting);
 
-    sp<IContextHub> contextHub;
+    sp<IContextHub> mContextHub;
+    sp<TestEndpointCallback> mEndpointCb;
+    sp<IEndpointCommunication> mHubInterface;
+};
+
+class ContextHubAidlWithTestMode : public ContextHubAidl {
+  public:
+    void SetUp() override {
+        ContextHubAidl::SetUp();
+
+        // Best effort enable test mode - this may not be supported on older HALS, so we
+        // ignore the return value.
+        mContextHub->setTestMode(/* enable= */ true);
+    }
+
+    void TearDown() override {
+        mContextHub->setTestMode(/* enable= */ false);
+        ContextHubAidl::TearDown();
+    }
 };
 
 TEST_P(ContextHubAidl, TestGetHubs) {
     std::vector<ContextHubInfo> hubs;
-    ASSERT_TRUE(contextHub->getContextHubs(&hubs).isOk());
+    ASSERT_TRUE(mContextHub->getContextHubs(&hubs).isOk());
 
     ALOGD("System reports %zu hubs", hubs.size());
 
@@ -111,7 +150,7 @@
 }
 
 TEST_P(ContextHubAidl, TestEnableTestMode) {
-    Status status = contextHub->setTestMode(true);
+    Status status = mContextHub->setTestMode(true);
     if (status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
         status.transactionError() == android::UNKNOWN_TRANSACTION) {
         GTEST_SKIP() << "Not supported -> old API; or not implemented";
@@ -121,7 +160,7 @@
 }
 
 TEST_P(ContextHubAidl, TestDisableTestMode) {
-    Status status = contextHub->setTestMode(false);
+    Status status = mContextHub->setTestMode(false);
     if (status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
         status.transactionError() == android::UNKNOWN_TRANSACTION) {
         GTEST_SKIP() << "Not supported -> old API; or not implemented";
@@ -170,7 +209,7 @@
 
 TEST_P(ContextHubAidl, TestRegisterCallback) {
     sp<EmptyContextHubCallback> cb = sp<EmptyContextHubCallback>::make();
-    ASSERT_TRUE(contextHub->registerCallback(getHubId(), cb).isOk());
+    ASSERT_TRUE(mContextHub->registerCallback(getHubId(), cb).isOk());
 }
 
 // Helper callback that puts the async appInfo callback data into a promise
@@ -219,8 +258,8 @@
 // Calls queryApps() and checks the returned metadata
 TEST_P(ContextHubAidl, TestQueryApps) {
     sp<QueryAppsCallback> cb = sp<QueryAppsCallback>::make();
-    ASSERT_TRUE(contextHub->registerCallback(getHubId(), cb).isOk());
-    ASSERT_TRUE(contextHub->queryNanoapps(getHubId()).isOk());
+    ASSERT_TRUE(mContextHub->registerCallback(getHubId(), cb).isOk());
+    ASSERT_TRUE(mContextHub->queryNanoapps(getHubId()).isOk());
 
     std::vector<NanoappInfo> appInfoList;
     ASSERT_TRUE(waitForCallback(cb->promise.get_future(), &appInfoList));
@@ -241,7 +280,7 @@
 // Calls getPreloadedNanoappsIds() and verifies there are preloaded nanoapps
 TEST_P(ContextHubAidl, TestGetPreloadedNanoappIds) {
     std::vector<int64_t> preloadedNanoappIds;
-    Status status = contextHub->getPreloadedNanoappIds(getHubId(), &preloadedNanoappIds);
+    Status status = mContextHub->getPreloadedNanoappIds(getHubId(), &preloadedNanoappIds);
     if (status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
         status.transactionError() == android::UNKNOWN_TRANSACTION) {
         GTEST_SKIP() << "Not supported -> old API; or not implemented";
@@ -304,7 +343,7 @@
   public:
     virtual void SetUp() override {
         ContextHubAidl::SetUp();
-        ASSERT_TRUE(contextHub->registerCallback(getHubId(), cb).isOk());
+        ASSERT_TRUE(mContextHub->registerCallback(getHubId(), cb).isOk());
     }
 
     sp<TransactionResultCallback> cb = sp<TransactionResultCallback>::make();
@@ -318,7 +357,7 @@
     std::fill(message.messageBody.begin(), message.messageBody.end(), 0);
 
     ALOGD("Sending message to non-existent nanoapp");
-    ASSERT_TRUE(contextHub->sendMessageToHub(getHubId(), message).isOk());
+    ASSERT_TRUE(mContextHub->sendMessageToHub(getHubId(), message).isOk());
 }
 
 TEST_P(ContextHubTransactionTest, TestLoadEmptyNanoapp) {
@@ -332,7 +371,7 @@
     emptyApp.targetChreApiMinorVersion = 0;
 
     ALOGD("Loading empty nanoapp");
-    bool success = contextHub->loadNanoapp(getHubId(), emptyApp, cb->expectedTransactionId).isOk();
+    bool success = mContextHub->loadNanoapp(getHubId(), emptyApp, cb->expectedTransactionId).isOk();
     if (success) {
         bool transactionSuccess;
         ASSERT_TRUE(waitForCallback(cb->promise.get_future(), &transactionSuccess));
@@ -345,7 +384,7 @@
 
     ALOGD("Unloading nonexistent nanoapp");
     bool success =
-            contextHub->unloadNanoapp(getHubId(), kNonExistentAppId, cb->expectedTransactionId)
+            mContextHub->unloadNanoapp(getHubId(), kNonExistentAppId, cb->expectedTransactionId)
                     .isOk();
     if (success) {
         bool transactionSuccess;
@@ -359,7 +398,7 @@
 
     ALOGD("Enabling nonexistent nanoapp");
     bool success =
-            contextHub->enableNanoapp(getHubId(), kNonExistentAppId, cb->expectedTransactionId)
+            mContextHub->enableNanoapp(getHubId(), kNonExistentAppId, cb->expectedTransactionId)
                     .isOk();
     if (success) {
         bool transactionSuccess;
@@ -373,7 +412,7 @@
 
     ALOGD("Disabling nonexistent nanoapp");
     bool success =
-            contextHub->disableNanoapp(getHubId(), kNonExistentAppId, cb->expectedTransactionId)
+            mContextHub->disableNanoapp(getHubId(), kNonExistentAppId, cb->expectedTransactionId)
                     .isOk();
     if (success) {
         bool transactionSuccess;
@@ -386,10 +425,10 @@
     // In VTS, we only test that sending the values doesn't cause things to blow up - GTS tests
     // verify the expected E2E behavior in CHRE
     sp<EmptyContextHubCallback> cb = sp<EmptyContextHubCallback>::make();
-    ASSERT_TRUE(contextHub->registerCallback(getHubId(), cb).isOk());
+    ASSERT_TRUE(mContextHub->registerCallback(getHubId(), cb).isOk());
 
-    ASSERT_TRUE(contextHub->onSettingChanged(setting, true /* enabled */).isOk());
-    ASSERT_TRUE(contextHub->onSettingChanged(setting, false /* enabled */).isOk());
+    ASSERT_TRUE(mContextHub->onSettingChanged(setting, true /* enabled */).isOk());
+    ASSERT_TRUE(mContextHub->onSettingChanged(setting, false /* enabled */).isOk());
 }
 
 TEST_P(ContextHubAidl, TestOnLocationSettingChanged) {
@@ -444,27 +483,27 @@
     hostEndpointInfo.type = HostEndpointInfo::Type::NATIVE;
     hostEndpointInfo.hostEndpointId = kHostEndpointId;
 
-    ASSERT_TRUE(contextHub->onHostEndpointConnected(hostEndpointInfo).isOk());
-    ASSERT_TRUE(contextHub->onHostEndpointDisconnected(kHostEndpointId).isOk());
+    ASSERT_TRUE(mContextHub->onHostEndpointConnected(hostEndpointInfo).isOk());
+    ASSERT_TRUE(mContextHub->onHostEndpointDisconnected(kHostEndpointId).isOk());
 }
 
 TEST_P(ContextHubTransactionTest, TestInvalidHostConnection) {
     constexpr char16_t kHostEndpointId = 1;
 
-    ASSERT_TRUE(contextHub->onHostEndpointDisconnected(kHostEndpointId).isOk());
+    ASSERT_TRUE(mContextHub->onHostEndpointDisconnected(kHostEndpointId).isOk());
 }
 
 TEST_P(ContextHubTransactionTest, TestNanSessionStateChange) {
     NanSessionStateUpdate update;
     update.state = true;
-    Status status = contextHub->onNanSessionStateChanged(update);
+    Status status = mContextHub->onNanSessionStateChanged(update);
     if (status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
         status.transactionError() == android::UNKNOWN_TRANSACTION) {
         GTEST_SKIP() << "Not supported -> old API; or not implemented";
     } else {
         ASSERT_TRUE(status.isOk());
         update.state = false;
-        ASSERT_TRUE(contextHub->onNanSessionStateChanged(update).isOk());
+        ASSERT_TRUE(mContextHub->onNanSessionStateChanged(update).isOk());
     }
 }
 
@@ -473,7 +512,7 @@
     messageDeliveryStatus.messageSequenceNumber = 123;
     messageDeliveryStatus.errorCode = ErrorCode::OK;
 
-    Status status = contextHub->sendMessageDeliveryStatusToHub(getHubId(), messageDeliveryStatus);
+    Status status = mContextHub->sendMessageDeliveryStatusToHub(getHubId(), messageDeliveryStatus);
     if (status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
         status.transactionError() == android::UNKNOWN_TRANSACTION) {
         GTEST_SKIP() << "Not supported -> old API; or not implemented";
@@ -546,7 +585,30 @@
     bool mWasOnEndpointSessionOpenCompleteCalled = false;
 };
 
-TEST_P(ContextHubAidl, RegisterEndpoint) {
+TEST_P(ContextHubAidlWithTestMode, RegisterHub) {
+    if (!registerDefaultHub()) {
+        GTEST_SKIP() << "Not supported -> old API; or not implemented";
+    }
+
+    sp<IEndpointCommunication> hub2;
+    Status status = registerHub(kDefaultHubId + 1, &hub2);
+    EXPECT_TRUE(status.isOk());
+
+    sp<IEndpointCommunication> hub3;
+    status = registerHub(kDefaultHubId + 1, &hub3);
+    ASSERT_FALSE(status.isOk());
+    EXPECT_EQ(status.exceptionCode(), Status::EX_ILLEGAL_STATE);
+
+    hub2->unregister();
+    status = registerHub(kDefaultHubId + 1, &hub3);
+    EXPECT_TRUE(status.isOk());
+}
+
+TEST_P(ContextHubAidlWithTestMode, RegisterEndpoint) {
+    if (!registerDefaultHub()) {
+        GTEST_SKIP() << "Not supported -> old API; or not implemented";
+    }
+
     EndpointInfo endpointInfo;
     endpointInfo.id.id = 1;
     endpointInfo.id.hubId = 0xCAFECAFECAFECAFE;
@@ -554,7 +616,7 @@
     endpointInfo.name = String16("Test host endpoint 1");
     endpointInfo.version = 42;
 
-    Status status = contextHub->registerEndpoint(endpointInfo);
+    Status status = mHubInterface->registerEndpoint(endpointInfo);
     if (status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
         status.transactionError() == android::UNKNOWN_TRANSACTION) {
         GTEST_SKIP() << "Not supported -> old API; or not implemented";
@@ -563,7 +625,11 @@
     }
 }
 
-TEST_P(ContextHubAidl, RegisterEndpointSameNameFailure) {
+TEST_P(ContextHubAidlWithTestMode, RegisterEndpointSameNameFailure) {
+    if (!registerDefaultHub()) {
+        GTEST_SKIP() << "Not supported -> old API; or not implemented";
+    }
+
     EndpointInfo endpointInfo;
     endpointInfo.id.id = 2;
     endpointInfo.id.hubId = 0xCAFECAFECAFECAFE;
@@ -578,7 +644,7 @@
     endpointInfo2.name = String16("Test host endpoint 2");
     endpointInfo2.version = 42;
 
-    Status status = contextHub->registerEndpoint(endpointInfo);
+    Status status = mHubInterface->registerEndpoint(endpointInfo);
     if (status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
         status.transactionError() == android::UNKNOWN_TRANSACTION) {
         GTEST_SKIP() << "Not supported -> old API; or not implemented";
@@ -586,10 +652,14 @@
         EXPECT_TRUE(status.isOk());
     }
 
-    EXPECT_FALSE(contextHub->registerEndpoint(endpointInfo2).isOk());
+    EXPECT_FALSE(mHubInterface->registerEndpoint(endpointInfo2).isOk());
 }
 
-TEST_P(ContextHubAidl, RegisterEndpointSameIdFailure) {
+TEST_P(ContextHubAidlWithTestMode, RegisterEndpointSameIdFailure) {
+    if (!registerDefaultHub()) {
+        GTEST_SKIP() << "Not supported -> old API; or not implemented";
+    }
+
     EndpointInfo endpointInfo;
     endpointInfo.id.id = 4;
     endpointInfo.id.hubId = 0xCAFECAFECAFECAFE;
@@ -604,7 +674,7 @@
     endpointInfo2.name = String16("Test host endpoint - same ID test");
     endpointInfo2.version = 42;
 
-    Status status = contextHub->registerEndpoint(endpointInfo);
+    Status status = mHubInterface->registerEndpoint(endpointInfo);
     if (status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
         status.transactionError() == android::UNKNOWN_TRANSACTION) {
         GTEST_SKIP() << "Not supported -> old API; or not implemented";
@@ -612,10 +682,14 @@
         EXPECT_TRUE(status.isOk());
     }
 
-    EXPECT_FALSE(contextHub->registerEndpoint(endpointInfo2).isOk());
+    EXPECT_FALSE(mHubInterface->registerEndpoint(endpointInfo2).isOk());
 }
 
-TEST_P(ContextHubAidl, UnregisterEndpoint) {
+TEST_P(ContextHubAidlWithTestMode, UnregisterEndpoint) {
+    if (!registerDefaultHub()) {
+        GTEST_SKIP() << "Not supported -> old API; or not implemented";
+    }
+
     EndpointInfo endpointInfo;
     endpointInfo.id.id = 6;
     endpointInfo.id.hubId = 0xCAFECAFECAFECAFE;
@@ -623,7 +697,7 @@
     endpointInfo.name = String16("Test host endpoint 6");
     endpointInfo.version = 42;
 
-    Status status = contextHub->registerEndpoint(endpointInfo);
+    Status status = mHubInterface->registerEndpoint(endpointInfo);
     if (status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
         status.transactionError() == android::UNKNOWN_TRANSACTION) {
         GTEST_SKIP() << "Not supported -> old API; or not implemented";
@@ -631,10 +705,14 @@
         EXPECT_TRUE(status.isOk());
     }
 
-    EXPECT_TRUE(contextHub->unregisterEndpoint(endpointInfo).isOk());
+    EXPECT_TRUE(mHubInterface->unregisterEndpoint(endpointInfo).isOk());
 }
 
-TEST_P(ContextHubAidl, UnregisterEndpointNonexistent) {
+TEST_P(ContextHubAidlWithTestMode, UnregisterEndpointNonexistent) {
+    if (!registerDefaultHub()) {
+        GTEST_SKIP() << "Not supported -> old API; or not implemented";
+    }
+
     EndpointInfo endpointInfo;
     endpointInfo.id.id = 100;
     endpointInfo.id.hubId = 0xCAFECAFECAFECAFE;
@@ -642,7 +720,7 @@
     endpointInfo.name = String16("Test host endpoint 100");
     endpointInfo.version = 42;
 
-    Status status = contextHub->unregisterEndpoint(endpointInfo);
+    Status status = mHubInterface->unregisterEndpoint(endpointInfo);
     if (status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
         status.transactionError() == android::UNKNOWN_TRANSACTION) {
         GTEST_SKIP() << "Not supported -> old API; or not implemented";
@@ -651,25 +729,9 @@
     }
 }
 
-TEST_P(ContextHubAidl, RegisterCallback) {
-    auto cb = sp<TestEndpointCallback>::make();
-    Status status = contextHub->registerEndpointCallback(cb);
-    if (status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
-        status.transactionError() == android::UNKNOWN_TRANSACTION) {
+TEST_P(ContextHubAidlWithTestMode, OpenEndpointSessionInvalidRange) {
+    if (!registerDefaultHub()) {
         GTEST_SKIP() << "Not supported -> old API; or not implemented";
-    } else {
-        EXPECT_TRUE(status.isOk());
-    }
-}
-
-TEST_P(ContextHubAidl, OpenEndpointSessionInvalidRange) {
-    auto cb = sp<TestEndpointCallback>::make();
-    Status status = contextHub->registerEndpointCallback(cb);
-    if (status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
-        status.transactionError() == android::UNKNOWN_TRANSACTION) {
-        GTEST_SKIP() << "Not supported -> old API; or not implemented";
-    } else {
-        EXPECT_TRUE(status.isOk());
     }
 
     // Register the endpoint
@@ -679,11 +741,11 @@
     initiatorEndpoint.type = EndpointInfo::EndpointType::NATIVE;
     initiatorEndpoint.name = String16("Test host endpoint 7");
     initiatorEndpoint.version = 42;
-    EXPECT_TRUE(contextHub->registerEndpoint(initiatorEndpoint).isOk());
+    EXPECT_TRUE(mHubInterface->registerEndpoint(initiatorEndpoint).isOk());
 
     // Find the destination, if it exists
     std::vector<EndpointInfo> endpoints;
-    EXPECT_TRUE(contextHub->getEndpoints(&endpoints).isOk());
+    EXPECT_TRUE(mContextHub->getEndpoints(&endpoints).isOk());
     const EndpointInfo* destinationEndpoint = nullptr;
     for (const EndpointInfo& endpoint : endpoints) {
         for (const Service& service : endpoint.services) {
@@ -700,30 +762,24 @@
     // Request the range
     constexpr int32_t requestedRange = 100;
     std::array<int32_t, 2> range;
-    ASSERT_TRUE(contextHub->requestSessionIdRange(requestedRange, &range).isOk());
+    ASSERT_TRUE(mHubInterface->requestSessionIdRange(requestedRange, &range).isOk());
     EXPECT_EQ(range.size(), 2);
     EXPECT_GE(range[1] - range[0] + 1, requestedRange);
 
     // Open the session
     int32_t sessionId = range[1] + 10;  // invalid
-    EXPECT_FALSE(contextHub
+    EXPECT_FALSE(mHubInterface
                          ->openEndpointSession(sessionId, destinationEndpoint->id,
                                                initiatorEndpoint.id,
                                                /* in_serviceDescriptor= */ kEchoServiceName)
                          .isOk());
 }
 
-TEST_P(ContextHubAidl, OpenEndpointSessionAndSendMessageEchoesBack) {
-    auto cb = sp<TestEndpointCallback>::make();
-    Status status = contextHub->registerEndpointCallback(cb);
-    if (status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
-        status.transactionError() == android::UNKNOWN_TRANSACTION) {
+TEST_P(ContextHubAidlWithTestMode, OpenEndpointSessionAndSendMessageEchoesBack) {
+    if (!registerDefaultHub()) {
         GTEST_SKIP() << "Not supported -> old API; or not implemented";
-    } else {
-        EXPECT_TRUE(status.isOk());
     }
-
-    std::unique_lock<std::mutex> lock(cb->getMutex());
+    std::unique_lock<std::mutex> lock(mEndpointCb->getMutex());
 
     // Register the endpoint
     EndpointInfo initiatorEndpoint;
@@ -732,11 +788,11 @@
     initiatorEndpoint.type = EndpointInfo::EndpointType::NATIVE;
     initiatorEndpoint.name = String16("Test host endpoint 7");
     initiatorEndpoint.version = 42;
-    EXPECT_TRUE(contextHub->registerEndpoint(initiatorEndpoint).isOk());
+    EXPECT_TRUE(mHubInterface->registerEndpoint(initiatorEndpoint).isOk());
 
     // Find the destination, if it exists
     std::vector<EndpointInfo> endpoints;
-    EXPECT_TRUE(contextHub->getEndpoints(&endpoints).isOk());
+    EXPECT_TRUE(mContextHub->getEndpoints(&endpoints).isOk());
     const EndpointInfo* destinationEndpoint = nullptr;
     for (const EndpointInfo& endpoint : endpoints) {
         for (const Service& service : endpoint.services) {
@@ -753,32 +809,32 @@
     // Request the range
     constexpr int32_t requestedRange = 100;
     std::array<int32_t, 2> range;
-    ASSERT_TRUE(contextHub->requestSessionIdRange(requestedRange, &range).isOk());
+    ASSERT_TRUE(mHubInterface->requestSessionIdRange(requestedRange, &range).isOk());
     EXPECT_EQ(range.size(), 2);
     EXPECT_GE(range[1] - range[0] + 1, requestedRange);
 
     // Open the session
-    cb->resetWasOnEndpointSessionOpenCompleteCalled();
+    mEndpointCb->resetWasOnEndpointSessionOpenCompleteCalled();
     int32_t sessionId = range[0];
-    ASSERT_TRUE(contextHub
+    ASSERT_TRUE(mHubInterface
                         ->openEndpointSession(sessionId, destinationEndpoint->id,
                                               initiatorEndpoint.id,
                                               /* in_serviceDescriptor= */ kEchoServiceName)
                         .isOk());
-    cb->getCondVar().wait(lock);
-    EXPECT_TRUE(cb->wasOnEndpointSessionOpenCompleteCalled());
+    mEndpointCb->getCondVar().wait(lock);
+    EXPECT_TRUE(mEndpointCb->wasOnEndpointSessionOpenCompleteCalled());
 
     // Send the message
     Message message;
     message.flags = 0;
     message.sequenceNumber = 0;
     message.content.push_back(42);
-    ASSERT_TRUE(contextHub->sendMessageToEndpoint(sessionId, message).isOk());
+    ASSERT_TRUE(mHubInterface->sendMessageToEndpoint(sessionId, message).isOk());
 
     // Check for echo
-    cb->getCondVar().wait(lock);
-    EXPECT_FALSE(cb->getMessages().empty());
-    EXPECT_EQ(cb->getMessages().back().content.back(), 42);
+    mEndpointCb->getCondVar().wait(lock);
+    EXPECT_FALSE(mEndpointCb->getMessages().empty());
+    EXPECT_EQ(mEndpointCb->getMessages().back().content.back(), 42);
 }
 
 std::string PrintGeneratedTest(const testing::TestParamInfo<ContextHubAidl::ParamType>& info) {
@@ -789,13 +845,17 @@
 INSTANTIATE_TEST_SUITE_P(ContextHub, ContextHubAidl, testing::ValuesIn(generateContextHubMapping()),
                          PrintGeneratedTest);
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ContextHubAidlWithTestMode);
+INSTANTIATE_TEST_SUITE_P(ContextHub, ContextHubAidlWithTestMode,
+                         testing::ValuesIn(generateContextHubMapping()), PrintGeneratedTest);
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ContextHubTransactionTest);
 INSTANTIATE_TEST_SUITE_P(ContextHub, ContextHubTransactionTest,
                          testing::ValuesIn(generateContextHubMapping()), PrintGeneratedTest);
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
-    ProcessState::self()->setThreadPoolMaxThreadCount(1);
+    ProcessState::self()->setThreadPoolMaxThreadCount(2);
     ProcessState::self()->startThreadPool();
     return RUN_ALL_TESTS();
 }
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/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
index 2945dab..e6d2fdf 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -45,6 +45,9 @@
   void deleteAllKeys();
   void destroyAttestationIds();
   android.hardware.security.keymint.BeginResult begin(in android.hardware.security.keymint.KeyPurpose purpose, in byte[] keyBlob, in android.hardware.security.keymint.KeyParameter[] params, in @nullable android.hardware.security.keymint.HardwareAuthToken authToken);
+  /**
+   * @deprecated Method has never been used due to design limitations
+   */
   void deviceLocked(in boolean passwordOnly, in @nullable android.hardware.security.secureclock.TimeStampToken timestampToken);
   void earlyBootEnded();
   byte[] convertStorageKeyToEphemeral(in byte[] storageKeyBlob);
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index b57dd8a..cafec70 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -826,6 +826,7 @@
      *
      * @param passwordOnly N/A due to the deprecation
      * @param timestampToken N/A due to the deprecation
+     * @deprecated Method has never been used due to design limitations
      */
     void deviceLocked(in boolean passwordOnly, in @nullable TimeStampToken timestampToken);
 
@@ -964,10 +965,11 @@
      * IKeyMintDevice must ignore KeyParameters with tags not included in the following list:
      *
      * o Tag::MODULE_HASH: holds a hash that must be included in attestations in the moduleHash
-     *   field of the software enforced authorization list. If Tag::MODULE_HASH is included in more
-     *   than one setAdditionalAttestationInfo call, the implementation should compare the initial
-     *   KeyParamValue with the more recent one. If they differ, the implementation should fail with
-     *   ErrorCode::MODULE_HASH_ALREADY_SET. If they are the same, no action needs to be taken.
+     *   field of the software enforced authorization list.
+     *
+     * @return error ErrorCode::MODULE_HASH_ALREADY_SET if this is not the first time
+     *         setAdditionalAttestationInfo is called with Tag::MODULE_HASH, and the associated
+     *         KeyParamValue of the current call doesn't match the KeyParamValue of the first call.
      */
     void setAdditionalAttestationInfo(in KeyParameter[] info);
 }
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
index eaeec32..5afaf31 100644
--- a/security/keymint/support/remote_prov_utils.cpp
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -870,7 +870,7 @@
     }
 
     auto csr = hwtrust::Csr::validate(encodedCsr, *diceChainKind, false /*isFactory*/,
-                                      false /*allowAnyMode*/, deviceSuffix(instanceName));
+                                      true /*allowAnyMode*/, deviceSuffix(instanceName));
     if (!csr.ok()) {
         return csr.error().message();
     }
@@ -904,7 +904,7 @@
     }
 
     auto csr1 = hwtrust::Csr::validate(encodedCsr1, *diceChainKind, false /*isFactory*/,
-                                       false /*allowAnyMode*/, deviceSuffix(instanceName1));
+                                       true /*allowAnyMode*/, deviceSuffix(instanceName1));
     if (!csr1.ok()) {
         return csr1.error().message();
     }
@@ -921,7 +921,7 @@
     }
 
     auto csr2 = hwtrust::Csr::validate(encodedCsr2, *diceChainKind, false /*isFactory*/,
-                                       false /*allowAnyMode*/, deviceSuffix(instanceName2));
+                                       true /*allowAnyMode*/, deviceSuffix(instanceName2));
     if (!csr2.ok()) {
         return csr2.error().message();
     }
@@ -952,7 +952,7 @@
     }
 
     auto csr = hwtrust::Csr::validate(encodedCsr, *diceChainKind, false /*isFactory*/,
-                                      false /*allowAnyMode*/, deviceSuffix(DEFAULT_INSTANCE_NAME));
+                                      true /*allowAnyMode*/, deviceSuffix(DEFAULT_INSTANCE_NAME));
     if (!csr.ok()) {
         return csr.error().message();
     }
diff --git a/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
index b31a06c..99eb761 100644
--- a/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
@@ -64,7 +64,7 @@
     int keySizeBytes;
   }
   union DerivedKeyPolicy {
-    android.hardware.security.see.hwcrypto.IHwCryptoKey.ClearKeyPolicy clearKey;
+    android.hardware.security.see.hwcrypto.IHwCryptoKey.ClearKeyPolicy clearKeyPolicy;
     byte[] opaqueKey;
   }
   parcelable DerivedKeyParameters {
diff --git a/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
index 7c87dd3..3adb2f9 100644
--- a/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
@@ -34,5 +34,5 @@
 package android.hardware.security.see.hwcrypto;
 @VintfStability
 interface IHwCryptoOperations {
-  android.hardware.security.see.hwcrypto.CryptoOperationResult[] processCommandList(inout android.hardware.security.see.hwcrypto.CryptoOperationSet[] operations, out android.hardware.security.see.hwcrypto.CryptoOperationErrorAdditionalInfo additionalErrorInfo);
+  android.hardware.security.see.hwcrypto.CryptoOperationResult[] processCommandList(inout android.hardware.security.see.hwcrypto.CryptoOperationSet[] operations);
 }
diff --git a/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
index 97a4c37..93d6cbc 100644
--- a/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
@@ -107,10 +107,12 @@
          * If used we will derive a clear key and pass it back as an array of bytes on
          * <code>HwCryptoKeyMaterial::explicitKey</code>.
          */
-        ClearKeyPolicy clearKey;
+        ClearKeyPolicy clearKeyPolicy;
 
         /*
          * Policy for the newly derived opaque key. Defines how the key can be used and its type.
+         * Its definition can be found in <code>KeyPolicy.cddl</code>, which is basically a CBOR
+         * serialization of the file <code>KeyPolicy.aidl</code>.
          */
         byte[] opaqueKey;
     }
@@ -154,11 +156,14 @@
      *     Key to be used to derive the new key using HKDF.
      *
      * @return:
-     *     A DiceCurrentBoundKeyResult containint the versioned key tied the current client version
+     *     A DiceCurrentBoundKeyResult containing the versioned key tied the current client version
      *     on success.
      *
      * @throws:
-     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs.
+     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs,
+     *      in particular:
+     *          - BAD_PARAMETER if an invalid DeviceKeyId is requested.
+     *          - INVALID_KEY if an opaque key is provided that is not suitable for key derivation.
      */
     DiceCurrentBoundKeyResult deriveCurrentDicePolicyBoundKey(
             in DiceBoundDerivationKey derivationKey);
@@ -184,7 +189,11 @@
      *      success.
      *
      * @throws:
-     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs.
+     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs,
+     *      in particular:
+     *          - BAD_PARAMETER if an invalid DeviceKeyId is requested or if dicePolicyForKeyVersion
+     *            is not a valid encrypted DICE policy.
+     *          - INVALID_KEY if an opaque key is provided that is not suitable for key derivation.
      */
     DiceBoundKeyResult deriveDicePolicyBoundKey(
             in DiceBoundDerivationKey derivationKey, in byte[] dicePolicyForKeyVersion);
@@ -197,10 +206,15 @@
      *      file for more information.
      *
      * @return:
-     *      A HwCryptoKeyMaterial containing the derived key on success.
+     *      A <code>DerivedKey</code> containing the derived key on success.
      *
      * @throws:
-     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs.
+     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs,
+     *      in particular:
+     *          - BAD_PARAMETER if an invalid key policy is provided or if the key policy conflicts
+     *            with the requested key.
+     *          - SERIALIZATION_ERROR if the provided key policy is not a valid CBOR key policy.
+     *          - INVALID_KEY if an opaque key is provided that is not suitable for key derivation.
      */
     DerivedKey deriveKey(in DerivedKeyParameters parameters);
 
@@ -233,7 +247,11 @@
      *      IOpaqueKey on success.
      *
      * @throws:
-     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs.
+     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs,
+     *      in particular:
+     *          - BAD_PARAMETER if an invalid Key policy is provided or if the key policy conflicts
+     *            with provided key material.
+     *          - ALLOCATION_ERROR if the system runs out of memory while carring out the operation.
      */
     IOpaqueKey importClearKey(in ExplicitKeyMaterial keyMaterial, in KeyPolicy newKeyPolicy);
 
@@ -248,7 +266,9 @@
      * passing the receiver DICE policy to insure that only that receiver can import the key.
      *
      * @return:
-     *      byte[] on success, which is the caller encrypted DICE policy.
+     *      byte[] on success, which is the caller encrypted DICE policy. The DICE policy follows
+     *      the structure defined on DicePolicy.cddl, located under
+     *      hardware/interfaces/security/authgraph/aidl/android/hardware/security/authgraph/
      */
     byte[] getCurrentDicePolicy();
 
@@ -266,10 +286,14 @@
      *      DICE policy used to seal the exported key.
      *
      * @return:
-     *      An IOpaqueKey that can be directly be used on the local HWCrypto service on success.
+     *      An IOpaqueKey that can be directly used on the local HWCrypto service on success.
      *
      * @throws:
-     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs.
+     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs,
+     *      in particular:
+     *          - BAD_PARAMETER if an invalid encrypted sealing DICE policy is provided.
+     *          - ALLOCATION_ERROR if the system runs out of memory while carring out the operation.
+     *          - UNAUTHORIZED if the sealingDicePolicy do not match the caller.
      */
     IOpaqueKey keyTokenImport(in OpaqueKeyToken requestedKey, in byte[] sealingDicePolicy);
 
@@ -287,8 +311,9 @@
      *      An IOpaqueKey corresponding to the requested key slot on success.
      *
      * @throws:
-     *      ServiceSpecificException <code>UNAUTHORIZED</code> if the caller cannot access the
-     *      requested key, another specific error based on <code>HalErrorCode</code> otherwise.
+     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs,
+     *      in particular:
+     *          - UNAUTHORIZED if the caller cannot access the requested key.
      */
     IOpaqueKey getKeyslotData(KeySlot slotId);
 }
diff --git a/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
index 9df6d67..dbe4d80 100644
--- a/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
@@ -31,19 +31,21 @@
      *
      * @param operations:
      *      Parameter containing 1 or more set of commands to execute. Additionally, each set can
-     *      also contain a context on which the commands will be executed.
-     *
-     * @param additionalErrorInfo:
-     *      Structure containing additional info when errors are encountered. Only valid if the
-     *      function failed its execution.
+     *      also contain a context on which the commands will be executed. The parameter has type
+     *      inout because it can contain buffers used to write the output of the operation.
      *
      * @return:
      *      CryptoOperationResult[] on success, which can contain a context to continue executing
      *      each of the provided operations sets.
      *
      * @throws:
-     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs.
+     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs,
+     *      in particular:
+     *          - INVALID_KEY if the provided key is not compatible with the operation requested.
+     *          - BAD_STATE if the provided <code>CryptoOperationSet</code> contains operations that
+     *            cannot be carried out in the current server state.
+     *          - UNSUPPORTED if the requested operation is not supported by the server.
+     *          - ALLOCATION_ERROR if the system runs out of memory while carring out the operation.
      */
-    CryptoOperationResult[] processCommandList(inout CryptoOperationSet[] operations,
-            out CryptoOperationErrorAdditionalInfo additionalErrorInfo);
+    CryptoOperationResult[] processCommandList(inout CryptoOperationSet[] operations);
 }
diff --git a/tv/mediaquality/aidl/vts/functional/VtsHalMediaQualityTest.cpp b/tv/mediaquality/aidl/vts/functional/VtsHalMediaQualityTest.cpp
index f785cad..a01d4b0 100644
--- a/tv/mediaquality/aidl/vts/functional/VtsHalMediaQualityTest.cpp
+++ b/tv/mediaquality/aidl/vts/functional/VtsHalMediaQualityTest.cpp
@@ -35,6 +35,7 @@
 #include <android/binder_manager.h>
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
+#include <log/log.h>
 #include <future>
 
 using aidl::android::hardware::graphics::common::PixelFormat;
@@ -63,6 +64,407 @@
 #define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
 #define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
 
+void validateParameterRange0To100(int value) {
+    EXPECT_GE(value, 0);
+    EXPECT_LE(value, 100);
+}
+
+void validateParameterRange0To2047(int value) {
+    EXPECT_GE(value, 0);
+    EXPECT_LE(value, 2047);
+}
+
+void validateColorTemperature(int value) {
+    EXPECT_GE(value, -100);
+    EXPECT_LE(value, 100);
+}
+
+void validatePictureParameter(const PictureParameter& param) {
+    switch (param.getTag()) {
+        case PictureParameter::Tag::brightness: {
+            ALOGD("[validatePictureParameter] validate brightness value");
+            float value = param.get<PictureParameter::Tag::brightness>();
+            EXPECT_TRUE(value >= 0.0f && value <= 1.0f);
+            break;
+        }
+        case PictureParameter::Tag::contrast: {
+            ALOGD("[validatePictureParameter] validate contrast value");
+            int value = param.get<PictureParameter::Tag::contrast>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::sharpness: {
+            ALOGD("[validatePictureParameter] validate sharpness value");
+            int value = param.get<PictureParameter::Tag::sharpness>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::saturation: {
+            ALOGD("[validatePictureParameter] validate saturation value");
+            int value = param.get<PictureParameter::Tag::saturation>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::hue: {
+            ALOGD("[validatePictureParameter] validate hue value");
+            int value = param.get<PictureParameter::Tag::hue>();
+            EXPECT_GE(value, -50);
+            EXPECT_LE(value, 50);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerBrightness: {
+            ALOGD("[validatePictureParameter] validate colorTunerBrightness value");
+            int value = param.get<PictureParameter::Tag::colorTunerBrightness>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerSaturation: {
+            ALOGD("[validatePictureParameter] validate colorTunerSaturation value");
+            int value = param.get<PictureParameter::Tag::colorTunerSaturation>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerHue: {
+            ALOGD("[validatePictureParameter] validate colorTunerHue value");
+            int value = param.get<PictureParameter::Tag::colorTunerHue>();
+            EXPECT_GE(value, -50);
+            EXPECT_LE(value, 50);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerRedOffset: {
+            ALOGD("[validatePictureParameter] validate colorTunerRedOffset value");
+            int value = param.get<PictureParameter::Tag::colorTunerRedOffset>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerGreenOffset: {
+            ALOGD("[validatePictureParameter] validate colorTunerGreenOffset value");
+            int value = param.get<PictureParameter::Tag::colorTunerGreenOffset>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerBlueOffset: {
+            ALOGD("[validatePictureParameter] validate colorTunerBlueOffset value");
+            int value = param.get<PictureParameter::Tag::colorTunerBlueOffset>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerRedGain: {
+            ALOGD("[validatePictureParameter] validate colorTunerRedGain value");
+            int value = param.get<PictureParameter::Tag::colorTunerRedGain>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerGreenGain: {
+            ALOGD("[validatePictureParameter] validate colorTunerGreenGain value");
+            int value = param.get<PictureParameter::Tag::colorTunerGreenGain>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerBlueGain: {
+            ALOGD("[validatePictureParameter] validate colorTunerBlueGain value");
+            int value = param.get<PictureParameter::Tag::colorTunerBlueGain>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::panelInitMaxLuminceNits: {
+            ALOGD("[validatePictureParameter] validate panelInitMaxLuminceNits value");
+            int value = param.get<PictureParameter::Tag::panelInitMaxLuminceNits>();
+            EXPECT_GE(value, 0);
+            EXPECT_LE(value, 10000);
+            break;
+        }
+        case PictureParameter::Tag::colorTemperatureRedGain: {
+            ALOGD("[validatePictureParameter] validate colorTemperatureRedGain value");
+            int value = param.get<PictureParameter::Tag::colorTemperatureRedGain>();
+            validateColorTemperature(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTemperatureGreenGain: {
+            ALOGD("[validatePictureParameter] validate colorTemperatureGreenGain value");
+            int value = param.get<PictureParameter::Tag::colorTemperatureGreenGain>();
+            validateColorTemperature(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTemperatureBlueGain: {
+            ALOGD("[validatePictureParameter] validate colorTemperatureBlueGain value");
+            int value = param.get<PictureParameter::Tag::colorTemperatureBlueGain>();
+            validateColorTemperature(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTemperatureRedOffset: {
+            ALOGD("[validatePictureParameter] validate ccolorTemperatureRedOffset value");
+            int value = param.get<PictureParameter::Tag::colorTemperatureRedOffset>();
+            validateColorTemperature(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTemperatureGreenOffset: {
+            ALOGD("[validatePictureParameter] validate colorTemperatureGreenOffset value");
+            int value = param.get<PictureParameter::Tag::colorTemperatureGreenOffset>();
+            validateColorTemperature(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTemperatureBlueOffset: {
+            ALOGD("[validatePictureParameter] validate colorTemperatureBlueOffset value");
+            int value = param.get<PictureParameter::Tag::colorTemperatureBlueOffset>();
+            validateColorTemperature(value);
+            break;
+        }
+        case PictureParameter::Tag::elevenPointRed: {
+            ALOGD("[validatePictureParameter] validate elevenPointRed value");
+            std::array<int, 11> elevenPointValues =
+                    param.get<PictureParameter::Tag::elevenPointRed>();
+            for (int value : elevenPointValues) {
+                validateParameterRange0To100(value);
+            }
+            break;
+        }
+        case PictureParameter::Tag::elevenPointGreen: {
+            ALOGD("[validatePictureParameter] validate elevenPointGreen value");
+            std::array<int, 11> elevenPointValues =
+                    param.get<PictureParameter::Tag::elevenPointGreen>();
+            for (int value : elevenPointValues) {
+                validateParameterRange0To100(value);
+            }
+            break;
+        }
+        case PictureParameter::Tag::elevenPointBlue: {
+            ALOGD("[validatePictureParameter] validate elevenPointBlue value");
+            std::array<int, 11> elevenPointValues =
+                    param.get<PictureParameter::Tag::elevenPointBlue>();
+            for (int value : elevenPointValues) {
+                validateParameterRange0To100(value);
+            }
+            break;
+        }
+        case PictureParameter::Tag::osdRedGain: {
+            ALOGD("[validatePictureParameter] validate osdRedGain value");
+            int value = param.get<PictureParameter::Tag::osdRedGain>();
+            validateParameterRange0To2047(value);
+            break;
+        }
+        case PictureParameter::Tag::osdGreenGain: {
+            ALOGD("[validatePictureParameter] validate osdGreenGain value");
+            int value = param.get<PictureParameter::Tag::osdGreenGain>();
+            validateParameterRange0To2047(value);
+            break;
+        }
+        case PictureParameter::Tag::osdBlueGain: {
+            ALOGD("[validatePictureParameter] validate osdBlueGain value");
+            int value = param.get<PictureParameter::Tag::osdBlueGain>();
+            validateParameterRange0To2047(value);
+            break;
+        }
+        case PictureParameter::Tag::osdRedOffset: {
+            ALOGD("[validatePictureParameter] validate osdRedOffset value");
+            int value = param.get<PictureParameter::Tag::osdRedOffset>();
+            validateParameterRange0To2047(value);
+            break;
+        }
+        case PictureParameter::Tag::osdGreenOffset: {
+            ALOGD("[validatePictureParameter] validate osdGreenOffset value");
+            int value = param.get<PictureParameter::Tag::osdGreenOffset>();
+            validateParameterRange0To2047(value);
+            break;
+        }
+        case PictureParameter::Tag::osdBlueOffset: {
+            ALOGD("[validatePictureParameter] validate osdBlueOffset value");
+            int value = param.get<PictureParameter::Tag::osdBlueOffset>();
+            validateParameterRange0To2047(value);
+            break;
+        }
+        case PictureParameter::Tag::osdHue: {
+            ALOGD("[validatePictureParameter] validate osdHue value");
+            int value = param.get<PictureParameter::Tag::osdHue>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::osdSaturation: {
+            ALOGD("[validatePictureParameter] validate osdSaturation value");
+            int value = param.get<PictureParameter::Tag::osdSaturation>();
+            EXPECT_GE(value, 0);
+            EXPECT_LE(value, 255);
+            break;
+        }
+        case PictureParameter::Tag::osdContrast: {
+            ALOGD("[validatePictureParameter] validate osdContrast value");
+            int value = param.get<PictureParameter::Tag::osdContrast>();
+            validateParameterRange0To2047(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerHueRed: {
+            ALOGD("[validatePictureParameter] validate colorTunerHueRed value");
+            int value = param.get<PictureParameter::Tag::colorTunerHueRed>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerHueGreen: {
+            ALOGD("[validatePictureParameter] validate colorTunerHueGreen value");
+            int value = param.get<PictureParameter::Tag::colorTunerHueGreen>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerHueBlue: {
+            ALOGD("[validatePictureParameter] validate colorTunerHueBlue value");
+            int value = param.get<PictureParameter::Tag::colorTunerHueBlue>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerHueCyan: {
+            ALOGD("[validatePictureParameter] validate colorTunerHueCyan value");
+            int value = param.get<PictureParameter::Tag::colorTunerHueCyan>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerHueMagenta: {
+            ALOGD("[validatePictureParameter] validate colorTunerHueMagenta value");
+            int value = param.get<PictureParameter::Tag::colorTunerHueMagenta>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerHueYellow: {
+            ALOGD("[validatePictureParameter] validate colorTunerHueYellow value");
+            int value = param.get<PictureParameter::Tag::colorTunerHueYellow>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerHueFlesh: {
+            ALOGD("[validatePictureParameter] validate colorTunerHueFlesh value");
+            int value = param.get<PictureParameter::Tag::colorTunerHueFlesh>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerSaturationRed: {
+            ALOGD("[validatePictureParameter] validate colorTunerSaturationRed value");
+            int value = param.get<PictureParameter::Tag::colorTunerSaturationRed>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerSaturationGreen: {
+            ALOGD("[validatePictureParameter] validate colorTunerSaturationGreen value");
+            int value = param.get<PictureParameter::Tag::colorTunerSaturationGreen>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerSaturationBlue: {
+            ALOGD("[validatePictureParameter] validate colorTunerSaturationBlue value");
+            int value = param.get<PictureParameter::Tag::colorTunerSaturationBlue>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerSaturationCyan: {
+            ALOGD("[validatePictureParameter] validate colorTunerSaturationCyan value");
+            int value = param.get<PictureParameter::Tag::colorTunerSaturationCyan>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerSaturationMagenta: {
+            ALOGD("[validatePictureParameter] validate colorTunerSaturationMagenta value");
+            int value = param.get<PictureParameter::Tag::colorTunerSaturationMagenta>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerSaturationYellow: {
+            ALOGD("[validatePictureParameter] validate colorTunerSaturationYellow value");
+            int value = param.get<PictureParameter::Tag::colorTunerSaturationYellow>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerSaturationFlesh: {
+            ALOGD("[validatePictureParameter] validate colorTunerSaturationFlesh value");
+            int value = param.get<PictureParameter::Tag::colorTunerSaturationFlesh>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerLuminanceRed: {
+            ALOGD("[validatePictureParameter] validate colorTunerLuminanceRed value");
+            int value = param.get<PictureParameter::Tag::colorTunerLuminanceRed>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerLuminanceGreen: {
+            ALOGD("[validatePictureParameter] validate colorTunerLuminanceGreen value");
+            int value = param.get<PictureParameter::Tag::colorTunerLuminanceGreen>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerLuminanceBlue: {
+            ALOGD("[validatePictureParameter] validate colorTunerLuminanceBlue value");
+            int value = param.get<PictureParameter::Tag::colorTunerLuminanceBlue>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerLuminanceCyan: {
+            ALOGD("[validatePictureParameter] validate colorTunerLuminanceCyan value");
+            int value = param.get<PictureParameter::Tag::colorTunerLuminanceCyan>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerLuminanceMagenta: {
+            ALOGD("[validatePictureParameter] validate colorTunerLuminanceMagenta value");
+            int value = param.get<PictureParameter::Tag::colorTunerLuminanceMagenta>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerLuminanceYellow: {
+            ALOGD("[validatePictureParameter] validate colorTunerLuminanceYellow value");
+            int value = param.get<PictureParameter::Tag::colorTunerLuminanceYellow>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case PictureParameter::Tag::colorTunerLuminanceFlesh: {
+            ALOGD("[validatePictureParameter] validate colorTunerLuminanceFlesh value");
+            int value = param.get<PictureParameter::Tag::colorTunerLuminanceFlesh>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        default:
+            ALOGD("Those parameters don't need to check.");
+            break;
+    }
+}
+
+void validateSoundParameter(const SoundParameter& param) {
+    switch (param.getTag()) {
+        case SoundParameter::Tag::balance: {
+            ALOGD("[validateSoundParameter] validate balance value");
+            int value = param.get<SoundParameter::Tag::balance>();
+            EXPECT_GE(value, -50);
+            EXPECT_LE(value, 50);
+            break;
+        }
+        case SoundParameter::Tag::bass: {
+            ALOGD("[validateSoundParameter] validate bass value");
+            int value = param.get<SoundParameter::Tag::bass>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case SoundParameter::Tag::treble: {
+            ALOGD("[validateSoundParameter] validate treble value");
+            int value = param.get<SoundParameter::Tag::treble>();
+            validateParameterRange0To100(value);
+            break;
+        }
+        case SoundParameter::Tag::speakersDelayMs: {
+            ALOGD("[validateSoundParameter] validate speakersDelayMs value");
+            int value = param.get<SoundParameter::Tag::speakersDelayMs>();
+            EXPECT_GE(value, 0);
+            EXPECT_LE(value, 250);
+            break;
+        }
+        case SoundParameter::Tag::digitalOutputDelayMs: {
+            ALOGD("[validateSoundParameter] validate digitalOutputDelayMs value");
+            int value = param.get<SoundParameter::Tag::digitalOutputDelayMs>();
+            EXPECT_GE(value, 0);
+            EXPECT_LE(value, 250);
+            break;
+        }
+        default:
+            ALOGD("Those parameters don't need to check.");
+            break;
+    }
+}
+
 class MediaQualityCallback : public BnMediaQualityCallback {
   public:
     explicit MediaQualityCallback(
@@ -83,7 +485,11 @@
             const std::function<void(const PictureProfile& pictureProfile)>&
                     on_hal_picture_profile_adjust)
         : on_hal_picture_profile_adjust_(on_hal_picture_profile_adjust) {}
+
     ScopedAStatus onPictureProfileAdjusted(const PictureProfile& pictureProfile) override {
+        for (const auto& param : pictureProfile.parameters.pictureParameters) {
+            validatePictureParameter(param);
+        }
         on_hal_picture_profile_adjust_(pictureProfile);
         return ScopedAStatus::ok();
     }
@@ -111,7 +517,11 @@
             const std::function<void(const SoundProfile& soundProfile)>&
                     on_hal_sound_profile_adjust)
         : on_hal_sound_profile_adjust_(on_hal_sound_profile_adjust) {}
+
     ScopedAStatus onSoundProfileAdjusted(const SoundProfile& soundProfile) override {
+        for (const auto& param : soundProfile.parameters.soundParameters) {
+            validateSoundParameter(param);
+        }
         on_hal_sound_profile_adjust_(soundProfile);
         return ScopedAStatus::ok();
     }
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
index 158e4f1..59d9593 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
@@ -214,9 +214,7 @@
     ASSERT_TRUE(mFilterTests.startFilter(filterId));
     // tune test
     ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
-    if (!isPassthroughFilter(filterConf)) {
-        ASSERT_TRUE(filterDataOutputTest());
-    }
+    ASSERT_TRUE(filterDataOutputTest());
     ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
     ASSERT_TRUE(mFilterTests.stopFilter(filterId));
     ASSERT_TRUE(mFilterTests.releaseShareAvHandle(filterId));
@@ -1383,6 +1381,10 @@
     auto live_configs = generateLiveConfigurations();
     for (auto& configuration : live_configs) {
         live = configuration;
+        // shared memory handle is not used by a passthrough filter at all
+        if (isPassthroughFilter(filterMap[live.videoFilterId])) {
+            continue;
+        }
         mediaFilterUsingSharedMemoryTest(filterMap[live.videoFilterId],
                                          frontendMap[live.frontendId]);
     }
diff --git a/virtualization/OWNERS b/virtualization/OWNERS
new file mode 100644
index 0000000..316145b
--- /dev/null
+++ b/virtualization/OWNERS
@@ -0,0 +1 @@
+include platform/packages/modules/Virtualization:/OWNERS
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_aidl_test_utils.cpp b/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp
index c68d8fd..202082e 100644
--- a/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp
+++ b/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp
@@ -276,3 +276,28 @@
     }
     return std::optional<std::vector<std::optional<OuiKeyedData>>>{dataList};
 }
+
+IWifiChip::ApIfaceParams generateApIfaceParams(IfaceConcurrencyType type, bool uses_mlo,
+                                               int oui_size) {
+    IWifiChip::ApIfaceParams params;
+    params.ifaceType = type;
+    params.usesMlo = uses_mlo;
+    params.vendorData = generateOuiKeyedDataListOptional(oui_size);
+    return params;
+}
+
+std::shared_ptr<IWifiApIface> getWifiApOrBridgedApIface(std::shared_ptr<IWifiChip> wifi_chip,
+                                                        IWifiChip::ApIfaceParams params) {
+    if (!wifi_chip.get()) {
+        return nullptr;
+    }
+    std::shared_ptr<IWifiApIface> iface;
+    if (!configureChipToSupportConcurrencyTypeInternal(wifi_chip, IfaceConcurrencyType::AP)) {
+        return nullptr;
+    }
+    auto status = wifi_chip->createApOrBridgedApIfaceWithParams(params, &iface);
+    if (!status.isOk()) {
+        return nullptr;
+    }
+    return iface;
+}
diff --git a/wifi/aidl/vts/functional/wifi_aidl_test_utils.h b/wifi/aidl/vts/functional/wifi_aidl_test_utils.h
index 9b47a9f..6d98bf0 100644
--- a/wifi/aidl/vts/functional/wifi_aidl_test_utils.h
+++ b/wifi/aidl/vts/functional/wifi_aidl_test_utils.h
@@ -43,6 +43,8 @@
 std::shared_ptr<IWifiApIface> getWifiApIface(std::shared_ptr<IWifiChip> wifi_chip);
 std::shared_ptr<IWifiApIface> getBridgedWifiApIface(const char* instance_name);
 std::shared_ptr<IWifiApIface> getBridgedWifiApIface(std::shared_ptr<IWifiChip> wifi_chip);
+std::shared_ptr<IWifiApIface> getWifiApOrBridgedApIface(std::shared_ptr<IWifiChip> wifi_chip,
+                                                        IWifiChip::ApIfaceParams params);
 // Configure the chip in a mode to support the creation of the provided iface type.
 bool configureChipToSupportConcurrencyType(const std::shared_ptr<IWifiChip>& wifi_chip,
                                            IfaceConcurrencyType type, int* configured_mode_id);
@@ -57,3 +59,7 @@
 // Generate test vendor data.
 std::vector<OuiKeyedData> generateOuiKeyedDataList(int size);
 std::optional<std::vector<std::optional<OuiKeyedData>>> generateOuiKeyedDataListOptional(int size);
+
+// Generate test ApIfaceParams
+IWifiChip::ApIfaceParams generateApIfaceParams(IfaceConcurrencyType type, bool uses_mlo,
+                                               int oui_size);
diff --git a/wifi/aidl/vts/functional/wifi_chip_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_chip_aidl_test.cpp
index a1b9ce1..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;
@@ -52,6 +56,7 @@
         stopWifiService(getInstanceName());
         wifi_chip_ = getWifiChip(getInstanceName());
         ASSERT_NE(nullptr, wifi_chip_.get());
+        ASSERT_TRUE(wifi_chip_->getInterfaceVersion(&interface_version_).isOk());
     }
 
     void TearDown() override { stopWifiService(getInstanceName()); }
@@ -139,6 +144,7 @@
     const char* getInstanceName() { return GetParam().c_str(); }
 
     std::shared_ptr<IWifiChip> wifi_chip_;
+    int interface_version_;
 };
 
 class WifiChipEventCallback : public BnWifiChipEventCallback {
@@ -268,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.
  */
@@ -902,6 +925,112 @@
     }
 }
 
+/**
+ * CreateApOrBridgedApIfaceWithParams for signal ap.
+ */
+TEST_P(WifiChipAidlTest, CreateApOrBridgedApIfaceWithParams_signal_ap) {
+    if (interface_version_ < 3) {
+        GTEST_SKIP() << "CreateApOrBridgedApIfaceWithParams is available as of WifiChip V3";
+    }
+    if (!isConcurrencyTypeSupported(IfaceConcurrencyType::AP)) {
+        GTEST_SKIP() << "AP is not supported";
+    }
+
+    std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(getInstanceName());
+    ASSERT_NE(nullptr, wifi_chip.get());
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApOrBridgedApIface(
+            wifi_chip, generateApIfaceParams(IfaceConcurrencyType::AP, false, 0));
+    ASSERT_NE(nullptr, wifi_ap_iface.get());
+}
+
+/**
+ * CreateApOrBridgedApIfaceWithParams for non mlo bridged ap.
+ */
+TEST_P(WifiChipAidlTest, CreateApOrBridgedApIfaceWithParams_non_mlo_bridged_ap) {
+    if (interface_version_ < 3) {
+        GTEST_SKIP() << "CreateApOrBridgedApIfaceWithParams is available as of WifiChip V3";
+    }
+    bool isBridgedSupport = testing::checkSubstringInCommandOutput(
+            "/system/bin/cmd wifi get-softap-supported-features",
+            "wifi_softap_bridged_ap_supported");
+    if (!isBridgedSupport) {
+        GTEST_SKIP() << "Missing Bridged AP support";
+    }
+
+    std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(getInstanceName());
+    ASSERT_NE(nullptr, wifi_chip.get());
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApOrBridgedApIface(
+            wifi_chip, generateApIfaceParams(IfaceConcurrencyType::AP_BRIDGED, false, 0));
+    ASSERT_NE(nullptr, wifi_ap_iface.get());
+
+    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_FALSE(uses_mlo);
+    EXPECT_EQ(instances.size(), 2);
+}
+
+/**
+ * CreateApOrBridgedApIfaceWithParams for mlo bridged ap.
+ */
+TEST_P(WifiChipAidlTest, CreateApOrBridgedApIfaceWithParams_mlo_bridged_ap) {
+    if (interface_version_ < 3) {
+        GTEST_SKIP() << "CreateApOrBridgedApIfaceWithParams is available as of WifiChip V3";
+    }
+    bool isBridgedSupport = testing::checkSubstringInCommandOutput(
+            "/system/bin/cmd wifi get-softap-supported-features",
+            "wifi_softap_bridged_ap_supported");
+    if (!isBridgedSupport) {
+        GTEST_SKIP() << "Missing Bridged AP support";
+    }
+
+    configureChipForConcurrencyType(IfaceConcurrencyType::STA);
+    int32_t features = getChipFeatureSet(wifi_chip_);
+    if (!(features & static_cast<int32_t>(IWifiChip::FeatureSetMask::MLO_SAP))) {
+        GTEST_SKIP() << "MLO_SAP is not supported by vendor.";
+    }
+    std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(getInstanceName());
+    ASSERT_NE(nullptr, wifi_chip.get());
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApOrBridgedApIface(
+            wifi_chip, generateApIfaceParams(IfaceConcurrencyType::AP_BRIDGED, true, 0));
+    ASSERT_NE(nullptr, wifi_ap_iface.get());
+
+    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);
+    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_rtt_controller_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_rtt_controller_aidl_test.cpp
index 1596602..aca1364 100644
--- a/wifi/aidl/vts/functional/wifi_rtt_controller_aidl_test.cpp
+++ b/wifi/aidl/vts/functional/wifi_rtt_controller_aidl_test.cpp
@@ -19,8 +19,10 @@
 #include <VtsCoreUtil.h>
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
+#include <aidl/android/hardware/wifi/Akm.h>
 #include <aidl/android/hardware/wifi/BnWifi.h>
 #include <aidl/android/hardware/wifi/BnWifiRttControllerEventCallback.h>
+#include <aidl/android/hardware/wifi/RttSecureConfig.h>
 #include <android-base/logging.h>
 #include <android/binder_manager.h>
 #include <android/binder_status.h>
@@ -29,6 +31,7 @@
 
 #include "wifi_aidl_test_utils.h"
 
+using aidl::android::hardware::wifi::Akm;
 using aidl::android::hardware::wifi::BnWifiRttControllerEventCallback;
 using aidl::android::hardware::wifi::IWifiRttController;
 using aidl::android::hardware::wifi::RttBw;
@@ -38,6 +41,7 @@
 using aidl::android::hardware::wifi::RttPreamble;
 using aidl::android::hardware::wifi::RttResponder;
 using aidl::android::hardware::wifi::RttResult;
+using aidl::android::hardware::wifi::RttSecureConfig;
 using aidl::android::hardware::wifi::RttType;
 using aidl::android::hardware::wifi::WifiChannelInfo;
 using aidl::android::hardware::wifi::WifiChannelWidthInMhz;
@@ -87,6 +91,15 @@
         return caps;
     }
 
+    int getMostSignificantSetBitMask(int n) {
+        if (n == 0) return 0;
+        int pos = std::numeric_limits<int>::digits - 1;
+        while ((n & (1 << pos)) == 0) {
+            pos--;
+        }
+        return 1 << pos;
+    }
+
     std::shared_ptr<IWifiRttController> wifi_rtt_controller_;
     int interface_version_;
 
@@ -161,6 +174,66 @@
 }
 
 /*
+ * Request80211azNtbSecureRangeMeasurement
+ * Tests the two sided 11az non-trigger based secure ranging - 802.11az NTB FTM protocol.
+ */
+TEST_P(WifiRttControllerAidlTest, Request80211azNtbSecureRangeMeasurement) {
+    if (interface_version_ < 3) {
+        GTEST_SKIP() << "Request80211azNtbRangeMeasurement is available as of RttController V3";
+    }
+
+    RttCapabilities caps = getCapabilities();
+    if (!caps.ntbInitiatorSupported) {
+        GTEST_SKIP() << "Skipping 11az NTB RTT since driver/fw does not support";
+    }
+    if (!caps.secureHeLtfSupported && !caps.rangingFrameProtectionSupported) {
+        GTEST_SKIP() << "Skipping 11az NTB secure RTT since driver/fw does not support";
+    }
+    if (!(caps.akmsSupported & Akm::PASN)) {
+        GTEST_SKIP() << "Skipping 11az NTB secure RTT since driver/fw does not support PASN";
+    }
+    if (!caps.cipherSuitesSupported) {
+        GTEST_SKIP()
+                << "Skipping 11az NTB secure RTT since driver/fw does not support Cipher Suites";
+    }
+
+    RttConfig config;
+    config.addr = {{0x00, 0x01, 0x02, 0x03, 0x04, 0x05}};
+    config.type = RttType::TWO_SIDED_11AZ_NTB_SECURE;
+    config.peer = RttPeerType::AP;
+    config.channel.width = WifiChannelWidthInMhz::WIDTH_80;
+    config.channel.centerFreq = 5180;
+    config.channel.centerFreq0 = 5210;
+    config.channel.centerFreq1 = 0;
+    config.bw = RttBw::BW_20MHZ;
+    config.preamble = RttPreamble::HT;
+    config.mustRequestLci = false;
+    config.mustRequestLcr = false;
+    config.numFramesPerBurst = 8;
+    config.numRetriesPerRttFrame = 0;
+    config.numRetriesPerFtmr = 0;
+    // 11az non-trigger based minimum measurement time in units of 100 microseconds.
+    config.ntbMinMeasurementTime = 2500;
+    // 11az non-trigger based maximum measurement time in units of 10 milliseconds.
+    config.ntbMaxMeasurementTime = 1500;
+    RttSecureConfig secureConfig;
+    // PASN is a must to test secure config; which does not need any password.
+    secureConfig.pasnConfig.baseAkm = Akm::PASN;
+    // Get the best Cipher suite supported by the chip.
+    secureConfig.pasnConfig.cipherSuite = getMostSignificantSetBitMask(caps.cipherSuitesSupported);
+    secureConfig.enableSecureHeLtf = caps.secureHeLtfSupported;
+    secureConfig.enableRangingFrameProtection = caps.rangingFrameProtectionSupported;
+    config.secureConfig = secureConfig;
+
+    int cmdId = 55;
+    std::vector<RttConfig> configs = {config};
+    EXPECT_TRUE(wifi_rtt_controller_->rangeRequest(cmdId, configs).isOk());
+
+    // Sleep for 2 seconds to wait for driver/firmware to complete RTT.
+    sleep(2);
+}
+
+/*
  * Request80211azNtbRangeMeasurement
  * Tests the two sided 11az non-trigger based ranging - 802.11az NTB FTM protocol.
  */
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..f997c43 100644
--- a/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp
+++ b/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp
@@ -36,6 +36,7 @@
 using aidl::android::hardware::wifi::Ssid;
 using aidl::android::hardware::wifi::StaApfPacketFilterCapabilities;
 using aidl::android::hardware::wifi::StaBackgroundScanCapabilities;
+using aidl::android::hardware::wifi::StaBackgroundScanParameters;
 using aidl::android::hardware::wifi::StaLinkLayerStats;
 using aidl::android::hardware::wifi::StaRoamingCapabilities;
 using aidl::android::hardware::wifi::StaRoamingConfig;
@@ -47,6 +48,12 @@
 using aidl::android::hardware::wifi::WifiDebugTxPacketFateReport;
 using aidl::android::hardware::wifi::WifiStatusCode;
 
+namespace {
+const int kTestCmdId = 123;
+const std::array<uint8_t, 6> kTestMacAddr1 = {0x1a, 0x2b, 0x3c, 0x4d, 0x5e, 0x6f};
+const std::array<uint8_t, 6> kTestMacAddr2 = {0x4a, 0x5b, 0x6c, 0x7d, 0x8e, 0x9f};
+}  // namespace
+
 class WifiStaIfaceAidlTest : public testing::TestWithParam<std::string> {
   public:
     void SetUp() override {
@@ -65,6 +72,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 +392,9 @@
     }
 }
 
+/**
+ * TwtGetCapabilities
+ */
 TEST_P(WifiStaIfaceAidlTest, TwtGetCapabilities) {
     if (interface_version_ < 2) {
         GTEST_SKIP() << "TwtGetCapabilities is available as of sta_iface V2";
@@ -400,6 +416,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 +443,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 +459,123 @@
     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());
+}
+
+/*
+ * GetName
+ */
+TEST_P(WifiStaIfaceAidlTest, GetName) {
+    std::string ifaceName;
+    EXPECT_TRUE(wifi_sta_iface_->getName(&ifaceName).isOk());
+}
+
+/*
+ * SetDtimMultiplier
+ */
+TEST_P(WifiStaIfaceAidlTest, SetDtimMultiplier) {
+    // Multiplied value
+    EXPECT_TRUE(wifi_sta_iface_->setDtimMultiplier(2).isOk());
+    // Driver default value
+    EXPECT_TRUE(wifi_sta_iface_->setDtimMultiplier(0).isOk());
+}
+
+/*
+ * Start/Stop Background Scan
+ */
+TEST_P(WifiStaIfaceAidlTest, StartAndStopBackgroundScan) {
+    if (!isFeatureSupported(IWifiStaIface::FeatureSetMask::BACKGROUND_SCAN)) {
+        GTEST_SKIP() << "Background scan is not supported";
+    }
+    StaBackgroundScanParameters scanParams;
+    EXPECT_TRUE(wifi_sta_iface_->startBackgroundScan(kTestCmdId, scanParams).isOk());
+    EXPECT_TRUE(wifi_sta_iface_->stopBackgroundScan(kTestCmdId).isOk());
+}
+
+/*
+ * Start/Stop Sending Keep-Alive Packets
+ */
+TEST_P(WifiStaIfaceAidlTest, StartAndStopSendingKeepAlivePackets) {
+    std::vector<uint8_t> ipPacketData(20);
+    uint16_t etherType = 0x0800;  // IPv4
+    uint32_t periodInMs = 1000;   // 1 sec
+
+    // Expected to fail with test values
+    EXPECT_FALSE(wifi_sta_iface_
+                         ->startSendingKeepAlivePackets(kTestCmdId, ipPacketData, etherType,
+                                                        kTestMacAddr1, kTestMacAddr2, periodInMs)
+                         .isOk());
+    EXPECT_FALSE(wifi_sta_iface_->stopSendingKeepAlivePackets(kTestCmdId).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/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
index 384ac9a..b0141df 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
@@ -84,8 +84,8 @@
   oneway void onPmkSaCacheAdded(in android.hardware.wifi.supplicant.PmkSaCacheData pmkSaData);
   oneway void onUsdPublishStarted(in int cmdId, in int publishId);
   oneway void onUsdSubscribeStarted(in int cmdId, in int subscribeId);
-  oneway void onUsdPublishConfigFailed(in int cmdId);
-  oneway void onUsdSubscribeConfigFailed(in int cmdId);
+  oneway void onUsdPublishConfigFailed(in int cmdId, in android.hardware.wifi.supplicant.ISupplicantStaIfaceCallback.UsdConfigErrorCode errorCode);
+  oneway void onUsdSubscribeConfigFailed(in int cmdId, in android.hardware.wifi.supplicant.ISupplicantStaIfaceCallback.UsdConfigErrorCode errorCode);
   oneway void onUsdPublishTerminated(in int publishId, in android.hardware.wifi.supplicant.UsdTerminateReasonCode reasonCode);
   oneway void onUsdSubscribeTerminated(in int subscribeId, in android.hardware.wifi.supplicant.UsdTerminateReasonCode reasonCode);
   oneway void onUsdPublishReplied(in android.hardware.wifi.supplicant.UsdServiceDiscoveryInfo info);
@@ -97,4 +97,10 @@
     MULTI_LINK_RECONFIG_AP_REMOVAL = 1,
     MULTI_LINK_DYNAMIC_RECONFIG = 2,
   }
+  @Backing(type="int") @VintfStability
+  enum UsdConfigErrorCode {
+    FAILURE_UNKNOWN = 0,
+    FAILURE_TIMEOUT = 1,
+    FAILURE_NOT_AVAILABLE = 2,
+  }
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
index 1ee873a..efbd066 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
@@ -439,12 +439,32 @@
     void onUsdSubscribeStarted(in int cmdId, in int subscribeId);
 
     /**
+     * Error codes returned by |onUsdPublishConfigFailed| and |onUsdSubscribeConfigFailed|.
+     */
+    @VintfStability
+    @Backing(type="int")
+    enum UsdConfigErrorCode {
+        /**
+         * Unknown failure.
+         */
+        FAILURE_UNKNOWN = 0,
+        /**
+         * The requested operation timed out.
+         */
+        FAILURE_TIMEOUT = 1,
+        /**
+         * The requested operation is currently not available.
+         */
+        FAILURE_NOT_AVAILABLE = 2,
+    }
+
+    /**
      * Called in response to |ISupplicantStaIface.startUsdPublish| to indicate that the
      * publish session could not be configured.
      *
      * @param cmdId Identifier for the original request.
      */
-    void onUsdPublishConfigFailed(in int cmdId);
+    void onUsdPublishConfigFailed(in int cmdId, in UsdConfigErrorCode errorCode);
 
     /**
      * Called in response to |ISupplicantStaIface.startUsdSubscribe| to indicate that the
@@ -452,7 +472,7 @@
      *
      * @param cmdId Identifier for the original request.
      */
-    void onUsdSubscribeConfigFailed(in int cmdId);
+    void onUsdSubscribeConfigFailed(in int cmdId, in UsdConfigErrorCode errorCode);
 
     /**
      * Called in response to |ISupplicantStaIface.cancelUsdPublish| to indicate that the session
diff --git a/wifi/supplicant/aidl/vts/functional/Android.bp b/wifi/supplicant/aidl/vts/functional/Android.bp
index f94eb46..95ff6cd 100644
--- a/wifi/supplicant/aidl/vts/functional/Android.bp
+++ b/wifi/supplicant/aidl/vts/functional/Android.bp
@@ -137,3 +137,41 @@
         "vts",
     ],
 }
+
+cc_test {
+    name: "VtsHalWifiSupplicantP2pNetworkTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["supplicant_p2p_network_aidl_test.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libbinder_ndk",
+        "libvndksupport",
+    ],
+    static_libs: [
+        "android.hardware.wifi@1.0",
+        "android.hardware.wifi@1.1",
+        "android.hardware.wifi@1.2",
+        "android.hardware.wifi@1.3",
+        "android.hardware.wifi@1.4",
+        "android.hardware.wifi@1.5",
+        "android.hardware.wifi.common-V2-ndk",
+        "android.hardware.wifi.supplicant@1.0",
+        "android.hardware.wifi.supplicant@1.1",
+        "android.hardware.wifi.supplicant-V4-ndk",
+        "libwifi-system",
+        "libwifi-system-iface",
+        "VtsHalWifiV1_0TargetTestUtil",
+        "VtsHalWifiV1_5TargetTestUtil",
+        "VtsHalWifiSupplicantV1_0TargetTestUtil",
+        "android.hardware.wifi.common-V2-ndk",
+        "android.hardware.wifi-V3-ndk",
+        "VtsHalWifiTargetTestUtil",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp b/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp
index 3638ac5..778e20a 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp
@@ -38,6 +38,7 @@
 using aidl::android::hardware::wifi::supplicant::IfaceType;
 using aidl::android::hardware::wifi::supplicant::ISupplicant;
 using aidl::android::hardware::wifi::supplicant::ISupplicantP2pIface;
+using aidl::android::hardware::wifi::supplicant::ISupplicantP2pNetwork;
 using aidl::android::hardware::wifi::supplicant::MiracastMode;
 using aidl::android::hardware::wifi::supplicant::P2pAddGroupConfigurationParams;
 using aidl::android::hardware::wifi::supplicant::P2pConnectInfo;
@@ -398,8 +399,8 @@
  * SetWpsModelNumber
  */
 TEST_P(SupplicantP2pIfaceAidlTest, SetWpsModelNumber) {
-    const std::string modelNumber = "TestModelNumber";
-    EXPECT_TRUE(p2p_iface_->setWpsModelName(modelNumber).isOk());
+    const std::string modelNumber = "Model1234";
+    EXPECT_TRUE(p2p_iface_->setWpsModelNumber(modelNumber).isOk());
 }
 
 /*
@@ -981,6 +982,96 @@
     EXPECT_TRUE(p2p_iface_->reinvokePersistentGroup(params).isOk());
 }
 
+/*
+ * Test the P2P network management functions.
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, ManageNetworks) {
+    std::shared_ptr<ISupplicantP2pNetwork> network;
+    EXPECT_TRUE(p2p_iface_->addNetwork(&network).isOk());
+    ASSERT_NE(network, nullptr);
+
+    std::vector<int32_t> networkList;
+    EXPECT_TRUE(p2p_iface_->listNetworks(&networkList).isOk());
+    ASSERT_FALSE(networkList.empty());
+
+    int networkId = networkList[0];
+    EXPECT_TRUE(p2p_iface_->getNetwork(networkId, &network).isOk());
+    ASSERT_NE(network, nullptr);
+    EXPECT_TRUE(p2p_iface_->removeNetwork(networkId).isOk());
+}
+
+/*
+ * Request and cancel service discovery
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, RequestAndCancelServiceDiscovery) {
+    int64_t discoveryId;
+    std::vector<uint8_t> query = {0x11, 0x22, 0x33};
+    EXPECT_TRUE(p2p_iface_->requestServiceDiscovery(kTestMacAddr, query, &discoveryId).isOk());
+    EXPECT_TRUE(p2p_iface_->cancelServiceDiscovery(discoveryId).isOk());
+}
+
+/*
+ * Start and stop WPS
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, StartAndStopWps) {
+    // Expected to fail with test values
+    std::string generatedPin;
+    EXPECT_FALSE(p2p_iface_->startWpsPbc(kTestGroupIfName, kTestMacAddr).isOk());
+    EXPECT_FALSE(
+            p2p_iface_->startWpsPinDisplay(kTestGroupIfName, kTestMacAddr, &generatedPin).isOk());
+    EXPECT_FALSE(p2p_iface_->startWpsPinKeypad(kTestGroupIfName, kTestConnectPin).isOk());
+    EXPECT_FALSE(p2p_iface_->cancelWps(kTestGroupIfName).isOk());
+}
+
+/*
+ * Create message and report handover for NFC Request
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, CreateAndReportNfcRequest) {
+    std::vector<uint8_t> requestMsg;
+    EXPECT_TRUE(p2p_iface_->createNfcHandoverRequestMessage(&requestMsg).isOk());
+    EXPECT_FALSE(requestMsg.empty());
+    EXPECT_TRUE(p2p_iface_->reportNfcHandoverResponse(requestMsg).isOk());
+}
+
+/*
+ * Create message and report handover for NFC Select
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, CreateAndReportNfcSelect) {
+    std::vector<uint8_t> selectMsg;
+    EXPECT_TRUE(p2p_iface_->createNfcHandoverSelectMessage(&selectMsg).isOk());
+    EXPECT_FALSE(selectMsg.empty());
+    EXPECT_TRUE(p2p_iface_->reportNfcHandoverInitiation(selectMsg).isOk());
+}
+
+/*
+ * RemoveClient
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, RemoveClient) {
+    // Method returns success for any valid MAC address
+    EXPECT_TRUE(p2p_iface_->removeClient(kTestMacAddr, false).isOk());
+    // Returns failure for any invalid MAC address
+    std::vector<uint8_t> invalidMacAddr = {0x11, 0x22};
+    EXPECT_FALSE(p2p_iface_->removeClient(invalidMacAddr, false).isOk());
+}
+
+/*
+ * ConfigureEapolIpAddressAllocationParams
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, ConfigureEapolIpAddressAllocationParams) {
+    if (interface_version_ < 2) {
+        GTEST_SKIP() << "ConfigureEapolIpAddressAllocationParams is available as of Supplicant V2";
+    }
+    // The IP addresses are IPV4 addresses and higher-order address bytes are in the
+    // lower-order int bytes (e.g. 192.168.1.1 is represented as 0x0101A8C0)
+    EXPECT_TRUE(p2p_iface_
+                        ->configureEapolIpAddressAllocationParams(0x0101A8C0, 0x00FFFFFF,
+                                                                  0x0501A8C0, 0x0801A8C0)
+                        .isOk());
+
+    // Clear the configuration.
+    EXPECT_TRUE(p2p_iface_->configureEapolIpAddressAllocationParams(0, 0, 0, 0).isOk());
+}
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SupplicantP2pIfaceAidlTest);
 INSTANTIATE_TEST_SUITE_P(Supplicant, SupplicantP2pIfaceAidlTest,
                          testing::ValuesIn(android::getAidlHalInstanceNames(
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_p2p_network_aidl_test.cpp b/wifi/supplicant/aidl/vts/functional/supplicant_p2p_network_aidl_test.cpp
new file mode 100644
index 0000000..c5a73f1
--- /dev/null
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_p2p_network_aidl_test.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsCoreUtil.h>
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/wifi/supplicant/BnSupplicant.h>
+#include <android/binder_manager.h>
+#include <android/binder_status.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <cutils/properties.h>
+
+#include "supplicant_test_utils.h"
+#include "wifi_aidl_test_utils.h"
+
+using aidl::android::hardware::wifi::supplicant::DebugLevel;
+using aidl::android::hardware::wifi::supplicant::IfaceType;
+using aidl::android::hardware::wifi::supplicant::ISupplicantP2pNetwork;
+using aidl::android::hardware::wifi::supplicant::MacAddress;
+using android::ProcessState;
+
+class SupplicantP2pNetworkAidlTest : public testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override {
+        initializeService();
+        supplicant_ = getSupplicant(GetParam().c_str());
+        ASSERT_NE(supplicant_, nullptr);
+        ASSERT_TRUE(supplicant_->setDebugParams(DebugLevel::EXCESSIVE, true, true).isOk());
+
+        bool p2pEnabled = testing::deviceSupportsFeature("android.hardware.wifi.direct");
+        if (!p2pEnabled) {
+            GTEST_SKIP() << "Wi-Fi Direct is not supported, skip this test.";
+        }
+
+        EXPECT_TRUE(supplicant_->getP2pInterface(getP2pIfaceName(), &p2p_iface_).isOk());
+        ASSERT_NE(p2p_iface_, nullptr);
+        EXPECT_TRUE(p2p_iface_->addNetwork(&p2p_network_).isOk());
+        ASSERT_NE(p2p_network_, nullptr);
+    }
+
+    void TearDown() override {
+        stopSupplicantService();
+        startWifiFramework();
+    }
+
+  protected:
+    std::shared_ptr<ISupplicant> supplicant_;
+    std::shared_ptr<ISupplicantP2pIface> p2p_iface_;
+    std::shared_ptr<ISupplicantP2pNetwork> p2p_network_;
+};
+
+/*
+ * GetBssid
+ */
+TEST_P(SupplicantP2pNetworkAidlTest, GetBssid) {
+    std::vector<uint8_t> bssid;
+    EXPECT_TRUE(p2p_network_->getBssid(&bssid).isOk());
+}
+
+/*
+ * GetClientList
+ */
+TEST_P(SupplicantP2pNetworkAidlTest, GetClientList) {
+    // Expect failure if there are no clients
+    std::vector<MacAddress> clientList;
+    EXPECT_FALSE(p2p_network_->getClientList(&clientList).isOk());
+}
+
+/*
+ * GetId
+ */
+TEST_P(SupplicantP2pNetworkAidlTest, GetId) {
+    int networkId;
+    EXPECT_TRUE(p2p_network_->getId(&networkId).isOk());
+}
+
+/*
+ * GetInterfaceName
+ */
+TEST_P(SupplicantP2pNetworkAidlTest, GetInterfaceName) {
+    std::string expectedName = getP2pIfaceName();
+    std::string retrievedName;
+    EXPECT_TRUE(p2p_network_->getInterfaceName(&retrievedName).isOk());
+    EXPECT_EQ(retrievedName, expectedName);
+}
+
+/*
+ * GetSsid
+ */
+TEST_P(SupplicantP2pNetworkAidlTest, GetSsid) {
+    std::vector<uint8_t> ssid;
+    EXPECT_TRUE(p2p_network_->getSsid(&ssid).isOk());
+}
+
+/*
+ * GetType
+ */
+TEST_P(SupplicantP2pNetworkAidlTest, GetType) {
+    IfaceType ifaceType;
+    EXPECT_TRUE(p2p_network_->getType(&ifaceType).isOk());
+    EXPECT_EQ(ifaceType, IfaceType::P2P);
+}
+
+/*
+ * IsCurrent
+ */
+TEST_P(SupplicantP2pNetworkAidlTest, IsCurrent) {
+    bool isCurrent;
+    EXPECT_TRUE(p2p_network_->isCurrent(&isCurrent).isOk());
+    EXPECT_FALSE(isCurrent);
+}
+
+/*
+ * IsGroupOwner
+ */
+TEST_P(SupplicantP2pNetworkAidlTest, IsGroupOwner) {
+    bool isGroupOwner;
+    EXPECT_TRUE(p2p_network_->isGroupOwner(&isGroupOwner).isOk());
+    EXPECT_FALSE(isGroupOwner);
+}
+
+/*
+ * IsPersistent
+ */
+TEST_P(SupplicantP2pNetworkAidlTest, IsPersistent) {
+    bool isPersistent;
+    EXPECT_TRUE(p2p_network_->isPersistent(&isPersistent).isOk());
+    EXPECT_FALSE(isPersistent);
+}
+
+/*
+ * SetClientList
+ */
+TEST_P(SupplicantP2pNetworkAidlTest, SetClientList) {
+    MacAddress client = {{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc}};
+    std::vector clientList = {client};
+    EXPECT_TRUE(p2p_network_->setClientList(clientList).isOk());
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SupplicantP2pNetworkAidlTest);
+INSTANTIATE_TEST_SUITE_P(
+        Supplicant, SupplicantP2pNetworkAidlTest,
+        testing::ValuesIn(android::getAidlHalInstanceNames(ISupplicant::descriptor)),
+        android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ProcessState::self()->setThreadPoolMaxThreadCount(1);
+    ProcessState::self()->startThreadPool();
+    return RUN_ALL_TESTS();
+}
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 da12a82..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,12 +43,19 @@
 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;
+using aidl::android::hardware::wifi::supplicant::UsdPublishConfig;
 using aidl::android::hardware::wifi::supplicant::UsdServiceDiscoveryInfo;
+using aidl::android::hardware::wifi::supplicant::UsdSubscribeConfig;
 using aidl::android::hardware::wifi::supplicant::UsdTerminateReasonCode;
 using aidl::android::hardware::wifi::supplicant::WpaDriverCapabilitiesMask;
 using aidl::android::hardware::wifi::supplicant::WpsConfigMethods;
@@ -254,10 +261,12 @@
                                                int32_t /* subscribeId */) override {
         return ndk::ScopedAStatus::ok();
     }
-    ::ndk::ScopedAStatus onUsdPublishConfigFailed(int32_t /* cmdId */) override {
+    ::ndk::ScopedAStatus onUsdPublishConfigFailed(int32_t /* cmdId */,
+                                                  UsdConfigErrorCode /* errorCode */) override {
         return ndk::ScopedAStatus::ok();
     }
-    ::ndk::ScopedAStatus onUsdSubscribeConfigFailed(int32_t /* cmdId */) override {
+    ::ndk::ScopedAStatus onUsdSubscribeConfigFailed(int32_t /* cmdId */,
+                                                    UsdConfigErrorCode /* errorCode */) override {
         return ndk::ScopedAStatus::ok();
     }
     ::ndk::ScopedAStatus onUsdPublishTerminated(int32_t /* publishId */,
@@ -878,6 +887,183 @@
     EXPECT_EQ(1, responseList.size());
 }
 
+/*
+ * Verify that all USD methods check the Service Specific Info (SSI) length
+ * and fail if the provided SSI is too long.
+ */
+TEST_P(SupplicantStaIfaceAidlTest, InvalidUsdServiceSpecificInfo) {
+    if (interface_version_ < 4) {
+        GTEST_SKIP() << "USD is available as of Supplicant V4";
+    }
+
+    UsdCapabilities caps;
+    EXPECT_TRUE(sta_iface_->getUsdCapabilities(&caps).isOk());
+    if (!caps.isUsdPublisherSupported && !caps.isUsdSubscriberSupported) {
+        GTEST_SKIP() << "USD publish and subscribe are not supported";
+    }
+
+    int commandId = 123;
+    std::vector<uint8_t> invalidSsi(caps.maxLocalSsiLengthBytes + 1);
+    UsdBaseConfig invalidBaseConfig;
+    invalidBaseConfig.serviceSpecificInfo = invalidSsi;
+
+    if (caps.isUsdPublisherSupported) {
+        UsdPublishConfig publishConfig;
+        publishConfig.usdBaseConfig = invalidBaseConfig;
+        EXPECT_FALSE(sta_iface_->startUsdPublish(commandId, publishConfig).isOk());
+        EXPECT_FALSE(sta_iface_->updateUsdPublish(commandId, invalidSsi).isOk());
+    }
+
+    if (caps.isUsdSubscriberSupported) {
+        UsdSubscribeConfig subscribeConfig;
+        subscribeConfig.usdBaseConfig = invalidBaseConfig;
+        EXPECT_FALSE(sta_iface_->startUsdSubscribe(commandId, subscribeConfig).isOk());
+    }
+
+    UsdMessageInfo messageInfo;
+    messageInfo.message = invalidSsi;
+    EXPECT_FALSE(sta_iface_->sendUsdMessage(messageInfo).isOk());
+}
+
+/*
+ * Cancel a USD Publish and Subscribe session.
+ */
+TEST_P(SupplicantStaIfaceAidlTest, CancelUsdSession) {
+    if (interface_version_ < 4) {
+        GTEST_SKIP() << "USD is available as of Supplicant V4";
+    }
+
+    UsdCapabilities caps;
+    EXPECT_TRUE(sta_iface_->getUsdCapabilities(&caps).isOk());
+    if (!caps.isUsdPublisherSupported && !caps.isUsdSubscriberSupported) {
+        GTEST_SKIP() << "USD publish and subscribe are not supported";
+    }
+
+    int sessionId = 123;
+    if (caps.isUsdPublisherSupported) {
+        // Method is expected to succeed, even if the session does not exist.
+        EXPECT_TRUE(sta_iface_->cancelUsdPublish(sessionId).isOk());
+    }
+    if (caps.isUsdSubscriberSupported) {
+        EXPECT_TRUE(sta_iface_->cancelUsdSubscribe(sessionId).isOk());
+    }
+}
+
+/*
+ * GenerateSelfDppConfiguration
+ */
+TEST_P(SupplicantStaIfaceAidlTest, GenerateSelfDppConfiguration) {
+    if (!keyMgmtSupported(sta_iface_, KeyMgmtMask::DPP)) {
+        GTEST_SKIP() << "Missing DPP support";
+    }
+    const std::string ssid = "my_test_ssid";
+    const std::vector<uint8_t> eckey_in = {0x2, 0x3, 0x4};
+
+    // Expect to fail as this test requires a DPP AKM supported AP and a valid private EC
+    // key generated by wpa_supplicant.
+    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(
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp b/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
index 9bdd2f5..2f0053a 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
@@ -32,6 +32,7 @@
 using aidl::android::hardware::wifi::supplicant::AuthAlgMask;
 using aidl::android::hardware::wifi::supplicant::BnSupplicantStaNetworkCallback;
 using aidl::android::hardware::wifi::supplicant::DebugLevel;
+using aidl::android::hardware::wifi::supplicant::DppConnectionKeys;
 using aidl::android::hardware::wifi::supplicant::EapMethod;
 using aidl::android::hardware::wifi::supplicant::EapPhase2Method;
 using aidl::android::hardware::wifi::supplicant::GroupCipherMask;
@@ -837,6 +838,21 @@
 }
 
 /*
+ * SetDppKeys
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetDppKeys) {
+    if (!keyMgmtSupported(sta_iface_, KeyMgmtMask::DPP)) {
+        GTEST_SKIP() << "Missing DPP support";
+    }
+
+    DppConnectionKeys in_keys;
+    in_keys.connector = std::vector<uint8_t>({0x11, 0x22, 0x33, 0x44});
+    in_keys.cSign = std::vector<uint8_t>({0x55, 0x66, 0x77, 0x88});
+    in_keys.netAccessKey = std::vector<uint8_t>({0xaa, 0xbb, 0xcc, 0xdd});
+    EXPECT_TRUE(sta_network_->setDppKeys(in_keys).isOk());
+}
+
+/*
  * SetVendorData
  */
 TEST_P(SupplicantStaNetworkAidlTest, SetVendorData) {
@@ -846,6 +862,20 @@
     EXPECT_TRUE(sta_network_->setVendorData(kTestVendorData).isOk());
 }
 
+/*
+ * Set/Get EDMG
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetEdmg) {
+    bool retrievedValue = false;
+    EXPECT_TRUE(sta_network_->setEdmg(true).isOk());
+    EXPECT_TRUE(sta_network_->getEdmg(&retrievedValue).isOk());
+    EXPECT_EQ(retrievedValue, true);
+
+    EXPECT_TRUE(sta_network_->setEdmg(false).isOk());
+    EXPECT_TRUE(sta_network_->getEdmg(&retrievedValue).isOk());
+    EXPECT_EQ(retrievedValue, false);
+}
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SupplicantStaNetworkAidlTest);
 INSTANTIATE_TEST_SUITE_P(Supplicant, SupplicantStaNetworkAidlTest,
                          testing::ValuesIn(android::getAidlHalInstanceNames(