Merge "libradiocompat: Expose AIDL indications" into main
diff --git a/audio/aidl/TEST_MAPPING b/audio/aidl/TEST_MAPPING
index 81c99f7..2b6207e 100644
--- a/audio/aidl/TEST_MAPPING
+++ b/audio/aidl/TEST_MAPPING
@@ -51,5 +51,10 @@
     {
       "name": "VtsHalNSTargetTest"
     }
+  ],
+  "postsubmit": [
+    {
+      "name": "VtsHalSpatializerTargetTest"
+    }
   ]
 }
diff --git a/audio/aidl/android/hardware/audio/core/IModule.aidl b/audio/aidl/android/hardware/audio/core/IModule.aidl
index 2d4d283..3c5f7f6 100644
--- a/audio/aidl/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/android/hardware/audio/core/IModule.aidl
@@ -928,7 +928,10 @@
      * using 'connectExternalDevice' method. 'disconnectExternalDevice' method will be called
      * soon after this method with the same 'portId'.
      *
-     * @param portId The ID of the audio port that is about to disconnect
+     * Note: This method is called after the external device is disconnected. The system does
+     * not try to predict the disconnection event.
+     *
+     * @param portId The ID of the audio port corresponding to the disconnected device
      * @throws EX_ILLEGAL_ARGUMENT In the following cases:
      *                             - If the port can not be found by the ID.
      *                             - If this is not a connected device port.
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 7cd0545..7e06c2c 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -204,6 +204,7 @@
     vendor: true,
     shared_libs: [
         "libaudioaidlcommon",
+        "libaudioutils",
         "libbase",
         "libbinder_ndk",
         "libcutils",
diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp
index 2a8e58f..baaa55f 100644
--- a/audio/aidl/default/Configuration.cpp
+++ b/audio/aidl/default/Configuration.cpp
@@ -32,6 +32,7 @@
 using aidl::android::media::audio::common::AudioFormatDescription;
 using aidl::android::media::audio::common::AudioFormatType;
 using aidl::android::media::audio::common::AudioGainConfig;
+using aidl::android::media::audio::common::AudioInputFlags;
 using aidl::android::media::audio::common::AudioIoFlags;
 using aidl::android::media::audio::common::AudioOutputFlags;
 using aidl::android::media::audio::common::AudioPort;
@@ -321,20 +322,25 @@
 //
 // Mix ports:
 //  * "r_submix output", maximum 10 opened streams, maximum 10 active streams
-//    - profile PCM 16-bit; STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+//    - profile PCM 16-bit; STEREO; 8000, 11025, 16000, 32000, 44100, 48000, 192000
 //  * "r_submix input", maximum 10 opened streams, maximum 10 active streams
-//    - profile PCM 16-bit; STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+//    - profile PCM 16-bit; STEREO; 8000, 11025, 16000, 32000, 44100, 48000, 192000
+//  * "r_submix output direct", DIRECT|IEC958_NONAUDIO, 1 max open, 1 max active
+//    - profile PCM 16-bit; STEREO; 8000, 11025, 16000, 32000, 44100, 48000, 192000
+//  * "r_submix input direct", DIRECT, 1 max open, 1 max active
+//    - profile PCM 16-bit; STEREO; 8000, 11025, 16000, 32000, 44100, 48000, 192000
+
 //
 // Routes:
-//  "r_submix output" -> "Remote Submix Out"
-//  "Remote Submix In" -> "r_submix input"
+//  "r_submix output", "r_submix output direct" -> "Remote Submix Out"
+//  "Remote Submix In" -> "r_submix input", "r_submix input direct"
 //
 std::unique_ptr<Configuration> getRSubmixConfiguration() {
     static const Configuration configuration = []() {
         Configuration c;
         const std::vector<AudioProfile> remoteSubmixPcmAudioProfiles{
                 createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO},
-                              {8000, 11025, 16000, 32000, 44100, 48000})};
+                              {8000, 11025, 16000, 32000, 44100, 48000, 192000})};
 
         // Device ports
 
@@ -359,13 +365,41 @@
         rsubmixOutMix.profiles = remoteSubmixPcmAudioProfiles;
         c.ports.push_back(rsubmixOutMix);
 
+        // Adding a DIRECT flag to rsubmixInMix breaks the mixer paths, so we need separate
+        // non direct and direct paths. It is added because for IEC61937 encapsulated over PCM, we
+        // need the DIRECT and IEC958_NONAUDIO flags as AudioFlinger adds them.
+        AudioPort rsubmixOutDirectMix =
+                createPort(c.nextPortId++, "r_submix output direct",
+                                makeBitPositionFlagMask({
+                                        AudioOutputFlags::DIRECT,
+                                        AudioOutputFlags::IEC958_NONAUDIO}),
+                                false /* isInput */,
+                                createPortMixExt(1 /* maxOpenStreamCount */,
+                                                 1 /* maxActiveStreamCount */));
+        rsubmixOutDirectMix.profiles = remoteSubmixPcmAudioProfiles;
+        c.ports.push_back(rsubmixOutDirectMix);
+
         AudioPort rsubmixInMix =
                 createPort(c.nextPortId++, "r_submix input", 0, true, createPortMixExt(10, 10));
         rsubmixInMix.profiles = remoteSubmixPcmAudioProfiles;
         c.ports.push_back(rsubmixInMix);
 
-        c.routes.push_back(createRoute({rsubmixOutMix}, rsubmixOutDevice));
+        // Adding a DIRECT flag to rsubmixInMix breaks the capture paths, so we need separate
+        // non direct and direct paths. It is added because for IEC61937 encapsulated over PCM, we
+        // need the DIRECT flag for the capability so AudioFlinger can find a DIRECT input match.
+        AudioPort rsubmixInDirectMix =
+                createPort(c.nextPortId++, "r_submix input direct",
+                                makeBitPositionFlagMask({AudioInputFlags::DIRECT}),
+                                true /* isInput */,
+                                createPortMixExt(1 /* maxOpenStreamCount */,
+                                                 1 /* maxActiveStreamCount */));
+        rsubmixInDirectMix.profiles = remoteSubmixPcmAudioProfiles;
+        c.ports.push_back(rsubmixInDirectMix);
+
+        c.routes.push_back(createRoute(
+                {rsubmixOutMix, rsubmixOutDirectMix}, rsubmixOutDevice));
         c.routes.push_back(createRoute({rsubmixInDevice}, rsubmixInMix));
+        c.routes.push_back(createRoute({rsubmixInDevice}, rsubmixInDirectMix));
 
         return c;
     }();
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index d0e8745..94aa4dc 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -93,32 +93,6 @@
     return std::all_of(profiles.begin(), profiles.end(), isDynamicProfile);
 }
 
-// Note: does not assign an ID to the config.
-bool generateDefaultPortConfig(const AudioPort& port, AudioPortConfig* config) {
-    const bool allowDynamicConfig = port.ext.getTag() == AudioPortExt::device;
-    *config = {};
-    config->portId = port.id;
-    for (const auto& profile : port.profiles) {
-        if (isDynamicProfile(profile)) continue;
-        config->format = profile.format;
-        config->channelMask = *profile.channelMasks.begin();
-        config->sampleRate = Int{.value = *profile.sampleRates.begin()};
-        config->flags = port.flags;
-        config->ext = port.ext;
-        return true;
-    }
-    if (allowDynamicConfig) {
-        config->format = AudioFormatDescription{};
-        config->channelMask = AudioChannelLayout{};
-        config->sampleRate = Int{.value = 0};
-        config->flags = port.flags;
-        config->ext = port.ext;
-        return true;
-    }
-    LOG(ERROR) << __func__ << ": port " << port.id << " only has dynamic profiles";
-    return false;
-}
-
 bool findAudioProfile(const AudioPort& port, const AudioFormatDescription& format,
                       AudioProfile* profile) {
     if (auto profilesIt =
@@ -204,10 +178,11 @@
     }
     auto& configs = getConfig().portConfigs;
     auto portConfigIt = findById<AudioPortConfig>(configs, in_portConfigId);
+    const int32_t nominalLatencyMs = getNominalLatencyMs(*portConfigIt);
     // Since this is a private method, it is assumed that
     // validity of the portConfigId has already been checked.
-    const int32_t minimumStreamBufferSizeFrames = calculateBufferSizeFrames(
-            getNominalLatencyMs(*portConfigIt), portConfigIt->sampleRate.value().value);
+    const int32_t minimumStreamBufferSizeFrames =
+            calculateBufferSizeFrames(nominalLatencyMs, portConfigIt->sampleRate.value().value);
     if (in_bufferSizeFrames < minimumStreamBufferSizeFrames) {
         LOG(ERROR) << __func__ << ": insufficient buffer size " << in_bufferSizeFrames
                    << ", must be at least " << minimumStreamBufferSizeFrames;
@@ -246,7 +221,7 @@
                 std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
                 std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
                 portConfigIt->format.value(), portConfigIt->channelMask.value(),
-                portConfigIt->sampleRate.value().value, flags, getNominalLatencyMs(*portConfigIt),
+                portConfigIt->sampleRate.value().value, flags, nominalLatencyMs,
                 portConfigIt->ext.get<AudioPortExt::mix>().handle,
                 std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
                 asyncCallback, outEventCallback, mSoundDose.getInstance(), params);
@@ -332,6 +307,29 @@
     return ndk::ScopedAStatus::ok();
 }
 
+bool Module::generateDefaultPortConfig(const AudioPort& port, AudioPortConfig* config) {
+    const bool allowDynamicConfig = port.ext.getTag() == AudioPortExt::device;
+    for (const auto& profile : port.profiles) {
+        if (isDynamicProfile(profile)) continue;
+        config->format = profile.format;
+        config->channelMask = *profile.channelMasks.begin();
+        config->sampleRate = Int{.value = *profile.sampleRates.begin()};
+        config->flags = port.flags;
+        config->ext = port.ext;
+        return true;
+    }
+    if (allowDynamicConfig) {
+        config->format = AudioFormatDescription{};
+        config->channelMask = AudioChannelLayout{};
+        config->sampleRate = Int{.value = 0};
+        config->flags = port.flags;
+        config->ext = port.ext;
+        return true;
+    }
+    LOG(ERROR) << __func__ << ": port " << port.id << " only has dynamic profiles";
+    return false;
+}
+
 void Module::populateConnectedProfiles() {
     Configuration& config = getConfig();
     for (const AudioPort& port : config.ports) {
@@ -621,10 +619,11 @@
 
     std::vector<AudioRoute*> routesToMixPorts = getAudioRoutesForAudioPortImpl(templateId);
     std::set<int32_t> routableMixPortIds = getRoutableAudioPortIds(templateId, &routesToMixPorts);
+    const int32_t nextPortId = getConfig().nextPortId++;
     if (!mDebug.simulateDeviceConnections) {
         // Even if the device port has static profiles, the HAL module might need to update
         // them, or abort the connection process.
-        RETURN_STATUS_IF_ERROR(populateConnectedDevicePort(&connectedPort));
+        RETURN_STATUS_IF_ERROR(populateConnectedDevicePort(&connectedPort, nextPortId));
     } else if (hasDynamicProfilesOnly(connectedPort.profiles)) {
         auto& connectedProfiles = getConfig().connectedProfiles;
         if (auto connectedProfilesIt = connectedProfiles.find(templateId);
@@ -648,7 +647,7 @@
         }
     }
 
-    connectedPort.id = getConfig().nextPortId++;
+    connectedPort.id = nextPortId;
     auto [connectedPortsIt, _] =
             mConnectedDevicePorts.insert(std::pair(connectedPort.id, std::set<int32_t>()));
     LOG(DEBUG) << __func__ << ": template port " << templateId << " external device connected, "
@@ -1039,6 +1038,18 @@
 
 ndk::ScopedAStatus Module::setAudioPortConfig(const AudioPortConfig& in_requested,
                                               AudioPortConfig* out_suggested, bool* _aidl_return) {
+    auto generate = [this](const AudioPort& port, AudioPortConfig* config) {
+        return generateDefaultPortConfig(port, config);
+    };
+    return setAudioPortConfigImpl(in_requested, generate, out_suggested, _aidl_return);
+}
+
+ndk::ScopedAStatus Module::setAudioPortConfigImpl(
+        const AudioPortConfig& in_requested,
+        const std::function<bool(const ::aidl::android::media::audio::common::AudioPort& port,
+                                 ::aidl::android::media::audio::common::AudioPortConfig* config)>&
+                fillPortConfig,
+        AudioPortConfig* out_suggested, bool* applied) {
     LOG(DEBUG) << __func__ << ": requested " << in_requested.toString();
     auto& configs = getConfig().portConfigs;
     auto existing = configs.end();
@@ -1067,7 +1078,8 @@
         *out_suggested = *existing;
     } else {
         AudioPortConfig newConfig;
-        if (generateDefaultPortConfig(*portIt, &newConfig)) {
+        newConfig.portId = portIt->id;
+        if (fillPortConfig(*portIt, &newConfig)) {
             *out_suggested = newConfig;
         } else {
             LOG(ERROR) << __func__ << ": unable generate a default config for port " << portId;
@@ -1172,17 +1184,17 @@
     if (existing == configs.end() && requestedIsValid && requestedIsFullySpecified) {
         out_suggested->id = getConfig().nextPortId++;
         configs.push_back(*out_suggested);
-        *_aidl_return = true;
+        *applied = true;
         LOG(DEBUG) << __func__ << ": created new port config " << out_suggested->toString();
     } else if (existing != configs.end() && requestedIsValid) {
         *existing = *out_suggested;
-        *_aidl_return = true;
+        *applied = true;
         LOG(DEBUG) << __func__ << ": updated port config " << out_suggested->toString();
     } else {
         LOG(DEBUG) << __func__ << ": not applied; existing config ? " << (existing != configs.end())
                    << "; requested is valid? " << requestedIsValid << ", fully specified? "
                    << requestedIsFullySpecified;
-        *_aidl_return = false;
+        *applied = false;
     }
     return ndk::ScopedAStatus::ok();
 }
@@ -1534,7 +1546,7 @@
     return mIsMmapSupported.value();
 }
 
-ndk::ScopedAStatus Module::populateConnectedDevicePort(AudioPort* audioPort) {
+ndk::ScopedAStatus Module::populateConnectedDevicePort(AudioPort* audioPort, int32_t) {
     if (audioPort->ext.getTag() != AudioPortExt::device) {
         LOG(ERROR) << __func__ << ": not a device port: " << audioPort->toString();
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
diff --git a/audio/aidl/default/acousticEchoCanceler/Android.bp b/audio/aidl/default/acousticEchoCanceler/Android.bp
index bfb7212..35d4a56 100644
--- a/audio/aidl/default/acousticEchoCanceler/Android.bp
+++ b/audio/aidl/default/acousticEchoCanceler/Android.bp
@@ -27,8 +27,6 @@
     name: "libaecsw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "AcousticEchoCancelerSw.cpp",
diff --git a/audio/aidl/default/alsa/ModuleAlsa.cpp b/audio/aidl/default/alsa/ModuleAlsa.cpp
index 8512631..9a2cce7 100644
--- a/audio/aidl/default/alsa/ModuleAlsa.cpp
+++ b/audio/aidl/default/alsa/ModuleAlsa.cpp
@@ -34,7 +34,7 @@
 
 namespace aidl::android::hardware::audio::core {
 
-ndk::ScopedAStatus ModuleAlsa::populateConnectedDevicePort(AudioPort* audioPort) {
+ndk::ScopedAStatus ModuleAlsa::populateConnectedDevicePort(AudioPort* audioPort, int32_t) {
     auto deviceProfile = alsa::getDeviceProfile(*audioPort);
     if (!deviceProfile.has_value()) {
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
diff --git a/audio/aidl/default/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml
index 6f0af21..827ff80 100644
--- a/audio/aidl/default/audio_effects_config.xml
+++ b/audio/aidl/default/audio_effects_config.xml
@@ -47,6 +47,7 @@
         <library name="visualizer" path="libvisualizeraidl.so"/>
         <library name="volumesw" path="libvolumesw.so"/>
         <library name="extensioneffect" path="libextensioneffect.so"/>
+        <library name="spatializersw" path="libspatializersw.so"/>
     </libraries>
 
     <!-- list of effects to load.
@@ -98,6 +99,7 @@
         <effect name="extension_effect" library="extensioneffect" uuid="fa81dd00-588b-11ed-9b6a-0242ac120002" type="fa81de0e-588b-11ed-9b6a-0242ac120002"/>
         <effect name="acoustic_echo_canceler" library="pre_processing" uuid="bb392ec0-8d4d-11e0-a896-0002a5d5c51b"/>
         <effect name="noise_suppression" library="pre_processing" uuid="c06c8400-8e06-11e0-9cb6-0002a5d5c51b"/>
+        <effect name="spatializer" library="spatializersw" uuid="fa81a880-588b-11ed-9b6a-0242ac120002"/>
     </effects>
 
     <preprocess>
diff --git a/audio/aidl/default/automaticGainControlV1/Android.bp b/audio/aidl/default/automaticGainControlV1/Android.bp
index 4ae8e63..05c2c54 100644
--- a/audio/aidl/default/automaticGainControlV1/Android.bp
+++ b/audio/aidl/default/automaticGainControlV1/Android.bp
@@ -27,8 +27,6 @@
     name: "libagc1sw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "AutomaticGainControlV1Sw.cpp",
diff --git a/audio/aidl/default/automaticGainControlV2/Android.bp b/audio/aidl/default/automaticGainControlV2/Android.bp
index 631cf58..dedc555 100644
--- a/audio/aidl/default/automaticGainControlV2/Android.bp
+++ b/audio/aidl/default/automaticGainControlV2/Android.bp
@@ -27,8 +27,6 @@
     name: "libagc2sw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "AutomaticGainControlV2Sw.cpp",
diff --git a/audio/aidl/default/bassboost/Android.bp b/audio/aidl/default/bassboost/Android.bp
index 82b2f20..9f47770 100644
--- a/audio/aidl/default/bassboost/Android.bp
+++ b/audio/aidl/default/bassboost/Android.bp
@@ -27,8 +27,6 @@
     name: "libbassboostsw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "BassBoostSw.cpp",
diff --git a/audio/aidl/default/bluetooth/DevicePortProxy.cpp b/audio/aidl/default/bluetooth/DevicePortProxy.cpp
index 1be0875..d772c20 100644
--- a/audio/aidl/default/bluetooth/DevicePortProxy.cpp
+++ b/audio/aidl/default/bluetooth/DevicePortProxy.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AHAL_BluetoothPortProxy"
+#define LOG_TAG "AHAL_BluetoothAudioPort"
 
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
@@ -254,12 +254,7 @@
     return (mCookie != ::aidl::android::hardware::bluetooth::audio::kObserversCookieUndefined);
 }
 
-bool BluetoothAudioPortAidl::getPreferredDataIntervalUs(size_t* interval_us) const {
-    if (!interval_us) {
-        LOG(ERROR) << __func__ << ": bad input arg";
-        return false;
-    }
-
+bool BluetoothAudioPortAidl::getPreferredDataIntervalUs(size_t& interval_us) const {
     if (!inUse()) {
         LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
         return false;
@@ -272,16 +267,11 @@
         return false;
     }
 
-    *interval_us = hal_audio_cfg.get<AudioConfiguration::pcmConfig>().dataIntervalUs;
+    interval_us = hal_audio_cfg.get<AudioConfiguration::pcmConfig>().dataIntervalUs;
     return true;
 }
 
-bool BluetoothAudioPortAidl::loadAudioConfig(PcmConfiguration* audio_cfg) const {
-    if (!audio_cfg) {
-        LOG(ERROR) << __func__ << ": bad input arg";
-        return false;
-    }
-
+bool BluetoothAudioPortAidl::loadAudioConfig(PcmConfiguration& audio_cfg) {
     if (!inUse()) {
         LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
         return false;
@@ -293,15 +283,26 @@
         LOG(ERROR) << __func__ << ": unsupported audio cfg tag";
         return false;
     }
-    *audio_cfg = hal_audio_cfg.get<AudioConfiguration::pcmConfig>();
+    audio_cfg = hal_audio_cfg.get<AudioConfiguration::pcmConfig>();
     LOG(VERBOSE) << __func__ << debugMessage() << ", state*=" << getState() << ", PcmConfig=["
-                 << audio_cfg->toString() << "]";
-    if (audio_cfg->channelMode == ChannelMode::UNKNOWN) {
+                 << audio_cfg.toString() << "]";
+    if (audio_cfg.channelMode == ChannelMode::UNKNOWN) {
         return false;
     }
     return true;
 }
 
+bool BluetoothAudioPortAidlOut::loadAudioConfig(PcmConfiguration& audio_cfg) {
+    if (!BluetoothAudioPortAidl::loadAudioConfig(audio_cfg)) return false;
+    // WAR to support Mono / 16 bits per sample as the Bluetooth stack requires
+    if (audio_cfg.channelMode == ChannelMode::MONO && audio_cfg.bitsPerSample == 16) {
+        mIsStereoToMono = true;
+        audio_cfg.channelMode = ChannelMode::STEREO;
+        LOG(INFO) << __func__ << ": force channels = to be AUDIO_CHANNEL_OUT_STEREO";
+    }
+    return true;
+}
+
 bool BluetoothAudioPortAidl::standby() {
     if (!inUse()) {
         LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
@@ -435,7 +436,7 @@
                 retval = condWaitState(BluetoothStreamState::SUSPENDING);
             } else {
                 LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState()
-                           << " Hal fails";
+                           << " failure to suspend stream";
             }
         }
     }
diff --git a/audio/aidl/default/bluetooth/ModuleBluetooth.cpp b/audio/aidl/default/bluetooth/ModuleBluetooth.cpp
index 8a1cbbf..9084b30 100644
--- a/audio/aidl/default/bluetooth/ModuleBluetooth.cpp
+++ b/audio/aidl/default/bluetooth/ModuleBluetooth.cpp
@@ -24,13 +24,25 @@
 
 using aidl::android::hardware::audio::common::SinkMetadata;
 using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::hardware::bluetooth::audio::ChannelMode;
+using aidl::android::hardware::bluetooth::audio::PcmConfiguration;
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioConfigBase;
 using aidl::android::media::audio::common::AudioDeviceDescription;
 using aidl::android::media::audio::common::AudioDeviceType;
+using aidl::android::media::audio::common::AudioFormatDescription;
+using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::AudioIoFlags;
 using aidl::android::media::audio::common::AudioOffloadInfo;
 using aidl::android::media::audio::common::AudioPort;
+using aidl::android::media::audio::common::AudioPortConfig;
 using aidl::android::media::audio::common::AudioPortExt;
+using aidl::android::media::audio::common::AudioProfile;
+using aidl::android::media::audio::common::Int;
 using aidl::android::media::audio::common::MicrophoneInfo;
+using aidl::android::media::audio::common::PcmType;
 using android::bluetooth::audio::aidl::BluetoothAudioPortAidl;
+using android::bluetooth::audio::aidl::BluetoothAudioPortAidlIn;
 using android::bluetooth::audio::aidl::BluetoothAudioPortAidlOut;
 
 // TODO(b/312265159) bluetooth audio should be in its own process
@@ -39,6 +51,35 @@
 
 namespace aidl::android::hardware::audio::core {
 
+namespace {
+
+PcmType pcmTypeFromBitsPerSample(int8_t bitsPerSample) {
+    if (bitsPerSample == 8)
+        return PcmType::UINT_8_BIT;
+    else if (bitsPerSample == 16)
+        return PcmType::INT_16_BIT;
+    else if (bitsPerSample == 24)
+        return PcmType::INT_24_BIT;
+    else if (bitsPerSample == 32)
+        return PcmType::INT_32_BIT;
+    ALOGE("Unsupported bitsPerSample: %d", bitsPerSample);
+    return PcmType::DEFAULT;
+}
+
+AudioChannelLayout channelLayoutFromChannelMode(ChannelMode mode) {
+    if (mode == ChannelMode::MONO) {
+        return AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+                AudioChannelLayout::LAYOUT_MONO);
+    } else if (mode == ChannelMode::STEREO || mode == ChannelMode::DUALMONO) {
+        return AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+                AudioChannelLayout::LAYOUT_STEREO);
+    }
+    ALOGE("Unsupported channel mode: %s", toString(mode).c_str());
+    return AudioChannelLayout{};
+}
+
+}  // namespace
+
 ModuleBluetooth::ModuleBluetooth(std::unique_ptr<Module::Configuration>&& config)
     : Module(Type::BLUETOOTH, std::move(config)) {
     // TODO(b/312265159) bluetooth audio should be in its own process
@@ -95,66 +136,130 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
+ndk::ScopedAStatus ModuleBluetooth::setAudioPortConfig(const AudioPortConfig& in_requested,
+                                                       AudioPortConfig* out_suggested,
+                                                       bool* _aidl_return) {
+    auto fillConfig = [this](const AudioPort& port, AudioPortConfig* config) {
+        if (port.ext.getTag() == AudioPortExt::device) {
+            CachedProxy proxy;
+            auto status = findOrCreateProxy(port, proxy);
+            if (status.isOk()) {
+                const auto& pcmConfig = proxy.pcmConfig;
+                LOG(DEBUG) << "setAudioPortConfig: suggesting port config from "
+                           << pcmConfig.toString();
+                const auto pcmType = pcmTypeFromBitsPerSample(pcmConfig.bitsPerSample);
+                const auto channelMask = channelLayoutFromChannelMode(pcmConfig.channelMode);
+                if (pcmType != PcmType::DEFAULT && channelMask != AudioChannelLayout{}) {
+                    config->format =
+                            AudioFormatDescription{.type = AudioFormatType::PCM, .pcm = pcmType};
+                    config->channelMask = channelMask;
+                    config->sampleRate = Int{.value = pcmConfig.sampleRateHz};
+                    config->flags = port.flags;
+                    config->ext = port.ext;
+                    return true;
+                }
+            }
+        }
+        return generateDefaultPortConfig(port, config);
+    };
+    return Module::setAudioPortConfigImpl(in_requested, fillConfig, out_suggested, _aidl_return);
+}
+
+ndk::ScopedAStatus ModuleBluetooth::checkAudioPatchEndpointsMatch(
+        const std::vector<AudioPortConfig*>& sources, const std::vector<AudioPortConfig*>& sinks) {
+    // Both sources and sinks must be non-empty, this is guaranteed by 'setAudioPatch'.
+    const bool isInput = sources[0]->ext.getTag() == AudioPortExt::device;
+    const int32_t devicePortId = isInput ? sources[0]->portId : sinks[0]->portId;
+    const auto proxyIt = mProxies.find(devicePortId);
+    if (proxyIt == mProxies.end()) return ndk::ScopedAStatus::ok();
+    const auto& pcmConfig = proxyIt->second.pcmConfig;
+    const AudioPortConfig* mixPortConfig = isInput ? sinks[0] : sources[0];
+    if (!StreamBluetooth::checkConfigParams(
+                pcmConfig, AudioConfigBase{.sampleRate = mixPortConfig->sampleRate->value,
+                                           .channelMask = *(mixPortConfig->channelMask),
+                                           .format = *(mixPortConfig->format)})) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+    if (int32_t handle = mixPortConfig->ext.get<AudioPortExt::mix>().handle; handle > 0) {
+        mConnections.insert(std::pair(handle, devicePortId));
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+void ModuleBluetooth::onExternalDeviceConnectionChanged(const AudioPort& audioPort,
+                                                        bool connected) {
+    if (!connected) mProxies.erase(audioPort.id);
+}
+
 ndk::ScopedAStatus ModuleBluetooth::createInputStream(
         StreamContext&& context, const SinkMetadata& sinkMetadata,
         const std::vector<MicrophoneInfo>& microphones, std::shared_ptr<StreamIn>* result) {
+    CachedProxy proxy;
+    RETURN_STATUS_IF_ERROR(fetchAndCheckProxy(context, proxy));
     return createStreamInstance<StreamInBluetooth>(result, std::move(context), sinkMetadata,
-                                                   microphones, getBtProfileManagerHandles());
+                                                   microphones, getBtProfileManagerHandles(),
+                                                   proxy.ptr, proxy.pcmConfig);
 }
 
 ndk::ScopedAStatus ModuleBluetooth::createOutputStream(
         StreamContext&& context, const SourceMetadata& sourceMetadata,
         const std::optional<AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) {
+    CachedProxy proxy;
+    RETURN_STATUS_IF_ERROR(fetchAndCheckProxy(context, proxy));
     return createStreamInstance<StreamOutBluetooth>(result, std::move(context), sourceMetadata,
-                                                    offloadInfo, getBtProfileManagerHandles());
+                                                    offloadInfo, getBtProfileManagerHandles(),
+                                                    proxy.ptr, proxy.pcmConfig);
 }
 
-ndk::ScopedAStatus ModuleBluetooth::populateConnectedDevicePort(AudioPort* audioPort) {
+ndk::ScopedAStatus ModuleBluetooth::populateConnectedDevicePort(AudioPort* audioPort,
+                                                                int32_t nextPortId) {
     if (audioPort->ext.getTag() != AudioPortExt::device) {
         LOG(ERROR) << __func__ << ": not a device port: " << audioPort->toString();
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
+    if (!::aidl::android::hardware::bluetooth::audio::BluetoothAudioSession::IsAidlAvailable()) {
+        LOG(ERROR) << __func__ << ": IBluetoothAudioProviderFactory AIDL service not available";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
     const auto& devicePort = audioPort->ext.get<AudioPortExt::device>();
     const auto& description = devicePort.device.type;
-    // Since the configuration of the BT module is static, there is nothing to populate here.
-    // However, this method must return an error when the device can not be connected,
-    // this is determined by the status of BT profiles.
+    // This method must return an error when the device can not be connected.
     if (description.connection == AudioDeviceDescription::CONNECTION_BT_A2DP) {
         bool isA2dpEnabled = false;
         if (!!mBluetoothA2dp) {
             RETURN_STATUS_IF_ERROR((*mBluetoothA2dp).isEnabled(&isA2dpEnabled));
         }
         LOG(DEBUG) << __func__ << ": isA2dpEnabled: " << isA2dpEnabled;
-        return isA2dpEnabled ? ndk::ScopedAStatus::ok()
-                             : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+        if (!isA2dpEnabled) return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     } else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE) {
         bool isLeEnabled = false;
         if (!!mBluetoothLe) {
             RETURN_STATUS_IF_ERROR((*mBluetoothLe).isEnabled(&isLeEnabled));
         }
         LOG(DEBUG) << __func__ << ": isLeEnabled: " << isLeEnabled;
-        return isLeEnabled ? ndk::ScopedAStatus::ok()
-                           : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+        if (!isLeEnabled) return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     } else if (description.connection == AudioDeviceDescription::CONNECTION_WIRELESS &&
                description.type == AudioDeviceType::OUT_HEARING_AID) {
-        // Hearing aids can use a number of profiles, thus the only way to check
-        // connectivity is to try to talk to the BT HAL.
-        if (!::aidl::android::hardware::bluetooth::audio::BluetoothAudioSession::
-                    IsAidlAvailable()) {
-            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-        }
-        std::shared_ptr<BluetoothAudioPortAidl> proxy = std::shared_ptr<BluetoothAudioPortAidl>(
-                std::make_shared<BluetoothAudioPortAidlOut>());
-        if (proxy->registerPort(description)) {
-            LOG(DEBUG) << __func__ << ": registered hearing aid port";
-            proxy->unregisterPort();
-            return ndk::ScopedAStatus::ok();
-        }
-        LOG(DEBUG) << __func__ << ": failed to register hearing aid port";
-        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+        // Hearing aids can use a number of profiles, no single switch exists.
+    } else {
+        LOG(ERROR) << __func__ << ": unsupported device type: " << audioPort->toString();
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
-    LOG(ERROR) << __func__ << ": unsupported device type: " << audioPort->toString();
-    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    CachedProxy proxy;
+    RETURN_STATUS_IF_ERROR(createProxy(*audioPort, nextPortId, proxy));
+    // Since the device is already connected and configured by the BT stack, provide
+    // the current configuration instead of all possible profiles.
+    const auto& pcmConfig = proxy.pcmConfig;
+    audioPort->profiles.clear();
+    audioPort->profiles.push_back(
+            AudioProfile{.format = AudioFormatDescription{.type = AudioFormatType::PCM,
+                                                          .pcm = pcmTypeFromBitsPerSample(
+                                                                  pcmConfig.bitsPerSample)},
+                         .channelMasks = std::vector<AudioChannelLayout>(
+                                 {channelLayoutFromChannelMode(pcmConfig.channelMode)}),
+                         .sampleRates = std::vector<int>({pcmConfig.sampleRateHz})});
+    LOG(DEBUG) << __func__ << ": " << audioPort->toString();
+    return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus ModuleBluetooth::onMasterMuteChanged(bool) {
@@ -167,4 +272,77 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
+int32_t ModuleBluetooth::getNominalLatencyMs(const AudioPortConfig& portConfig) {
+    const auto connectionsIt = mConnections.find(portConfig.ext.get<AudioPortExt::mix>().handle);
+    if (connectionsIt != mConnections.end()) {
+        const auto proxyIt = mProxies.find(connectionsIt->second);
+        if (proxyIt != mProxies.end()) {
+            auto proxy = proxyIt->second.ptr;
+            size_t dataIntervalUs = 0;
+            if (!proxy->getPreferredDataIntervalUs(dataIntervalUs)) {
+                LOG(WARNING) << __func__ << ": could not fetch preferred data interval";
+            }
+            const bool isInput = portConfig.flags->getTag() == AudioIoFlags::input;
+            return isInput ? StreamInBluetooth::getNominalLatencyMs(dataIntervalUs)
+                           : StreamOutBluetooth::getNominalLatencyMs(dataIntervalUs);
+        }
+    }
+    LOG(ERROR) << __func__ << ": no connection or proxy found for " << portConfig.toString();
+    return Module::getNominalLatencyMs(portConfig);
+}
+
+ndk::ScopedAStatus ModuleBluetooth::createProxy(const AudioPort& audioPort, int32_t instancePortId,
+                                                CachedProxy& proxy) {
+    const bool isInput = audioPort.flags.getTag() == AudioIoFlags::input;
+    proxy.ptr = isInput ? std::shared_ptr<BluetoothAudioPortAidl>(
+                                  std::make_shared<BluetoothAudioPortAidlIn>())
+                        : std::shared_ptr<BluetoothAudioPortAidl>(
+                                  std::make_shared<BluetoothAudioPortAidlOut>());
+    const auto& devicePort = audioPort.ext.get<AudioPortExt::device>();
+    if (const auto device = devicePort.device.type; !proxy.ptr->registerPort(device)) {
+        LOG(ERROR) << __func__ << ": failed to register BT port for " << device.toString();
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if (!proxy.ptr->loadAudioConfig(proxy.pcmConfig)) {
+        LOG(ERROR) << __func__ << ": state=" << proxy.ptr->getState()
+                   << ", failed to load audio config";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    mProxies.insert(std::pair(instancePortId, proxy));
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleBluetooth::fetchAndCheckProxy(const StreamContext& context,
+                                                       CachedProxy& proxy) {
+    const auto connectionsIt = mConnections.find(context.getMixPortHandle());
+    if (connectionsIt != mConnections.end()) {
+        const auto proxyIt = mProxies.find(connectionsIt->second);
+        if (proxyIt != mProxies.end()) {
+            proxy = proxyIt->second;
+            mProxies.erase(proxyIt);
+        }
+        mConnections.erase(connectionsIt);
+    }
+    if (proxy.ptr != nullptr) {
+        if (!StreamBluetooth::checkConfigParams(
+                    proxy.pcmConfig, AudioConfigBase{.sampleRate = context.getSampleRate(),
+                                                     .channelMask = context.getChannelLayout(),
+                                                     .format = context.getFormat()})) {
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+        }
+    }
+    // Not having a proxy is OK, it may happen in VTS tests when streams are opened on unconnected
+    // mix ports.
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleBluetooth::findOrCreateProxy(const AudioPort& audioPort,
+                                                      CachedProxy& proxy) {
+    if (auto proxyIt = mProxies.find(audioPort.id); proxyIt != mProxies.end()) {
+        proxy = proxyIt->second;
+        return ndk::ScopedAStatus::ok();
+    }
+    return createProxy(audioPort, audioPort.id, proxy);
+}
+
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/bluetooth/StreamBluetooth.cpp b/audio/aidl/default/bluetooth/StreamBluetooth.cpp
index 0cee7f4..a73af1b 100644
--- a/audio/aidl/default/bluetooth/StreamBluetooth.cpp
+++ b/audio/aidl/default/bluetooth/StreamBluetooth.cpp
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AHAL_StreamBluetooth"
+#include <algorithm>
 
+#define LOG_TAG "AHAL_StreamBluetooth"
 #include <Utils.h>
 #include <android-base/logging.h>
 #include <audio_utils/clock.h>
@@ -31,6 +32,7 @@
 using aidl::android::hardware::bluetooth::audio::PcmConfiguration;
 using aidl::android::hardware::bluetooth::audio::PresentationPosition;
 using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioConfigBase;
 using aidl::android::media::audio::common::AudioDevice;
 using aidl::android::media::audio::common::AudioDeviceAddress;
 using aidl::android::media::audio::common::AudioFormatDescription;
@@ -48,51 +50,33 @@
 constexpr int kBluetoothDefaultInputBufferMs = 20;
 constexpr int kBluetoothDefaultOutputBufferMs = 10;
 // constexpr int kBluetoothSpatializerOutputBufferMs = 10;
+constexpr int kBluetoothDefaultRemoteDelayMs = 200;
 
-// pcm configuration params are not really used by the module
 StreamBluetooth::StreamBluetooth(StreamContext* context, const Metadata& metadata,
-                                 ModuleBluetooth::BtProfileHandles&& btHandles)
+                                 ModuleBluetooth::BtProfileHandles&& btHandles,
+                                 const std::shared_ptr<BluetoothAudioPortAidl>& btDeviceProxy,
+                                 const PcmConfiguration& pcmConfig)
     : StreamCommonImpl(context, metadata),
-      mSampleRate(getContext().getSampleRate()),
-      mChannelLayout(getContext().getChannelLayout()),
-      mFormat(getContext().getFormat()),
       mFrameSizeBytes(getContext().getFrameSize()),
       mIsInput(isInput(metadata)),
       mBluetoothA2dp(std::move(std::get<ModuleBluetooth::BtInterface::BTA2DP>(btHandles))),
-      mBluetoothLe(std::move(std::get<ModuleBluetooth::BtInterface::BTLE>(btHandles))) {
-    mPreferredDataIntervalUs =
-            (mIsInput ? kBluetoothDefaultInputBufferMs : kBluetoothDefaultOutputBufferMs) * 1000;
-    mPreferredFrameCount = frameCountFromDurationUs(mPreferredDataIntervalUs, mSampleRate);
-    mIsInitialized = false;
-    mIsReadyToClose = false;
-}
+      mBluetoothLe(std::move(std::get<ModuleBluetooth::BtInterface::BTLE>(btHandles))),
+      mPreferredDataIntervalUs(pcmConfig.dataIntervalUs != 0
+                                       ? pcmConfig.dataIntervalUs
+                                       : (mIsInput ? kBluetoothDefaultInputBufferMs
+                                                   : kBluetoothDefaultOutputBufferMs) *
+                                                 1000),
+      mPreferredFrameCount(
+              frameCountFromDurationUs(mPreferredDataIntervalUs, pcmConfig.sampleRateHz)),
+      mBtDeviceProxy(btDeviceProxy) {}
 
 ::android::status_t StreamBluetooth::init() {
-    return ::android::OK;  // defering this till we get AudioDeviceDescription
-}
-
-const StreamCommonInterface::ConnectedDevices& StreamBluetooth::getConnectedDevices() const {
     std::lock_guard guard(mLock);
-    return StreamCommonImpl::getConnectedDevices();
-}
-
-ndk::ScopedAStatus StreamBluetooth::setConnectedDevices(
-        const std::vector<AudioDevice>& connectedDevices) {
-    if (mIsInput && connectedDevices.size() > 1) {
-        LOG(ERROR) << __func__ << ": wrong device size(" << connectedDevices.size()
-                   << ") for input stream";
-        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    if (mBtDeviceProxy == nullptr) {
+        // This is a normal situation in VTS tests.
+        LOG(INFO) << __func__ << ": no BT HAL proxy, stream is non-functional";
     }
-    for (const auto& connectedDevice : connectedDevices) {
-        if (connectedDevice.address.getTag() != AudioDeviceAddress::mac) {
-            LOG(ERROR) << __func__ << ": bad device address" << connectedDevice.address.toString();
-            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
-        }
-    }
-    std::lock_guard guard(mLock);
-    RETURN_STATUS_IF_ERROR(StreamCommonImpl::setConnectedDevices(connectedDevices));
-    mIsInitialized = false;  // updated connected device list, need initialization
-    return ndk::ScopedAStatus::ok();
+    return ::android::OK;
 }
 
 ::android::status_t StreamBluetooth::drain(StreamDescriptor::DrainMode) {
@@ -112,167 +96,111 @@
 ::android::status_t StreamBluetooth::transfer(void* buffer, size_t frameCount,
                                               size_t* actualFrameCount, int32_t* latencyMs) {
     std::lock_guard guard(mLock);
-    if (!mIsInitialized || mIsReadyToClose) {
-        // 'setConnectedDevices' has been called or stream is ready to close, so no transfers
+    if (mBtDeviceProxy == nullptr || mBtDeviceProxy->getState() == BluetoothStreamState::DISABLED) {
         *actualFrameCount = 0;
         *latencyMs = StreamDescriptor::LATENCY_UNKNOWN;
         return ::android::OK;
     }
     *actualFrameCount = 0;
     *latencyMs = 0;
-    for (auto proxy : mBtDeviceProxies) {
-        if (!proxy->start()) {
-            LOG(ERROR) << __func__ << ": state = " << proxy->getState() << " failed to start ";
-            return -EIO;
-        }
-        const size_t fc = std::min(frameCount, mPreferredFrameCount);
-        const size_t bytesToTransfer = fc * mFrameSizeBytes;
-        if (mIsInput) {
-            const size_t totalRead = proxy->readData(buffer, bytesToTransfer);
-            *actualFrameCount = std::max(*actualFrameCount, totalRead / mFrameSizeBytes);
-        } else {
-            const size_t totalWrite = proxy->writeData(buffer, bytesToTransfer);
-            *actualFrameCount = std::max(*actualFrameCount, totalWrite / mFrameSizeBytes);
-        }
-        PresentationPosition presentation_position;
-        if (!proxy->getPresentationPosition(presentation_position)) {
-            LOG(ERROR) << __func__ << ": getPresentationPosition returned error ";
-            return ::android::UNKNOWN_ERROR;
-        }
-        *latencyMs =
-                std::max(*latencyMs, (int32_t)(presentation_position.remoteDeviceAudioDelayNanos /
-                                               NANOS_PER_MILLISECOND));
+    if (!mBtDeviceProxy->start()) {
+        LOG(ERROR) << __func__ << ": state= " << mBtDeviceProxy->getState() << " failed to start";
+        return -EIO;
     }
+    const size_t fc = std::min(frameCount, mPreferredFrameCount);
+    const size_t bytesToTransfer = fc * mFrameSizeBytes;
+    if (mIsInput) {
+        const size_t totalRead = mBtDeviceProxy->readData(buffer, bytesToTransfer);
+        *actualFrameCount = std::max(*actualFrameCount, totalRead / mFrameSizeBytes);
+    } else {
+        const size_t totalWrite = mBtDeviceProxy->writeData(buffer, bytesToTransfer);
+        *actualFrameCount = std::max(*actualFrameCount, totalWrite / mFrameSizeBytes);
+    }
+    PresentationPosition presentation_position;
+    if (!mBtDeviceProxy->getPresentationPosition(presentation_position)) {
+        presentation_position.remoteDeviceAudioDelayNanos =
+                kBluetoothDefaultRemoteDelayMs * NANOS_PER_MILLISECOND;
+        LOG(WARNING) << __func__ << ": getPresentationPosition failed, latency info is unavailable";
+    }
+    // TODO(b/317117580): incorporate logic from
+    //                    packages/modules/Bluetooth/system/audio_bluetooth_hw/stream_apis.cc
+    //                    out_calculate_feeding_delay_ms / in_calculate_starving_delay_ms
+    *latencyMs = std::max(*latencyMs, (int32_t)(presentation_position.remoteDeviceAudioDelayNanos /
+                                                NANOS_PER_MILLISECOND));
     return ::android::OK;
 }
 
-::android::status_t StreamBluetooth::initialize() {
-    if (!::aidl::android::hardware::bluetooth::audio::BluetoothAudioSession::IsAidlAvailable()) {
-        LOG(ERROR) << __func__ << ": IBluetoothAudioProviderFactory service not available";
-        return ::android::UNKNOWN_ERROR;
-    }
-    if (StreamCommonImpl::getConnectedDevices().empty()) {
-        LOG(ERROR) << __func__ << ", has no connected devices";
-        return ::android::NO_INIT;
-    }
-    // unregister older proxies (if any)
-    for (auto proxy : mBtDeviceProxies) {
-        proxy->stop();
-        proxy->unregisterPort();
-    }
-    mBtDeviceProxies.clear();
-    for (auto it = StreamCommonImpl::getConnectedDevices().begin();
-         it != StreamCommonImpl::getConnectedDevices().end(); ++it) {
-        std::shared_ptr<BluetoothAudioPortAidl> proxy =
-                mIsInput ? std::shared_ptr<BluetoothAudioPortAidl>(
-                                   std::make_shared<BluetoothAudioPortAidlIn>())
-                         : std::shared_ptr<BluetoothAudioPortAidl>(
-                                   std::make_shared<BluetoothAudioPortAidlOut>());
-        if (proxy->registerPort(it->type)) {
-            LOG(ERROR) << __func__ << ": cannot init HAL";
-            return ::android::UNKNOWN_ERROR;
-        }
-        PcmConfiguration config;
-        if (!proxy->loadAudioConfig(&config)) {
-            LOG(ERROR) << __func__ << ": state=" << proxy->getState()
-                       << " failed to get audio config";
-            return ::android::UNKNOWN_ERROR;
-        }
-        // TODO: Ensure minimum duration for spatialized output?
-        // WAR to support Mono / 16 bits per sample as the Bluetooth stack required
-        if (!mIsInput && config.channelMode == ChannelMode::MONO && config.bitsPerSample == 16) {
-            proxy->forcePcmStereoToMono(true);
-            config.channelMode = ChannelMode::STEREO;
-            LOG(INFO) << __func__ << ": force channels = to be AUDIO_CHANNEL_OUT_STEREO";
-        }
-        if (!checkConfigParams(config)) {
-            LOG(ERROR) << __func__ << " checkConfigParams failed";
-            return ::android::UNKNOWN_ERROR;
-        }
-        mBtDeviceProxies.push_back(std::move(proxy));
-    }
-    mIsInitialized = true;
-    return ::android::OK;
-}
-
-bool StreamBluetooth::checkConfigParams(
-        ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& config) {
-    if ((int)mSampleRate != config.sampleRateHz) {
-        LOG(ERROR) << __func__ << ": Sample Rate mismatch, stream val = " << mSampleRate
-                   << " hal val = " << config.sampleRateHz;
+// static
+bool StreamBluetooth::checkConfigParams(const PcmConfiguration& pcmConfig,
+                                        const AudioConfigBase& config) {
+    if ((int)config.sampleRate != pcmConfig.sampleRateHz) {
+        LOG(ERROR) << __func__ << ": sample rate mismatch, stream value=" << config.sampleRate
+                   << ", BT HAL value=" << pcmConfig.sampleRateHz;
         return false;
     }
-    auto channelCount = aidl::android::hardware::audio::common::getChannelCount(mChannelLayout);
-    if ((config.channelMode == ChannelMode::MONO && channelCount != 1) ||
-        (config.channelMode == ChannelMode::STEREO && channelCount != 2)) {
-        LOG(ERROR) << __func__ << ": Channel count mismatch, stream val = " << channelCount
-                   << " hal val = " << toString(config.channelMode);
+    const auto channelCount =
+            aidl::android::hardware::audio::common::getChannelCount(config.channelMask);
+    if ((pcmConfig.channelMode == ChannelMode::MONO && channelCount != 1) ||
+        (pcmConfig.channelMode == ChannelMode::STEREO && channelCount != 2)) {
+        LOG(ERROR) << __func__ << ": Channel count mismatch, stream value=" << channelCount
+                   << ", BT HAL value=" << toString(pcmConfig.channelMode);
         return false;
     }
-    if (mFormat.type != AudioFormatType::PCM) {
-        LOG(ERROR) << __func__ << ": unexpected format type "
-                   << aidl::android::media::audio::common::toString(mFormat.type);
+    if (config.format.type != AudioFormatType::PCM) {
+        LOG(ERROR) << __func__
+                   << ": unexpected stream format type: " << toString(config.format.type);
         return false;
     }
-    int8_t bps = aidl::android::hardware::audio::common::getPcmSampleSizeInBytes(mFormat.pcm) * 8;
-    if (bps != config.bitsPerSample) {
-        LOG(ERROR) << __func__ << ": bits per sample mismatch, stream val = " << bps
-                   << " hal val = " << config.bitsPerSample;
+    const int8_t bitsPerSample =
+            aidl::android::hardware::audio::common::getPcmSampleSizeInBytes(config.format.pcm) * 8;
+    if (bitsPerSample != pcmConfig.bitsPerSample) {
+        LOG(ERROR) << __func__ << ": bits per sample mismatch, stream value=" << bitsPerSample
+                   << ", BT HAL value=" << pcmConfig.bitsPerSample;
         return false;
     }
-    if (config.dataIntervalUs > 0) {
-        mPreferredDataIntervalUs =
-                std::min((int32_t)mPreferredDataIntervalUs, config.dataIntervalUs);
-        mPreferredFrameCount = frameCountFromDurationUs(mPreferredDataIntervalUs, mSampleRate);
-    }
     return true;
 }
 
 ndk::ScopedAStatus StreamBluetooth::prepareToClose() {
     std::lock_guard guard(mLock);
-    mIsReadyToClose = true;
+    if (mBtDeviceProxy != nullptr) {
+        if (mBtDeviceProxy->getState() != BluetoothStreamState::DISABLED) {
+            mBtDeviceProxy->stop();
+        }
+    }
     return ndk::ScopedAStatus::ok();
 }
 
 ::android::status_t StreamBluetooth::standby() {
     std::lock_guard guard(mLock);
-    if (!mIsInitialized) {
-        if (auto status = initialize(); status != ::android::OK) return status;
-    }
-    for (auto proxy : mBtDeviceProxies) {
-        if (!proxy->suspend()) {
-            LOG(ERROR) << __func__ << ": state = " << proxy->getState() << " failed to stand by ";
-            return -EIO;
-        }
-    }
+    if (mBtDeviceProxy != nullptr) mBtDeviceProxy->suspend();
     return ::android::OK;
 }
 
 ::android::status_t StreamBluetooth::start() {
     std::lock_guard guard(mLock);
-    if (!mIsInitialized) return initialize();
+    if (mBtDeviceProxy != nullptr) mBtDeviceProxy->start();
     return ::android::OK;
 }
 
 void StreamBluetooth::shutdown() {
     std::lock_guard guard(mLock);
-    for (auto proxy : mBtDeviceProxies) {
-        proxy->stop();
-        proxy->unregisterPort();
+    if (mBtDeviceProxy != nullptr) {
+        mBtDeviceProxy->stop();
+        mBtDeviceProxy = nullptr;
     }
-    mBtDeviceProxies.clear();
 }
 
 ndk::ScopedAStatus StreamBluetooth::updateMetadataCommon(const Metadata& metadata) {
     std::lock_guard guard(mLock);
-    if (!mIsInitialized) return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    if (mBtDeviceProxy == nullptr) {
+        return ndk::ScopedAStatus::ok();
+    }
     bool isOk = true;
     if (isInput(metadata)) {
-        isOk = mBtDeviceProxies[0]->updateSinkMetadata(std::get<SinkMetadata>(metadata));
+        isOk = mBtDeviceProxy->updateSinkMetadata(std::get<SinkMetadata>(metadata));
     } else {
-        for (auto proxy : mBtDeviceProxies) {
-            if (!proxy->updateSourceMetadata(std::get<SourceMetadata>(metadata))) isOk = false;
-        }
+        isOk = mBtDeviceProxy->updateSourceMetadata(std::get<SourceMetadata>(metadata));
     }
     return isOk ? ndk::ScopedAStatus::ok()
                 : ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
@@ -280,7 +208,6 @@
 
 ndk::ScopedAStatus StreamBluetooth::bluetoothParametersUpdated() {
     if (mIsInput) {
-        LOG(WARNING) << __func__ << ": not handled";
         return ndk::ScopedAStatus::ok();
     }
     auto applyParam = [](const std::shared_ptr<BluetoothAudioPortAidl>& proxy,
@@ -297,15 +224,10 @@
     bool hasLeParam, enableLe;
     auto btLe = mBluetoothLe.lock();
     hasLeParam = btLe != nullptr && btLe->isEnabled(&enableLe).isOk();
-    std::unique_lock lock(mLock);
-    ::android::base::ScopedLockAssertion lock_assertion(mLock);
-    if (!mIsInitialized) {
-        LOG(WARNING) << __func__ << ": init not done";
-        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-    }
-    for (auto proxy : mBtDeviceProxies) {
-        if ((hasA2dpParam && proxy->isA2dp() && !applyParam(proxy, enableA2dp)) ||
-            (hasLeParam && proxy->isLeAudio() && !applyParam(proxy, enableLe))) {
+    std::lock_guard guard(mLock);
+    if (mBtDeviceProxy != nullptr) {
+        if ((hasA2dpParam && mBtDeviceProxy->isA2dp() && !applyParam(mBtDeviceProxy, enableA2dp)) ||
+            (hasLeParam && mBtDeviceProxy->isLeAudio() && !applyParam(mBtDeviceProxy, enableLe))) {
             LOG(DEBUG) << __func__ << ": applyParam failed";
             return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
         }
@@ -313,11 +235,20 @@
     return ndk::ScopedAStatus::ok();
 }
 
+// static
+int32_t StreamInBluetooth::getNominalLatencyMs(size_t dataIntervalUs) {
+    if (dataIntervalUs == 0) dataIntervalUs = kBluetoothDefaultInputBufferMs * 1000LL;
+    return dataIntervalUs / 1000LL;
+}
+
 StreamInBluetooth::StreamInBluetooth(StreamContext&& context, const SinkMetadata& sinkMetadata,
                                      const std::vector<MicrophoneInfo>& microphones,
-                                     ModuleBluetooth::BtProfileHandles&& btProfileHandles)
+                                     ModuleBluetooth::BtProfileHandles&& btProfileHandles,
+                                     const std::shared_ptr<BluetoothAudioPortAidl>& btDeviceProxy,
+                                     const PcmConfiguration& pcmConfig)
     : StreamIn(std::move(context), microphones),
-      StreamBluetooth(&mContextInstance, sinkMetadata, std::move(btProfileHandles)) {}
+      StreamBluetooth(&mContextInstance, sinkMetadata, std::move(btProfileHandles), btDeviceProxy,
+                      pcmConfig) {}
 
 ndk::ScopedAStatus StreamInBluetooth::getActiveMicrophones(
         std::vector<MicrophoneDynamicInfo>* _aidl_return __unused) {
@@ -325,11 +256,20 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
+// static
+int32_t StreamOutBluetooth::getNominalLatencyMs(size_t dataIntervalUs) {
+    if (dataIntervalUs == 0) dataIntervalUs = kBluetoothDefaultOutputBufferMs * 1000LL;
+    return dataIntervalUs / 1000LL;
+}
+
 StreamOutBluetooth::StreamOutBluetooth(StreamContext&& context,
                                        const SourceMetadata& sourceMetadata,
                                        const std::optional<AudioOffloadInfo>& offloadInfo,
-                                       ModuleBluetooth::BtProfileHandles&& btProfileHandles)
+                                       ModuleBluetooth::BtProfileHandles&& btProfileHandles,
+                                       const std::shared_ptr<BluetoothAudioPortAidl>& btDeviceProxy,
+                                       const PcmConfiguration& pcmConfig)
     : StreamOut(std::move(context), offloadInfo),
-      StreamBluetooth(&mContextInstance, sourceMetadata, std::move(btProfileHandles)) {}
+      StreamBluetooth(&mContextInstance, sourceMetadata, std::move(btProfileHandles), btDeviceProxy,
+                      pcmConfig) {}
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/downmix/Android.bp b/audio/aidl/default/downmix/Android.bp
index 6d15cdb..8657283 100644
--- a/audio/aidl/default/downmix/Android.bp
+++ b/audio/aidl/default/downmix/Android.bp
@@ -27,8 +27,6 @@
     name: "libdownmixsw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "DownmixSw.cpp",
diff --git a/audio/aidl/default/dynamicProcessing/Android.bp b/audio/aidl/default/dynamicProcessing/Android.bp
index 1c0312d..c0a648d 100644
--- a/audio/aidl/default/dynamicProcessing/Android.bp
+++ b/audio/aidl/default/dynamicProcessing/Android.bp
@@ -27,8 +27,6 @@
     name: "libdynamicsprocessingsw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "DynamicsProcessingSw.cpp",
diff --git a/audio/aidl/default/envReverb/Android.bp b/audio/aidl/default/envReverb/Android.bp
index dd4219a..2443c2a 100644
--- a/audio/aidl/default/envReverb/Android.bp
+++ b/audio/aidl/default/envReverb/Android.bp
@@ -27,8 +27,6 @@
     name: "libenvreverbsw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "EnvReverbSw.cpp",
diff --git a/audio/aidl/default/equalizer/Android.bp b/audio/aidl/default/equalizer/Android.bp
index 3610563..42708d1 100644
--- a/audio/aidl/default/equalizer/Android.bp
+++ b/audio/aidl/default/equalizer/Android.bp
@@ -27,8 +27,6 @@
     name: "libequalizersw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "EqualizerSw.cpp",
diff --git a/audio/aidl/default/extension/Android.bp b/audio/aidl/default/extension/Android.bp
index 4e5d352..5fee479 100644
--- a/audio/aidl/default/extension/Android.bp
+++ b/audio/aidl/default/extension/Android.bp
@@ -27,8 +27,6 @@
     name: "libextensioneffect",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "ExtensionEffect.cpp",
diff --git a/audio/aidl/default/hapticGenerator/Android.bp b/audio/aidl/default/hapticGenerator/Android.bp
index 0df9a94..8fb9a3d 100644
--- a/audio/aidl/default/hapticGenerator/Android.bp
+++ b/audio/aidl/default/hapticGenerator/Android.bp
@@ -27,8 +27,6 @@
     name: "libhapticgeneratorsw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "HapticGeneratorSw.cpp",
diff --git a/audio/aidl/default/include/core-impl/DevicePortProxy.h b/audio/aidl/default/include/core-impl/DevicePortProxy.h
index 17a8cf3..ccb23bb 100644
--- a/audio/aidl/default/include/core-impl/DevicePortProxy.h
+++ b/audio/aidl/default/include/core-impl/DevicePortProxy.h
@@ -73,12 +73,7 @@
      * Bluetooth stack
      */
     virtual bool loadAudioConfig(
-            ::aidl::android::hardware::bluetooth::audio::PcmConfiguration*) const = 0;
-
-    /**
-     * WAR to support Mono mode / 16 bits per sample
-     */
-    virtual void forcePcmStereoToMono(bool) = 0;
+            ::aidl::android::hardware::bluetooth::audio::PcmConfiguration&) = 0;
 
     /**
      * When the Audio framework / HAL wants to change the stream state, it invokes
@@ -145,7 +140,7 @@
 
     virtual bool isLeAudio() const = 0;
 
-    virtual bool getPreferredDataIntervalUs(size_t*) const = 0;
+    virtual bool getPreferredDataIntervalUs(size_t&) const = 0;
 
     virtual size_t writeData(const void*, size_t) const { return 0; }
 
@@ -162,10 +157,8 @@
 
     void unregisterPort() override;
 
-    bool loadAudioConfig(::aidl::android::hardware::bluetooth::audio::PcmConfiguration* audio_cfg)
-            const override;
-
-    void forcePcmStereoToMono(bool force) override { mIsStereoToMono = force; }
+    bool loadAudioConfig(
+            ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& audio_cfg) override;
 
     bool standby() override;
     bool start() override;
@@ -193,7 +186,7 @@
 
     bool isLeAudio() const override;
 
-    bool getPreferredDataIntervalUs(size_t* interval_us) const override;
+    bool getPreferredDataIntervalUs(size_t& interval_us) const override;
 
   protected:
     uint16_t mCookie;
@@ -228,6 +221,9 @@
 
 class BluetoothAudioPortAidlOut : public BluetoothAudioPortAidl {
   public:
+    bool loadAudioConfig(
+            ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& audio_cfg) override;
+
     // The audio data path to the Bluetooth stack (Software encoding)
     size_t writeData(const void* buffer, size_t bytes) const override;
 };
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index 572b597..ce71d70 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <functional>
 #include <iostream>
 #include <map>
 #include <memory>
@@ -188,7 +189,7 @@
     // If the module is unable to populate the connected device port correctly, the returned error
     // code must correspond to the errors of `IModule.connectedExternalDevice` method.
     virtual ndk::ScopedAStatus populateConnectedDevicePort(
-            ::aidl::android::media::audio::common::AudioPort* audioPort);
+            ::aidl::android::media::audio::common::AudioPort* audioPort, int32_t nextPortId);
     // If the module finds that the patch endpoints configurations are not matched, the returned
     // error code must correspond to the errors of `IModule.setAudioPatch` method.
     virtual ndk::ScopedAStatus checkAudioPatchEndpointsMatch(
@@ -210,6 +211,7 @@
         const int32_t rawSizeFrames =
                 aidl::android::hardware::audio::common::frameCountFromDurationMs(latencyMs,
                                                                                  sampleRateHz);
+        if (latencyMs >= 5) return rawSizeFrames;
         int32_t powerOf2 = 1;
         while (powerOf2 < rawSizeFrames) powerOf2 <<= 1;
         return powerOf2;
@@ -227,12 +229,16 @@
     std::set<int32_t> findConnectedPortConfigIds(int32_t portConfigId);
     ndk::ScopedAStatus findPortIdForNewStream(
             int32_t in_portConfigId, ::aidl::android::media::audio::common::AudioPort** port);
+    // Note: does not assign an ID to the config.
+    bool generateDefaultPortConfig(const ::aidl::android::media::audio::common::AudioPort& port,
+                                   ::aidl::android::media::audio::common::AudioPortConfig* config);
     std::vector<AudioRoute*> getAudioRoutesForAudioPortImpl(int32_t portId);
     Configuration& getConfig();
     const ConnectedDevicePorts& getConnectedDevicePorts() const { return mConnectedDevicePorts; }
     bool getMasterMute() const { return mMasterMute; }
     bool getMasterVolume() const { return mMasterVolume; }
     bool getMicMute() const { return mMicMute; }
+    const ModuleDebug& getModuleDebug() const { return mDebug; }
     const Patches& getPatches() const { return mPatches; }
     std::set<int32_t> getRoutableAudioPortIds(int32_t portId,
                                               std::vector<AudioRoute*>* routes = nullptr);
@@ -243,6 +249,12 @@
     template <typename C>
     std::set<int32_t> portIdsFromPortConfigIds(C portConfigIds);
     void registerPatch(const AudioPatch& patch);
+    ndk::ScopedAStatus setAudioPortConfigImpl(
+            const ::aidl::android::media::audio::common::AudioPortConfig& in_requested,
+            const std::function<bool(const ::aidl::android::media::audio::common::AudioPort& port,
+                                     ::aidl::android::media::audio::common::AudioPortConfig*
+                                             config)>& fillPortConfig,
+            ::aidl::android::media::audio::common::AudioPortConfig* out_suggested, bool* applied);
     ndk::ScopedAStatus updateStreamsConnectedState(const AudioPatch& oldPatch,
                                                    const AudioPatch& newPatch);
 };
diff --git a/audio/aidl/default/include/core-impl/ModuleAlsa.h b/audio/aidl/default/include/core-impl/ModuleAlsa.h
index 2774fe5..3392b41 100644
--- a/audio/aidl/default/include/core-impl/ModuleAlsa.h
+++ b/audio/aidl/default/include/core-impl/ModuleAlsa.h
@@ -33,7 +33,8 @@
   protected:
     // Extension methods of 'Module'.
     ndk::ScopedAStatus populateConnectedDevicePort(
-            ::aidl::android::media::audio::common::AudioPort* audioPort) override;
+            ::aidl::android::media::audio::common::AudioPort* audioPort,
+            int32_t nextPortId) override;
 };
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/ModuleBluetooth.h b/audio/aidl/default/include/core-impl/ModuleBluetooth.h
index 631b088..9451411 100644
--- a/audio/aidl/default/include/core-impl/ModuleBluetooth.h
+++ b/audio/aidl/default/include/core-impl/ModuleBluetooth.h
@@ -16,7 +16,10 @@
 
 #pragma once
 
+#include <map>
+
 #include "core-impl/Bluetooth.h"
+#include "core-impl/DevicePortProxy.h"
 #include "core-impl/Module.h"
 
 namespace aidl::android::hardware::audio::core {
@@ -31,6 +34,11 @@
     ModuleBluetooth(std::unique_ptr<Configuration>&& config);
 
   private:
+    struct CachedProxy {
+        std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl> ptr;
+        ::aidl::android::hardware::bluetooth::audio::PcmConfiguration pcmConfig;
+    };
+
     ChildInterface<BluetoothA2dp>& getBtA2dp();
     ChildInterface<BluetoothLe>& getBtLe();
     BtProfileHandles getBtProfileManagerHandles();
@@ -40,6 +48,17 @@
     ndk::ScopedAStatus getMicMute(bool* _aidl_return) override;
     ndk::ScopedAStatus setMicMute(bool in_mute) override;
 
+    ndk::ScopedAStatus setAudioPortConfig(
+            const ::aidl::android::media::audio::common::AudioPortConfig& in_requested,
+            ::aidl::android::media::audio::common::AudioPortConfig* out_suggested,
+            bool* _aidl_return) override;
+
+    ndk::ScopedAStatus checkAudioPatchEndpointsMatch(
+            const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sources,
+            const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks)
+            override;
+    void onExternalDeviceConnectionChanged(
+            const ::aidl::android::media::audio::common::AudioPort& audioPort, bool connected);
     ndk::ScopedAStatus createInputStream(
             StreamContext&& context,
             const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
@@ -52,12 +71,24 @@
                     offloadInfo,
             std::shared_ptr<StreamOut>* result) override;
     ndk::ScopedAStatus populateConnectedDevicePort(
-            ::aidl::android::media::audio::common::AudioPort* audioPort) override;
+            ::aidl::android::media::audio::common::AudioPort* audioPort,
+            int32_t nextPortId) override;
     ndk::ScopedAStatus onMasterMuteChanged(bool mute) override;
     ndk::ScopedAStatus onMasterVolumeChanged(float volume) override;
+    int32_t getNominalLatencyMs(
+            const ::aidl::android::media::audio::common::AudioPortConfig& portConfig) override;
+
+    ndk::ScopedAStatus createProxy(
+            const ::aidl::android::media::audio::common::AudioPort& audioPort,
+            int32_t instancePortId, CachedProxy& proxy);
+    ndk::ScopedAStatus fetchAndCheckProxy(const StreamContext& context, CachedProxy& proxy);
+    ndk::ScopedAStatus findOrCreateProxy(
+            const ::aidl::android::media::audio::common::AudioPort& audioPort, CachedProxy& proxy);
 
     ChildInterface<BluetoothA2dp> mBluetoothA2dp;
     ChildInterface<BluetoothLe> mBluetoothLe;
+    std::map<int32_t /*instantiated device port ID*/, CachedProxy> mProxies;
+    std::map<int32_t /*mix port handle*/, int32_t /*instantiated device port ID*/> mConnections;
 };
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h b/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h
index 9f8acc9..613ac62 100644
--- a/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h
+++ b/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h
@@ -29,6 +29,10 @@
     // IModule interfaces
     ndk::ScopedAStatus getMicMute(bool* _aidl_return) override;
     ndk::ScopedAStatus setMicMute(bool in_mute) override;
+    ndk::ScopedAStatus setAudioPortConfig(
+            const ::aidl::android::media::audio::common::AudioPortConfig& in_requested,
+            ::aidl::android::media::audio::common::AudioPortConfig* out_suggested,
+            bool* _aidl_return) override;
 
     // Module interfaces
     ndk::ScopedAStatus createInputStream(
@@ -43,7 +47,8 @@
                     offloadInfo,
             std::shared_ptr<StreamOut>* result) override;
     ndk::ScopedAStatus populateConnectedDevicePort(
-            ::aidl::android::media::audio::common::AudioPort* audioPort) override;
+            ::aidl::android::media::audio::common::AudioPort* audioPort,
+            int32_t nextPortId) override;
     ndk::ScopedAStatus checkAudioPatchEndpointsMatch(
             const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sources,
             const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks)
diff --git a/audio/aidl/default/include/core-impl/ModuleUsb.h b/audio/aidl/default/include/core-impl/ModuleUsb.h
index 6ee8f8a..d9ac4f0 100644
--- a/audio/aidl/default/include/core-impl/ModuleUsb.h
+++ b/audio/aidl/default/include/core-impl/ModuleUsb.h
@@ -44,7 +44,8 @@
                     offloadInfo,
             std::shared_ptr<StreamOut>* result) override;
     ndk::ScopedAStatus populateConnectedDevicePort(
-            ::aidl::android::media::audio::common::AudioPort* audioPort) override;
+            ::aidl::android::media::audio::common::AudioPort* audioPort,
+            int32_t nextPortId) override;
     ndk::ScopedAStatus checkAudioPatchEndpointsMatch(
             const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sources,
             const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks)
diff --git a/audio/aidl/default/include/core-impl/StreamBluetooth.h b/audio/aidl/default/include/core-impl/StreamBluetooth.h
index 1258d38..35c3183 100644
--- a/audio/aidl/default/include/core-impl/StreamBluetooth.h
+++ b/audio/aidl/default/include/core-impl/StreamBluetooth.h
@@ -31,8 +31,16 @@
 
 class StreamBluetooth : public StreamCommonImpl {
   public:
-    StreamBluetooth(StreamContext* context, const Metadata& metadata,
-                    ModuleBluetooth::BtProfileHandles&& btHandles);
+    static bool checkConfigParams(
+            const ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& pcmConfig,
+            const ::aidl::android::media::audio::common::AudioConfigBase& config);
+
+    StreamBluetooth(
+            StreamContext* context, const Metadata& metadata,
+            ModuleBluetooth::BtProfileHandles&& btHandles,
+            const std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl>&
+                    btDeviceProxy,
+            const ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& pcmConfig);
     // Methods of 'DriverInterface'.
     ::android::status_t init() override;
     ::android::status_t drain(StreamDescriptor::DrainMode) override;
@@ -47,40 +55,35 @@
     // Overridden methods of 'StreamCommonImpl', called on a Binder thread.
     ndk::ScopedAStatus updateMetadataCommon(const Metadata& metadata) override;
     ndk::ScopedAStatus prepareToClose() override;
-    const ConnectedDevices& getConnectedDevices() const override;
-    ndk::ScopedAStatus setConnectedDevices(const ConnectedDevices& devices) override;
     ndk::ScopedAStatus bluetoothParametersUpdated() override;
 
   private:
-    // Audio Pcm Config
-    const uint32_t mSampleRate;
-    const ::aidl::android::media::audio::common::AudioChannelLayout mChannelLayout;
-    const ::aidl::android::media::audio::common::AudioFormatDescription mFormat;
     const size_t mFrameSizeBytes;
     const bool mIsInput;
     const std::weak_ptr<IBluetoothA2dp> mBluetoothA2dp;
     const std::weak_ptr<IBluetoothLe> mBluetoothLe;
-    size_t mPreferredDataIntervalUs;
-    size_t mPreferredFrameCount;
-
+    const size_t mPreferredDataIntervalUs;
+    const size_t mPreferredFrameCount;
     mutable std::mutex mLock;
-    bool mIsInitialized GUARDED_BY(mLock);
-    bool mIsReadyToClose GUARDED_BY(mLock);
-    std::vector<std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl>>
-            mBtDeviceProxies GUARDED_BY(mLock);
-
-    ::android::status_t initialize() REQUIRES(mLock);
-    bool checkConfigParams(::aidl::android::hardware::bluetooth::audio::PcmConfiguration& config);
+    // The lock is also used to serialize calls to the proxy.
+    std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl> mBtDeviceProxy
+            GUARDED_BY(mLock);  // proxy may be null if the stream is not connected to a device
 };
 
 class StreamInBluetooth final : public StreamIn, public StreamBluetooth {
   public:
     friend class ndk::SharedRefBase;
+
+    static int32_t getNominalLatencyMs(size_t dataIntervalUs);
+
     StreamInBluetooth(
             StreamContext&& context,
             const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
-            ModuleBluetooth::BtProfileHandles&& btHandles);
+            ModuleBluetooth::BtProfileHandles&& btHandles,
+            const std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl>&
+                    btDeviceProxy,
+            const ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& pcmConfig);
 
   private:
     void onClose(StreamDescriptor::State) override { defaultOnClose(); }
@@ -92,12 +95,18 @@
 class StreamOutBluetooth final : public StreamOut, public StreamBluetooth {
   public:
     friend class ndk::SharedRefBase;
+
+    static int32_t getNominalLatencyMs(size_t dataIntervalUs);
+
     StreamOutBluetooth(
             StreamContext&& context,
             const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
                     offloadInfo,
-            ModuleBluetooth::BtProfileHandles&& btHandles);
+            ModuleBluetooth::BtProfileHandles&& btHandles,
+            const std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl>&
+                    btDeviceProxy,
+            const ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& pcmConfig);
 
   private:
     void onClose(StreamDescriptor::State) override { defaultOnClose(); }
diff --git a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
index ee10abf..cc06881 100644
--- a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
+++ b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
@@ -16,7 +16,6 @@
 
 #pragma once
 
-#include <mutex>
 #include <vector>
 
 #include "core-impl/Stream.h"
@@ -56,13 +55,6 @@
     r_submix::AudioConfig mStreamConfig;
     std::shared_ptr<r_submix::SubmixRoute> mCurrentRoute = nullptr;
 
-    // Mutex lock to protect vector of submix routes, each of these submix routes have their mutex
-    // locks and none of the mutex locks should be taken together.
-    static std::mutex sSubmixRoutesLock;
-    static std::map<::aidl::android::media::audio::common::AudioDeviceAddress,
-                    std::shared_ptr<r_submix::SubmixRoute>>
-            sSubmixRoutes GUARDED_BY(sSubmixRoutesLock);
-
     // limit for number of read error log entries to avoid spamming the logs
     static constexpr int kMaxReadErrorLogs = 5;
     // The duration of kMaxReadFailureAttempts * READ_ATTEMPT_SLEEP_MS must be strictly inferior
diff --git a/audio/aidl/default/loudnessEnhancer/Android.bp b/audio/aidl/default/loudnessEnhancer/Android.bp
index 89a72fe..cd44b50 100644
--- a/audio/aidl/default/loudnessEnhancer/Android.bp
+++ b/audio/aidl/default/loudnessEnhancer/Android.bp
@@ -27,8 +27,6 @@
     name: "libloudnessenhancersw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "LoudnessEnhancerSw.cpp",
diff --git a/audio/aidl/default/noiseSuppression/Android.bp b/audio/aidl/default/noiseSuppression/Android.bp
index dad3d49..f24ded6 100644
--- a/audio/aidl/default/noiseSuppression/Android.bp
+++ b/audio/aidl/default/noiseSuppression/Android.bp
@@ -27,8 +27,6 @@
     name: "libnssw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "NoiseSuppressionSw.cpp",
diff --git a/audio/aidl/default/presetReverb/Android.bp b/audio/aidl/default/presetReverb/Android.bp
index 18bdd17..d600141 100644
--- a/audio/aidl/default/presetReverb/Android.bp
+++ b/audio/aidl/default/presetReverb/Android.bp
@@ -27,8 +27,6 @@
     name: "libpresetreverbsw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "PresetReverbSw.cpp",
diff --git a/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp b/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp
index 2f42889..47ade49 100644
--- a/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp
+++ b/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp
@@ -27,13 +27,36 @@
 
 using aidl::android::hardware::audio::common::SinkMetadata;
 using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::media::audio::common::AudioDeviceAddress;
+using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::AudioIoFlags;
 using aidl::android::media::audio::common::AudioOffloadInfo;
 using aidl::android::media::audio::common::AudioPort;
 using aidl::android::media::audio::common::AudioPortConfig;
+using aidl::android::media::audio::common::AudioPortExt;
+using aidl::android::media::audio::common::AudioProfile;
+using aidl::android::media::audio::common::Int;
 using aidl::android::media::audio::common::MicrophoneInfo;
 
 namespace aidl::android::hardware::audio::core {
 
+namespace {
+
+std::optional<r_submix::AudioConfig> getRemoteEndConfig(const AudioPort& audioPort) {
+    const auto& deviceAddress = audioPort.ext.get<AudioPortExt::device>().device.address;
+    const bool isInput = audioPort.flags.getTag() == AudioIoFlags::input;
+    if (auto submixRoute = r_submix::SubmixRoute::findRoute(deviceAddress);
+        submixRoute != nullptr) {
+        if ((isInput && submixRoute->isStreamOutOpen()) ||
+            (!isInput && submixRoute->isStreamInOpen())) {
+            return submixRoute->getPipeConfig();
+        }
+    }
+    return {};
+}
+
+}  // namespace
+
 ndk::ScopedAStatus ModuleRemoteSubmix::getMicMute(bool* _aidl_return __unused) {
     LOG(DEBUG) << __func__ << ": is not supported";
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
@@ -44,9 +67,33 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
+ndk::ScopedAStatus ModuleRemoteSubmix::setAudioPortConfig(const AudioPortConfig& in_requested,
+                                                          AudioPortConfig* out_suggested,
+                                                          bool* _aidl_return) {
+    auto fillConfig = [this](const AudioPort& port, AudioPortConfig* config) {
+        if (port.ext.getTag() == AudioPortExt::device) {
+            if (auto pipeConfig = getRemoteEndConfig(port); pipeConfig.has_value()) {
+                LOG(DEBUG) << "setAudioPortConfig: suggesting port config from the remote end.";
+                config->format = pipeConfig->format;
+                config->channelMask = pipeConfig->channelLayout;
+                config->sampleRate = Int{.value = pipeConfig->sampleRate};
+                config->flags = port.flags;
+                config->ext = port.ext;
+                return true;
+            }
+        }
+        return generateDefaultPortConfig(port, config);
+    };
+    return Module::setAudioPortConfigImpl(in_requested, fillConfig, out_suggested, _aidl_return);
+}
+
 ndk::ScopedAStatus ModuleRemoteSubmix::createInputStream(
         StreamContext&& context, const SinkMetadata& sinkMetadata,
         const std::vector<MicrophoneInfo>& microphones, std::shared_ptr<StreamIn>* result) {
+    if (context.getFormat().type != AudioFormatType::PCM) {
+        LOG(DEBUG) << __func__ << ": not supported for format " << context.getFormat().toString();
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
     return createStreamInstance<StreamInRemoteSubmix>(result, std::move(context), sinkMetadata,
                                                       microphones);
 }
@@ -54,12 +101,31 @@
 ndk::ScopedAStatus ModuleRemoteSubmix::createOutputStream(
         StreamContext&& context, const SourceMetadata& sourceMetadata,
         const std::optional<AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) {
+    if (context.getFormat().type != AudioFormatType::PCM) {
+        LOG(DEBUG) << __func__ << ": not supported for format " << context.getFormat().toString();
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
     return createStreamInstance<StreamOutRemoteSubmix>(result, std::move(context), sourceMetadata,
                                                        offloadInfo);
 }
 
-ndk::ScopedAStatus ModuleRemoteSubmix::populateConnectedDevicePort(AudioPort* audioPort) {
-    // Find the corresponding mix port and copy its profiles.
+ndk::ScopedAStatus ModuleRemoteSubmix::populateConnectedDevicePort(AudioPort* audioPort, int32_t) {
+    if (audioPort->ext.getTag() != AudioPortExt::device) {
+        LOG(ERROR) << __func__ << ": not a device port: " << audioPort->toString();
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    // If there is already a pipe with a stream for the port address, provide its configuration as
+    // the only option. Otherwise, find the corresponding mix port and copy its profiles.
+    if (auto pipeConfig = getRemoteEndConfig(*audioPort); pipeConfig.has_value()) {
+        audioPort->profiles.clear();
+        audioPort->profiles.push_back(AudioProfile{
+                .format = pipeConfig->format,
+                .channelMasks = std::vector<AudioChannelLayout>({pipeConfig->channelLayout}),
+                .sampleRates = std::vector<int>({pipeConfig->sampleRate})});
+        LOG(DEBUG) << __func__ << ": populated from remote end as: " << audioPort->toString();
+        return ndk::ScopedAStatus::ok();
+    }
+
     // At this moment, the port has the same ID as the template port, see connectExternalDevice.
     std::vector<AudioRoute*> routes = getAudioRoutesForAudioPortImpl(audioPort->id);
     if (routes.empty()) {
@@ -78,6 +144,7 @@
         RETURN_STATUS_IF_ERROR(getAudioPort(route->sinkPortId, &mixPort));
     }
     audioPort->profiles = mixPort.profiles;
+    LOG(DEBUG) << __func__ << ": populated from the mix port as: " << audioPort->toString();
     return ndk::ScopedAStatus::ok();
 }
 
diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
index d238aa4..df706ac 100644
--- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
+++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
@@ -43,26 +43,10 @@
     mStreamConfig.sampleRate = context->getSampleRate();
 }
 
-std::mutex StreamRemoteSubmix::sSubmixRoutesLock;
-std::map<AudioDeviceAddress, std::shared_ptr<SubmixRoute>> StreamRemoteSubmix::sSubmixRoutes;
-
 ::android::status_t StreamRemoteSubmix::init() {
-    {
-        std::lock_guard guard(sSubmixRoutesLock);
-        auto routeItr = sSubmixRoutes.find(mDeviceAddress);
-        if (routeItr != sSubmixRoutes.end()) {
-            mCurrentRoute = routeItr->second;
-        }
-        // If route is not available for this port, add it.
-        if (mCurrentRoute == nullptr) {
-            // Initialize the pipe.
-            mCurrentRoute = std::make_shared<SubmixRoute>();
-            if (::android::OK != mCurrentRoute->createPipe(mStreamConfig)) {
-                LOG(ERROR) << __func__ << ": create pipe failed";
-                return ::android::NO_INIT;
-            }
-            sSubmixRoutes.emplace(mDeviceAddress, mCurrentRoute);
-        }
+    mCurrentRoute = SubmixRoute::findOrCreateRoute(mDeviceAddress, mStreamConfig);
+    if (mCurrentRoute == nullptr) {
+        return ::android::NO_INIT;
     }
     if (!mCurrentRoute->isStreamConfigValid(mIsInput, mStreamConfig)) {
         LOG(ERROR) << __func__ << ": invalid stream config";
@@ -80,7 +64,6 @@
             return ::android::NO_INIT;
         }
     }
-
     mCurrentRoute->openStream(mIsInput);
     return ::android::OK;
 }
@@ -114,14 +97,7 @@
 
 ndk::ScopedAStatus StreamRemoteSubmix::prepareToClose() {
     if (!mIsInput) {
-        std::shared_ptr<SubmixRoute> route = nullptr;
-        {
-            std::lock_guard guard(sSubmixRoutesLock);
-            auto routeItr = sSubmixRoutes.find(mDeviceAddress);
-            if (routeItr != sSubmixRoutes.end()) {
-                route = routeItr->second;
-            }
-        }
+        std::shared_ptr<SubmixRoute> route = SubmixRoute::findRoute(mDeviceAddress);
         if (route != nullptr) {
             sp<MonoPipe> sink = route->getSink();
             if (sink == nullptr) {
@@ -148,9 +124,7 @@
     if (!mCurrentRoute->hasAtleastOneStreamOpen()) {
         mCurrentRoute->releasePipe();
         LOG(DEBUG) << __func__ << ": pipe destroyed";
-
-        std::lock_guard guard(sSubmixRoutesLock);
-        sSubmixRoutes.erase(mDeviceAddress);
+        SubmixRoute::removeRoute(mDeviceAddress);
     }
     mCurrentRoute.reset();
 }
@@ -201,7 +175,7 @@
 
 // Calculate the maximum size of the pipe buffer in frames for the specified stream.
 size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() {
-    auto pipeConfig = mCurrentRoute->mPipeConfig;
+    auto pipeConfig = mCurrentRoute->getPipeConfig();
     const size_t maxFrameSize = std::max(mStreamConfig.frameSize, pipeConfig.frameSize);
     return (pipeConfig.frameCount * pipeConfig.frameSize) / maxFrameSize;
 }
diff --git a/audio/aidl/default/r_submix/SubmixRoute.cpp b/audio/aidl/default/r_submix/SubmixRoute.cpp
index 235c9a3..7d706c2 100644
--- a/audio/aidl/default/r_submix/SubmixRoute.cpp
+++ b/audio/aidl/default/r_submix/SubmixRoute.cpp
@@ -23,9 +23,49 @@
 #include "SubmixRoute.h"
 
 using aidl::android::hardware::audio::common::getChannelCount;
+using aidl::android::media::audio::common::AudioDeviceAddress;
 
 namespace aidl::android::hardware::audio::core::r_submix {
 
+// static
+SubmixRoute::RoutesMonitor SubmixRoute::getRoutes() {
+    static std::mutex submixRoutesLock;
+    static RoutesMap submixRoutes;
+    return RoutesMonitor(submixRoutesLock, submixRoutes);
+}
+
+// static
+std::shared_ptr<SubmixRoute> SubmixRoute::findOrCreateRoute(const AudioDeviceAddress& deviceAddress,
+                                                            const AudioConfig& pipeConfig) {
+    auto routes = getRoutes();
+    auto routeItr = routes->find(deviceAddress);
+    if (routeItr != routes->end()) {
+        return routeItr->second;
+    }
+    auto route = std::make_shared<SubmixRoute>();
+    if (::android::OK != route->createPipe(pipeConfig)) {
+        LOG(ERROR) << __func__ << ": create pipe failed";
+        return nullptr;
+    }
+    routes->emplace(deviceAddress, route);
+    return route;
+}
+
+// static
+std::shared_ptr<SubmixRoute> SubmixRoute::findRoute(const AudioDeviceAddress& deviceAddress) {
+    auto routes = getRoutes();
+    auto routeItr = routes->find(deviceAddress);
+    if (routeItr != routes->end()) {
+        return routeItr->second;
+    }
+    return nullptr;
+}
+
+// static
+void SubmixRoute::removeRoute(const AudioDeviceAddress& deviceAddress) {
+    getRoutes()->erase(deviceAddress);
+}
+
 // Verify a submix input or output stream can be opened.
 bool SubmixRoute::isStreamConfigValid(bool isInput, const AudioConfig& streamConfig) {
     // If the stream is already open, don't open it again.
@@ -44,6 +84,7 @@
 // Compare this stream config with existing pipe config, returning false if they do *not*
 // match, true otherwise.
 bool SubmixRoute::isStreamConfigCompatible(const AudioConfig& streamConfig) {
+    std::lock_guard guard(mLock);
     if (streamConfig.channelLayout != mPipeConfig.channelLayout) {
         LOG(ERROR) << __func__ << ": channel count mismatch, stream channels = "
                    << streamConfig.channelLayout.toString()
@@ -162,17 +203,14 @@
         LOG(FATAL) << __func__ << ": Negotiation for the source failed, index = " << index;
         return ::android::BAD_INDEX;
     }
-    LOG(VERBOSE) << __func__ << ": created pipe";
-
-    mPipeConfig = streamConfig;
-    mPipeConfig.frameCount = sink->maxFrames();
-
-    LOG(VERBOSE) << __func__ << ": Pipe frame size : " << mPipeConfig.frameSize
-                 << ", pipe frames : " << mPipeConfig.frameCount;
+    LOG(VERBOSE) << __func__ << ": Pipe frame size : " << streamConfig.frameSize
+                 << ", pipe frames : " << sink->maxFrames();
 
     // Save references to the source and sink.
     {
         std::lock_guard guard(mLock);
+        mPipeConfig = streamConfig;
+        mPipeConfig.frameCount = sink->maxFrames();
         mSink = std::move(sink);
         mSource = std::move(source);
     }
@@ -181,15 +219,15 @@
 }
 
 // Release references to the sink and source.
-void SubmixRoute::releasePipe() {
+AudioConfig SubmixRoute::releasePipe() {
     std::lock_guard guard(mLock);
     mSink.clear();
     mSource.clear();
+    return mPipeConfig;
 }
 
 ::android::status_t SubmixRoute::resetPipe() {
-    releasePipe();
-    return createPipe(mPipeConfig);
+    return createPipe(releasePipe());
 }
 
 void SubmixRoute::standby(bool isInput) {
diff --git a/audio/aidl/default/r_submix/SubmixRoute.h b/audio/aidl/default/r_submix/SubmixRoute.h
index 252b1c9..160df41 100644
--- a/audio/aidl/default/r_submix/SubmixRoute.h
+++ b/audio/aidl/default/r_submix/SubmixRoute.h
@@ -25,6 +25,7 @@
 #include <media/nbaio/MonoPipeReader.h>
 
 #include <aidl/android/media/audio/common/AudioChannelLayout.h>
+#include <aidl/android/media/audio/common/AudioDeviceAddress.h>
 #include <aidl/android/media/audio/common/AudioFormatDescription.h>
 
 using aidl::android::media::audio::common::AudioChannelLayout;
@@ -60,7 +61,13 @@
 
 class SubmixRoute {
   public:
-    AudioConfig mPipeConfig;
+    static std::shared_ptr<SubmixRoute> findOrCreateRoute(
+            const ::aidl::android::media::audio::common::AudioDeviceAddress& deviceAddress,
+            const AudioConfig& pipeConfig);
+    static std::shared_ptr<SubmixRoute> findRoute(
+            const ::aidl::android::media::audio::common::AudioDeviceAddress& deviceAddress);
+    static void removeRoute(
+            const ::aidl::android::media::audio::common::AudioDeviceAddress& deviceAddress);
 
     bool isStreamInOpen() {
         std::lock_guard guard(mLock);
@@ -90,6 +97,10 @@
         std::lock_guard guard(mLock);
         return mSource;
     }
+    AudioConfig getPipeConfig() {
+        std::lock_guard guard(mLock);
+        return mPipeConfig;
+    }
 
     bool isStreamConfigValid(bool isInput, const AudioConfig& streamConfig);
     void closeStream(bool isInput);
@@ -98,17 +109,31 @@
     bool hasAtleastOneStreamOpen();
     int notifyReadError();
     void openStream(bool isInput);
-    void releasePipe();
+    AudioConfig releasePipe();
     ::android::status_t resetPipe();
     bool shouldBlockWrite();
     void standby(bool isInput);
     long updateReadCounterFrames(size_t frameCount);
 
   private:
+    using RoutesMap = std::map<::aidl::android::media::audio::common::AudioDeviceAddress,
+                               std::shared_ptr<r_submix::SubmixRoute>>;
+    class RoutesMonitor {
+      public:
+        RoutesMonitor(std::mutex& mutex, RoutesMap& routes) : mLock(mutex), mRoutes(routes) {}
+        RoutesMap* operator->() { return &mRoutes; }
+
+      private:
+        std::lock_guard<std::mutex> mLock;
+        RoutesMap& mRoutes;
+    };
+
+    static RoutesMonitor getRoutes();
+
     bool isStreamConfigCompatible(const AudioConfig& streamConfig);
 
     std::mutex mLock;
-
+    AudioConfig mPipeConfig GUARDED_BY(mLock);
     bool mStreamInOpen GUARDED_BY(mLock) = false;
     int mInputRefCount GUARDED_BY(mLock) = 0;
     bool mStreamInStandby GUARDED_BY(mLock) = true;
diff --git a/audio/aidl/default/spatializer/Android.bp b/audio/aidl/default/spatializer/Android.bp
new file mode 100644
index 0000000..05ed365
--- /dev/null
+++ b/audio/aidl/default/spatializer/Android.bp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+    name: "libspatializersw",
+    defaults: [
+        "aidlaudioeffectservice_defaults",
+    ],
+    srcs: [
+        "SpatializerSw.cpp",
+        ":effectCommonFile",
+    ],
+    relative_install_path: "soundfx",
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
+    ],
+}
diff --git a/audio/aidl/default/spatializer/SpatializerSw.cpp b/audio/aidl/default/spatializer/SpatializerSw.cpp
new file mode 100644
index 0000000..434ed5a
--- /dev/null
+++ b/audio/aidl/default/spatializer/SpatializerSw.cpp
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHAL_SpatializerSw"
+
+#include "SpatializerSw.h"
+
+#include <android-base/logging.h>
+#include <system/audio_effects/effect_uuid.h>
+
+#include <optional>
+
+using aidl::android::hardware::audio::common::getChannelCount;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::getEffectImplUuidSpatializerSw;
+using aidl::android::hardware::audio::effect::getEffectTypeUuidSpatializer;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::SpatializerSw;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioUuid;
+using aidl::android::media::audio::common::HeadTracking;
+using aidl::android::media::audio::common::Spatialization;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+                                           std::shared_ptr<IEffect>* instanceSpp) {
+    if (!in_impl_uuid || *in_impl_uuid != getEffectImplUuidSpatializerSw()) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (!instanceSpp) {
+        LOG(ERROR) << __func__ << " invalid input parameter!";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+
+    *instanceSpp = ndk::SharedRefBase::make<SpatializerSw>();
+    LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
+    return EX_NONE;
+}
+
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+    if (!in_impl_uuid || *in_impl_uuid != getEffectImplUuidSpatializerSw()) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    *_aidl_return = SpatializerSw::kDescriptor;
+    return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+const std::string SpatializerSw::kEffectName = "SpatializerSw";
+
+const std::vector<Range::SpatializerRange> SpatializerSw::kRanges = {
+        MAKE_RANGE(Spatializer, supportedChannelLayout, std::vector<AudioChannelLayout>{},
+                   std::vector<AudioChannelLayout>{}),
+        MAKE_RANGE(Spatializer, spatializationLevel, Spatialization::Level::NONE,
+                   Spatialization::Level::BED_PLUS_OBJECTS),
+        MAKE_RANGE(Spatializer, spatializationMode, Spatialization::Mode::BINAURAL,
+                   Spatialization::Mode::TRANSAURAL),
+        MAKE_RANGE(Spatializer, headTrackingSensorId, std::numeric_limits<int>::min(),
+                   std::numeric_limits<int>::max()),
+        MAKE_RANGE(Spatializer, headTrackingMode, HeadTracking::Mode::OTHER,
+                   HeadTracking::Mode::RELATIVE_SCREEN),
+        MAKE_RANGE(Spatializer, headTrackingConnectionMode,
+                   HeadTracking::ConnectionMode::FRAMEWORK_PROCESSED,
+                   HeadTracking::ConnectionMode::DIRECT_TO_SENSOR_TUNNEL)};
+const Capability SpatializerSw::kCapability = {.range = {SpatializerSw::kRanges}};
+const Descriptor SpatializerSw::kDescriptor = {
+        .common = {.id = {.type = getEffectTypeUuidSpatializer(),
+                          .uuid = getEffectImplUuidSpatializerSw()},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::FIRST,
+                             .hwAcceleratorMode = Flags::HardwareAccelerator::NONE},
+                   .name = SpatializerSw::kEffectName,
+                   .implementor = "The Android Open Source Project"},
+        .capability = SpatializerSw::kCapability};
+
+ndk::ScopedAStatus SpatializerSw::getDescriptor(Descriptor* _aidl_return) {
+    LOG(DEBUG) << __func__ << kDescriptor.toString();
+    *_aidl_return = kDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus SpatializerSw::setParameterSpecific(const Parameter::Specific& specific) {
+    RETURN_IF(Parameter::Specific::spatializer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+              "EffectNotSupported");
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    auto& param = specific.get<Parameter::Specific::spatializer>();
+    RETURN_IF(!inRange(param, kRanges), EX_ILLEGAL_ARGUMENT, "outOfRange");
+
+    return mContext->setParam(param.getTag(), param);
+}
+
+ndk::ScopedAStatus SpatializerSw::getParameterSpecific(const Parameter::Id& id,
+                                                       Parameter::Specific* specific) {
+    auto tag = id.getTag();
+    RETURN_IF(Parameter::Id::spatializerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+    auto spatializerId = id.get<Parameter::Id::spatializerTag>();
+    auto spatializerTag = spatializerId.getTag();
+    switch (spatializerTag) {
+        case Spatializer::Id::commonTag: {
+            auto specificTag = spatializerId.get<Spatializer::Id::commonTag>();
+            std::optional<Spatializer> param = mContext->getParam(specificTag);
+            if (!param.has_value()) {
+                return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                        EX_ILLEGAL_ARGUMENT, "SpatializerTagNotSupported");
+            }
+            specific->set<Parameter::Specific::spatializer>(param.value());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "SpatializerTagNotSupported");
+        }
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> SpatializerSw::createContext(const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+    } else {
+        mContext = std::make_shared<SpatializerSwContext>(1 /* statusFmqDepth */, common);
+    }
+    return mContext;
+}
+
+std::shared_ptr<EffectContext> SpatializerSw::getContext() {
+    return mContext;
+}
+
+RetCode SpatializerSw::releaseContext() {
+    if (mContext) {
+        mContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+SpatializerSw::~SpatializerSw() {
+    cleanUp();
+    LOG(DEBUG) << __func__;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status SpatializerSw::effectProcessImpl(float* in, float* out, int samples) {
+    RETURN_VALUE_IF(!mContext, (IEffect::Status{EX_NULL_POINTER, 0, 0}), "nullContext");
+    return mContext->process(in, out, samples);
+}
+
+SpatializerSwContext::SpatializerSwContext(int statusDepth, const Parameter::Common& common)
+    : EffectContext(statusDepth, common) {
+    LOG(DEBUG) << __func__;
+}
+
+SpatializerSwContext::~SpatializerSwContext() {
+    LOG(DEBUG) << __func__;
+}
+
+template <typename TAG>
+std::optional<Spatializer> SpatializerSwContext::getParam(TAG tag) {
+    if (mParamsMap.find(tag) != mParamsMap.end()) {
+        return mParamsMap.at(tag);
+    }
+    return std::nullopt;
+}
+
+template <typename TAG>
+ndk::ScopedAStatus SpatializerSwContext::setParam(TAG tag, Spatializer spatializer) {
+    mParamsMap[tag] = spatializer;
+    return ndk::ScopedAStatus::ok();
+}
+
+IEffect::Status SpatializerSwContext::process(float* in, float* out, int samples) {
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+    IEffect::Status status = {EX_ILLEGAL_ARGUMENT, 0, 0};
+
+    const auto inputChannelCount = getChannelCount(mCommon.input.base.channelMask);
+    const auto outputChannelCount = getChannelCount(mCommon.output.base.channelMask);
+    if (outputChannelCount < 2 || inputChannelCount < outputChannelCount) {
+        LOG(ERROR) << __func__ << " invalid channel count, in: " << inputChannelCount
+                   << " out: " << outputChannelCount;
+        return status;
+    }
+
+    int iFrames = samples / inputChannelCount;
+    for (int i = 0; i < iFrames; i++) {
+        std::memcpy(out, in, outputChannelCount);
+        in += inputChannelCount;
+        out += outputChannelCount;
+    }
+    return {STATUS_OK, static_cast<int32_t>(iFrames * inputChannelCount),
+            static_cast<int32_t>(iFrames * outputChannelCount)};
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/spatializer/SpatializerSw.h b/audio/aidl/default/spatializer/SpatializerSw.h
new file mode 100644
index 0000000..b205704
--- /dev/null
+++ b/audio/aidl/default/spatializer/SpatializerSw.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#pragma once
+
+#include "effect-impl/EffectContext.h"
+#include "effect-impl/EffectImpl.h"
+
+#include <fmq/AidlMessageQueue.h>
+
+#include <unordered_map>
+#include <vector>
+
+namespace aidl::android::hardware::audio::effect {
+
+class SpatializerSwContext final : public EffectContext {
+  public:
+    SpatializerSwContext(int statusDepth, const Parameter::Common& common);
+    ~SpatializerSwContext();
+
+    template <typename TAG>
+    std::optional<Spatializer> getParam(TAG tag);
+    template <typename TAG>
+    ndk::ScopedAStatus setParam(TAG tag, Spatializer spatializer);
+
+    IEffect::Status process(float* in, float* out, int samples);
+
+  private:
+    std::unordered_map<Spatializer::Tag, Spatializer> mParamsMap;
+};
+
+class SpatializerSw final : public EffectImpl {
+  public:
+    static const std::string kEffectName;
+    static const Capability kCapability;
+    static const Descriptor kDescriptor;
+    ~SpatializerSw();
+
+    ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
+                                            Parameter::Specific* specific) override;
+
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    std::shared_ptr<EffectContext> getContext() override;
+    RetCode releaseContext() override;
+
+    std::string getEffectName() override { return kEffectName; };
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+
+  private:
+    static const std::vector<Range::SpatializerRange> kRanges;
+    std::shared_ptr<SpatializerSwContext> mContext = nullptr;
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/usb/ModuleUsb.cpp b/audio/aidl/default/usb/ModuleUsb.cpp
index f926e09..1d97bc4 100644
--- a/audio/aidl/default/usb/ModuleUsb.cpp
+++ b/audio/aidl/default/usb/ModuleUsb.cpp
@@ -87,12 +87,13 @@
                                               offloadInfo);
 }
 
-ndk::ScopedAStatus ModuleUsb::populateConnectedDevicePort(AudioPort* audioPort) {
+ndk::ScopedAStatus ModuleUsb::populateConnectedDevicePort(AudioPort* audioPort,
+                                                          int32_t nextPortId) {
     if (!isUsbDevicePort(*audioPort)) {
         LOG(ERROR) << __func__ << ": port id " << audioPort->id << " is not a usb device port";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
-    return ModuleAlsa::populateConnectedDevicePort(audioPort);
+    return ModuleAlsa::populateConnectedDevicePort(audioPort, nextPortId);
 }
 
 ndk::ScopedAStatus ModuleUsb::checkAudioPatchEndpointsMatch(
diff --git a/audio/aidl/default/virtualizer/Android.bp b/audio/aidl/default/virtualizer/Android.bp
index ed0199d..1c41bb5 100644
--- a/audio/aidl/default/virtualizer/Android.bp
+++ b/audio/aidl/default/virtualizer/Android.bp
@@ -27,8 +27,6 @@
     name: "libvirtualizersw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "VirtualizerSw.cpp",
diff --git a/audio/aidl/default/visualizer/Android.bp b/audio/aidl/default/visualizer/Android.bp
index 091daa2..68f7177 100644
--- a/audio/aidl/default/visualizer/Android.bp
+++ b/audio/aidl/default/visualizer/Android.bp
@@ -27,8 +27,6 @@
     name: "libvisualizersw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "VisualizerSw.cpp",
diff --git a/audio/aidl/default/volume/Android.bp b/audio/aidl/default/volume/Android.bp
index 418bb8d..f1a051f 100644
--- a/audio/aidl/default/volume/Android.bp
+++ b/audio/aidl/default/volume/Android.bp
@@ -27,8 +27,6 @@
     name: "libvolumesw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "VolumeSw.cpp",
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index 191f928..9b0e233 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -41,11 +41,21 @@
         "vts",
     ],
     srcs: [
-        ":effectCommonFile",
         "TestUtils.cpp",
     ],
 }
 
+cc_defaults {
+    name: "VtsHalAudioEffectTargetTestDefaults",
+    defaults: [
+        "latest_android_hardware_audio_effect_ndk_static",
+        "VtsHalAudioTargetTestDefaults",
+    ],
+    srcs: [
+        ":effectCommonFile",
+    ],
+}
+
 cc_test {
     name: "VtsHalAudioCoreTargetTest",
     defaults: [
@@ -66,25 +76,25 @@
 
 cc_test {
     name: "VtsHalAudioEffectFactoryTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalAudioEffectFactoryTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalAudioEffectTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalAudioEffectTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalBassBoostTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalBassBoostTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalDownmixTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalDownmixTargetTest.cpp"],
     shared_libs: [
         "libaudioutils",
@@ -93,79 +103,85 @@
 
 cc_test {
     name: "VtsHalDynamicsProcessingTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     static_libs: ["libaudioaidlranges"],
     srcs: ["VtsHalDynamicsProcessingTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalEnvironmentalReverbTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalEnvironmentalReverbTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalEqualizerTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalEqualizerTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalHapticGeneratorTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalHapticGeneratorTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalLoudnessEnhancerTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalLoudnessEnhancerTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalPresetReverbTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalPresetReverbTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalVirtualizerTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalVirtualizerTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalVisualizerTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalVisualizerTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalVolumeTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalVolumeTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalAECTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalAECTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalAGC1TargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalAGC1TargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalAGC2TargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalAGC2TargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalNSTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalNSTargetTest.cpp"],
 }
+
+cc_test {
+    name: "VtsHalSpatializerTargetTest",
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
+    srcs: ["VtsHalSpatializerTargetTest.cpp"],
+}
diff --git a/audio/aidl/vts/EffectFactoryHelper.h b/audio/aidl/vts/EffectFactoryHelper.h
index a2499fd..ca36655 100644
--- a/audio/aidl/vts/EffectFactoryHelper.h
+++ b/audio/aidl/vts/EffectFactoryHelper.h
@@ -21,6 +21,7 @@
 #include <unordered_map>
 #include <vector>
 
+#include <aidl/Vintf.h>
 #include <android/binder_auto_utils.h>
 
 #include "TestUtils.h"
diff --git a/audio/aidl/vts/EffectHelper.h b/audio/aidl/vts/EffectHelper.h
index d813554..4a5c537 100644
--- a/audio/aidl/vts/EffectHelper.h
+++ b/audio/aidl/vts/EffectHelper.h
@@ -21,6 +21,7 @@
 #include <string>
 #include <type_traits>
 #include <unordered_map>
+#include <utility>
 #include <vector>
 
 #include <Utils.h>
@@ -263,12 +264,11 @@
         return s;
     }
 
-    template <typename T, typename S, Range::Tag R, typename T::Tag tag, typename Functor>
+    template <typename T, typename S, Range::Tag R, typename T::Tag tag>
     static std::set<S> getTestValueSet(
-            std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kFactoryDescList,
-            Functor functor) {
+            std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> descList) {
         std::set<S> result;
-        for (const auto& [_, desc] : kFactoryDescList) {
+        for (const auto& [_, desc] : descList) {
             if (desc.capability.range.getTag() == R) {
                 const auto& ranges = desc.capability.range.get<R>();
                 for (const auto& range : ranges) {
@@ -281,6 +281,14 @@
                 }
             }
         }
+        return result;
+    }
+
+    template <typename T, typename S, Range::Tag R, typename T::Tag tag, typename Functor>
+    static std::set<S> getTestValueSet(
+            std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> descList,
+            Functor functor) {
+        auto result = getTestValueSet<T, S, R, tag>(descList);
         return functor(result);
     }
 
diff --git a/audio/aidl/vts/VtsHalAECTargetTest.cpp b/audio/aidl/vts/VtsHalAECTargetTest.cpp
index 39168b1..f972b84 100644
--- a/audio/aidl/vts/VtsHalAECTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAECTargetTest.cpp
@@ -18,7 +18,6 @@
 #include <string>
 #include <unordered_set>
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalAECParamTest"
 #include <android-base/logging.h>
 
diff --git a/audio/aidl/vts/VtsHalAGC1TargetTest.cpp b/audio/aidl/vts/VtsHalAGC1TargetTest.cpp
index 6066025..75da589 100644
--- a/audio/aidl/vts/VtsHalAGC1TargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAGC1TargetTest.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalAGC1ParamTest"
 #include <android-base/logging.h>
 
diff --git a/audio/aidl/vts/VtsHalAGC2TargetTest.cpp b/audio/aidl/vts/VtsHalAGC2TargetTest.cpp
index 8793e4c..5f57a88 100644
--- a/audio/aidl/vts/VtsHalAGC2TargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAGC2TargetTest.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalAGC2ParamTest"
 #include <android-base/logging.h>
 #include <android/binder_enums.h>
diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
index aaf9ad4..418fedb 100644
--- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -16,13 +16,11 @@
 
 #define LOG_TAG "VtsHalAudioEffectTargetTest"
 
-#include <chrono>
 #include <memory>
 #include <string>
 #include <vector>
 
 #include <aidl/Gtest.h>
-#include <aidl/Vintf.h>
 #include <aidl/android/hardware/audio/effect/IEffect.h>
 #include <aidl/android/hardware/audio/effect/IFactory.h>
 #include <android-base/logging.h>
diff --git a/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp b/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
index 2d9a233..135940d 100644
--- a/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
@@ -14,9 +14,6 @@
  * limitations under the License.
  */
 
-#include <limits.h>
-
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalBassBoostTest"
 #include <android-base/logging.h>
 
diff --git a/audio/aidl/vts/VtsHalDownmixTargetTest.cpp b/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
index d7db567..2272e92 100644
--- a/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalDownmixTargetTest"
 #include <android-base/logging.h>
 
diff --git a/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
index 2650f49..3f7a76d 100644
--- a/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
+++ b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
@@ -18,7 +18,6 @@
 #include <string>
 #include <unordered_set>
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalDynamicsProcessingTest"
 #include <android-base/logging.h>
 
diff --git a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
index 474b361..765c377 100644
--- a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalEnvironmentalReverbTest"
 #include <android-base/logging.h>
 
diff --git a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
index 09396d1..76838cef 100644
--- a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
@@ -15,15 +15,10 @@
  */
 
 #include <algorithm>
-#include <limits>
-#include <map>
-#include <memory>
-#include <optional>
 #include <string>
 #include <vector>
 
 #include <aidl/Gtest.h>
-#include <aidl/Vintf.h>
 #include <aidl/android/hardware/audio/effect/IEffect.h>
 #include <aidl/android/hardware/audio/effect/IFactory.h>
 #define LOG_TAG "VtsHalEqualizerTest"
diff --git a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
index 5a32398..d312111 100644
--- a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
@@ -18,7 +18,6 @@
 #include <utility>
 #include <vector>
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalHapticGeneratorTargetTest"
 #include <android-base/logging.h>
 #include <android/binder_enums.h>
diff --git a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
index 925f9ec..7f0091f 100644
--- a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
@@ -16,7 +16,6 @@
 
 #include <string>
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalLoudnessEnhancerTest"
 #include <android-base/logging.h>
 
diff --git a/audio/aidl/vts/VtsHalNSTargetTest.cpp b/audio/aidl/vts/VtsHalNSTargetTest.cpp
index 12d56b0..5c13512 100644
--- a/audio/aidl/vts/VtsHalNSTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalNSTargetTest.cpp
@@ -16,7 +16,6 @@
 
 #include <unordered_set>
 
-#include <aidl/Vintf.h>
 #include <aidl/android/hardware/audio/effect/NoiseSuppression.h>
 #define LOG_TAG "VtsHalNSParamTest"
 #include <android-base/logging.h>
diff --git a/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp b/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp
index 57eda09..1453495 100644
--- a/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalPresetReverbTargetTest"
 #include <android-base/logging.h>
 #include <android/binder_enums.h>
diff --git a/audio/aidl/vts/VtsHalSpatializerTargetTest.cpp b/audio/aidl/vts/VtsHalSpatializerTargetTest.cpp
new file mode 100644
index 0000000..f0b51b9
--- /dev/null
+++ b/audio/aidl/vts/VtsHalSpatializerTargetTest.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VtsHalSpatializerTest"
+#include <android-base/logging.h>
+
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::getEffectTypeUuidSpatializer;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::Parameter;
+using aidl::android::hardware::audio::effect::Range;
+using aidl::android::hardware::audio::effect::Spatializer;
+using aidl::android::media::audio::common::HeadTracking;
+using aidl::android::media::audio::common::Spatialization;
+using android::hardware::audio::common::testing::detail::TestExecutionTracer;
+using ::android::internal::ToString;
+
+enum ParamName {
+    PARAM_INSTANCE_NAME,
+    PARAM_SPATIALIZATION_LEVEL,
+    PARAM_SPATIALIZATION_MODE,
+    PARAM_HEADTRACK_SENSORID,
+    PARAM_HEADTRACK_MODE,
+    PARAM_HEADTRACK_CONNECTION_MODE
+};
+
+using SpatializerParamTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, Spatialization::Level,
+                   Spatialization::Mode, int /* sensor ID */, HeadTracking::Mode,
+                   HeadTracking::ConnectionMode>;
+
+class SpatializerParamTest : public ::testing::TestWithParam<SpatializerParamTestParam>,
+                             public EffectHelper {
+  public:
+    SpatializerParamTest()
+        : mSpatializerParams([&]() {
+              Spatialization::Level level = std::get<PARAM_SPATIALIZATION_LEVEL>(GetParam());
+              Spatialization::Mode mode = std::get<PARAM_SPATIALIZATION_MODE>(GetParam());
+              int sensorId = std::get<PARAM_HEADTRACK_SENSORID>(GetParam());
+              HeadTracking::Mode htMode = std::get<PARAM_HEADTRACK_MODE>(GetParam());
+              HeadTracking::ConnectionMode htConnectMode =
+                      std::get<PARAM_HEADTRACK_CONNECTION_MODE>(GetParam());
+              std::map<Spatializer::Tag, Spatializer> params;
+              params[Spatializer::spatializationLevel] =
+                      Spatializer::make<Spatializer::spatializationLevel>(level);
+              params[Spatializer::spatializationMode] =
+                      Spatializer::make<Spatializer::spatializationMode>(mode);
+              params[Spatializer::headTrackingSensorId] =
+                      Spatializer::make<Spatializer::headTrackingSensorId>(sensorId);
+              params[Spatializer::headTrackingMode] =
+                      Spatializer::make<Spatializer::headTrackingMode>(htMode);
+              params[Spatializer::headTrackingConnectionMode] =
+                      Spatializer::make<Spatializer::headTrackingConnectionMode>(htConnectMode);
+              return params;
+          }()) {
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    }
+
+    void SetUp() override {
+        ASSERT_NE(nullptr, mFactory);
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+        Parameter::Specific specific = getDefaultParamSpecific();
+        Parameter::Common common = EffectHelper::createParamCommon(
+                0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+        IEffect::OpenEffectReturn ret;
+        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+        ASSERT_NE(nullptr, mEffect);
+    }
+
+    void TearDown() override {
+        ASSERT_NO_FATAL_FAILURE(close(mEffect));
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+    }
+
+    Parameter::Specific getDefaultParamSpecific() {
+        Spatializer spatializer = Spatializer::make<Spatializer::headTrackingSensorId>(0);
+        Parameter::Specific specific =
+                Parameter::Specific::make<Parameter::Specific::spatializer>(spatializer);
+        return specific;
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+    const std::map<Spatializer::Tag, Spatializer> mSpatializerParams;
+};
+
+TEST_P(SpatializerParamTest, SetAndGetParam) {
+    for (const auto& it : mSpatializerParams) {
+        auto& tag = it.first;
+        auto& spatializer = it.second;
+
+        // validate parameter
+        Descriptor desc;
+        ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+        const bool valid = isParameterValid<Spatializer, Range::spatializer>(it.second, desc);
+        const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+        // set parameter
+        Parameter expectParam;
+        Parameter::Specific specific;
+        specific.set<Parameter::Specific::spatializer>(spatializer);
+        expectParam.set<Parameter::specific>(specific);
+        EXPECT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+        // only get if parameter in range and set success
+        if (expected == EX_NONE) {
+            Parameter getParam;
+            Parameter::Id id;
+            Spatializer::Id spatializerId;
+            spatializerId.set<Spatializer::Id::commonTag>(tag);
+            id.set<Parameter::Id::spatializerTag>(spatializerId);
+            // if set success, then get should match
+            EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
+            EXPECT_EQ(expectParam, getParam);
+        }
+    }
+}
+
+std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kDescPair;
+INSTANTIATE_TEST_SUITE_P(
+        SpatializerTest, SpatializerParamTest,
+        ::testing::Combine(
+                testing::ValuesIn(kDescPair = EffectFactoryHelper::getAllEffectDescriptors(
+                                          IFactory::descriptor, getEffectTypeUuidSpatializer())),
+                testing::ValuesIn(EffectHelper::getTestValueSet<
+                                  Spatializer, Spatialization::Level, Range::spatializer,
+                                  Spatializer::spatializationLevel>(kDescPair)),
+                testing::ValuesIn(EffectHelper::getTestValueSet<
+                                  Spatializer, Spatialization::Mode, Range::spatializer,
+                                  Spatializer::spatializationMode>(kDescPair)),
+                testing::ValuesIn(
+                        EffectHelper::getTestValueSet<Spatializer, int, Range::spatializer,
+                                                      Spatializer::headTrackingSensorId>(
+                                kDescPair, EffectHelper::expandTestValueBasic<int>)),
+                testing::ValuesIn(EffectHelper::getTestValueSet<
+                                  Spatializer, HeadTracking::Mode, Range::spatializer,
+                                  Spatializer::headTrackingMode>(kDescPair)),
+                testing::ValuesIn(EffectHelper::getTestValueSet<
+                                  Spatializer, HeadTracking::ConnectionMode, Range::spatializer,
+                                  Spatializer::headTrackingConnectionMode>(kDescPair))),
+        [](const testing::TestParamInfo<SpatializerParamTest::ParamType>& info) {
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string level = ToString(std::get<PARAM_SPATIALIZATION_LEVEL>(info.param));
+            std::string mode = ToString(std::get<PARAM_SPATIALIZATION_MODE>(info.param));
+            std::string sensorId = ToString(std::get<PARAM_HEADTRACK_SENSORID>(info.param));
+            std::string htMode = ToString(std::get<PARAM_HEADTRACK_MODE>(info.param));
+            std::string htConnectMode =
+                    ToString(std::get<PARAM_HEADTRACK_CONNECTION_MODE>(info.param));
+            std::string name = getPrefix(descriptor) + "_sensorID_" + level + "_mode_" + mode +
+                               "_sensorID_" + sensorId + "_HTMode_" + htMode +
+                               "_HTConnectionMode_" + htConnectMode;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SpatializerParamTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp b/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
index 3e39d3a..0c24f90 100644
--- a/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalVirtualizerTest"
 #include <android-base/logging.h>
 
diff --git a/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
index 1b8352b..db83715 100644
--- a/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
@@ -16,7 +16,6 @@
 
 #include <unordered_set>
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalVisualizerTest"
 #include <android-base/logging.h>
 #include <android/binder_enums.h>
diff --git a/audio/aidl/vts/VtsHalVolumeTargetTest.cpp b/audio/aidl/vts/VtsHalVolumeTargetTest.cpp
index 257100b..aa2c05f 100644
--- a/audio/aidl/vts/VtsHalVolumeTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalVolumeTargetTest.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalVolumeTest"
 #include <android-base/logging.h>
 
diff --git a/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl b/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl
index ccfa22d..5c5917b 100644
--- a/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl
+++ b/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl
@@ -41,9 +41,10 @@
   void clearRemoteTaskCallback();
   void notifyApStateChange(in android.hardware.automotive.remoteaccess.ApState state);
   boolean isTaskScheduleSupported();
+  android.hardware.automotive.remoteaccess.TaskType[] getSupportedTaskTypesForScheduling();
   void scheduleTask(in android.hardware.automotive.remoteaccess.ScheduleInfo scheduleInfo);
   void unscheduleTask(String clientId, String scheduleId);
   void unscheduleAllTasks(String clientId);
   boolean isTaskScheduled(String clientId, String scheduleId);
-  List<android.hardware.automotive.remoteaccess.ScheduleInfo> getAllScheduledTasks(String clientId);
+  List<android.hardware.automotive.remoteaccess.ScheduleInfo> getAllPendingScheduledTasks(String clientId);
 }
diff --git a/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/ScheduleInfo.aidl b/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/ScheduleInfo.aidl
index a929e10..a5d81cf 100644
--- a/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/ScheduleInfo.aidl
+++ b/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/ScheduleInfo.aidl
@@ -36,6 +36,7 @@
 parcelable ScheduleInfo {
   String clientId;
   String scheduleId;
+  android.hardware.automotive.remoteaccess.TaskType taskType;
   byte[] taskData;
   int count;
   long startTimeInEpochSeconds;
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl b/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/TaskType.aidl
similarity index 91%
copy from security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
copy to automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/TaskType.aidl
index cc07f9b..da70626 100644
--- a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
+++ b/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/TaskType.aidl
@@ -31,12 +31,9 @@
 // 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.security.secretkeeper;
-/* @hide */
+package android.hardware.automotive.remoteaccess;
 @Backing(type="int") @VintfStability
-enum ErrorCode {
-  OK = 0,
-  UNKNOWN_KEY_ID = 1,
-  INTERNAL_ERROR = 2,
-  REQUEST_MALFORMED = 3,
+enum TaskType {
+  CUSTOM = 0,
+  ENTER_GARAGE_MODE = 1,
 }
diff --git a/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl
index 4912651..705cdbd 100644
--- a/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl
+++ b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl
@@ -19,12 +19,39 @@
 import android.hardware.automotive.remoteaccess.ApState;
 import android.hardware.automotive.remoteaccess.IRemoteTaskCallback;
 import android.hardware.automotive.remoteaccess.ScheduleInfo;
+import android.hardware.automotive.remoteaccess.TaskType;
 
 /**
- * Interface representing a remote wakeup client.
+ * The remote access HAL.
  *
- * A wakeup client is a binary outside Android framework that communicates with
- * a wakeup server and receives wake up command.
+ * <p>This HAL represents an external system that is always on even when Android
+ * is powered off. It is capable of wakeing up and notifying Android when a
+ * remote task arrives.
+ *
+ * <p>For cloud-based remote access, a cloud server will issue the remote task
+ * to the external system, which will then be forwarded to Android. The client
+ * is expected to call {@code setRemoteTaskCallback} to register the remote
+ * task callback and uses the information returned from {@code getVehicleId},
+ * {@code getWakeupServiceName} and {@code getProcessorId} to register with
+ * a remote server.
+ *
+ * <p>For serverless remote access, the remote task comes from the external
+ * system alone and no server is involved. The external system may support
+ * scheduling a remote task to executed later through {@code scheduleTask}.
+ *
+ * <p>For both cloud-based and serverless remote access, the ideal use case
+ * is to wake up Android when the vehicle is not in use and then shutdown
+ * Android after the task is complete. However, user may access the vehicle
+ * during this period, and Android must not be shutdown if this happens.
+ *
+ * <p>If this interface is implemented, then VHAL property
+ * {@code VEHICLE_IN_USE} must be supported to represent whether the vehicle is
+ * currently in use. Android will check this before sending the shutdown
+ * request.
+ *
+ * <p>The external power controller system must also check whether vehicle is
+ * in use upon receiving the shutdown request and makes sure that an
+ * user-unexpected shutdown must not happen.
  */
 @VintfStability
 interface IRemoteAccess {
@@ -110,6 +137,17 @@
     boolean isTaskScheduleSupported();
 
     /**
+     * Returns the supported task types for scheduling.
+     *
+     * <p>If task scheduling is not supported, this returns an empty array.
+     *
+     * <p>Otherwise, at least {@code TaskType.CUSTOM} must be supported.
+     *
+     * @return An array of supported task types.
+     */
+    TaskType[] getSupportedTaskTypesForScheduling();
+
+    /**
      * Schedules a task to be executed later even when the vehicle is off.
      *
      * <p>If {@link isTaskScheduleSupported} returns {@code false}. This is no-op.
@@ -127,6 +165,8 @@
      *
      * <p>Must return {@code EX_ILLEGAL_ARGUMENT} if a pending schedule with the same
      * {@code scheduleId} for this client exists.
+     *
+     * <p>Must return {@code EX_ILLEGAL_ARGUMENT} if the task type is not supported.
      */
     void scheduleTask(in ScheduleInfo scheduleInfo);
 
@@ -161,5 +201,5 @@
      *
      * <p>The finished scheduled tasks will not be included.
      */
-    List<ScheduleInfo> getAllScheduledTasks(String clientId);
+    List<ScheduleInfo> getAllPendingScheduledTasks(String clientId);
 }
diff --git a/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteTaskCallback.aidl b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteTaskCallback.aidl
index 2cd7a5d..ee6f900 100644
--- a/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteTaskCallback.aidl
+++ b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteTaskCallback.aidl
@@ -22,7 +22,7 @@
 @VintfStability
 interface IRemoteTaskCallback {
     /**
-     * A callback that is called when a remote task is requested.
+     * A callback that is called when a custom type remote task is requested.
      *
      * The data is passed down from the remote server to the remote task client
      * which is an Android application, and is not interpreted/parsed by the
diff --git a/automotive/remoteaccess/android/hardware/automotive/remoteaccess/ScheduleInfo.aidl b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/ScheduleInfo.aidl
index cf1437b..40fba6f 100644
--- a/automotive/remoteaccess/android/hardware/automotive/remoteaccess/ScheduleInfo.aidl
+++ b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/ScheduleInfo.aidl
@@ -16,6 +16,8 @@
 
 package android.hardware.automotive.remoteaccess;
 
+import android.hardware.automotive.remoteaccess.TaskType;
+
 @VintfStability
 @JavaDerive(equals=true, toString=true)
 parcelable ScheduleInfo {
@@ -31,8 +33,14 @@
      */
     String scheduleId;
     /**
+     * The type for the task.
+     */
+    TaskType taskType;
+    /**
      * The opaque task data that will be sent back to the remote task client app when the task is
      * executed. It is not interpreted/parsed by the Android system.
+     *
+     * <p>This is only used for {@code TaskType.CUSTOM}.
      */
     byte[] taskData;
     /**
diff --git a/automotive/remoteaccess/android/hardware/automotive/remoteaccess/TaskType.aidl b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/TaskType.aidl
new file mode 100644
index 0000000..761eb15
--- /dev/null
+++ b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/TaskType.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 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.automotive.remoteaccess;
+
+@VintfStability
+@Backing(type="int")
+enum TaskType {
+    /**
+     * A custom task that is opaque to anyone other than the remote task client app.
+     *
+     * <p>The opaque task data in the {@code ScheduleInfo} will be sent back to the app when the
+     * task is to be executed.
+     */
+    CUSTOM = 0,
+    /**
+     * Enters the garage mode if allowed.
+     *
+     * <p>Make the Android system enters garage mode if vehicle is currently not in use and
+     * entering garage mode is allowed (e.g. battery level is high enough).
+     *
+     * <p>This is based on best-effort and it is not guaranteed.
+     *
+     * <p>If allowed, the external system should set {@code AP_POWER_BOOTUP_REASON} to
+     * {@code SYSTEM_ENTER_GARAGE_MODE} and then boot up (or resume) the head unit.
+     */
+    ENTER_GARAGE_MODE = 1,
+}
diff --git a/automotive/remoteaccess/hal/default/fuzzer/fuzzer.cpp b/automotive/remoteaccess/hal/default/fuzzer/fuzzer.cpp
index 9224ebc..7707ee6 100644
--- a/automotive/remoteaccess/hal/default/fuzzer/fuzzer.cpp
+++ b/automotive/remoteaccess/hal/default/fuzzer/fuzzer.cpp
@@ -75,8 +75,9 @@
         return Status::OK;
     }
 
-    Status GetAllScheduledTasks(ClientContext* context, const GetAllScheduledTasksRequest& request,
-                                GetAllScheduledTasksResponse* response) {
+    Status GetAllPendingScheduledTasks(ClientContext* context,
+                                       const GetAllPendingScheduledTasksRequest& request,
+                                       GetAllPendingScheduledTasksResponse* response) {
         return Status::OK;
     }
 
@@ -165,17 +166,19 @@
         return nullptr;
     }
 
-    ClientAsyncResponseReaderInterface<GetAllScheduledTasksResponse>* AsyncGetAllScheduledTasksRaw(
+    ClientAsyncResponseReaderInterface<GetAllPendingScheduledTasksResponse>*
+    AsyncGetAllPendingScheduledTasksRaw(
             [[maybe_unused]] ClientContext* context,
-            [[maybe_unused]] const GetAllScheduledTasksRequest& request,
+            [[maybe_unused]] const GetAllPendingScheduledTasksRequest& request,
             [[maybe_unused]] CompletionQueue* cq) {
         return nullptr;
     }
 
-    ClientAsyncResponseReaderInterface<GetAllScheduledTasksResponse>*
-    PrepareAsyncGetAllScheduledTasksRaw([[maybe_unused]] ClientContext* context,
-                                        [[maybe_unused]] const GetAllScheduledTasksRequest& request,
-                                        [[maybe_unused]] CompletionQueue* c) {
+    ClientAsyncResponseReaderInterface<GetAllPendingScheduledTasksResponse>*
+    PrepareAsyncGetAllPendingScheduledTasksRaw(
+            [[maybe_unused]] ClientContext* context,
+            [[maybe_unused]] const GetAllPendingScheduledTasksRequest& request,
+            [[maybe_unused]] CompletionQueue* c) {
         return nullptr;
     }
 };
diff --git a/automotive/remoteaccess/hal/default/include/RemoteAccessService.h b/automotive/remoteaccess/hal/default/include/RemoteAccessService.h
index 1fc4037..6266de8 100644
--- a/automotive/remoteaccess/hal/default/include/RemoteAccessService.h
+++ b/automotive/remoteaccess/hal/default/include/RemoteAccessService.h
@@ -81,6 +81,9 @@
 
     ndk::ScopedAStatus isTaskScheduleSupported(bool* out) override;
 
+    ndk::ScopedAStatus getSupportedTaskTypesForScheduling(
+            std::vector<aidl::android::hardware::automotive::remoteaccess::TaskType>* out) override;
+
     ndk::ScopedAStatus scheduleTask(
             const aidl::android::hardware::automotive::remoteaccess::ScheduleInfo& scheduleInfo)
             override;
@@ -93,7 +96,7 @@
     ndk::ScopedAStatus isTaskScheduled(const std::string& clientId, const std::string& scheduleId,
                                        bool* out) override;
 
-    ndk::ScopedAStatus getAllScheduledTasks(
+    ndk::ScopedAStatus getAllPendingScheduledTasks(
             const std::string& clientId,
             std::vector<aidl::android::hardware::automotive::remoteaccess::ScheduleInfo>* out)
             override;
diff --git a/automotive/remoteaccess/hal/default/proto/wakeup_client.proto b/automotive/remoteaccess/hal/default/proto/wakeup_client.proto
index e061016..14ba0a5 100644
--- a/automotive/remoteaccess/hal/default/proto/wakeup_client.proto
+++ b/automotive/remoteaccess/hal/default/proto/wakeup_client.proto
@@ -99,7 +99,8 @@
      *
      * <p>The finished scheduled tasks will not be included.
      */
-    rpc GetAllScheduledTasks(GetAllScheduledTasksRequest) returns (GetAllScheduledTasksResponse) {}
+    rpc GetAllPendingScheduledTasks(GetAllPendingScheduledTasksRequest)
+            returns (GetAllPendingScheduledTasksResponse) {}
 }
 
 message GetRemoteTasksRequest {}
@@ -154,10 +155,10 @@
     bool isTaskScheduled = 1;
 }
 
-message GetAllScheduledTasksRequest {
+message GetAllPendingScheduledTasksRequest {
     string clientId = 1;
 }
 
-message GetAllScheduledTasksResponse {
+message GetAllPendingScheduledTasksResponse {
     repeated GrpcScheduleInfo allScheduledTasks = 1;
 }
diff --git a/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp b/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
index 0944d86..2a7f209 100644
--- a/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
+++ b/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
@@ -40,6 +40,7 @@
 using ::aidl::android::hardware::automotive::remoteaccess::ApState;
 using ::aidl::android::hardware::automotive::remoteaccess::IRemoteTaskCallback;
 using ::aidl::android::hardware::automotive::remoteaccess::ScheduleInfo;
+using ::aidl::android::hardware::automotive::remoteaccess::TaskType;
 using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
 using ::android::base::Error;
 using ::android::base::ParseInt;
@@ -319,6 +320,13 @@
     return ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus RemoteAccessService::getSupportedTaskTypesForScheduling(
+        std::vector<TaskType>* out) {
+    // TODO(b/316233421): support ENTER_GARAGE_MODE type.
+    out->push_back(TaskType::CUSTOM);
+    return ScopedAStatus::ok();
+}
+
 ScopedAStatus RemoteAccessService::scheduleTask(const ScheduleInfo& scheduleInfo) {
     ClientContext context;
     ScheduleTaskRequest request = {};
@@ -391,13 +399,13 @@
     return ScopedAStatus::ok();
 }
 
-ScopedAStatus RemoteAccessService::getAllScheduledTasks(const std::string& clientId,
-                                                        std::vector<ScheduleInfo>* out) {
+ScopedAStatus RemoteAccessService::getAllPendingScheduledTasks(const std::string& clientId,
+                                                               std::vector<ScheduleInfo>* out) {
     ClientContext context;
-    GetAllScheduledTasksRequest request = {};
-    GetAllScheduledTasksResponse response = {};
+    GetAllPendingScheduledTasksRequest request = {};
+    GetAllPendingScheduledTasksResponse response = {};
     request.set_clientid(clientId);
-    Status status = mGrpcStub->GetAllScheduledTasks(&context, request, &response);
+    Status status = mGrpcStub->GetAllPendingScheduledTasks(&context, request, &response);
     if (!status.ok()) {
         return rpcStatusToScopedAStatus(status, "Failed to call isTaskScheduled");
     }
diff --git a/automotive/remoteaccess/hal/default/test/RemoteAccessServiceUnitTest.cpp b/automotive/remoteaccess/hal/default/test/RemoteAccessServiceUnitTest.cpp
index c0038c2..a46a983 100644
--- a/automotive/remoteaccess/hal/default/test/RemoteAccessServiceUnitTest.cpp
+++ b/automotive/remoteaccess/hal/default/test/RemoteAccessServiceUnitTest.cpp
@@ -48,6 +48,7 @@
 using ::aidl::android::hardware::automotive::remoteaccess::ApState;
 using ::aidl::android::hardware::automotive::remoteaccess::BnRemoteTaskCallback;
 using ::aidl::android::hardware::automotive::remoteaccess::ScheduleInfo;
+using ::aidl::android::hardware::automotive::remoteaccess::TaskType;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 
 using ::grpc::ClientAsyncReaderInterface;
@@ -61,6 +62,7 @@
 using ::ndk::ScopedAStatus;
 using ::testing::_;
 using ::testing::DoAll;
+using ::testing::ElementsAre;
 using ::testing::Return;
 using ::testing::SetArgPointee;
 
@@ -93,9 +95,9 @@
     MOCK_METHOD(Status, IsTaskScheduled,
                 (ClientContext * context, const IsTaskScheduledRequest& request,
                  IsTaskScheduledResponse* response));
-    MOCK_METHOD(Status, GetAllScheduledTasks,
-                (ClientContext * context, const GetAllScheduledTasksRequest& request,
-                 GetAllScheduledTasksResponse* response));
+    MOCK_METHOD(Status, GetAllPendingScheduledTasks,
+                (ClientContext * context, const GetAllPendingScheduledTasksRequest& request,
+                 GetAllPendingScheduledTasksResponse* response));
     // Async methods which we do not care.
     MOCK_METHOD(ClientAsyncReaderInterface<GetRemoteTasksResponse>*, AsyncGetRemoteTasksRaw,
                 (ClientContext * context, const GetRemoteTasksRequest& request, CompletionQueue* cq,
@@ -139,13 +141,13 @@
                 PrepareAsyncIsTaskScheduledRaw,
                 (ClientContext * context, const IsTaskScheduledRequest& request,
                  CompletionQueue* cq));
-    MOCK_METHOD(ClientAsyncResponseReaderInterface<GetAllScheduledTasksResponse>*,
-                AsyncGetAllScheduledTasksRaw,
-                (ClientContext * context, const GetAllScheduledTasksRequest& request,
+    MOCK_METHOD(ClientAsyncResponseReaderInterface<GetAllPendingScheduledTasksResponse>*,
+                AsyncGetAllPendingScheduledTasksRaw,
+                (ClientContext * context, const GetAllPendingScheduledTasksRequest& request,
                  CompletionQueue* cq));
-    MOCK_METHOD(ClientAsyncResponseReaderInterface<GetAllScheduledTasksResponse>*,
-                PrepareAsyncGetAllScheduledTasksRaw,
-                (ClientContext * context, const GetAllScheduledTasksRequest& request,
+    MOCK_METHOD(ClientAsyncResponseReaderInterface<GetAllPendingScheduledTasksResponse>*,
+                PrepareAsyncGetAllPendingScheduledTasksRaw,
+                (ClientContext * context, const GetAllPendingScheduledTasksRequest& request,
                  CompletionQueue* cq));
 };
 
@@ -434,6 +436,14 @@
     EXPECT_TRUE(out);
 }
 
+TEST_F(RemoteAccessServiceUnitTest, TestGetSupportedTaskTypesForScheduling) {
+    std::vector<TaskType> out;
+    ScopedAStatus status = getService()->getSupportedTaskTypesForScheduling(&out);
+
+    EXPECT_TRUE(status.isOk());
+    EXPECT_THAT(out, ElementsAre(TaskType::CUSTOM));
+}
+
 TEST_F(RemoteAccessServiceUnitTest, TestScheduleTask) {
     ScheduleTaskRequest grpcRequest = {};
     EXPECT_CALL(*getGrpcWakeupClientStub(), ScheduleTask)
@@ -563,13 +573,13 @@
     EXPECT_EQ(grpcRequest.scheduleid(), kTestScheduleId);
 }
 
-TEST_F(RemoteAccessServiceUnitTest, testGetAllScheduledTasks) {
+TEST_F(RemoteAccessServiceUnitTest, testGetAllPendingScheduledTasks) {
     std::vector<ScheduleInfo> result;
-    GetAllScheduledTasksRequest grpcRequest = {};
-    EXPECT_CALL(*getGrpcWakeupClientStub(), GetAllScheduledTasks)
+    GetAllPendingScheduledTasksRequest grpcRequest = {};
+    EXPECT_CALL(*getGrpcWakeupClientStub(), GetAllPendingScheduledTasks)
             .WillOnce([&grpcRequest]([[maybe_unused]] ClientContext* context,
-                                     const GetAllScheduledTasksRequest& request,
-                                     GetAllScheduledTasksResponse* response) {
+                                     const GetAllPendingScheduledTasksRequest& request,
+                                     GetAllPendingScheduledTasksResponse* response) {
                 grpcRequest = request;
                 GrpcScheduleInfo* newInfo = response->add_allscheduledtasks();
                 newInfo->set_clientid(kTestClientId);
@@ -581,7 +591,7 @@
                 return Status();
             });
 
-    ScopedAStatus status = getService()->getAllScheduledTasks(kTestClientId, &result);
+    ScopedAStatus status = getService()->getAllPendingScheduledTasks(kTestClientId, &result);
 
     ASSERT_TRUE(status.isOk());
     EXPECT_EQ(grpcRequest.clientid(), kTestClientId);
diff --git a/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.h b/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.h
index 2aab904..a7f47c2 100644
--- a/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.h
+++ b/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.h
@@ -138,9 +138,9 @@
                                  const IsTaskScheduledRequest* request,
                                  IsTaskScheduledResponse* response) override;
 
-    grpc::Status GetAllScheduledTasks(grpc::ServerContext* context,
-                                      const GetAllScheduledTasksRequest* request,
-                                      GetAllScheduledTasksResponse* response) override;
+    grpc::Status GetAllPendingScheduledTasks(
+            grpc::ServerContext* context, const GetAllPendingScheduledTasksRequest* request,
+            GetAllPendingScheduledTasksResponse* response) override;
 
     /**
      * Starts generating fake tasks for the specific client repeatedly.
diff --git a/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp b/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp
index 1db991c..d223353 100644
--- a/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp
+++ b/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp
@@ -469,11 +469,11 @@
     return Status::OK;
 }
 
-Status TestWakeupClientServiceImpl::GetAllScheduledTasks(ServerContext* context,
-                                                         const GetAllScheduledTasksRequest* request,
-                                                         GetAllScheduledTasksResponse* response) {
+Status TestWakeupClientServiceImpl::GetAllPendingScheduledTasks(
+        ServerContext* context, const GetAllPendingScheduledTasksRequest* request,
+        GetAllPendingScheduledTasksResponse* response) {
     const std::string& clientId = request->clientid();
-    printf("GetAllScheduledTasks called with client Id: %s\n", clientId.c_str());
+    printf("GetAllPendingScheduledTasks called with client Id: %s\n", clientId.c_str());
     response->clear_allscheduledtasks();
     {
         std::unique_lock lk(mLock);
diff --git a/automotive/remoteaccess/test_grpc_server/impl/test/TestWakeupClientServiceImplUnitTest.cpp b/automotive/remoteaccess/test_grpc_server/impl/test/TestWakeupClientServiceImplUnitTest.cpp
index 960020d..63458ae 100644
--- a/automotive/remoteaccess/test_grpc_server/impl/test/TestWakeupClientServiceImplUnitTest.cpp
+++ b/automotive/remoteaccess/test_grpc_server/impl/test/TestWakeupClientServiceImplUnitTest.cpp
@@ -280,7 +280,7 @@
     EXPECT_EQ(getRemoteTaskResponses().size(), 0);
 }
 
-TEST_F(TestWakeupClientServiceImplUnitTest, TestGetAllScheduledTasks) {
+TEST_F(TestWakeupClientServiceImplUnitTest, TestGetAllPendingScheduledTasks) {
     std::string scheduleId1 = "scheduleId1";
     std::string scheduleId2 = "scheduleId2";
     int64_t time1 = getNow();
@@ -296,19 +296,19 @@
     ASSERT_TRUE(status.ok());
 
     ClientContext context;
-    GetAllScheduledTasksRequest request;
-    GetAllScheduledTasksResponse response;
+    GetAllPendingScheduledTasksRequest request;
+    GetAllPendingScheduledTasksResponse response;
     request.set_clientid("invalid client Id");
-    status = getStub()->GetAllScheduledTasks(&context, request, &response);
+    status = getStub()->GetAllPendingScheduledTasks(&context, request, &response);
 
     ASSERT_TRUE(status.ok());
     EXPECT_EQ(response.allscheduledtasks_size(), 0);
 
     ClientContext context2;
-    GetAllScheduledTasksRequest request2;
-    GetAllScheduledTasksResponse response2;
+    GetAllPendingScheduledTasksRequest request2;
+    GetAllPendingScheduledTasksResponse response2;
     request2.set_clientid(kTestClientId);
-    status = getStub()->GetAllScheduledTasks(&context2, request2, &response2);
+    status = getStub()->GetAllPendingScheduledTasks(&context2, request2, &response2);
 
     ASSERT_TRUE(status.ok());
     ASSERT_EQ(response2.allscheduledtasks_size(), 2);
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp b/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
index c16b29a..03a9df5 100644
--- a/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
@@ -30,7 +30,7 @@
 
 std::unique_ptr<VehiclePropValue> createVehiclePropValue(
     VehiclePropertyType type, size_t vecSize) {
-    auto val = std::unique_ptr<VehiclePropValue>(new VehiclePropValue);
+    auto val = std::unique_ptr<VehiclePropValue>(new VehiclePropValue());
     switch (type) {
         case VehiclePropertyType::INT32:      // fall through
         case VehiclePropertyType::INT32_VEC:  // fall through
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SubscribeOptions.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SubscribeOptions.aidl
index 69f6190..14469b5 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SubscribeOptions.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SubscribeOptions.aidl
@@ -45,8 +45,8 @@
      *
      * This value indicates the resolution at which continuous property updates should be sent to
      * the platform. For example, if resolution is 0.01, the subscribed property value should be
-     * rounded to two decimal places. If the incoming resolution value is not an integer multiple of
-     * 10, VHAL should return a StatusCode::INVALID_ARG.
+     * rounded to two decimal places. If the incoming resolution value is not an integer power of
+     * 10 (i.e. 10^-2, 10^-1, 10^2, etc.), VHAL should return a StatusCode::INVALID_ARG.
      */
     float resolution = 0.0f;
 
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
index e7d4464..15056e2 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
@@ -22,8 +22,7 @@
 
 // clang-format off
 
-#ifndef android_hardware_automotive_vehicle_aidl_generated_lib_AccessForVehicleProperty_H_
-#define android_hardware_automotive_vehicle_aidl_generated_lib_AccessForVehicleProperty_H_
+#pragma once
 
 #include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
 #include <aidl/android/hardware/automotive/vehicle/VehiclePropertyAccess.h>
@@ -125,6 +124,7 @@
         {VehicleProperty::DISPLAY_BRIGHTNESS, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::PER_DISPLAY_BRIGHTNESS, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::VALET_MODE_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::HEAD_UP_DISPLAY_ENABLED, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::HW_KEY_INPUT, VehiclePropertyAccess::READ},
         {VehicleProperty::HW_KEY_INPUT_V2, VehiclePropertyAccess::READ},
         {VehicleProperty::HW_MOTION_INPUT, VehiclePropertyAccess::READ},
@@ -204,6 +204,7 @@
         {VehicleProperty::ULTRASONICS_SENSOR_FIELD_OF_VIEW, VehiclePropertyAccess::READ},
         {VehicleProperty::ULTRASONICS_SENSOR_DETECTION_RANGE, VehiclePropertyAccess::READ},
         {VehicleProperty::ULTRASONICS_SENSOR_SUPPORTED_RANGES, VehiclePropertyAccess::READ},
+        {VehicleProperty::ULTRASONICS_SENSOR_MEASURED_DISTANCE, VehiclePropertyAccess::READ},
         {VehicleProperty::OBD2_LIVE_FRAME, VehiclePropertyAccess::READ},
         {VehicleProperty::OBD2_FREEZE_FRAME, VehiclePropertyAccess::READ},
         {VehicleProperty::OBD2_FREEZE_FRAME_INFO, VehiclePropertyAccess::READ},
@@ -298,6 +299,8 @@
         {VehicleProperty::LOW_SPEED_COLLISION_WARNING_STATE, VehiclePropertyAccess::READ},
         {VehicleProperty::CROSS_TRAFFIC_MONITORING_ENABLED, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::CROSS_TRAFFIC_MONITORING_WARNING_STATE, VehiclePropertyAccess::READ},
+        {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyAccess::READ},
 };
 
 }  // namespace vehicle
@@ -305,5 +308,3 @@
 }  // namespace hardware
 }  // namespace android
 }  // aidl
-
-#endif  // android_hardware_automotive_vehicle_aidl_generated_lib_AccessForVehicleProperty_H_
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
index 3a46a92..d3f97e3 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
@@ -22,8 +22,7 @@
 
 // clang-format off
 
-#ifndef android_hardware_automotive_vehicle_aidl_generated_lib_ChangeModeForVehicleProperty_H_
-#define android_hardware_automotive_vehicle_aidl_generated_lib_ChangeModeForVehicleProperty_H_
+#pragma once
 
 #include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
 #include <aidl/android/hardware/automotive/vehicle/VehiclePropertyChangeMode.h>
@@ -125,6 +124,7 @@
         {VehicleProperty::DISPLAY_BRIGHTNESS, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::PER_DISPLAY_BRIGHTNESS, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::VALET_MODE_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::HEAD_UP_DISPLAY_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::HW_KEY_INPUT, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::HW_KEY_INPUT_V2, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::HW_MOTION_INPUT, VehiclePropertyChangeMode::ON_CHANGE},
@@ -204,6 +204,7 @@
         {VehicleProperty::ULTRASONICS_SENSOR_FIELD_OF_VIEW, VehiclePropertyChangeMode::STATIC},
         {VehicleProperty::ULTRASONICS_SENSOR_DETECTION_RANGE, VehiclePropertyChangeMode::STATIC},
         {VehicleProperty::ULTRASONICS_SENSOR_SUPPORTED_RANGES, VehiclePropertyChangeMode::STATIC},
+        {VehicleProperty::ULTRASONICS_SENSOR_MEASURED_DISTANCE, VehiclePropertyChangeMode::CONTINUOUS},
         {VehicleProperty::OBD2_LIVE_FRAME, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::OBD2_FREEZE_FRAME, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::OBD2_FREEZE_FRAME_INFO, VehiclePropertyChangeMode::ON_CHANGE},
@@ -298,6 +299,8 @@
         {VehicleProperty::LOW_SPEED_COLLISION_WARNING_STATE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::CROSS_TRAFFIC_MONITORING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::CROSS_TRAFFIC_MONITORING_WARNING_STATE, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyChangeMode::ON_CHANGE},
 };
 
 }  // namespace vehicle
@@ -305,5 +308,3 @@
 }  // namespace hardware
 }  // namespace android
 }  // aidl
-
-#endif  // android_hardware_automotive_vehicle_aidl_generated_lib_ChangeModeForVehicleProperty_H_
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/VersionForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/VersionForVehicleProperty.h
new file mode 100644
index 0000000..70c914d
--- /dev/null
+++ b/automotive/vehicle/aidl/generated_lib/cpp/VersionForVehicleProperty.h
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+/**
+ * DO NOT EDIT MANUALLY!!!
+ *
+ * Generated by tools/generate_annotation_enums.py.
+ */
+
+// clang-format off
+
+#pragma once
+
+#include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
+
+#include <unordered_map>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+std::unordered_map<VehicleProperty, int32_t> VersionForVehicleProperty = {
+        {VehicleProperty::INFO_VIN, 2},
+        {VehicleProperty::INFO_MAKE, 2},
+        {VehicleProperty::INFO_MODEL, 2},
+        {VehicleProperty::INFO_MODEL_YEAR, 2},
+        {VehicleProperty::INFO_FUEL_CAPACITY, 2},
+        {VehicleProperty::INFO_FUEL_TYPE, 2},
+        {VehicleProperty::INFO_EV_BATTERY_CAPACITY, 2},
+        {VehicleProperty::INFO_EV_CONNECTOR_TYPE, 2},
+        {VehicleProperty::INFO_FUEL_DOOR_LOCATION, 2},
+        {VehicleProperty::INFO_EV_PORT_LOCATION, 2},
+        {VehicleProperty::INFO_DRIVER_SEAT, 2},
+        {VehicleProperty::INFO_EXTERIOR_DIMENSIONS, 2},
+        {VehicleProperty::INFO_MULTI_EV_PORT_LOCATIONS, 2},
+        {VehicleProperty::PERF_ODOMETER, 2},
+        {VehicleProperty::PERF_VEHICLE_SPEED, 2},
+        {VehicleProperty::PERF_VEHICLE_SPEED_DISPLAY, 2},
+        {VehicleProperty::PERF_STEERING_ANGLE, 2},
+        {VehicleProperty::PERF_REAR_STEERING_ANGLE, 2},
+        {VehicleProperty::ENGINE_COOLANT_TEMP, 2},
+        {VehicleProperty::ENGINE_OIL_LEVEL, 2},
+        {VehicleProperty::ENGINE_OIL_TEMP, 2},
+        {VehicleProperty::ENGINE_RPM, 2},
+        {VehicleProperty::WHEEL_TICK, 2},
+        {VehicleProperty::FUEL_LEVEL, 2},
+        {VehicleProperty::FUEL_DOOR_OPEN, 2},
+        {VehicleProperty::EV_BATTERY_LEVEL, 2},
+        {VehicleProperty::EV_CURRENT_BATTERY_CAPACITY, 2},
+        {VehicleProperty::EV_CHARGE_PORT_OPEN, 2},
+        {VehicleProperty::EV_CHARGE_PORT_CONNECTED, 2},
+        {VehicleProperty::EV_BATTERY_INSTANTANEOUS_CHARGE_RATE, 2},
+        {VehicleProperty::RANGE_REMAINING, 2},
+        {VehicleProperty::EV_BATTERY_AVERAGE_TEMPERATURE, 3},
+        {VehicleProperty::TIRE_PRESSURE, 2},
+        {VehicleProperty::CRITICALLY_LOW_TIRE_PRESSURE, 2},
+        {VehicleProperty::ENGINE_IDLE_AUTO_STOP_ENABLED, 2},
+        {VehicleProperty::IMPACT_DETECTED, 3},
+        {VehicleProperty::GEAR_SELECTION, 2},
+        {VehicleProperty::CURRENT_GEAR, 2},
+        {VehicleProperty::PARKING_BRAKE_ON, 2},
+        {VehicleProperty::PARKING_BRAKE_AUTO_APPLY, 2},
+        {VehicleProperty::EV_BRAKE_REGENERATION_LEVEL, 2},
+        {VehicleProperty::FUEL_LEVEL_LOW, 2},
+        {VehicleProperty::NIGHT_MODE, 2},
+        {VehicleProperty::TURN_SIGNAL_STATE, 2},
+        {VehicleProperty::IGNITION_STATE, 2},
+        {VehicleProperty::ABS_ACTIVE, 2},
+        {VehicleProperty::TRACTION_CONTROL_ACTIVE, 2},
+        {VehicleProperty::EV_STOPPING_MODE, 2},
+        {VehicleProperty::ELECTRONIC_STABILITY_CONTROL_ENABLED, 3},
+        {VehicleProperty::ELECTRONIC_STABILITY_CONTROL_STATE, 2},
+        {VehicleProperty::HVAC_FAN_SPEED, 2},
+        {VehicleProperty::HVAC_FAN_DIRECTION, 2},
+        {VehicleProperty::HVAC_TEMPERATURE_CURRENT, 2},
+        {VehicleProperty::HVAC_TEMPERATURE_SET, 2},
+        {VehicleProperty::HVAC_DEFROSTER, 2},
+        {VehicleProperty::HVAC_AC_ON, 2},
+        {VehicleProperty::HVAC_MAX_AC_ON, 2},
+        {VehicleProperty::HVAC_MAX_DEFROST_ON, 2},
+        {VehicleProperty::HVAC_RECIRC_ON, 2},
+        {VehicleProperty::HVAC_DUAL_ON, 2},
+        {VehicleProperty::HVAC_AUTO_ON, 2},
+        {VehicleProperty::HVAC_SEAT_TEMPERATURE, 2},
+        {VehicleProperty::HVAC_SIDE_MIRROR_HEAT, 2},
+        {VehicleProperty::HVAC_STEERING_WHEEL_HEAT, 2},
+        {VehicleProperty::HVAC_TEMPERATURE_DISPLAY_UNITS, 2},
+        {VehicleProperty::HVAC_ACTUAL_FAN_SPEED_RPM, 2},
+        {VehicleProperty::HVAC_POWER_ON, 2},
+        {VehicleProperty::HVAC_FAN_DIRECTION_AVAILABLE, 2},
+        {VehicleProperty::HVAC_AUTO_RECIRC_ON, 2},
+        {VehicleProperty::HVAC_SEAT_VENTILATION, 2},
+        {VehicleProperty::HVAC_ELECTRIC_DEFROSTER_ON, 2},
+        {VehicleProperty::HVAC_TEMPERATURE_VALUE_SUGGESTION, 2},
+        {VehicleProperty::DISTANCE_DISPLAY_UNITS, 2},
+        {VehicleProperty::FUEL_VOLUME_DISPLAY_UNITS, 2},
+        {VehicleProperty::TIRE_PRESSURE_DISPLAY_UNITS, 2},
+        {VehicleProperty::EV_BATTERY_DISPLAY_UNITS, 2},
+        {VehicleProperty::FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME, 2},
+        {VehicleProperty::VEHICLE_SPEED_DISPLAY_UNITS, 2},
+        {VehicleProperty::EXTERNAL_CAR_TIME, 2},
+        {VehicleProperty::ANDROID_EPOCH_TIME, 2},
+        {VehicleProperty::STORAGE_ENCRYPTION_BINDING_SEED, 2},
+        {VehicleProperty::ENV_OUTSIDE_TEMPERATURE, 2},
+        {VehicleProperty::AP_POWER_STATE_REQ, 2},
+        {VehicleProperty::AP_POWER_STATE_REPORT, 2},
+        {VehicleProperty::AP_POWER_BOOTUP_REASON, 2},
+        {VehicleProperty::DISPLAY_BRIGHTNESS, 2},
+        {VehicleProperty::PER_DISPLAY_BRIGHTNESS, 2},
+        {VehicleProperty::VALET_MODE_ENABLED, 3},
+        {VehicleProperty::HEAD_UP_DISPLAY_ENABLED, 3},
+        {VehicleProperty::HW_KEY_INPUT, 2},
+        {VehicleProperty::HW_KEY_INPUT_V2, 2},
+        {VehicleProperty::HW_MOTION_INPUT, 2},
+        {VehicleProperty::HW_ROTARY_INPUT, 2},
+        {VehicleProperty::HW_CUSTOM_INPUT, 2},
+        {VehicleProperty::DOOR_POS, 2},
+        {VehicleProperty::DOOR_MOVE, 2},
+        {VehicleProperty::DOOR_LOCK, 2},
+        {VehicleProperty::DOOR_CHILD_LOCK_ENABLED, 2},
+        {VehicleProperty::MIRROR_Z_POS, 2},
+        {VehicleProperty::MIRROR_Z_MOVE, 2},
+        {VehicleProperty::MIRROR_Y_POS, 2},
+        {VehicleProperty::MIRROR_Y_MOVE, 2},
+        {VehicleProperty::MIRROR_LOCK, 2},
+        {VehicleProperty::MIRROR_FOLD, 2},
+        {VehicleProperty::MIRROR_AUTO_FOLD_ENABLED, 2},
+        {VehicleProperty::MIRROR_AUTO_TILT_ENABLED, 2},
+        {VehicleProperty::SEAT_MEMORY_SELECT, 2},
+        {VehicleProperty::SEAT_MEMORY_SET, 2},
+        {VehicleProperty::SEAT_BELT_BUCKLED, 2},
+        {VehicleProperty::SEAT_BELT_HEIGHT_POS, 2},
+        {VehicleProperty::SEAT_BELT_HEIGHT_MOVE, 2},
+        {VehicleProperty::SEAT_FORE_AFT_POS, 2},
+        {VehicleProperty::SEAT_FORE_AFT_MOVE, 2},
+        {VehicleProperty::SEAT_BACKREST_ANGLE_1_POS, 2},
+        {VehicleProperty::SEAT_BACKREST_ANGLE_1_MOVE, 2},
+        {VehicleProperty::SEAT_BACKREST_ANGLE_2_POS, 2},
+        {VehicleProperty::SEAT_BACKREST_ANGLE_2_MOVE, 2},
+        {VehicleProperty::SEAT_HEIGHT_POS, 2},
+        {VehicleProperty::SEAT_HEIGHT_MOVE, 2},
+        {VehicleProperty::SEAT_DEPTH_POS, 2},
+        {VehicleProperty::SEAT_DEPTH_MOVE, 2},
+        {VehicleProperty::SEAT_TILT_POS, 2},
+        {VehicleProperty::SEAT_TILT_MOVE, 2},
+        {VehicleProperty::SEAT_LUMBAR_FORE_AFT_POS, 2},
+        {VehicleProperty::SEAT_LUMBAR_FORE_AFT_MOVE, 2},
+        {VehicleProperty::SEAT_LUMBAR_SIDE_SUPPORT_POS, 2},
+        {VehicleProperty::SEAT_LUMBAR_SIDE_SUPPORT_MOVE, 2},
+        {VehicleProperty::SEAT_HEADREST_HEIGHT_POS, 2},
+        {VehicleProperty::SEAT_HEADREST_HEIGHT_POS_V2, 2},
+        {VehicleProperty::SEAT_HEADREST_HEIGHT_MOVE, 2},
+        {VehicleProperty::SEAT_HEADREST_ANGLE_POS, 2},
+        {VehicleProperty::SEAT_HEADREST_ANGLE_MOVE, 2},
+        {VehicleProperty::SEAT_HEADREST_FORE_AFT_POS, 2},
+        {VehicleProperty::SEAT_HEADREST_FORE_AFT_MOVE, 2},
+        {VehicleProperty::SEAT_FOOTWELL_LIGHTS_STATE, 2},
+        {VehicleProperty::SEAT_FOOTWELL_LIGHTS_SWITCH, 2},
+        {VehicleProperty::SEAT_EASY_ACCESS_ENABLED, 2},
+        {VehicleProperty::SEAT_AIRBAG_ENABLED, 3},
+        {VehicleProperty::SEAT_AIRBAGS_DEPLOYED, 2},
+        {VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_POS, 2},
+        {VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_MOVE, 2},
+        {VehicleProperty::SEAT_LUMBAR_VERTICAL_POS, 2},
+        {VehicleProperty::SEAT_LUMBAR_VERTICAL_MOVE, 2},
+        {VehicleProperty::SEAT_WALK_IN_POS, 2},
+        {VehicleProperty::SEAT_BELT_PRETENSIONER_DEPLOYED, 3},
+        {VehicleProperty::SEAT_OCCUPANCY, 2},
+        {VehicleProperty::WINDOW_POS, 2},
+        {VehicleProperty::WINDOW_MOVE, 2},
+        {VehicleProperty::WINDOW_LOCK, 2},
+        {VehicleProperty::WINDSHIELD_WIPERS_PERIOD, 2},
+        {VehicleProperty::WINDSHIELD_WIPERS_STATE, 2},
+        {VehicleProperty::WINDSHIELD_WIPERS_SWITCH, 2},
+        {VehicleProperty::STEERING_WHEEL_DEPTH_POS, 2},
+        {VehicleProperty::STEERING_WHEEL_DEPTH_MOVE, 2},
+        {VehicleProperty::STEERING_WHEEL_HEIGHT_POS, 2},
+        {VehicleProperty::STEERING_WHEEL_HEIGHT_MOVE, 2},
+        {VehicleProperty::STEERING_WHEEL_THEFT_LOCK_ENABLED, 2},
+        {VehicleProperty::STEERING_WHEEL_LOCKED, 2},
+        {VehicleProperty::STEERING_WHEEL_EASY_ACCESS_ENABLED, 2},
+        {VehicleProperty::GLOVE_BOX_DOOR_POS, 2},
+        {VehicleProperty::GLOVE_BOX_LOCKED, 2},
+        {VehicleProperty::VEHICLE_MAP_SERVICE, 2},
+        {VehicleProperty::LOCATION_CHARACTERIZATION, 2},
+        {VehicleProperty::ULTRASONICS_SENSOR_POSITION, 3},
+        {VehicleProperty::ULTRASONICS_SENSOR_ORIENTATION, 3},
+        {VehicleProperty::ULTRASONICS_SENSOR_FIELD_OF_VIEW, 3},
+        {VehicleProperty::ULTRASONICS_SENSOR_DETECTION_RANGE, 3},
+        {VehicleProperty::ULTRASONICS_SENSOR_SUPPORTED_RANGES, 3},
+        {VehicleProperty::ULTRASONICS_SENSOR_MEASURED_DISTANCE, 3},
+        {VehicleProperty::OBD2_LIVE_FRAME, 2},
+        {VehicleProperty::OBD2_FREEZE_FRAME, 2},
+        {VehicleProperty::OBD2_FREEZE_FRAME_INFO, 2},
+        {VehicleProperty::OBD2_FREEZE_FRAME_CLEAR, 2},
+        {VehicleProperty::HEADLIGHTS_STATE, 2},
+        {VehicleProperty::HIGH_BEAM_LIGHTS_STATE, 2},
+        {VehicleProperty::FOG_LIGHTS_STATE, 2},
+        {VehicleProperty::HAZARD_LIGHTS_STATE, 2},
+        {VehicleProperty::HEADLIGHTS_SWITCH, 2},
+        {VehicleProperty::HIGH_BEAM_LIGHTS_SWITCH, 2},
+        {VehicleProperty::FOG_LIGHTS_SWITCH, 2},
+        {VehicleProperty::HAZARD_LIGHTS_SWITCH, 2},
+        {VehicleProperty::CABIN_LIGHTS_STATE, 2},
+        {VehicleProperty::CABIN_LIGHTS_SWITCH, 2},
+        {VehicleProperty::READING_LIGHTS_STATE, 2},
+        {VehicleProperty::READING_LIGHTS_SWITCH, 2},
+        {VehicleProperty::STEERING_WHEEL_LIGHTS_STATE, 2},
+        {VehicleProperty::STEERING_WHEEL_LIGHTS_SWITCH, 2},
+        {VehicleProperty::SUPPORT_CUSTOMIZE_VENDOR_PERMISSION, 2},
+        {VehicleProperty::DISABLED_OPTIONAL_FEATURES, 2},
+        {VehicleProperty::INITIAL_USER_INFO, 2},
+        {VehicleProperty::SWITCH_USER, 2},
+        {VehicleProperty::CREATE_USER, 2},
+        {VehicleProperty::REMOVE_USER, 2},
+        {VehicleProperty::USER_IDENTIFICATION_ASSOCIATION, 2},
+        {VehicleProperty::EVS_SERVICE_REQUEST, 2},
+        {VehicleProperty::POWER_POLICY_REQ, 2},
+        {VehicleProperty::POWER_POLICY_GROUP_REQ, 2},
+        {VehicleProperty::CURRENT_POWER_POLICY, 2},
+        {VehicleProperty::WATCHDOG_ALIVE, 2},
+        {VehicleProperty::WATCHDOG_TERMINATED_PROCESS, 2},
+        {VehicleProperty::VHAL_HEARTBEAT, 2},
+        {VehicleProperty::CLUSTER_SWITCH_UI, 2},
+        {VehicleProperty::CLUSTER_DISPLAY_STATE, 2},
+        {VehicleProperty::CLUSTER_REPORT_STATE, 2},
+        {VehicleProperty::CLUSTER_REQUEST_DISPLAY, 2},
+        {VehicleProperty::CLUSTER_NAVIGATION_STATE, 2},
+        {VehicleProperty::ELECTRONIC_TOLL_COLLECTION_CARD_TYPE, 2},
+        {VehicleProperty::ELECTRONIC_TOLL_COLLECTION_CARD_STATUS, 2},
+        {VehicleProperty::FRONT_FOG_LIGHTS_STATE, 2},
+        {VehicleProperty::FRONT_FOG_LIGHTS_SWITCH, 2},
+        {VehicleProperty::REAR_FOG_LIGHTS_STATE, 2},
+        {VehicleProperty::REAR_FOG_LIGHTS_SWITCH, 2},
+        {VehicleProperty::EV_CHARGE_CURRENT_DRAW_LIMIT, 2},
+        {VehicleProperty::EV_CHARGE_PERCENT_LIMIT, 2},
+        {VehicleProperty::EV_CHARGE_STATE, 2},
+        {VehicleProperty::EV_CHARGE_SWITCH, 2},
+        {VehicleProperty::EV_CHARGE_TIME_REMAINING, 2},
+        {VehicleProperty::EV_REGENERATIVE_BRAKING_STATE, 2},
+        {VehicleProperty::TRAILER_PRESENT, 2},
+        {VehicleProperty::VEHICLE_CURB_WEIGHT, 2},
+        {VehicleProperty::GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT, 2},
+        {VehicleProperty::SUPPORTED_PROPERTY_IDS, 2},
+        {VehicleProperty::SHUTDOWN_REQUEST, 2},
+        {VehicleProperty::VEHICLE_IN_USE, 2},
+        {VehicleProperty::CLUSTER_HEARTBEAT, 3},
+        {VehicleProperty::VEHICLE_DRIVING_AUTOMATION_CURRENT_LEVEL, 3},
+        {VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_ENABLED, 2},
+        {VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_STATE, 2},
+        {VehicleProperty::FORWARD_COLLISION_WARNING_ENABLED, 2},
+        {VehicleProperty::FORWARD_COLLISION_WARNING_STATE, 2},
+        {VehicleProperty::BLIND_SPOT_WARNING_ENABLED, 2},
+        {VehicleProperty::BLIND_SPOT_WARNING_STATE, 2},
+        {VehicleProperty::LANE_DEPARTURE_WARNING_ENABLED, 2},
+        {VehicleProperty::LANE_DEPARTURE_WARNING_STATE, 2},
+        {VehicleProperty::LANE_KEEP_ASSIST_ENABLED, 2},
+        {VehicleProperty::LANE_KEEP_ASSIST_STATE, 2},
+        {VehicleProperty::LANE_CENTERING_ASSIST_ENABLED, 2},
+        {VehicleProperty::LANE_CENTERING_ASSIST_COMMAND, 2},
+        {VehicleProperty::LANE_CENTERING_ASSIST_STATE, 2},
+        {VehicleProperty::EMERGENCY_LANE_KEEP_ASSIST_ENABLED, 2},
+        {VehicleProperty::EMERGENCY_LANE_KEEP_ASSIST_STATE, 2},
+        {VehicleProperty::CRUISE_CONTROL_ENABLED, 2},
+        {VehicleProperty::CRUISE_CONTROL_TYPE, 2},
+        {VehicleProperty::CRUISE_CONTROL_STATE, 2},
+        {VehicleProperty::CRUISE_CONTROL_COMMAND, 2},
+        {VehicleProperty::CRUISE_CONTROL_TARGET_SPEED, 2},
+        {VehicleProperty::ADAPTIVE_CRUISE_CONTROL_TARGET_TIME_GAP, 2},
+        {VehicleProperty::ADAPTIVE_CRUISE_CONTROL_LEAD_VEHICLE_MEASURED_DISTANCE, 2},
+        {VehicleProperty::HANDS_ON_DETECTION_ENABLED, 2},
+        {VehicleProperty::HANDS_ON_DETECTION_DRIVER_STATE, 2},
+        {VehicleProperty::HANDS_ON_DETECTION_WARNING, 2},
+        {VehicleProperty::DRIVER_DROWSINESS_ATTENTION_SYSTEM_ENABLED, 3},
+        {VehicleProperty::DRIVER_DROWSINESS_ATTENTION_STATE, 3},
+        {VehicleProperty::DRIVER_DROWSINESS_ATTENTION_WARNING_ENABLED, 3},
+        {VehicleProperty::DRIVER_DROWSINESS_ATTENTION_WARNING, 3},
+        {VehicleProperty::DRIVER_DISTRACTION_SYSTEM_ENABLED, 3},
+        {VehicleProperty::DRIVER_DISTRACTION_STATE, 3},
+        {VehicleProperty::DRIVER_DISTRACTION_WARNING_ENABLED, 2},
+        {VehicleProperty::DRIVER_DISTRACTION_WARNING, 3},
+        {VehicleProperty::LOW_SPEED_COLLISION_WARNING_ENABLED, 3},
+        {VehicleProperty::LOW_SPEED_COLLISION_WARNING_STATE, 3},
+        {VehicleProperty::CROSS_TRAFFIC_MONITORING_ENABLED, 3},
+        {VehicleProperty::CROSS_TRAFFIC_MONITORING_WARNING_STATE, 3},
+        {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED, 3},
+        {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, 3},
+};
+
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+}  // aidl
diff --git a/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
index 7b5412f..e55f4dc 100644
--- a/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
@@ -117,6 +117,7 @@
         Map.entry(VehicleProperty.DISPLAY_BRIGHTNESS, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.PER_DISPLAY_BRIGHTNESS, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.VALET_MODE_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.HEAD_UP_DISPLAY_ENABLED, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.HW_KEY_INPUT, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.HW_KEY_INPUT_V2, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.HW_MOTION_INPUT, VehiclePropertyAccess.READ),
@@ -196,6 +197,7 @@
         Map.entry(VehicleProperty.ULTRASONICS_SENSOR_FIELD_OF_VIEW, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.ULTRASONICS_SENSOR_DETECTION_RANGE, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.ULTRASONICS_SENSOR_SUPPORTED_RANGES, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.ULTRASONICS_SENSOR_MEASURED_DISTANCE, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.OBD2_LIVE_FRAME, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.OBD2_FREEZE_FRAME, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.OBD2_FREEZE_FRAME_INFO, VehiclePropertyAccess.READ),
@@ -289,7 +291,9 @@
         Map.entry(VehicleProperty.LOW_SPEED_COLLISION_WARNING_ENABLED, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.LOW_SPEED_COLLISION_WARNING_STATE, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.CROSS_TRAFFIC_MONITORING_ENABLED, VehiclePropertyAccess.READ_WRITE),
-        Map.entry(VehicleProperty.CROSS_TRAFFIC_MONITORING_WARNING_STATE, VehiclePropertyAccess.READ)
+        Map.entry(VehicleProperty.CROSS_TRAFFIC_MONITORING_WARNING_STATE, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyAccess.READ)
     );
 
 }
diff --git a/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
index 4fe45ef..e351a3f 100644
--- a/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
@@ -117,6 +117,7 @@
         Map.entry(VehicleProperty.DISPLAY_BRIGHTNESS, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.PER_DISPLAY_BRIGHTNESS, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.VALET_MODE_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.HEAD_UP_DISPLAY_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.HW_KEY_INPUT, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.HW_KEY_INPUT_V2, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.HW_MOTION_INPUT, VehiclePropertyChangeMode.ON_CHANGE),
@@ -196,6 +197,7 @@
         Map.entry(VehicleProperty.ULTRASONICS_SENSOR_FIELD_OF_VIEW, VehiclePropertyChangeMode.STATIC),
         Map.entry(VehicleProperty.ULTRASONICS_SENSOR_DETECTION_RANGE, VehiclePropertyChangeMode.STATIC),
         Map.entry(VehicleProperty.ULTRASONICS_SENSOR_SUPPORTED_RANGES, VehiclePropertyChangeMode.STATIC),
+        Map.entry(VehicleProperty.ULTRASONICS_SENSOR_MEASURED_DISTANCE, VehiclePropertyChangeMode.CONTINUOUS),
         Map.entry(VehicleProperty.OBD2_LIVE_FRAME, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.OBD2_FREEZE_FRAME, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.OBD2_FREEZE_FRAME_INFO, VehiclePropertyChangeMode.ON_CHANGE),
@@ -289,7 +291,9 @@
         Map.entry(VehicleProperty.LOW_SPEED_COLLISION_WARNING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.LOW_SPEED_COLLISION_WARNING_STATE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.CROSS_TRAFFIC_MONITORING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
-        Map.entry(VehicleProperty.CROSS_TRAFFIC_MONITORING_WARNING_STATE, VehiclePropertyChangeMode.ON_CHANGE)
+        Map.entry(VehicleProperty.CROSS_TRAFFIC_MONITORING_WARNING_STATE, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyChangeMode.ON_CHANGE)
     );
 
 }
diff --git a/automotive/vehicle/aidl/generated_lib/java/EnumForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/EnumForVehicleProperty.java
index b4f24a6..4b8060f 100644
--- a/automotive/vehicle/aidl/generated_lib/java/EnumForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/java/EnumForVehicleProperty.java
@@ -103,7 +103,8 @@
         Map.entry(VehicleProperty.DRIVER_DISTRACTION_STATE, List.of(DriverDistractionState.class, ErrorState.class)),
         Map.entry(VehicleProperty.DRIVER_DISTRACTION_WARNING, List.of(DriverDistractionWarning.class, ErrorState.class)),
         Map.entry(VehicleProperty.LOW_SPEED_COLLISION_WARNING_STATE, List.of(LowSpeedCollisionWarningState.class, ErrorState.class)),
-        Map.entry(VehicleProperty.CROSS_TRAFFIC_MONITORING_WARNING_STATE, List.of(CrossTrafficMonitoringWarningState.class, ErrorState.class))
+        Map.entry(VehicleProperty.CROSS_TRAFFIC_MONITORING_WARNING_STATE, List.of(CrossTrafficMonitoringWarningState.class, ErrorState.class)),
+        Map.entry(VehicleProperty.LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, List.of(LowSpeedAutomaticEmergencyBrakingState.class, ErrorState.class))
     );
 
 }
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
index 146da69..3e6e7dc 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
@@ -63,6 +63,7 @@
 using ::aidl::android::hardware::automotive::vehicle::LaneDepartureWarningState;
 using ::aidl::android::hardware::automotive::vehicle::LaneKeepAssistState;
 using ::aidl::android::hardware::automotive::vehicle::LocationCharacterization;
+using ::aidl::android::hardware::automotive::vehicle::LowSpeedAutomaticEmergencyBrakingState;
 using ::aidl::android::hardware::automotive::vehicle::LowSpeedCollisionWarningState;
 using ::aidl::android::hardware::automotive::vehicle::RawPropValues;
 using ::aidl::android::hardware::automotive::vehicle::VehicleAirbagLocation;
@@ -297,6 +298,8 @@
             std::make_unique<ConstantParser<ElectronicStabilityControlState>>();
     mConstantParsersByType["CrossTrafficMonitoringWarningState"] =
             std::make_unique<ConstantParser<CrossTrafficMonitoringWarningState>>();
+    mConstantParsersByType["LowSpeedAutomaticEmergencyBrakingState"] =
+            std::make_unique<ConstantParser<LowSpeedAutomaticEmergencyBrakingState>>();
     mConstantParsersByType["Constants"] = std::make_unique<LocalVariableParser>();
 #ifdef ENABLE_VEHICLE_HAL_TEST_PROPERTIES
     mConstantParsersByType["TestVendorProperty"] =
diff --git a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
index 665c10e..56d8b4b 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
+++ b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
@@ -3219,6 +3219,19 @@
             }
         },
         {
+            "property": "VehicleProperty::HEAD_UP_DISPLAY_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": "Constants::SEAT_1_LEFT"
+                }
+            ]
+        },
+        {
             "property": "VehicleProperty::OBD2_LIVE_FRAME",
             "configArray": [
                 0,
@@ -4191,6 +4204,36 @@
                     ]
                 }
             ]
+        },
+        {
+            "property": "VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    1
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE",
+            "defaultValue": {
+                "int32Values": [
+                    "LowSpeedAutomaticEmergencyBrakingState::ENABLED"
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": 0,
+                    "supportedEnumValues": [
+                        "ErrorState::NOT_AVAILABLE_SAFETY",
+                        "ErrorState::NOT_AVAILABLE_POOR_VISIBILITY",
+                        "ErrorState::NOT_AVAILABLE_SPEED_HIGH",
+                        "ErrorState::NOT_AVAILABLE_DISABLED",
+                        "LowSpeedAutomaticEmergencyBrakingState::ENABLED",
+                        "LowSpeedAutomaticEmergencyBrakingState::ACTIVATED",
+                        "LowSpeedAutomaticEmergencyBrakingState::USER_OVERRIDE"
+                    ]
+                }
+            ]
         }
     ]
 }
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index dced624..385f616 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -246,6 +246,13 @@
                         toInt(VehicleProperty::CROSS_TRAFFIC_MONITORING_WARNING_STATE),
                 },
         },
+        // LSAEB
+        {
+                toInt(VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED),
+                {
+                        toInt(VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE),
+                },
+        },
 };
 }  // namespace
 
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
index bbd88da..0c8ebbd 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
@@ -50,6 +50,7 @@
 #include <aidl/android/hardware/automotive/vehicle/LaneDepartureWarningState.h>
 #include <aidl/android/hardware/automotive/vehicle/LaneKeepAssistState.h>
 #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/Obd2CommonIgnitionMonitors.h>
 #include <aidl/android/hardware/automotive/vehicle/Obd2FuelSystemStatus.h>
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleObjectPool.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleObjectPool.h
index 6e812d1..501ce40 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleObjectPool.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleObjectPool.h
@@ -235,7 +235,7 @@
 
     bool isDisposable(aidl::android::hardware::automotive::vehicle::VehiclePropertyType type,
                       size_t vectorSize) const {
-        return vectorSize > mMaxRecyclableVectorSize || isComplexType(type);
+        return vectorSize == 0 || vectorSize > mMaxRecyclableVectorSize || isComplexType(type);
     }
 
     RecyclableType obtainDisposable(
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
index 546421e..523cac5 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
@@ -124,7 +124,6 @@
             break;  // Valid, but nothing to do.
         default:
             ALOGE("createVehiclePropValue: unknown type: %d", toInt(type));
-            val.reset(nullptr);
     }
     return val;
 }
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehicleObjectPool.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehicleObjectPool.cpp
index 2480a73..7e02767 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehicleObjectPool.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehicleObjectPool.cpp
@@ -55,13 +55,6 @@
     int propId = src.prop;
     VehiclePropertyType type = getPropType(propId);
     size_t vectorSize = getVehicleRawValueVectorSize(src.value, type);
-    if (vectorSize == 0 && !isComplexType(type)) {
-        ALOGW("empty vehicle prop value, contains no content");
-        ALOGW("empty vehicle prop value, contains no content, prop: %d", propId);
-        // Return any empty VehiclePropValue.
-        return RecyclableType{new VehiclePropValue{}, mDisposableDeleter};
-    }
-
     auto dest = obtain(type, vectorSize);
 
     dest->prop = propId;
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/VehicleObjectPoolTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/VehicleObjectPoolTest.cpp
index a62532c..6226e89 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/VehicleObjectPoolTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/VehicleObjectPoolTest.cpp
@@ -267,6 +267,20 @@
     ASSERT_EQ(*gotValue, prop);
 }
 
+TEST_F(VehicleObjectPoolTest, testObtainCopyInt32ValuesEmptyArray) {
+    VehiclePropValue prop{
+            // INT32_VEC property.
+            .prop = toInt(VehicleProperty::INFO_FUEL_TYPE),
+            .areaId = 2,
+            .timestamp = 3,
+            .value = {.int32Values = {}},
+    };
+    auto gotValue = mValuePool->obtain(prop);
+
+    ASSERT_NE(gotValue, nullptr);
+    ASSERT_EQ(*gotValue, prop);
+}
+
 TEST_F(VehicleObjectPoolTest, testObtainCopyInt64Values) {
     VehiclePropValue prop{
             // INT64_VEC property.
diff --git a/automotive/vehicle/aidl/impl/vhal/Android.bp b/automotive/vehicle/aidl/impl/vhal/Android.bp
index c29345f..20bba7f 100644
--- a/automotive/vehicle/aidl/impl/vhal/Android.bp
+++ b/automotive/vehicle/aidl/impl/vhal/Android.bp
@@ -61,6 +61,7 @@
     ],
     header_libs: [
         "IVehicleHardware",
+        "IVehicleGeneratedHeaders",
     ],
     shared_libs: [
         "libbinder_ndk",
diff --git a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
index f7a71b4..250b30c 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
@@ -49,6 +49,9 @@
 
     explicit DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware);
 
+    // Test-only
+    DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware, int32_t testInterfaceVersion);
+
     ~DefaultVehicleHal();
 
     ndk::ScopedAStatus getAllPropConfigs(
@@ -153,6 +156,8 @@
             mPropertyChangeEventsBatchingConsumer;
     // Only set once during initialization.
     std::chrono::nanoseconds mEventBatchingWindow;
+    // Only used for testing.
+    int32_t mTestInterfaceVersion = 0;
 
     std::mutex mLock;
     std::unordered_map<const AIBinder*, std::unique_ptr<OnBinderDiedContext>> mOnBinderDiedContexts
@@ -227,6 +232,8 @@
             std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
                     batchedEvents);
 
+    int32_t getVhalInterfaceVersion();
+
     // Puts the property change events into a queue so that they can handled in batch.
     static void batchPropertyChangeEvent(
             const std::weak_ptr<ConcurrentQueue<
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index 76d2f31..cc5edcc 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -22,6 +22,7 @@
 #include <LargeParcelableBase.h>
 #include <VehicleHalTypes.h>
 #include <VehicleUtils.h>
+#include <VersionForVehicleProperty.h>
 
 #include <android-base/result.h>
 #include <android-base/stringprintf.h>
@@ -61,6 +62,7 @@
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyChangeMode;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+using ::aidl::android::hardware::automotive::vehicle::VersionForVehicleProperty;
 using ::android::automotive::car_binder_lib::LargeParcelableBase;
 using ::android::base::Error;
 using ::android::base::expected;
@@ -94,8 +96,13 @@
 }  // namespace
 
 DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> vehicleHardware)
+    : DefaultVehicleHal(std::move(vehicleHardware), /* testInterfaceVersion= */ 0){};
+
+DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> vehicleHardware,
+                                     int32_t testInterfaceVersion)
     : mVehicleHardware(std::move(vehicleHardware)),
-      mPendingRequestPool(std::make_shared<PendingRequestPool>(TIMEOUT_IN_NANO)) {
+      mPendingRequestPool(std::make_shared<PendingRequestPool>(TIMEOUT_IN_NANO)),
+      mTestInterfaceVersion(testInterfaceVersion) {
     if (!getAllPropConfigsFromHardware()) {
         return;
     }
@@ -312,13 +319,46 @@
     mPendingRequestPool = std::make_unique<PendingRequestPool>(timeoutInNano);
 }
 
+int32_t DefaultVehicleHal::getVhalInterfaceVersion() {
+    if (mTestInterfaceVersion != 0) {
+        return mTestInterfaceVersion;
+    }
+    int32_t myVersion = 0;
+    getInterfaceVersion(&myVersion);
+    return myVersion;
+}
+
 bool DefaultVehicleHal::getAllPropConfigsFromHardware() {
     auto configs = mVehicleHardware->getAllPropertyConfigs();
+    std::vector<VehiclePropConfig> filteredConfigs;
+    int32_t myVersion = getVhalInterfaceVersion();
     for (auto& config : configs) {
+        if (!isSystemProp(config.prop)) {
+            filteredConfigs.push_back(std::move(config));
+            continue;
+        }
+        VehicleProperty property = static_cast<VehicleProperty>(config.prop);
+        std::string propertyName = aidl::android::hardware::automotive::vehicle::toString(property);
+        auto it = VersionForVehicleProperty.find(property);
+        if (it == VersionForVehicleProperty.end()) {
+            ALOGE("The property: %s is not a supported system property, ignore",
+                  propertyName.c_str());
+            continue;
+        }
+        int requiredVersion = it->second;
+        if (myVersion < requiredVersion) {
+            ALOGE("The property: %s is not supported for current client VHAL version, "
+                  "require %d, current version: %d, ignore",
+                  propertyName.c_str(), requiredVersion, myVersion);
+            continue;
+        }
+        filteredConfigs.push_back(std::move(config));
+    }
+    for (auto& config : filteredConfigs) {
         mConfigsByPropId[config.prop] = config;
     }
     VehiclePropConfigs vehiclePropConfigs;
-    vehiclePropConfigs.payloads = std::move(configs);
+    vehiclePropConfigs.payloads = std::move(filteredConfigs);
     auto result = LargeParcelableBase::parcelableToStableLargeParcelable(vehiclePropConfigs);
     if (!result.ok()) {
         ALOGE("failed to convert configs to shared memory file, error: %s, code: %d",
@@ -413,9 +453,9 @@
                     .status = getErrorCode(result),
                     .prop = {},
             });
-        } else {
-            hardwareRequests.push_back(request);
+            continue;
         }
+        hardwareRequests.push_back(request);
     }
 
     // The set of request Ids that we would send to hardware.
@@ -816,6 +856,7 @@
     if (!result.ok()) {
         return StatusError(StatusCode::INVALID_ARG) << getErrorMsg(result);
     }
+
     const VehiclePropConfig* config = result.value();
     const VehicleAreaConfig* areaConfig = getAreaConfig(value, *config);
 
@@ -900,6 +941,7 @@
     dprintf(fd, "Vehicle HAL State: \n");
     {
         std::scoped_lock<std::mutex> lockGuard(mLock);
+        dprintf(fd, "Interface version: %" PRId32 "\n", getVhalInterfaceVersion());
         dprintf(fd, "Containing %zu property configs\n", mConfigsByPropId.size());
         dprintf(fd, "Currently have %zu getValues clients\n", mGetValuesClients.size());
         dprintf(fd, "Currently have %zu setValues clients\n", mSetValuesClients.size());
diff --git a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
index a63cb84..bb82108 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
@@ -79,36 +79,37 @@
 using ::ndk::SpAIBinder;
 
 using ::testing::ContainsRegex;
+using ::testing::ElementsAre;
 using ::testing::Eq;
 using ::testing::UnorderedElementsAre;
 using ::testing::UnorderedElementsAreArray;
 using ::testing::WhenSortedBy;
 
 constexpr int32_t INVALID_PROP_ID = 0;
-// VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
-constexpr int32_t INT32_WINDOW_PROP = 10001 + 0x10000000 + 0x03000000 + 0x00400000;
-// VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
-constexpr int32_t GLOBAL_ON_CHANGE_PROP = 10002 + 0x10000000 + 0x01000000 + 0x00400000;
-// VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
-constexpr int32_t GLOBAL_CONTINUOUS_PROP = 10003 + 0x10000000 + 0x01000000 + 0x00400000;
-// VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
-constexpr int32_t AREA_ON_CHANGE_PROP = 10004 + 0x10000000 + 0x03000000 + 0x00400000;
-// VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
-constexpr int32_t AREA_CONTINUOUS_PROP = 10005 + 0x10000000 + 0x03000000 + 0x00400000;
-// VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
-constexpr int32_t READ_ONLY_PROP = 10006 + 0x10000000 + 0x01000000 + 0x00400000;
-// VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
-constexpr int32_t WRITE_ONLY_PROP = 10007 + 0x10000000 + 0x01000000 + 0x00400000;
-// VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
-constexpr int32_t GLOBAL_CONTINUOUS_PROP_NO_VUR = 10008 + 0x10000000 + 0x01000000 + 0x00400000;
-// VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
-constexpr int32_t GLOBAL_NONE_ACCESS_PROP = 10009 + 0x10000000 + 0x01000000 + 0x00400000;
-// VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
-constexpr int32_t AREA_NONE_ACCESS_PROP = 10010 + 0x10000000 + 0x03000000 + 0x00400000;
+// VehiclePropertyGroup:VENDOR,VehicleArea:WINDOW,VehiclePropertyType:INT32
+constexpr int32_t INT32_WINDOW_PROP = 10001 + 0x20000000 + 0x03000000 + 0x00400000;
+// VehiclePropertyGroup:VENDOR,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+constexpr int32_t GLOBAL_ON_CHANGE_PROP = 10002 + 0x20000000 + 0x01000000 + 0x00400000;
+// VehiclePropertyGroup:VENDOR,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+constexpr int32_t GLOBAL_CONTINUOUS_PROP = 10003 + 0x20000000 + 0x01000000 + 0x00400000;
+// VehiclePropertyGroup:VENDOR,VehicleArea:WINDOW,VehiclePropertyType:INT32
+constexpr int32_t AREA_ON_CHANGE_PROP = 10004 + 0x20000000 + 0x03000000 + 0x00400000;
+// VehiclePropertyGroup:VENDOR,VehicleArea:WINDOW,VehiclePropertyType:INT32
+constexpr int32_t AREA_CONTINUOUS_PROP = 10005 + 0x20000000 + 0x03000000 + 0x00400000;
+// VehiclePropertyGroup:VENDOR,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+constexpr int32_t READ_ONLY_PROP = 10006 + 0x20000000 + 0x01000000 + 0x00400000;
+// VehiclePropertyGroup:VENDOR,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+constexpr int32_t WRITE_ONLY_PROP = 10007 + 0x20000000 + 0x01000000 + 0x00400000;
+// VehiclePropertyGroup:VENDOR,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+constexpr int32_t GLOBAL_CONTINUOUS_PROP_NO_VUR = 10008 + 0x20000000 + 0x01000000 + 0x00400000;
+// VehiclePropertyGroup:VENDOR,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+constexpr int32_t GLOBAL_NONE_ACCESS_PROP = 10009 + 0x20000000 + 0x01000000 + 0x00400000;
+// VehiclePropertyGroup:VENDOR,VehicleArea:WINDOW,VehiclePropertyType:INT32
+constexpr int32_t AREA_NONE_ACCESS_PROP = 10010 + 0x20000000 + 0x03000000 + 0x00400000;
 
 int32_t testInt32VecProp(size_t i) {
-    // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
-    return static_cast<int32_t>(i) + 0x10000000 + 0x01000000 + 0x00410000;
+    // VehiclePropertyGroup:VENDOR,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
+    return static_cast<int32_t>(i) + 0x20000000 + 0x01000000 + 0x00410000;
 }
 
 std::string toString(const std::vector<SubscribeOptions>& options) {
@@ -556,10 +557,10 @@
 TEST_F(DefaultVehicleHalTest, testGetAllPropConfigsSmall) {
     auto testConfigs = std::vector<VehiclePropConfig>({
             VehiclePropConfig{
-                    .prop = 1,
+                    .prop = testInt32VecProp(1),
             },
             VehiclePropConfig{
-                    .prop = 2,
+                    .prop = testInt32VecProp(2),
             },
     });
 
@@ -580,7 +581,7 @@
     // 5000 VehiclePropConfig exceeds 4k memory limit, so it would be sent through shared memory.
     for (size_t i = 0; i < 5000; i++) {
         testConfigs.push_back(VehiclePropConfig{
-                .prop = static_cast<int32_t>(i),
+                .prop = testInt32VecProp(i),
         });
     }
 
@@ -600,13 +601,42 @@
     ASSERT_EQ(result.value().getObject()->payloads, testConfigs);
 }
 
+TEST_F(DefaultVehicleHalTest, testGetAllPropConfigsFilterOutUnsupportedPropIdsForThisVersion) {
+    auto testConfigs = std::vector<VehiclePropConfig>({
+            // This is supported from V2.
+            VehiclePropConfig{
+                    .prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED),
+            },
+            // This is supported from V3
+            VehiclePropConfig{
+                    .prop = toInt(VehicleProperty::ULTRASONICS_SENSOR_POSITION),
+            },
+    });
+
+    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());
+
+    VehiclePropConfigs output;
+    auto status = client->getAllPropConfigs(&output);
+
+    ASSERT_TRUE(status.isOk()) << "getAllPropConfigs failed: " << status.getMessage();
+    ASSERT_THAT(output.payloads, ElementsAre(VehiclePropConfig{
+                                         .prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED),
+                                 }));
+}
+
 TEST_F(DefaultVehicleHalTest, testGetPropConfigs) {
+    int32_t propId1 = testInt32VecProp(1);
+    int32_t propId2 = testInt32VecProp(2);
     auto testConfigs = std::vector<VehiclePropConfig>({
             VehiclePropConfig{
-                    .prop = 1,
+                    .prop = propId1,
             },
             VehiclePropConfig{
-                    .prop = 2,
+                    .prop = propId2,
             },
     });
 
@@ -616,7 +646,7 @@
     std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
 
     VehiclePropConfigs output;
-    auto status = client->getPropConfigs(std::vector<int32_t>({1, 2}), &output);
+    auto status = client->getPropConfigs(std::vector<int32_t>({propId1, propId2}), &output);
 
     ASSERT_TRUE(status.isOk()) << "getPropConfigs failed: " << status.getMessage();
     ASSERT_EQ(output.payloads, testConfigs);
@@ -625,10 +655,10 @@
 TEST_F(DefaultVehicleHalTest, testGetPropConfigsInvalidArg) {
     auto testConfigs = std::vector<VehiclePropConfig>({
             VehiclePropConfig{
-                    .prop = 1,
+                    .prop = testInt32VecProp(1),
             },
             VehiclePropConfig{
-                    .prop = 2,
+                    .prop = testInt32VecProp(2),
             },
     });
 
@@ -638,7 +668,9 @@
     std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
 
     VehiclePropConfigs output;
-    auto status = client->getPropConfigs(std::vector<int32_t>({1, 2, 3}), &output);
+    auto status = client->getPropConfigs(
+            std::vector<int32_t>({testInt32VecProp(1), testInt32VecProp(2), testInt32VecProp(3)}),
+            &output);
 
     ASSERT_FALSE(status.isOk()) << "getPropConfigs must fail with invalid prop ID";
     ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::INVALID_ARG));
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/LowSpeedAutomaticEmergencyBrakingState.aidl
similarity index 90%
copy from security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
copy to automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/LowSpeedAutomaticEmergencyBrakingState.aidl
index cc07f9b..70014e1 100644
--- a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/LowSpeedAutomaticEmergencyBrakingState.aidl
@@ -31,12 +31,11 @@
 // 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.security.secretkeeper;
-/* @hide */
+package android.hardware.automotive.vehicle;
 @Backing(type="int") @VintfStability
-enum ErrorCode {
-  OK = 0,
-  UNKNOWN_KEY_ID = 1,
-  INTERNAL_ERROR = 2,
-  REQUEST_MALFORMED = 3,
+enum LowSpeedAutomaticEmergencyBrakingState {
+  OTHER = 0,
+  ENABLED = 1,
+  ACTIVATED = 2,
+  USER_OVERRIDE = 3,
 }
diff --git a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.aidl
index 9720aca..55af2ab 100644
--- a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.aidl
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.aidl
@@ -37,4 +37,5 @@
   USER_POWER_ON = 0,
   SYSTEM_USER_DETECTION = 1,
   SYSTEM_REMOTE_ACCESS = 2,
+  SYSTEM_ENTER_GARAGE_MODE = 3,
 }
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 efae92f..52876d1 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
@@ -123,6 +123,7 @@
   DISPLAY_BRIGHTNESS = (((0x0A03 + 0x10000000) + 0x01000000) + 0x00400000) /* 289409539 */,
   PER_DISPLAY_BRIGHTNESS = (((0x0A04 + 0x10000000) + 0x01000000) + 0x00410000) /* 289475076 */,
   VALET_MODE_ENABLED = (((0x0A05 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 287312389 */,
+  HEAD_UP_DISPLAY_ENABLED = (((0x0A06 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.SEAT) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 354421254 */,
   HW_KEY_INPUT = (((0x0A10 + 0x10000000) + 0x01000000) + 0x00410000) /* 289475088 */,
   HW_KEY_INPUT_V2 = (((0x0A11 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.SEAT) + android.hardware.automotive.vehicle.VehiclePropertyType.MIXED) /* 367004177 */,
   HW_MOTION_INPUT = (((0x0A12 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.SEAT) + android.hardware.automotive.vehicle.VehiclePropertyType.MIXED) /* 367004178 */,
@@ -202,6 +203,7 @@
   ULTRASONICS_SENSOR_FIELD_OF_VIEW = (((0x0C22 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.VENDOR) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32_VEC) /* 406916130 */,
   ULTRASONICS_SENSOR_DETECTION_RANGE = (((0x0C23 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.VENDOR) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32_VEC) /* 406916131 */,
   ULTRASONICS_SENSOR_SUPPORTED_RANGES = (((0x0C24 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.VENDOR) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32_VEC) /* 406916132 */,
+  ULTRASONICS_SENSOR_MEASURED_DISTANCE = (((0x0C25 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.VENDOR) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32_VEC) /* 406916133 */,
   OBD2_LIVE_FRAME = (((0x0D00 + 0x10000000) + 0x01000000) + 0x00e00000) /* 299896064 */,
   OBD2_FREEZE_FRAME = (((0x0D01 + 0x10000000) + 0x01000000) + 0x00e00000) /* 299896065 */,
   OBD2_FREEZE_FRAME_INFO = (((0x0D02 + 0x10000000) + 0x01000000) + 0x00e00000) /* 299896066 */,
@@ -296,4 +298,6 @@
   LOW_SPEED_COLLISION_WARNING_STATE = (((0x1022 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 289411106 */,
   CROSS_TRAFFIC_MONITORING_ENABLED = (((0x1023 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 287313955 */,
   CROSS_TRAFFIC_MONITORING_WARNING_STATE = (((0x1024 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 289411108 */,
+  LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED = (((0x1025 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 287313957 */,
+  LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE = (((0x1026 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 289411110 */,
 }
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/LowSpeedAutomaticEmergencyBrakingState.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/LowSpeedAutomaticEmergencyBrakingState.aidl
new file mode 100644
index 0000000..978da25
--- /dev/null
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/LowSpeedAutomaticEmergencyBrakingState.aidl
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2023 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.automotive.vehicle;
+
+/**
+ * Used to enumerate the state of Low Speed Automatic Emergency Braking.
+ */
+@VintfStability
+@Backing(type="int")
+enum LowSpeedAutomaticEmergencyBrakingState {
+
+    /**
+     * This state is used as an alternative to any LowSpeedAutomaticEmergencyBrakingState value that
+     * is not defined in the platform. Ideally, implementations of
+     * VehicleProperty#LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE should not use this state. The
+     * framework can use this field to remain backwards compatible if
+     * LowSpeedAutomaticEmergencyBrakingState is extended to include additional states.
+     */
+    OTHER = 0,
+    /**
+     * Low Speed Automatic Emergency Braking is enabled and monitoring safety, but brakes are not
+     * activated.
+     */
+    ENABLED = 1,
+    /**
+     * Low Speed Automatic Emergency Braking is enabled and currently has the brakes applied for the
+     * vehicle.
+     */
+    ACTIVATED = 2,
+    /**
+     * Many Low Speed Automatic Emergency Braking implementations allow the driver to override Low
+     * Speed Automatic Emergency Braking. This means that the car has determined it should brake,
+     * but a user decides to take over and do something else. This is often done for safety reasons
+     * and to ensure that the driver can always take control of the vehicle. This state should be
+     * set when the user is actively overriding the low speed automatic emergency braking system.
+     */
+    USER_OVERRIDE = 3,
+}
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.aidl
index e325b38..8c8c2da 100644
--- a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.aidl
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.aidl
@@ -34,7 +34,24 @@
     SYSTEM_USER_DETECTION = 1,
     /**
      * Automatic power on to execute a remote task. This is triggered by
-     * receiving a wakeup message from TCU wakeup client.
+     * receiving a wakeup message from an external system in the vehicle.
      */
     SYSTEM_REMOTE_ACCESS = 2,
+    /**
+     * Automatic power on to enter garage mode. This is triggered by
+     * receiving a wakeup message from an external system in the vehicle.
+     *
+     * Note that this does not necessarily mean Android will enter
+     * the garage mode since user may enter the vehicle after this is set.
+     * The system will only enter garage mode if VEHICLE_IN_USE is not true
+     * upon check.
+     *
+     * To consider the Time-Of-Check-Time-Of-Use issue, there is a slight chance
+     * that the vehicle become in-use after car service does the VEHICLE_IN_USE
+     * check. The external power controller must also check whether the vehicle
+     * is in use upon receiving the SHUTDOWN_REQUEST, before sending out
+     * SHUTDOWN_PREPARE, to make sure the system does not enter garage mode or
+     * shutdown if the vehicle is currently in use.
+     */
+    SYSTEM_ENTER_GARAGE_MODE = 3,
 }
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleApPowerStateShutdownParam.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleApPowerStateShutdownParam.aidl
index 923d42a..966ff65 100644
--- a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleApPowerStateShutdownParam.aidl
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleApPowerStateShutdownParam.aidl
@@ -20,33 +20,41 @@
 @Backing(type="int")
 enum VehicleApPowerStateShutdownParam {
     /**
-     * AP must shutdown immediately. Postponing is not allowed.
+     * AP must shutdown without Garage mode. Postponing is not allowed.
+     * If AP need to shutdown as soon as possible, EMERGENCY_SHUTDOWN shall be used.
      */
     SHUTDOWN_IMMEDIATELY = 1,
     /**
      * AP can enter deep sleep instead of shutting down completely.
+     * AP can postpone entering deep sleep to run Garage mode.
      */
     CAN_SLEEP = 2,
     /**
-     * AP can only shutdown with postponing allowed.
+     * AP can only shutdown.
+     * AP can postpone shutdown to run Garage mode.
      */
     SHUTDOWN_ONLY = 3,
     /**
-     * AP may enter deep sleep, but must either sleep or shut down immediately.
+     * AP can enter deep sleep, without Garage mode.
      * Postponing is not allowed.
+     * Depending on the actual implementation, it may shut down immediately
      */
     SLEEP_IMMEDIATELY = 4,
     /**
-     * AP must hibernate (suspend to disk) immediately. Postponing is not allowed.
-     * Depending on the actual implementation, it may shut down immediately
+     * AP can hibernate (suspend to disk) without Garage mode.
+     * Postponing is not allowed.
+     * Depending on the actual implementation, it may shut down immediately.
      */
     HIBERNATE_IMMEDIATELY = 5,
     /**
      * AP can enter hibernation (suspend to disk) instead of shutting down completely.
+     * AP can postpone hibernation to run Garage mode.
      */
     CAN_HIBERNATE = 6,
     /**
-     * AP must shutdown (gracefully) without a delay.
+     * AP must shutdown (gracefully) without a delay. AP cannot run Garage mode.
+     * This type must be used only in critical situations when AP must shutdown as soon as possible.
+     * CarService will only notify listeners, but will not wait for completion reports.
      */
     EMERGENCY_SHUTDOWN = 7,
 }
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 acb6aeb..026c040 100644
--- a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -52,6 +52,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     INFO_VIN = 0x0100 + 0x10000000 + 0x01000000
             + 0x00100000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:STRING
@@ -60,6 +61,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     INFO_MAKE = 0x0101 + 0x10000000 + 0x01000000
             + 0x00100000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:STRING
@@ -68,6 +70,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     INFO_MODEL = 0x0102 + 0x10000000 + 0x01000000
             + 0x00100000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:STRING
@@ -77,6 +80,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:YEAR
+     * @version 2
      */
     INFO_MODEL_YEAR = 0x0103 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -86,6 +90,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:MILLILITER
+     * @version 2
      */
     INFO_FUEL_CAPACITY = 0x0104 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -105,6 +110,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
      * @data_enum FuelType
+     * @version 2
      */
     INFO_FUEL_TYPE = 0x0105 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -119,6 +125,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:WH
+     * @version 2
      */
     INFO_EV_BATTERY_CAPACITY = 0x0106 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -128,6 +135,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @data_enum EvConnectorType
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     INFO_EV_CONNECTOR_TYPE = 0x0107 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -137,6 +145,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @data_enum PortLocationType
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     INFO_FUEL_DOOR_LOCATION = 0x0108 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -146,6 +155,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
      * @data_enum PortLocationType
+     * @version 2
      */
     INFO_EV_PORT_LOCATION = 0x0109 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -156,6 +166,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @data_enum VehicleAreaSeat
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     INFO_DRIVER_SEAT = 0x010A + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -174,6 +185,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:MILLIMETER
+     * @version 2
      */
     INFO_EXTERIOR_DIMENSIONS = 0x010B + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -189,6 +201,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
      * @data_enum PortLocationType
+     * @version 2
      */
     INFO_MULTI_EV_PORT_LOCATIONS = 0x010C + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -198,6 +211,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:KILOMETER
+     * @version 2
      */
     PERF_ODOMETER = 0x0204 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -213,6 +227,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:METER_PER_SEC
+     * @version 2
      */
     PERF_VEHICLE_SPEED = 0x0207 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -225,6 +240,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:METER_PER_SEC
+     * @version 2
      */
     PERF_VEHICLE_SPEED_DISPLAY = 0x0208 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -236,6 +252,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:DEGREES
+     * @version 2
      */
     PERF_STEERING_ANGLE = 0x0209 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -247,6 +264,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:DEGREES
+     * @version 2
      */
     PERF_REAR_STEERING_ANGLE = 0x0210 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -256,6 +274,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:CELSIUS
+     * @version 2
      */
     ENGINE_COOLANT_TEMP = 0x0301 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -265,6 +284,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleOilLevel
+     * @version 2
      */
     ENGINE_OIL_LEVEL = 0x0303 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -274,6 +294,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:CELSIUS
+     * @version 2
      */
     ENGINE_OIL_TEMP = 0x0304 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -283,6 +304,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:RPM
+     * @version 2
      */
     ENGINE_RPM = 0x0305 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -323,6 +345,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     WHEEL_TICK = 0x0306 + 0x10000000 + 0x01000000
             + 0x00510000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT64_VEC
@@ -334,6 +357,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:MILLILITER
+     * @version 2
      */
     FUEL_LEVEL = 0x0307 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -346,6 +370,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     FUEL_DOOR_OPEN = 0x0308 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -359,6 +384,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:WH
+     * @version 2
      */
     EV_BATTERY_LEVEL = 0x0309 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -373,6 +399,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:WH
+     * @version 2
      */
     EV_CURRENT_BATTERY_CAPACITY =
             0x030D + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.FLOAT,
@@ -385,6 +412,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     EV_CHARGE_PORT_OPEN = 0x030A + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -393,6 +421,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     EV_CHARGE_PORT_CONNECTED = 0x030B + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -405,6 +434,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:MW
+     * @version 2
      */
     EV_BATTERY_INSTANTANEOUS_CHARGE_RATE = 0x030C + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -423,6 +453,7 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:METER
+     * @version 2
      */
     RANGE_REMAINING = 0x0308 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -436,6 +467,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:CELSIUS
+     * @version 3
      */
     EV_BATTERY_AVERAGE_TEMPERATURE =
             0x030E + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.FLOAT,
@@ -463,6 +495,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:KILOPASCAL
+     * @version 2
      */
     TIRE_PRESSURE = 0x0309 + 0x10000000 + 0x07000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:WHEEL,VehiclePropertyType:FLOAT
@@ -478,6 +511,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:KILOPASCAL
+     * @version 2
      */
     CRITICALLY_LOW_TIRE_PRESSURE = 0x030A + 0x10000000 + 0x07000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:WHEEL,VehiclePropertyType:FLOAT
@@ -493,6 +527,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     ENGINE_IDLE_AUTO_STOP_ENABLED =
             0x0320 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -509,6 +544,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum ImpactSensorLocation
+     * @version 3
      */
     IMPACT_DETECTED =
             0x0330 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -529,6 +565,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleGear
+     * @version 2
      */
     GEAR_SELECTION = 0x0400 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -548,6 +585,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleGear
+     * @version 2
      */
     CURRENT_GEAR = 0x0401 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -559,6 +597,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     PARKING_BRAKE_ON = 0x0402 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -576,6 +615,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     PARKING_BRAKE_AUTO_APPLY = 0x0403 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -594,6 +634,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     EV_BRAKE_REGENERATION_LEVEL =
             0x040C + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -612,6 +653,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     FUEL_LEVEL_LOW = 0x0405 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -624,6 +666,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     NIGHT_MODE = 0x0407 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -633,6 +676,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleTurnSignal
+     * @version 2
      */
     TURN_SIGNAL_STATE = 0x0408 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -642,6 +686,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleIgnitionState
+     * @version 2
      */
     IGNITION_STATE = 0x0409 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -654,6 +699,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     ABS_ACTIVE = 0x040A + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -666,6 +712,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     TRACTION_CONTROL_ACTIVE = 0x040B + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -684,6 +731,7 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @data_enum EvStoppingMode
+     * @version 2
      */
     EV_STOPPING_MODE =
             0x040D + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -705,6 +753,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 3
      */
     ELECTRONIC_STABILITY_CONTROL_ENABLED =
             0x040E + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -723,6 +772,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum ElectronicStabilityControlState
      * @data_enum ErrorState
+     * @version 2
      */
     ELECTRONIC_STABILITY_CONTROL_STATE =
             0x040F + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -789,6 +839,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_FAN_SPEED = 0x0500 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -802,6 +853,7 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleHvacFanDirection
+     * @version 2
      */
     HVAC_FAN_DIRECTION = 0x0501 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -811,6 +863,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:CELSIUS
+     * @version 2
      */
     HVAC_TEMPERATURE_CURRENT = 0x0502 + 0x10000000 + 0x05000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:FLOAT
@@ -842,6 +895,7 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:CELSIUS
+     * @version 2
      */
     HVAC_TEMPERATURE_SET = 0x0503 + 0x10000000 + 0x05000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:FLOAT
@@ -854,6 +908,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_DEFROSTER = 0x0504 + 0x10000000 + 0x03000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:BOOLEAN
@@ -867,6 +922,7 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @config_flags Supported areaIds
+     * @version 2
      */
     HVAC_AC_ON = 0x0505 + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -884,6 +940,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_MAX_AC_ON = 0x0506 + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -907,6 +964,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_MAX_DEFROST_ON = 0x0507 + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -924,6 +982,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_RECIRC_ON = 0x0508 + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -963,6 +1022,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_DUAL_ON = 0x0509 + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -985,6 +1045,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_AUTO_ON = 0x050A + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -1007,6 +1068,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_SEAT_TEMPERATURE = 0x050B + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -1030,6 +1092,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_SIDE_MIRROR_HEAT = 0x050C + 0x10000000 + 0x04000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:MIRROR,VehiclePropertyType:INT32
@@ -1053,6 +1116,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_STEERING_WHEEL_HEAT = 0x050D + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -1079,6 +1143,7 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleUnit
+     * @version 2
      */
     HVAC_TEMPERATURE_DISPLAY_UNITS = 0x050E + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -1087,6 +1152,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_ACTUAL_FAN_SPEED_RPM = 0x050F + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -1133,6 +1199,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_POWER_ON = 0x0510 + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -1152,6 +1219,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleHvacFanDirection
+     * @version 2
      */
     HVAC_FAN_DIRECTION_AVAILABLE = 0x0511 + 0x10000000 + 0x05000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32_VEC
@@ -1168,6 +1236,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_AUTO_RECIRC_ON = 0x0512 + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -1193,6 +1262,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_SEAT_VENTILATION = 0x0513 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -1205,6 +1275,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_ELECTRIC_DEFROSTER_ON = 0x0514 + 0x10000000 + 0x03000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:BOOLEAN
@@ -1245,6 +1316,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @version 2
      */
     HVAC_TEMPERATURE_VALUE_SUGGESTION = 0x0515 + 0x10000000 + 0x01000000
             + 0x00610000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT_VEC
@@ -1270,6 +1342,7 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleUnit
+     * @version 2
      */
     DISTANCE_DISPLAY_UNITS = 0x0600 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -1294,6 +1367,7 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleUnit
+     * @version 2
      */
     FUEL_VOLUME_DISPLAY_UNITS = 0x0601 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -1319,6 +1393,7 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleUnit
+     * @version 2
      */
     TIRE_PRESSURE_DISPLAY_UNITS = 0x0602 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -1344,6 +1419,7 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleUnit
+     * @version 2
      */
     EV_BATTERY_DISPLAY_UNITS = 0x0603 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -1360,6 +1436,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME = 0x0604 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -1383,6 +1460,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     VEHICLE_SPEED_DISPLAY_UNITS = 0x0605 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -1427,6 +1505,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:MILLI_SECS
+     * @version 2
      */
     EXTERNAL_CAR_TIME = 0x0608 + 0x10000000 // VehiclePropertyGroup:SYSTEM
             + 0x01000000 // VehicleArea:GLOBAL
@@ -1456,6 +1535,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
      * @unit VehicleUnit:MILLI_SECS
+     * @version 2
      */
     ANDROID_EPOCH_TIME = 0x0606 + 0x10000000 + 0x01000000
             + 0x00500000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT64
@@ -1470,6 +1550,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @version 2
      */
     STORAGE_ENCRYPTION_BINDING_SEED = 0x0607 + 0x10000000 + 0x01000000
             + 0x00700000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BYTES
@@ -1479,6 +1560,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:CELSIUS
+     * @version 2
      */
     ENV_OUTSIDE_TEMPERATURE = 0x0703 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -1497,6 +1579,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     AP_POWER_STATE_REQ = 0x0A00 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -1511,6 +1594,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @version 2
      */
     AP_POWER_STATE_REPORT = 0x0A01 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -1525,6 +1609,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     AP_POWER_BOOTUP_REASON = 0x0A02 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -1547,6 +1632,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @version 2
      */
     DISPLAY_BRIGHTNESS = 0x0A03 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -1570,6 +1656,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @version 2
      */
     PER_DISPLAY_BRIGHTNESS = 0x0A04 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -1586,10 +1673,28 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 3
      */
     VALET_MODE_ENABLED =
             0x0A05 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
     /**
+     * Head up display (HUD) enabled
+     *
+     * This property allows the user to turn on/off the HUD for their seat.
+     *
+     * Each HUD in the vehicle should be assigned to the seat that is intended to use it. For
+     * example, if there is a single HUD in the vehicle that is used by the driver so that they no
+     * longer need to continuously look at the instrument cluster, then this property should be
+     * defined with a single area ID equal to the driver's seat area value.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 3
+     */
+    HEAD_UP_DISPLAY_ENABLED =
+            0x0A06 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.BOOLEAN,
+    /**
      * Property to feed H/W input events to android
      *
      * int32Values[0] : action defined by VehicleHwKeyInputAction
@@ -1603,6 +1708,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @config_flags
+     * @version 2
      */
     HW_KEY_INPUT = 0x0A10 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -1625,6 +1731,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @config_flags
+     * @version 2
      */
     HW_KEY_INPUT_V2 =
             0x0A11 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.MIXED,
@@ -1659,6 +1766,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @config_flags
+     * @version 2
      */
     HW_MOTION_INPUT =
             0x0A12 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.MIXED,
@@ -1682,6 +1790,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @data_enum RotaryInputType
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HW_ROTARY_INPUT = 0x0A20 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -1705,6 +1814,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @data_enum CustomInputType
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HW_CUSTOM_INPUT = 0X0A30 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -1749,6 +1859,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     DOOR_POS = 0x0B00 + 0x10000000 + 0x06000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:DOOR,VehiclePropertyType:INT32
@@ -1774,6 +1885,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     DOOR_MOVE = 0x0B01 + 0x10000000 + 0x06000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:DOOR,VehiclePropertyType:INT32
@@ -1788,6 +1900,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     DOOR_LOCK = 0x0B02 + 0x10000000 + 0x06000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:DOOR,VehiclePropertyType:BOOLEAN
@@ -1804,6 +1917,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     DOOR_CHILD_LOCK_ENABLED =
             0x0B03 + VehiclePropertyGroup.SYSTEM + VehicleArea.DOOR + VehiclePropertyType.BOOLEAN,
@@ -1830,6 +1944,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     MIRROR_Z_POS = 0x0B40 + 0x10000000 + 0x04000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:MIRROR,VehiclePropertyType:INT32
@@ -1856,6 +1971,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     MIRROR_Z_MOVE = 0x0B41 + 0x10000000 + 0x04000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:MIRROR,VehiclePropertyType:INT32
@@ -1882,6 +1998,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     MIRROR_Y_POS = 0x0B42 + 0x10000000 + 0x04000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:MIRROR,VehiclePropertyType:INT32
@@ -1907,6 +2024,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     MIRROR_Y_MOVE = 0x0B43 + 0x10000000 + 0x04000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:MIRROR,VehiclePropertyType:INT32
@@ -1921,6 +2039,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     MIRROR_LOCK = 0x0B44 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -1935,6 +2054,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     MIRROR_FOLD = 0x0B45 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -1952,6 +2072,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
 
     MIRROR_AUTO_FOLD_ENABLED =
@@ -1970,6 +2091,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
 
     MIRROR_AUTO_TILT_ENABLED =
@@ -1989,6 +2111,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
+     * @version 2
      */
     SEAT_MEMORY_SELECT = 0x0B80 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2002,6 +2125,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
+     * @version 2
      */
     SEAT_MEMORY_SET = 0x0B81 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2019,6 +2143,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_BELT_BUCKLED = 0x0B82 + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -2044,6 +2169,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_BELT_HEIGHT_POS = 0x0B83 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2072,6 +2198,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_BELT_HEIGHT_MOVE = 0x0B84 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2097,6 +2224,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_FORE_AFT_POS = 0x0B85 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2124,6 +2252,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_FORE_AFT_MOVE = 0x0B86 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2151,6 +2280,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_BACKREST_ANGLE_1_POS = 0x0B87 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2178,6 +2308,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_BACKREST_ANGLE_1_MOVE = 0x0B88 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2207,6 +2338,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_BACKREST_ANGLE_2_POS = 0x0B89 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2234,6 +2366,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_BACKREST_ANGLE_2_MOVE = 0x0B8A + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2257,6 +2390,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_HEIGHT_POS = 0x0B8B + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2282,6 +2416,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_HEIGHT_MOVE = 0x0B8C + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2310,6 +2445,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_DEPTH_POS = 0x0B8D + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2336,6 +2472,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_DEPTH_MOVE = 0x0B8E + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2363,6 +2500,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_TILT_POS = 0x0B8F + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2390,6 +2528,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_TILT_MOVE = 0x0B90 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2415,6 +2554,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_LUMBAR_FORE_AFT_POS = 0x0B91 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2443,6 +2583,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_LUMBAR_FORE_AFT_MOVE = 0x0B92 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2468,6 +2609,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_LUMBAR_SIDE_SUPPORT_POS = 0x0B93 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2496,6 +2638,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 0x0B94 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2516,6 +2659,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_HEADREST_HEIGHT_POS = 0x0B95 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -2543,6 +2687,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_HEADREST_HEIGHT_POS_V2 =
             0x0BA4 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -2572,6 +2717,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_HEADREST_HEIGHT_MOVE = 0x0B96 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2595,6 +2741,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_HEADREST_ANGLE_POS = 0x0B97 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2623,6 +2770,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_HEADREST_ANGLE_MOVE = 0x0B98 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2646,6 +2794,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_HEADREST_FORE_AFT_POS = 0x0B99 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2674,6 +2823,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_HEADREST_FORE_AFT_MOVE = 0x0B9A + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2695,6 +2845,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightState
+     * @version 2
      */
     SEAT_FOOTWELL_LIGHTS_STATE =
             0x0B9B + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -2720,6 +2871,7 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
+     * @version 2
      */
     SEAT_FOOTWELL_LIGHTS_SWITCH =
             0x0B9C + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -2736,6 +2888,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_EASY_ACCESS_ENABLED =
             0x0B9D + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.BOOLEAN,
@@ -2756,6 +2909,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 3
      */
     SEAT_AIRBAG_ENABLED =
             0x0B9E + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.BOOLEAN,
@@ -2778,6 +2932,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleAirbagLocation
+     * @version 2
      */
     SEAT_AIRBAGS_DEPLOYED =
             0x0BA5 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -2803,6 +2958,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_CUSHION_SIDE_SUPPORT_POS =
             0x0B9F + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -2831,6 +2987,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_CUSHION_SIDE_SUPPORT_MOVE =
             0x0BA0 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -2854,6 +3011,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_LUMBAR_VERTICAL_POS =
             0x0BA1 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -2880,6 +3038,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_LUMBAR_VERTICAL_MOVE =
             0x0BA2 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -2906,6 +3065,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_WALK_IN_POS =
             0x0BA3 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -2924,6 +3084,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 3
      */
     SEAT_BELT_PRETENSIONER_DEPLOYED =
             0x0BA6 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.BOOLEAN,
@@ -2936,6 +3097,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleSeatOccupancyState
+     * @version 2
      */
     SEAT_OCCUPANCY = 0x0BB0 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2972,6 +3134,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     WINDOW_POS = 0x0BC0 + 0x10000000 + 0x03000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
@@ -3014,6 +3177,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     WINDOW_MOVE = 0x0BC1 + 0x10000000 + 0x03000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
@@ -3028,6 +3192,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     WINDOW_LOCK = 0x0BC4 + 0x10000000 + 0x03000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:BOOLEAN
@@ -3048,6 +3213,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:MILLI_SECS
+     * @version 2
      */
     WINDSHIELD_WIPERS_PERIOD =
             0x0BC5 + VehiclePropertyGroup.SYSTEM + VehicleArea.WINDOW + VehiclePropertyType.INT32,
@@ -3069,6 +3235,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum WindshieldWipersState
+     * @version 2
      */
     WINDSHIELD_WIPERS_STATE =
             0x0BC6 + VehiclePropertyGroup.SYSTEM + VehicleArea.WINDOW + VehiclePropertyType.INT32,
@@ -3095,6 +3262,7 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @data_enum WindshieldWipersSwitch
+     * @version 2
      */
     WINDSHIELD_WIPERS_SWITCH =
             0x0BC7 + VehiclePropertyGroup.SYSTEM + VehicleArea.WINDOW + VehiclePropertyType.INT32,
@@ -3121,6 +3289,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     STEERING_WHEEL_DEPTH_POS =
             0x0BE0 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -3147,6 +3316,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     STEERING_WHEEL_DEPTH_MOVE =
             0x0BE1 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -3170,6 +3340,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     STEERING_WHEEL_HEIGHT_POS =
             0x0BE2 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -3196,6 +3367,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     STEERING_WHEEL_HEIGHT_MOVE =
             0x0BE3 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -3211,6 +3383,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     STEERING_WHEEL_THEFT_LOCK_ENABLED =
             0x0BE4 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -3225,6 +3398,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     STEERING_WHEEL_LOCKED =
             0x0BE5 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -3240,6 +3414,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     STEERING_WHEEL_EASY_ACCESS_ENABLED =
             0x0BE6 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -3267,6 +3442,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     GLOVE_BOX_DOOR_POS =
             0x0BF0 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -3286,6 +3462,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     GLOVE_BOX_LOCKED =
             0x0BF1 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.BOOLEAN,
@@ -3305,6 +3482,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @version 2
      */
     VEHICLE_MAP_SERVICE = 0x0C00 + 0x10000000 + 0x01000000
             + 0x00e00000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:MIXED
@@ -3324,6 +3502,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     LOCATION_CHARACTERIZATION =
             0x0C10 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -3347,6 +3526,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
+     * @version 3
      */
     ULTRASONICS_SENSOR_POSITION = 0x0C20 + VehiclePropertyGroup.SYSTEM + VehicleArea.VENDOR
             + VehiclePropertyType.INT32_VEC,
@@ -3378,6 +3558,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
+     * @version 3
      */
     ULTRASONICS_SENSOR_ORIENTATION = 0x0C21 + VehiclePropertyGroup.SYSTEM + VehicleArea.VENDOR
             + VehiclePropertyType.INT32_VEC,
@@ -3401,6 +3582,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
+     * @version 3
      */
     ULTRASONICS_SENSOR_FIELD_OF_VIEW = 0x0C22 + VehiclePropertyGroup.SYSTEM + VehicleArea.VENDOR
             + VehiclePropertyType.INT32_VEC,
@@ -3422,6 +3604,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
+     * @version 3
      */
     ULTRASONICS_SENSOR_DETECTION_RANGE = 0x0C23 + VehiclePropertyGroup.SYSTEM + VehicleArea.VENDOR
             + VehiclePropertyType.INT32_VEC,
@@ -3468,11 +3651,39 @@
      *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
+     * @version 3
      */
     ULTRASONICS_SENSOR_SUPPORTED_RANGES = 0x0C24 + VehiclePropertyGroup.SYSTEM + VehicleArea.VENDOR
             + VehiclePropertyType.INT32_VEC,
 
     /**
+     * The distance reading of the nearest detected object per sensor in millimeters.
+     *
+     * Each individual sensor is identified by its VehicleAreaConfig#areaId and returns the sensor's
+     * measured distance formatted as [distance, distance_error] where:
+     *
+     *     int32Values[0] = distance, the measured distance of the nearest object in millimeters.
+     *                      If only a range is supported, this value must be set to the minimum
+     *                      supported distance in the detected range as specified in
+     *                      ULTRASONICS_SENSOR_SUPPORTED_RANGES.
+     *     int32Values[1] = distance_error, the error of the measured distance value in
+     *                      millimeters.
+     *
+     * If no object is detected, an empty vector must be returned. If distance_error is not
+     * available then an array of only the measured distance must be returned.
+     *
+     * If the data is aggregated by another ECU, then OEMs have the option of reporting the same
+     * reading across all included sensors or reporting a virtual representation of all the included
+     * sensors as if they were one sensor.
+     *
+     * @change_mode VehiclePropertyChangeMode.CONTINUOUS
+     * @access VehiclePropertyAccess.READ
+     * @version 3
+     */
+    ULTRASONICS_SENSOR_MEASURED_DISTANCE = 0x0C25 + VehiclePropertyGroup.SYSTEM + VehicleArea.VENDOR
+            + VehiclePropertyType.INT32_VEC,
+
+    /**
      * OBD2 Live Sensor Data
      *
      * Reports a snapshot of the current (live) values of the OBD2 sensors available.
@@ -3512,6 +3723,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     OBD2_LIVE_FRAME = 0x0D00 + 0x10000000 + 0x01000000
             + 0x00e00000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:MIXED
@@ -3538,6 +3750,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     OBD2_FREEZE_FRAME = 0x0D01 + 0x10000000 + 0x01000000
             + 0x00e00000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:MIXED
@@ -3555,6 +3768,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     OBD2_FREEZE_FRAME_INFO = 0x0D02 + 0x10000000 + 0x01000000
             + 0x00e00000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:MIXED
@@ -3577,6 +3791,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
+     * @version 2
      */
     OBD2_FREEZE_FRAME_CLEAR = 0x0D03 + 0x10000000 + 0x01000000
             + 0x00e00000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:MIXED
@@ -3588,6 +3803,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightState
+     * @version 2
      */
     HEADLIGHTS_STATE = 0x0E00 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -3599,6 +3815,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightState
+     * @version 2
      */
     HIGH_BEAM_LIGHTS_STATE = 0x0E01 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -3626,6 +3843,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightState
+     * @version 2
      */
     FOG_LIGHTS_STATE = 0x0E02 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -3637,6 +3855,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightState
+     * @version 2
      */
     HAZARD_LIGHTS_STATE = 0x0E03 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -3652,6 +3871,7 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
+     * @version 2
      */
     HEADLIGHTS_SWITCH = 0x0E10 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -3667,6 +3887,7 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
+     * @version 2
      */
     HIGH_BEAM_LIGHTS_SWITCH = 0x0E11 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -3698,6 +3919,7 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
+     * @version 2
      */
     FOG_LIGHTS_SWITCH = 0x0E12 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -3713,6 +3935,7 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
+     * @version 2
      */
     HAZARD_LIGHTS_SWITCH = 0x0E13 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -3724,6 +3947,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightState
+     * @version 2
      */
     CABIN_LIGHTS_STATE = 0x0F01 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -3742,6 +3966,7 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
+     * @version 2
      */
     CABIN_LIGHTS_SWITCH = 0x0F02 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -3753,6 +3978,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightState
+     * @version 2
      */
     READING_LIGHTS_STATE = 0x0F03 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -3771,6 +3997,7 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
+     * @version 2
      */
     READING_LIGHTS_SWITCH = 0x0F04 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -3792,6 +4019,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightState
+     * @version 2
      */
     STEERING_WHEEL_LIGHTS_STATE =
             0x0F0C + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -3817,6 +4045,7 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
+     * @version 2
      */
     STEERING_WHEEL_LIGHTS_SWITCH =
             0x0F0D + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -3845,6 +4074,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SUPPORT_CUSTOMIZE_VENDOR_PERMISSION = 0x0F05 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -3861,6 +4091,7 @@
      * ex) "com.android.car.user.CarUserNoticeService,storage_monitoring"
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     DISABLED_OPTIONAL_FEATURES = 0x0F06 + 0x10000000 + 0x01000000
             + 0x00100000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:STRING
@@ -3911,6 +4142,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @version 2
      */
     INITIAL_USER_INFO = 0x0F07 + 0x10000000 + 0x01000000
             + 0x00e00000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:MIXED
@@ -4077,6 +4309,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @version 2
      */
     SWITCH_USER = 0x0F08 + 0x10000000 + 0x01000000
             + 0x00e00000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:MIXED
@@ -4123,6 +4356,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @version 2
      */
     CREATE_USER = 0x0F09 + 0x10000000 + 0x01000000
             + 0x00e00000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:MIXED
@@ -4154,6 +4388,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.WRITE
+     * @version 2
      */
     REMOVE_USER = 0x0F0A + 0x10000000 + 0x01000000
             + 0x00e00000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:MIXED
@@ -4229,6 +4464,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @version 2
      */
     USER_IDENTIFICATION_ASSOCIATION = 0x0F0B + 0x10000000 + 0x01000000
             + 0x00e00000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:MIXED
@@ -4248,6 +4484,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     EVS_SERVICE_REQUEST = 0x0F10 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -4265,6 +4502,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     POWER_POLICY_REQ = 0x0F21 + 0x10000000 + 0x01000000
             + 0x00100000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:STRING
@@ -4284,6 +4522,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     POWER_POLICY_GROUP_REQ = 0x0F22 + 0x10000000 + 0x01000000
             + 0x00100000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:STRING
@@ -4296,6 +4535,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @version 2
      */
     CURRENT_POWER_POLICY = 0x0F23 + 0x10000000 + 0x01000000
             + 0x00100000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:STRING
@@ -4307,6 +4547,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
+     * @version 2
      */
     WATCHDOG_ALIVE = 0xF31 + 0x10000000 + 0x01000000
             + 0x00500000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT64
@@ -4318,6 +4559,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
+     * @version 2
      */
     WATCHDOG_TERMINATED_PROCESS = 0x0F32 + 0x10000000 + 0x01000000
             + 0x00e00000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:MIXED
@@ -4333,6 +4575,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     VHAL_HEARTBEAT = 0x0F33 + 0x10000000 + 0x01000000
             + 0x00500000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT64
@@ -4346,6 +4589,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     CLUSTER_SWITCH_UI = 0x0F34 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4370,6 +4614,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     CLUSTER_DISPLAY_STATE = 0x0F35 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -4405,6 +4650,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
+     * @version 2
      */
     CLUSTER_REPORT_STATE = 0x0F36 + 0x10000000 + 0x01000000
             + 0x00e00000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:MIXED
@@ -4419,6 +4665,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
+     * @version 2
      */
     CLUSTER_REQUEST_DISPLAY = 0x0F37 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4429,6 +4676,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
+     * @version 2
      */
     CLUSTER_NAVIGATION_STATE = 0x0F38 + 0x10000000 + 0x01000000
             + 0x00700000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BYTES
@@ -4442,6 +4690,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum ElectronicTollCollectionCardType
+     * @version 2
      */
     ELECTRONIC_TOLL_COLLECTION_CARD_TYPE = 0x0F39 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4456,6 +4705,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum ElectronicTollCollectionCardStatus
+     * @version 2
      */
     ELECTRONIC_TOLL_COLLECTION_CARD_STATUS = 0x0F3A + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4469,6 +4719,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightState
+     * @version 2
      */
     FRONT_FOG_LIGHTS_STATE = 0x0F3B + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4487,6 +4738,7 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
+     * @version 2
      */
     FRONT_FOG_LIGHTS_SWITCH = 0x0F3C + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4501,6 +4753,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightState
+     * @version 2
      */
     REAR_FOG_LIGHTS_STATE = 0x0F3D + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4519,6 +4772,7 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
+     * @version 2
      */
     REAR_FOG_LIGHTS_SWITCH = 0x0F3E + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4536,6 +4790,7 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:AMPERE
+     * @version 2
      */
     EV_CHARGE_CURRENT_DRAW_LIMIT = 0x0F3F + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -4557,6 +4812,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     EV_CHARGE_PERCENT_LIMIT = 0x0F40 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -4569,6 +4825,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum EvChargeState
+     * @version 2
      */
     EV_CHARGE_STATE = 0x0F41 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4585,6 +4842,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     EV_CHARGE_SWITCH = 0x0F42 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -4597,6 +4855,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:SECS
+     * @version 2
      */
     EV_CHARGE_TIME_REMAINING = 0x0F43 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4610,6 +4869,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum EvRegenerativeBrakingState
+     * @version 2
      */
     EV_REGENERATIVE_BRAKING_STATE = 0x0F44 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4622,6 +4882,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum TrailerState
+     * @version 2
      */
     TRAILER_PRESENT = 0x0F45 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4645,6 +4906,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:KILOGRAM
+     * @version 2
      */
 
     VEHICLE_CURB_WEIGHT = 0x0F46 + 0x10000000 + 0x01000000
@@ -4659,6 +4921,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
      * @data_enum GsrComplianceRequirementType
+     * @version 2
      */
     GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT = 0x0F47 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4683,6 +4946,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SUPPORTED_PROPERTY_IDS = 0x0F48 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -4690,12 +4954,22 @@
     /**
      * Request the head unit to be shutdown.
      *
+     * <p>This is required for executing a task when the head unit is powered off (remote task
+     * feature). After the head unit is powered-on to execute the task, the head unit should
+     * be shutdown. The head unit will send this message once the task is finished.
+     *
+     * <p>This is not for the case when a user wants to shutdown the head unit.
+     *
      * <p>This usually involves telling a separate system outside the head unit (e.g. a power
      * controller) to prepare shutting down the head unit.
      *
-     * <p>This does not mean the head unit will shutdown immediately.
+     * <p>Note that the external system must validate whether this request is valid by checking
+     * whether the vehicle is currently in use. If a user enters the vehicle after a
+     * SHUTDOWN_REQUEST is sent, then the system must ignore this request. It
+     * is recommended to store a VehicleInUse property in the power controller and exposes it
+     * through VEHICLE_IN_USE property. A shutdown request must be ignored if VehicleInUse is true.
      *
-     * <p>This means that another system will start sending a shutdown signal to the head unit,
+     * <p>If allowed, the external system will start sending a shutdown signal to the head unit,
      * which will cause VHAL to send SHUTDOWN_PREPARE message to Android. Android will then start
      * the shut down process by handling the message.
      *
@@ -4720,6 +4994,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
      * @data_enum VehicleApPowerStateShutdownParam
+     * @version 2
      */
     SHUTDOWN_REQUEST =
             0x0F49 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -4752,6 +5027,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     VEHICLE_IN_USE =
             0x0F4A + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -4766,6 +5042,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
+     * @version 3
      */
     CLUSTER_HEARTBEAT =
             0x0F4B + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.MIXED,
@@ -4785,6 +5062,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleAutonomousState
+     * @version 3
      */
     VEHICLE_DRIVING_AUTOMATION_CURRENT_LEVEL =
             0x0F4C + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -4799,7 +5077,9 @@
      * Enable or disable Automatic Emergency Braking (AEB).
      *
      * Set true to enable AEB and false to disable AEB. When AEB is enabled, the ADAS system in the
-     * vehicle should be turned on and monitoring to avoid potential collisions.
+     * vehicle should be turned on and monitoring to avoid potential collisions. This property
+     * should apply for higher speed applications only. For enabling low speed automatic emergency
+     * braking, LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED should be used.
      *
      * In general, AUTOMATIC_EMERGENCY_BRAKING_ENABLED should always return true or false. If the
      * feature is not available due to some temporary state, such as the vehicle speed being too
@@ -4812,6 +5092,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     AUTOMATIC_EMERGENCY_BRAKING_ENABLED =
             0x1000 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -4821,7 +5102,9 @@
      *
      * Returns 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.
+     * 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.
      *
      * If AEB includes forward collision warnings before activating the brakes, those warnings must
      * be surfaced through the Forward Collision Warning (FCW) properties.
@@ -4834,6 +5117,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum AutomaticEmergencyBrakingState
      * @data_enum ErrorState
+     * @version 2
      */
     AUTOMATIC_EMERGENCY_BRAKING_STATE =
             0x1001 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -4855,6 +5139,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     FORWARD_COLLISION_WARNING_ENABLED =
             0x1002 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -4874,6 +5159,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum ForwardCollisionWarningState
      * @data_enum ErrorState
+     * @version 2
      */
     FORWARD_COLLISION_WARNING_STATE =
             0x1003 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -4895,6 +5181,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     BLIND_SPOT_WARNING_ENABLED =
             0x1004 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -4914,6 +5201,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum BlindSpotWarningState
      * @data_enum ErrorState
+     * @version 2
      */
     BLIND_SPOT_WARNING_STATE =
             0x1005 + VehiclePropertyGroup.SYSTEM + VehicleArea.MIRROR + VehiclePropertyType.INT32,
@@ -4936,6 +5224,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     LANE_DEPARTURE_WARNING_ENABLED =
             0x1006 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -4955,6 +5244,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum LaneDepartureWarningState
      * @data_enum ErrorState
+     * @version 2
      */
     LANE_DEPARTURE_WARNING_STATE =
             0x1007 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -4981,6 +5271,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     LANE_KEEP_ASSIST_ENABLED =
             0x1008 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -5003,6 +5294,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum LaneKeepAssistState
      * @data_enum ErrorState
+     * @version 2
      */
     LANE_KEEP_ASSIST_STATE =
             0x1009 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -5030,6 +5322,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     LANE_CENTERING_ASSIST_ENABLED =
             0x100A + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -5060,6 +5353,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
      * @data_enum LaneCenteringAssistCommand
+     * @version 2
      */
     LANE_CENTERING_ASSIST_COMMAND =
             0x100B + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -5082,6 +5376,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum LaneCenteringAssistState
      * @data_enum ErrorState
+     * @version 2
      */
     LANE_CENTERING_ASSIST_STATE =
             0x100C + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -5105,6 +5400,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     EMERGENCY_LANE_KEEP_ASSIST_ENABLED =
             0x100D + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -5125,6 +5421,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum EmergencyLaneKeepAssistState
      * @data_enum ErrorState
+     * @version 2
      */
     EMERGENCY_LANE_KEEP_ASSIST_STATE =
             0x100E + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -5149,6 +5446,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     CRUISE_CONTROL_ENABLED =
             0x100F + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -5177,6 +5475,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum CruiseControlType
      * @data_enum ErrorState
+     * @version 2
      */
     CRUISE_CONTROL_TYPE =
             0x1010 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -5197,6 +5496,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum CruiseControlState
      * @data_enum ErrorState
+     * @version 2
      */
     CRUISE_CONTROL_STATE =
             0x1011 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -5220,6 +5520,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
      * @data_enum CruiseControlCommand
+     * @version 2
      */
     CRUISE_CONTROL_COMMAND =
             0x1012 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -5243,6 +5544,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:METER_PER_SEC
+     * @version 2
      */
     CRUISE_CONTROL_TARGET_SPEED =
             0x1013 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.FLOAT,
@@ -5274,6 +5576,7 @@
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:MILLI_SECS
+     * @version 2
      */
     ADAPTIVE_CRUISE_CONTROL_TARGET_TIME_GAP =
             0x1014 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -5304,6 +5607,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:MILLIMETER
+     * @version 2
      */
     ADAPTIVE_CRUISE_CONTROL_LEAD_VEHICLE_MEASURED_DISTANCE =
             0x1015 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -5325,6 +5629,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HANDS_ON_DETECTION_ENABLED =
             0x1016 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -5349,6 +5654,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum HandsOnDetectionDriverState
      * @data_enum ErrorState
+     * @version 2
      */
     HANDS_ON_DETECTION_DRIVER_STATE =
             0x1017 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -5371,6 +5677,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum HandsOnDetectionWarning
      * @data_enum ErrorState
+     * @version 2
      */
     HANDS_ON_DETECTION_WARNING =
             0x1018 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -5393,6 +5700,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 3
      */
     DRIVER_DROWSINESS_ATTENTION_SYSTEM_ENABLED =
             0x1019 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -5419,6 +5727,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum DriverDrowsinessAttentionState
      * @data_enum ErrorState
+     * @version 3
      */
     DRIVER_DROWSINESS_ATTENTION_STATE =
             0x101A + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -5443,6 +5752,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 3
      */
     DRIVER_DROWSINESS_ATTENTION_WARNING_ENABLED =
             0x101B + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -5464,6 +5774,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum DriverDrowsinessAttentionWarning
      * @data_enum ErrorState
+     * @version 3
      */
     DRIVER_DROWSINESS_ATTENTION_WARNING =
             0x101C + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -5486,6 +5797,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 3
      */
     DRIVER_DISTRACTION_SYSTEM_ENABLED =
             0x101D + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -5510,6 +5822,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum DriverDistractionState
      * @data_enum ErrorState
+     * @version 3
      */
     DRIVER_DISTRACTION_STATE =
             0x101E + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -5533,6 +5846,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     DRIVER_DISTRACTION_WARNING_ENABLED =
             0x101F + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -5554,6 +5868,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum DriverDistractionWarning
      * @data_enum ErrorState
+     * @version 3
      */
     DRIVER_DISTRACTION_WARNING =
             0x1020 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -5579,6 +5894,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 3
      */
     LOW_SPEED_COLLISION_WARNING_ENABLED =
             0x1021 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -5601,6 +5917,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum LowSpeedCollisionWarningState
      * @data_enum ErrorState
+     * @version 3
      */
     LOW_SPEED_COLLISION_WARNING_STATE =
             0x1022 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -5623,6 +5940,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
+     * @version 3
      */
     CROSS_TRAFFIC_MONITORING_ENABLED =
             0x1023 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -5642,10 +5960,65 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum CrossTrafficMonitoringWarningState
      * @data_enum ErrorState
+     * @version 3
      */
     CROSS_TRAFFIC_MONITORING_WARNING_STATE =
             0x1024 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
 
+    /**
+     * Enable or disable Low Speed Automatic Emergency Braking.
+     *
+     * Set true to enable Low Speed Automatic Emergency Braking or false to disable Low Speed
+     * Automatic Emergency Braking. When Low Speed Automatic Emergency Braking is enabled, the ADAS
+     * system in the vehicle should be turned on and monitoring to avoid potential collisions in low
+     * speed conditions. This property is different from the pre-existing
+     * AUTOMATIC_EMERGENCY_BRAKING_ENABLED, 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.
+     *
+     * In general, LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED should always return true or false.
+     * If the feature is not available due to some temporary state, such as the vehicle speed being
+     * too low, that information must be conveyed through the ErrorState values in the
+     * LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE property.
+     *
+     * 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
+     * @version 3
+     */
+    LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED =
+            0x1025 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /**
+     * Low Speed Automatic Emergency Braking state.
+     *
+     * Returns 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.
+     *
+     * If 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.
+     *
+     * For 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.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ
+     * @data_enum LowSpeedAutomaticEmergencyBrakingState
+     * @data_enum ErrorState
+     * @version 3
+     */
+    LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE =
+            0x1026 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+
     /***************************************************************************
      * End of ADAS Properties
      **************************************************************************/
diff --git a/automotive/vehicle/tools/generate_annotation_enums.py b/automotive/vehicle/tools/generate_annotation_enums.py
index 05fc99a..87e9bdc 100755
--- a/automotive/vehicle/tools/generate_annotation_enums.py
+++ b/automotive/vehicle/tools/generate_annotation_enums.py
@@ -42,6 +42,8 @@
     'AccessForVehicleProperty.java')
 ENUM_JAVA_FILE_PATH = ('hardware/interfaces/automotive/vehicle/aidl/generated_lib/java/' +
                          'EnumForVehicleProperty.java')
+VERSION_CPP_FILE_PATH = ('hardware/interfaces/automotive/vehicle/aidl/generated_lib/cpp/' +
+    'VersionForVehicleProperty.h')
 SCRIPT_PATH = 'hardware/interfaces/automotive/vehicle/tools/generate_annotation_enums.py'
 
 TAB = '    '
@@ -50,6 +52,7 @@
 RE_COMMENT_BEGIN = re.compile('\s*\/\*\*?')
 RE_COMMENT_END = re.compile('\s*\*\/')
 RE_CHANGE_MODE = re.compile('\s*\* @change_mode (\S+)\s*')
+RE_VERSION = re.compile('\s*\* @version (\S+)\s*')
 RE_ACCESS = re.compile('\s*\* @access (\S+)\s*')
 RE_DATA_ENUM = re.compile('\s*\* @data_enum (\S+)\s*')
 RE_UNIT = re.compile('\s*\* @unit (\S+)\s+')
@@ -81,8 +84,7 @@
 
 """
 
-CHANGE_MODE_CPP_HEADER = """#ifndef android_hardware_automotive_vehicle_aidl_generated_lib_ChangeModeForVehicleProperty_H_
-#define android_hardware_automotive_vehicle_aidl_generated_lib_ChangeModeForVehicleProperty_H_
+CHANGE_MODE_CPP_HEADER = """#pragma once
 
 #include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
 #include <aidl/android/hardware/automotive/vehicle/VehiclePropertyChangeMode.h>
@@ -98,7 +100,7 @@
 std::unordered_map<VehicleProperty, VehiclePropertyChangeMode> ChangeModeForVehicleProperty = {
 """
 
-CHANGE_MODE_CPP_FOOTER = """
+CPP_FOOTER = """
 };
 
 }  // namespace vehicle
@@ -106,12 +108,9 @@
 }  // namespace hardware
 }  // namespace android
 }  // aidl
-
-#endif  // android_hardware_automotive_vehicle_aidl_generated_lib_ChangeModeForVehicleProperty_H_
 """
 
-ACCESS_CPP_HEADER = """#ifndef android_hardware_automotive_vehicle_aidl_generated_lib_AccessForVehicleProperty_H_
-#define android_hardware_automotive_vehicle_aidl_generated_lib_AccessForVehicleProperty_H_
+ACCESS_CPP_HEADER = """#pragma once
 
 #include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
 #include <aidl/android/hardware/automotive/vehicle/VehiclePropertyAccess.h>
@@ -127,16 +126,19 @@
 std::unordered_map<VehicleProperty, VehiclePropertyAccess> AccessForVehicleProperty = {
 """
 
-ACCESS_CPP_FOOTER = """
-};
+VERSION_CPP_HEADER = """#pragma once
 
-}  // namespace vehicle
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
-}  // aidl
+#include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
 
-#endif  // android_hardware_automotive_vehicle_aidl_generated_lib_AccessForVehicleProperty_H_
+#include <unordered_map>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+std::unordered_map<VehicleProperty, int32_t> VersionForVehicleProperty = {
 """
 
 CHANGE_MODE_JAVA_HEADER = """package android.hardware.automotive.vehicle;
@@ -148,7 +150,7 @@
     public static final Map<Integer, Integer> values = Map.ofEntries(
 """
 
-CHANGE_MODE_JAVA_FOOTER = """
+JAVA_FOOTER = """
     );
 
 }
@@ -163,12 +165,6 @@
     public static final Map<Integer, Integer> values = Map.ofEntries(
 """
 
-ACCESS_JAVA_FOOTER = """
-    );
-
-}
-"""
-
 ENUM_JAVA_HEADER = """package android.hardware.automotive.vehicle;
 
 import java.util.List;
@@ -179,12 +175,6 @@
     public static final Map<Integer, List<Class<?>>> values = Map.ofEntries(
 """
 
-ENUM_JAVA_FOOTER = """
-    );
-
-}
-"""
-
 
 class PropertyConfig:
     """Represents one VHAL property definition in VehicleProperty.aidl."""
@@ -196,6 +186,7 @@
         self.access_modes = []
         self.enum_types = []
         self.unit_type = None
+        self.version = None
 
     def __repr__(self):
         return self.__str__()
@@ -258,6 +249,11 @@
                     match = RE_DATA_ENUM.match(line)
                     if match:
                         config.enum_types.append(match.group(1))
+                    match = RE_VERSION.match(line)
+                    if match:
+                        if config.version != None:
+                            raise Exception('Duplicate version annotation for property: ' + prop_name)
+                        config.version = match.group(1)
                 else:
                     match = RE_VALUE.match(line)
                     if match:
@@ -270,6 +266,9 @@
                         if not config.access_modes:
                             raise Exception(
                                     'No access_mode annotation for property: ' + prop_name)
+                        if not config.version:
+                            raise Exception(
+                                    'no version annotation for property: ' + prop_name)
                         config.name = prop_name
                         configs.append(config)
 
@@ -295,6 +294,9 @@
                     continue;
                 if not cpp:
                     annotation = "List.of(" + ', '.join([class_name + ".class" for class_name in config.enum_types]) + ")"
+            elif field == 'version':
+                if cpp:
+                    annotation = config.version
             else:
                 raise Exception('Unknown field: ' + field)
             if counter != 0:
@@ -347,6 +349,69 @@
     return f.name
 
 
+class GeneratedFile:
+
+    def __init__(self, type):
+        self.type = type
+        self.cpp_file_path = None
+        self.java_file_path = None
+        self.cpp_header = None
+        self.java_header = None
+        self.cpp_footer = None
+        self.java_footer = None
+        self.cpp_output_file = None
+        self.java_output_file = None
+
+    def setCppFilePath(self, cpp_file_path):
+        self.cpp_file_path = cpp_file_path
+
+    def setJavaFilePath(self, java_file_path):
+        self.java_file_path = java_file_path
+
+    def setCppHeader(self, cpp_header):
+        self.cpp_header = cpp_header
+
+    def setCppFooter(self, cpp_footer):
+        self.cpp_footer = cpp_footer
+
+    def setJavaHeader(self, java_header):
+        self.java_header = java_header
+
+    def setJavaFooter(self, java_footer):
+        self.java_footer = java_footer
+
+    def convert(self, file_parser, check_only, temp_files):
+        if self.cpp_file_path:
+            output_file = GeneratedFile._getOutputFile(self.cpp_file_path, check_only, temp_files)
+            file_parser.convert(output_file, self.cpp_header, self.cpp_footer, True, self.type)
+            self.cpp_output_file = output_file
+
+        if self.java_file_path:
+            output_file = GeneratedFile._getOutputFile(self.java_file_path, check_only, temp_files)
+            file_parser.convert(output_file, self.java_header, self.java_footer, False, self.type)
+            self.java_output_file = output_file
+
+    def cmp(self):
+        if self.cpp_file_path:
+            if not filecmp.cmp(self.cpp_output_file, self.cpp_file_path):
+                return False
+
+        if self.java_file_path:
+            if not filecmp.cmp(self.java_output_file, self.java_file_path):
+                return False
+
+        return True
+
+    @staticmethod
+    def _getOutputFile(file_path, check_only, temp_files):
+        if not check_only:
+            return file_path
+
+        temp_file = createTempFile()
+        temp_files.append(temp_file)
+        return temp_file
+
+
 def main():
     parser = argparse.ArgumentParser(
             description='Generate Java and C++ enums based on annotations in VehicleProperty.aidl')
@@ -382,51 +447,52 @@
         f.outputAsCsv(args.output_csv)
         return
 
-    change_mode_cpp_file = os.path.join(android_top, CHANGE_MODE_CPP_FILE_PATH);
-    access_cpp_file = os.path.join(android_top, ACCESS_CPP_FILE_PATH);
-    change_mode_java_file = os.path.join(android_top, CHANGE_MODE_JAVA_FILE_PATH);
-    access_java_file = os.path.join(android_top, ACCESS_JAVA_FILE_PATH);
-    enum_java_file = os.path.join(android_top, ENUM_JAVA_FILE_PATH);
+    generated_files = []
+
+    change_mode = GeneratedFile('change_mode')
+    change_mode.setCppFilePath(os.path.join(android_top, CHANGE_MODE_CPP_FILE_PATH))
+    change_mode.setJavaFilePath(os.path.join(android_top, CHANGE_MODE_JAVA_FILE_PATH))
+    change_mode.setCppHeader(CHANGE_MODE_CPP_HEADER)
+    change_mode.setCppFooter(CPP_FOOTER)
+    change_mode.setJavaHeader(CHANGE_MODE_JAVA_HEADER)
+    change_mode.setJavaFooter(JAVA_FOOTER)
+    generated_files.append(change_mode)
+
+    access_mode = GeneratedFile('access_mode')
+    access_mode.setCppFilePath(os.path.join(android_top, ACCESS_CPP_FILE_PATH))
+    access_mode.setJavaFilePath(os.path.join(android_top, ACCESS_JAVA_FILE_PATH))
+    access_mode.setCppHeader(ACCESS_CPP_HEADER)
+    access_mode.setCppFooter(CPP_FOOTER)
+    access_mode.setJavaHeader(ACCESS_JAVA_HEADER)
+    access_mode.setJavaFooter(JAVA_FOOTER)
+    generated_files.append(access_mode)
+
+    enum_types = GeneratedFile('enum_types')
+    enum_types.setJavaFilePath(os.path.join(android_top, ENUM_JAVA_FILE_PATH))
+    enum_types.setJavaHeader(ENUM_JAVA_HEADER)
+    enum_types.setJavaFooter(JAVA_FOOTER)
+    generated_files.append(enum_types)
+
+    version = GeneratedFile('version')
+    version.setCppFilePath(os.path.join(android_top, VERSION_CPP_FILE_PATH))
+    version.setCppHeader(VERSION_CPP_HEADER)
+    version.setCppFooter(CPP_FOOTER)
+    generated_files.append(version)
+
     temp_files = []
 
-    if not args.check_only:
-        change_mode_cpp_output = change_mode_cpp_file
-        access_cpp_output = access_cpp_file
-        change_mode_java_output = change_mode_java_file
-        access_java_output = access_java_file
-        enum_java_output = enum_java_file
-    else:
-        change_mode_cpp_output = createTempFile()
-        temp_files.append(change_mode_cpp_output)
-        access_cpp_output = createTempFile()
-        temp_files.append(access_cpp_output)
-        change_mode_java_output = createTempFile()
-        temp_files.append(change_mode_java_output)
-        access_java_output = createTempFile()
-        temp_files.append(access_java_output)
-        enum_java_output = createTempFile()
-        temp_files.append(enum_java_output)
-
     try:
-        f.convert(change_mode_cpp_output, CHANGE_MODE_CPP_HEADER, CHANGE_MODE_CPP_FOOTER,
-                True, 'change_mode')
-        f.convert(change_mode_java_output, CHANGE_MODE_JAVA_HEADER,
-                CHANGE_MODE_JAVA_FOOTER, False, 'change_mode')
-        f.convert(access_cpp_output, ACCESS_CPP_HEADER, ACCESS_CPP_FOOTER, True, 'access_mode')
-        f.convert(access_java_output, ACCESS_JAVA_HEADER, ACCESS_JAVA_FOOTER, False, 'access_mode')
-        f.convert(enum_java_output, ENUM_JAVA_HEADER, ENUM_JAVA_FOOTER, False, 'enum_types')
+        for generated_file in generated_files:
+            generated_file.convert(f, args.check_only, temp_files)
 
         if not args.check_only:
             return
 
-        if ((not filecmp.cmp(change_mode_cpp_output, change_mode_cpp_file)) or
-                (not filecmp.cmp(change_mode_java_output, change_mode_java_file)) or
-                (not filecmp.cmp(access_cpp_output, access_cpp_file)) or
-                (not filecmp.cmp(access_java_output, access_java_file)) or
-                (not filecmp.cmp(enum_java_output, enum_java_file))):
-            print('The generated enum files for VehicleProperty.aidl requires update, ')
-            print('Run \npython ' + android_top + '/' + SCRIPT_PATH)
-            sys.exit(1)
+        for generated_file in generated_files:
+            if not generated_file.cmp():
+                print('The generated enum files for VehicleProperty.aidl requires update, ')
+                print('Run \npython ' + android_top + '/' + SCRIPT_PATH)
+                sys.exit(1)
     except Exception as e:
         print('Error parsing VehicleProperty.aidl')
         print(e)
diff --git a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
index d3c34c5..b5ee335 100644
--- a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
+++ b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
@@ -579,6 +579,13 @@
                    VehiclePropertyType::INT32_VEC);
 }
 
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyUltrasonicsSensorMeasuredDistanceConfig) {
+    verifyProperty(VehicleProperty::ULTRASONICS_SENSOR_MEASURED_DISTANCE,
+                   VehiclePropertyAccess::READ, VehiclePropertyChangeMode::CONTINUOUS,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::VENDOR,
+                   VehiclePropertyType::INT32_VEC);
+}
+
 TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyEmergencyLaneKeepAssistEnabledConfig) {
     verifyProperty(VehicleProperty::EMERGENCY_LANE_KEEP_ASSIST_ENABLED,
                    VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
@@ -1042,6 +1049,24 @@
                    VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::INT32);
 }
 
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyHeadUpDisplayEnabledConfig) {
+    verifyProperty(VehicleProperty::HEAD_UP_DISPLAY_ENABLED, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::SEAT, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyLowSpeedAutomaticEmergencyBrakingEnabledConfig) {
+    verifyProperty(VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyLowSpeedAutomaticEmergencyBrakingStateConfig) {
+    verifyProperty(VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE,
+                   VehiclePropertyAccess::READ, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
 bool VtsHalAutomotiveVehicleTargetTest::checkIsSupported(int32_t propertyId) {
     auto result = mVhalClient->getPropConfigs({propertyId});
     return result.ok();
diff --git a/bluetooth/audio/aidl/default/A2dpBits.h b/bluetooth/audio/aidl/default/A2dpBits.h
index f467c95..fb7587c 100644
--- a/bluetooth/audio/aidl/default/A2dpBits.h
+++ b/bluetooth/audio/aidl/default/A2dpBits.h
@@ -23,7 +23,8 @@
   uint8_t* data_;
 
  public:
-  A2dpBits(const std::vector<uint8_t>& vector) : cdata_(vector.data()) {}
+  A2dpBits(const std::vector<uint8_t>& vector)
+      : cdata_(vector.data()), data_(nullptr) {}
 
   A2dpBits(std::vector<uint8_t>& vector)
       : cdata_(vector.data()), data_(vector.data()) {}
diff --git a/bluetooth/audio/flags/Android.bp b/bluetooth/audio/flags/Android.bp
new file mode 100644
index 0000000..0d18a4d
--- /dev/null
+++ b/bluetooth/audio/flags/Android.bp
@@ -0,0 +1,12 @@
+aconfig_declarations {
+    name: "btaudiohal_flags",
+    package: "com.android.btaudio.hal.flags",
+    srcs: ["btaudiohal.aconfig"],
+}
+
+cc_aconfig_library {
+    name: "btaudiohal_flags_c_lib",
+    aconfig_declarations: "btaudiohal_flags",
+    vendor: true,
+    host_supported: true,
+}
diff --git a/bluetooth/audio/flags/btaudiohal.aconfig b/bluetooth/audio/flags/btaudiohal.aconfig
new file mode 100644
index 0000000..763777e
--- /dev/null
+++ b/bluetooth/audio/flags/btaudiohal.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.btaudio.hal.flags"
+
+flag {
+    name: "dsa_lea"
+    namespace: "pixel_bluetooth"
+    description: "Flag for DSA Over LEA"
+    bug: "270987427"
+}
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index f5f8163..c0817f5 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -63,6 +63,10 @@
         "libhidlbase",
         "libxml2",
         "libflatbuffers-cpp",
+        "server_configurable_flags",
+    ],
+    static_libs: [
+        "btaudiohal_flags_c_lib",
     ],
     generated_sources: ["le_audio_codec_capabilities"],
     generated_headers: [
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
index 3519ace..67ba93c 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
@@ -20,6 +20,7 @@
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android/binder_manager.h>
+#include <com_android_btaudio_hal_flags.h>
 #include <hardware/audio.h>
 
 #include "BluetoothAudioSession.h"
@@ -36,6 +37,14 @@
 static constexpr int kWritePollMs = 1;  // polled non-blocking interval
 static constexpr int kReadPollMs = 1;   // polled non-blocking interval
 
+static std::string toString(const std::vector<LatencyMode>& latencies) {
+  std::stringstream latencyModesStr;
+  for (LatencyMode mode : latencies) {
+    latencyModesStr << " " << toString(mode);
+  }
+  return latencyModesStr.str();
+}
+
 BluetoothAudioSession::BluetoothAudioSession(const SessionType& session_type)
     : session_type_(session_type), stack_iface_(nullptr), data_mq_(nullptr) {}
 
@@ -65,6 +74,7 @@
     stack_iface_ = stack_iface;
     latency_modes_ = latency_modes;
     LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+              << " - All LatencyModes=" << toString(latency_modes)
               << ", AudioConfiguration=" << audio_config.toString();
     ReportSessionStatus();
   }
@@ -490,14 +500,12 @@
                << " has NO session";
     return false;
   }
-  bool retval = false;
-
   if (!stack_iface_->getPresentationPosition(&presentation_position).isOk()) {
     LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
                  << toString(session_type_) << " failed";
     return false;
   }
-  return retval;
+  return true;
 }
 
 void BluetoothAudioSession::UpdateSourceMetadata(
@@ -604,31 +612,46 @@
     return std::vector<LatencyMode>();
   }
 
-  std::vector<LatencyMode> supported_latency_modes;
-  if (session_type_ ==
-      SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
-    for (LatencyMode mode : latency_modes_) {
-      if (mode == LatencyMode::LOW_LATENCY) {
-        // LOW_LATENCY is not supported for LE_HARDWARE_OFFLOAD_ENC sessions
-        continue;
+  if (com::android::btaudio::hal::flags::dsa_lea()) {
+    std::vector<LatencyMode> supported_latency_modes;
+    if (session_type_ ==
+        SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+      for (LatencyMode mode : latency_modes_) {
+        if (mode == LatencyMode::LOW_LATENCY) {
+          // LOW_LATENCY is not supported for LE_HARDWARE_OFFLOAD_ENC sessions
+          continue;
+        }
+        supported_latency_modes.push_back(mode);
       }
-      supported_latency_modes.push_back(mode);
+    } else {
+      for (LatencyMode mode : latency_modes_) {
+        if (!low_latency_allowed_ && mode == LatencyMode::LOW_LATENCY) {
+          // ignore LOW_LATENCY mode if Bluetooth stack doesn't allow
+          continue;
+        }
+        if (mode == LatencyMode::DYNAMIC_SPATIAL_AUDIO_SOFTWARE ||
+            mode == LatencyMode::DYNAMIC_SPATIAL_AUDIO_HARDWARE) {
+          // DSA_SW and DSA_HW only supported for LE_HARDWARE_OFFLOAD_ENC
+          // sessions
+          continue;
+        }
+        supported_latency_modes.push_back(mode);
+      }
     }
-  } else {
-    for (LatencyMode mode : latency_modes_) {
-      if (!low_latency_allowed_ && mode == LatencyMode::LOW_LATENCY) {
-        // ignore LOW_LATENCY mode if Bluetooth stack doesn't allow
-        continue;
-      }
-      if (mode == LatencyMode::DYNAMIC_SPATIAL_AUDIO_SOFTWARE ||
-          mode == LatencyMode::DYNAMIC_SPATIAL_AUDIO_HARDWARE) {
-        // DSA_SW and DSA_HW only supported for LE_HARDWARE_OFFLOAD_ENC sessions
-        continue;
-      }
-      supported_latency_modes.push_back(mode);
-    }
+    LOG(DEBUG) << __func__ << " - Supported LatencyMode="
+               << toString(supported_latency_modes);
+    return supported_latency_modes;
   }
-  return supported_latency_modes;
+
+  if (low_latency_allowed_) return latency_modes_;
+  std::vector<LatencyMode> modes;
+  for (LatencyMode mode : latency_modes_) {
+    if (mode == LatencyMode::LOW_LATENCY)
+      // ignore those low latency mode if Bluetooth stack doesn't allow
+      continue;
+    modes.push_back(mode);
+  }
+  return modes;
 }
 
 void BluetoothAudioSession::SetLatencyMode(const LatencyMode& latency_mode) {
diff --git a/bluetooth/lmp_event/aidl/Android.bp b/bluetooth/lmp_event/aidl/Android.bp
new file mode 100644
index 0000000..6c2f278
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/Android.bp
@@ -0,0 +1,33 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.bluetooth.lmp_event",
+    vendor_available: true,
+    host_supported: true,
+    srcs: ["android/hardware/bluetooth/lmp_event/*.aidl"],
+    stability: "vintf",
+    backend: {
+        java: {
+            enabled: true,
+            platform_apis: true,
+        },
+        cpp: {
+            enabled: true,
+        },
+        ndk: {
+            enabled: true,
+            min_sdk_version: "33",
+        },
+        rust: {
+            enabled: true,
+            min_sdk_version: "33",
+        },
+    },
+}
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/AddressType.aidl
similarity index 86%
copy from security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
copy to bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/AddressType.aidl
index cc07f9b..0f239e8 100644
--- a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
+++ b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/AddressType.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 2023 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.
@@ -31,12 +31,9 @@
 // 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.security.secretkeeper;
-/* @hide */
-@Backing(type="int") @VintfStability
-enum ErrorCode {
-  OK = 0,
-  UNKNOWN_KEY_ID = 1,
-  INTERNAL_ERROR = 2,
-  REQUEST_MALFORMED = 3,
+package android.hardware.bluetooth.lmp_event;
+@Backing(type="byte") @VintfStability
+enum AddressType {
+  PUBLIC = 0x00,
+  RANDOM = 0x01,
 }
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/Direction.aidl
similarity index 86%
copy from security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
copy to bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/Direction.aidl
index cc07f9b..6f807cc 100644
--- a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
+++ b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/Direction.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 2023 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.
@@ -31,12 +31,9 @@
 // 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.security.secretkeeper;
-/* @hide */
-@Backing(type="int") @VintfStability
-enum ErrorCode {
-  OK = 0,
-  UNKNOWN_KEY_ID = 1,
-  INTERNAL_ERROR = 2,
-  REQUEST_MALFORMED = 3,
+package android.hardware.bluetooth.lmp_event;
+@Backing(type="byte") @VintfStability
+enum Direction {
+  TX = 0x00,
+  RX = 0x01,
 }
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/IBluetoothLmpEvent.aidl
similarity index 75%
copy from security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
copy to bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/IBluetoothLmpEvent.aidl
index cc07f9b..3431010 100644
--- a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
+++ b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/IBluetoothLmpEvent.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 2023 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.
@@ -31,12 +31,9 @@
 // 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.security.secretkeeper;
-/* @hide */
-@Backing(type="int") @VintfStability
-enum ErrorCode {
-  OK = 0,
-  UNKNOWN_KEY_ID = 1,
-  INTERNAL_ERROR = 2,
-  REQUEST_MALFORMED = 3,
+package android.hardware.bluetooth.lmp_event;
+@VintfStability
+interface IBluetoothLmpEvent {
+  void registerForLmpEvents(in android.hardware.bluetooth.lmp_event.IBluetoothLmpEventCallback callback, in android.hardware.bluetooth.lmp_event.AddressType addressType, in byte[6] address, in android.hardware.bluetooth.lmp_event.LmpEventId[] lmpEventIds);
+  void unregisterLmpEvents(in android.hardware.bluetooth.lmp_event.AddressType addressType, in byte[6] address);
 }
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/IBluetoothLmpEventCallback.aidl
similarity index 75%
copy from security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
copy to bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/IBluetoothLmpEventCallback.aidl
index cc07f9b..fc6758c 100644
--- a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
+++ b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/IBluetoothLmpEventCallback.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 2023 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.
@@ -31,12 +31,9 @@
 // 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.security.secretkeeper;
-/* @hide */
-@Backing(type="int") @VintfStability
-enum ErrorCode {
-  OK = 0,
-  UNKNOWN_KEY_ID = 1,
-  INTERNAL_ERROR = 2,
-  REQUEST_MALFORMED = 3,
+package android.hardware.bluetooth.lmp_event;
+@VintfStability
+interface IBluetoothLmpEventCallback {
+  void onEventGenerated(in android.hardware.bluetooth.lmp_event.Timestamp timestamp, in android.hardware.bluetooth.lmp_event.AddressType addressType, in byte[6] address, in android.hardware.bluetooth.lmp_event.Direction direction, in android.hardware.bluetooth.lmp_event.LmpEventId lmpEventId, in char connEventCounter);
+  void onRegistered(in boolean status);
 }
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/LmpEventId.aidl
similarity index 86%
copy from security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
copy to bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/LmpEventId.aidl
index cc07f9b..4ee95d1 100644
--- a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
+++ b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/LmpEventId.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 2023 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.
@@ -31,12 +31,9 @@
 // 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.security.secretkeeper;
-/* @hide */
-@Backing(type="int") @VintfStability
-enum ErrorCode {
-  OK = 0,
-  UNKNOWN_KEY_ID = 1,
-  INTERNAL_ERROR = 2,
-  REQUEST_MALFORMED = 3,
+package android.hardware.bluetooth.lmp_event;
+@Backing(type="byte") @VintfStability
+enum LmpEventId {
+  CONNECT_IND = 0x00,
+  LL_PHY_UPDATE_IND = 0x01,
 }
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/Timestamp.aidl
similarity index 86%
copy from security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
copy to bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/Timestamp.aidl
index cc07f9b..5ef32ba 100644
--- a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
+++ b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/Timestamp.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 2023 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.
@@ -31,12 +31,9 @@
 // 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.security.secretkeeper;
-/* @hide */
-@Backing(type="int") @VintfStability
-enum ErrorCode {
-  OK = 0,
-  UNKNOWN_KEY_ID = 1,
-  INTERNAL_ERROR = 2,
-  REQUEST_MALFORMED = 3,
+package android.hardware.bluetooth.lmp_event;
+@VintfStability
+parcelable Timestamp {
+  long systemTimeUs;
+  long bluetoothTimeUs;
 }
diff --git a/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/AddressType.aidl b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/AddressType.aidl
new file mode 100644
index 0000000..6bfc7c7
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/AddressType.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2023 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.bluetooth.lmp_event;
+
+/**
+ * Type of Address
+ */
+@VintfStability
+@Backing(type="byte")
+enum AddressType {
+    PUBLIC = 0x00,
+    RANDOM = 0x01,
+}
diff --git a/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/Direction.aidl b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/Direction.aidl
new file mode 100644
index 0000000..884c2bb
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/Direction.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2023 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.bluetooth.lmp_event;
+
+/**
+ * Direction of the LMP event
+ */
+@VintfStability
+@Backing(type="byte")
+enum Direction {
+    TX = 0x00,
+    RX = 0x01,
+}
diff --git a/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/IBluetoothLmpEvent.aidl b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/IBluetoothLmpEvent.aidl
new file mode 100644
index 0000000..3828af6
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/IBluetoothLmpEvent.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2023 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.bluetooth.lmp_event;
+
+import android.hardware.bluetooth.lmp_event.IBluetoothLmpEventCallback;
+import android.hardware.bluetooth.lmp_event.AddressType;
+import android.hardware.bluetooth.lmp_event.LmpEventId;
+
+@VintfStability
+interface IBluetoothLmpEvent {
+    /**
+     * API to monitor specific LMP event timestamp for given Bluetooth device.
+     *
+     * @param callback An instance of the |IBluetoothLmpEventCallback| AIDL interface object.
+     * @param addressType  Type of bluetooth address.
+     * @param address Bluetooth address to monitor.
+     * @param lmpEventIds LMP events to monitor.
+     */
+    void registerForLmpEvents(in IBluetoothLmpEventCallback callback,
+                              in AddressType addressType,
+                              in byte[6] address,
+                              in LmpEventId[] lmpEventIds);
+
+    /**
+     * API to stop monitoring a given Bluetooth device.
+     *
+     * @param addressType  Type of Bluetooth address.
+     * @param address Bluetooth device to stop monitoring.
+     */
+    void unregisterLmpEvents(in AddressType addressType, in byte[6] address);
+}
diff --git a/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/IBluetoothLmpEventCallback.aidl b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/IBluetoothLmpEventCallback.aidl
new file mode 100644
index 0000000..3295ef0
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/IBluetoothLmpEventCallback.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2023 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.bluetooth.lmp_event;
+
+import android.hardware.bluetooth.lmp_event.Direction;
+import android.hardware.bluetooth.lmp_event.AddressType;
+import android.hardware.bluetooth.lmp_event.LmpEventId;
+import android.hardware.bluetooth.lmp_event.Timestamp;
+
+@VintfStability
+interface IBluetoothLmpEventCallback {
+    /**
+     * Callback when monitored LMP event invoked.
+     *
+     * @param timestamp Timestamp when the LMP event invoked
+     * @param addressType  Type of Bluetooth address.
+     * @param address Remote bluetooth address that invoke LMP event
+     * @param direction Direction of the invoked LMP event
+     * @param lmpEventId LMP event id that bluetooth chip invoked
+     * @param connEventCounter counter incremented by one for each new connection event
+     */
+    void onEventGenerated(in Timestamp timestamp,
+                          in AddressType addressType,
+                          in byte[6] address,
+                          in Direction direction,
+                          in LmpEventId lmpEventId,
+                          in char connEventCounter);
+
+    /**
+     * Callback when registration done.
+     */
+    void onRegistered(in boolean status);
+}
diff --git a/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/LmpEventId.aidl b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/LmpEventId.aidl
new file mode 100644
index 0000000..3584b0c
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/LmpEventId.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2023 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.bluetooth.lmp_event;
+
+/**
+ * LMP event id to be monitored
+ * CONNECT_IND indicator for initiating connection
+ * LL_PHY_UPDATE_IND indicator for PHY update
+ */
+@VintfStability
+@Backing(type="byte")
+enum LmpEventId {
+    CONNECT_IND = 0x00,
+    LL_PHY_UPDATE_IND = 0x01,
+}
diff --git a/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/Timestamp.aidl b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/Timestamp.aidl
new file mode 100644
index 0000000..e3c991d
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/Timestamp.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2023 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.bluetooth.lmp_event;
+
+/**
+ * Generic structure to return the timestamp
+ */
+@VintfStability
+parcelable Timestamp {
+    /**
+     * Timestamp in microsecond since system boot.
+     *  if systemTimeUs is set to 0, its value is to be ignored
+     */
+    long systemTimeUs;
+    /**
+     * Timestamp in microsecond since Bluetooth controller power up.
+     */
+    long bluetoothTimeUs;
+}
diff --git a/bluetooth/lmp_event/aidl/default/Android.bp b/bluetooth/lmp_event/aidl/default/Android.bp
new file mode 100644
index 0000000..f8ca5e6
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/default/Android.bp
@@ -0,0 +1,28 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+rust_binary {
+    name: "android.hardware.bluetooth.lmp_event-service.default",
+    relative_install_path: "hw",
+    init_rc: ["lmp_event-default.rc"],
+    vintf_fragments: [":manifest_android.hardware.bluetooth.lmp_event-service.default.xml"],
+    vendor: true,
+    rustlibs: [
+        "liblogger",
+        "liblog_rust",
+        "libbinder_rs",
+        "android.hardware.bluetooth.lmp_event-V1-rust",
+    ],
+    srcs: [ "src/main.rs" ],
+}
+
+filegroup {
+    name: "manifest_android.hardware.bluetooth.lmp_event-service.default.xml",
+    srcs: [ "lmp_event-default.xml" ],
+}
diff --git a/bluetooth/lmp_event/aidl/default/lmp_event-default.rc b/bluetooth/lmp_event/aidl/default/lmp_event-default.rc
new file mode 100644
index 0000000..845e04d
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/default/lmp_event-default.rc
@@ -0,0 +1,6 @@
+service vendor.bluetooth.lmp_event-default /vendor/bin/hw/android.hardware.bluetooth.lmp_event-service.default
+    class hal
+    capabilities BLOCK_SUSPEND NET_ADMIN SYS_NICE
+    user bluetooth
+    group bluetooth
+    task_profiles HighPerformance
diff --git a/bluetooth/lmp_event/aidl/default/lmp_event-default.xml b/bluetooth/lmp_event/aidl/default/lmp_event-default.xml
new file mode 100644
index 0000000..24d93f8
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/default/lmp_event-default.xml
@@ -0,0 +1,10 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.bluetooth.lmp_event</name>
+        <version>1</version>
+        <interface>
+            <name>IBluetoothLmpEvent</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/bluetooth/lmp_event/aidl/default/src/lmp_event.rs b/bluetooth/lmp_event/aidl/default/src/lmp_event.rs
new file mode 100644
index 0000000..f016c3f
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/default/src/lmp_event.rs
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+//! Implements LMP Event AIDL Interface.
+
+use android_hardware_bluetooth_lmp_event::aidl::android::hardware::bluetooth::lmp_event::{
+    Direction::Direction, AddressType::AddressType, IBluetoothLmpEvent::IBluetoothLmpEvent,
+    IBluetoothLmpEventCallback::IBluetoothLmpEventCallback, LmpEventId::LmpEventId,
+    Timestamp::Timestamp,
+};
+
+use binder::{Interface, Result, Strong};
+
+use log::info;
+use std::thread;
+use std::time;
+
+
+pub struct LmpEvent;
+
+impl LmpEvent {
+    pub fn new() -> Self {
+        Self
+    }
+}
+
+impl Interface for LmpEvent {}
+
+impl IBluetoothLmpEvent for LmpEvent {
+    fn registerForLmpEvents(&self,
+                            callback: &Strong<dyn IBluetoothLmpEventCallback>,
+                            address_type: AddressType,
+                            address: &[u8; 6],
+                            lmp_event_ids: &[LmpEventId]
+    ) -> Result<()> {
+        info!("registerForLmpEvents");
+
+        let cb = callback.clone();
+        let addr_type = address_type;
+        let addr = address.clone();
+        let lmp_event = lmp_event_ids.to_vec();
+
+        let thread_handle = thread::spawn(move || {
+            let ts = Timestamp {
+                bluetoothTimeUs: 1000000,
+                systemTimeUs: 2000000,
+            };
+
+            info!("sleep for 1000 ms");
+            thread::sleep(time::Duration::from_millis(1000));
+
+            info!("callback event");
+            cb.onEventGenerated(&ts, addr_type, &addr, Direction::RX, lmp_event[0], 1)
+                .expect("onEventGenerated failed");
+        });
+
+        info!("callback register");
+        callback.onRegistered(true)?;
+
+        thread_handle.join().expect("join failed");
+        Ok(())
+    }
+    fn unregisterLmpEvents(&self, _address_type: AddressType, _address: &[u8; 6]) -> Result<()> {
+        info!("unregisterLmpEvents");
+
+        Ok(())
+    }
+}
diff --git a/bluetooth/lmp_event/aidl/default/src/main.rs b/bluetooth/lmp_event/aidl/default/src/main.rs
new file mode 100644
index 0000000..cbdd4d1
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/default/src/main.rs
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+//! Implements LMP Event Example Service.
+
+
+use android_hardware_bluetooth_lmp_event::aidl::android::hardware::bluetooth::lmp_event::IBluetoothLmpEvent::{
+    IBluetoothLmpEvent, BnBluetoothLmpEvent
+};
+
+use binder::BinderFeatures;
+use log::{info, Level};
+
+mod lmp_event;
+
+const LOG_TAG: &str = "lmp_event_service_example";
+
+fn main() {
+    info!("{LOG_TAG}: starting service");
+    let logger_success = logger::init(
+        logger::Config::default().with_tag_on_device(LOG_TAG).with_min_level(Level::Trace)
+    );
+    if !logger_success {
+        panic!("{LOG_TAG}: Failed to start logger");
+    }
+
+    binder::ProcessState::set_thread_pool_max_thread_count(0);
+
+    let lmp_event_service = lmp_event::LmpEvent::new();
+    let lmp_event_service_binder = BnBluetoothLmpEvent::new_binder(lmp_event_service, BinderFeatures::default());
+
+    binder::add_service(
+        &format!("{}/default", lmp_event::LmpEvent::get_descriptor()),
+        lmp_event_service_binder.as_binder(),
+    ).expect("Failed to register service");
+
+    binder::ProcessState::join_thread_pool()
+}
diff --git a/bluetooth/lmp_event/aidl/vts/Android.bp b/bluetooth/lmp_event/aidl/vts/Android.bp
new file mode 100644
index 0000000..b89351e
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/vts/Android.bp
@@ -0,0 +1,20 @@
+cc_test {
+    name: "VtsHalLmpEventTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalLmpEventTargetTest.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libbinder_ndk"
+    ],
+    static_libs: [
+        "android.hardware.bluetooth.lmp_event-V1-ndk",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ]
+}
+
diff --git a/bluetooth/lmp_event/aidl/vts/VtsHalLmpEventTargetTest.cpp b/bluetooth/lmp_event/aidl/vts/VtsHalLmpEventTargetTest.cpp
new file mode 100644
index 0000000..c49f60b
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/vts/VtsHalLmpEventTargetTest.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2023 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 std::shared_ptrecific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "lmp_event_hal_test"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+
+#include <aidl/android/hardware/bluetooth/lmp_event/BnBluetoothLmpEvent.h>
+#include <aidl/android/hardware/bluetooth/lmp_event/BnBluetoothLmpEventCallback.h>
+#include <aidl/android/hardware/bluetooth/lmp_event/Direction.h>
+#include <aidl/android/hardware/bluetooth/lmp_event/AddressType.h>
+#include <aidl/android/hardware/bluetooth/lmp_event/LmpEventId.h>
+#include <aidl/android/hardware/bluetooth/lmp_event/Timestamp.h>
+
+#include <android/binder_auto_utils.h>
+#include <android/binder_manager.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <log/log.h>
+
+#include <chrono>
+#include <condition_variable>
+#include <cinttypes>
+#include <thread>
+
+using ::aidl::android::hardware::bluetooth::lmp_event::BnBluetoothLmpEventCallback;
+using ::aidl::android::hardware::bluetooth::lmp_event::IBluetoothLmpEvent;
+using ::aidl::android::hardware::bluetooth::lmp_event::IBluetoothLmpEventCallback;
+using ::aidl::android::hardware::bluetooth::lmp_event::Direction;
+using ::aidl::android::hardware::bluetooth::lmp_event::AddressType;
+using ::aidl::android::hardware::bluetooth::lmp_event::LmpEventId;
+using ::aidl::android::hardware::bluetooth::lmp_event::Timestamp;
+
+using ::android::ProcessState;
+using ::ndk::SpAIBinder;
+
+namespace {
+    static constexpr std::chrono::milliseconds kEventTimeoutMs(10000);
+}
+
+class BluetoothLmpEventTest : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        ALOGI("%s", __func__);
+
+        ibt_lmp_event_ = IBluetoothLmpEvent::fromBinder(SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+        ASSERT_NE(ibt_lmp_event_, nullptr);
+
+        ibt_lmp_event_cb_ = ndk::SharedRefBase::make<BluetoothLmpEventCallback>(*this);
+        ASSERT_NE(ibt_lmp_event_cb_, nullptr);
+    }
+
+    virtual void TearDown() override {
+        ALOGI("%s", __func__);
+        ibt_lmp_event_->unregisterLmpEvents(address_type, address);
+
+        ibt_lmp_event_cb_ = nullptr;
+    }
+
+    class BluetoothLmpEventCallback : public BnBluetoothLmpEventCallback {
+        public:
+            BluetoothLmpEventTest& parent_;
+            BluetoothLmpEventCallback(BluetoothLmpEventTest& parent)
+                : parent_(parent) {}
+            ~BluetoothLmpEventCallback() = default;
+
+            ::ndk::ScopedAStatus onEventGenerated(const Timestamp& timestamp, AddressType address_type,
+                    const std::array<uint8_t, 6>& address, Direction direction,
+                    LmpEventId lmp_event_id, char16_t conn_event_counter) override {
+                for (auto t: address) {
+                    ALOGD("%s: 0x%02x", __func__, t);
+                }
+                if (direction == Direction::TX) {
+                    ALOGD("%s: Transmitting", __func__);
+                } else if (direction == Direction::RX) {
+                    ALOGD("%s: Receiving", __func__);
+                }
+                if (address_type == AddressType::PUBLIC) {
+                    ALOGD("%s: Public address", __func__);
+                } else if (address_type == AddressType::RANDOM) {
+                    ALOGD("%s: Random address", __func__);
+                }
+                if (lmp_event_id == LmpEventId::CONNECT_IND) {
+                    ALOGD("%s: initiating connection", __func__);
+                } else if (lmp_event_id == LmpEventId::LL_PHY_UPDATE_IND) {
+                    ALOGD("%s: PHY update indication", __func__);
+                }
+
+                ALOGD("%s: time: %" PRId64 "counter value: %x", __func__, timestamp.bluetoothTimeUs, conn_event_counter);
+
+                parent_.event_recv = true;
+                parent_.notify();
+
+                return ::ndk::ScopedAStatus::ok();
+            }
+            ::ndk::ScopedAStatus onRegistered(bool status) override {
+                ALOGD("%s: status: %d", __func__, status);
+                parent_.status_recv = status;
+                parent_.notify();
+                return ::ndk::ScopedAStatus::ok();
+            }
+    };
+
+    inline void notify() {
+        std::unique_lock<std::mutex> lock(lmp_event_mtx);
+        lmp_event_cv.notify_one();
+    }
+
+    inline void wait(bool is_register_event) {
+        std::unique_lock<std::mutex> lock(lmp_event_mtx);
+
+
+        if (is_register_event) {
+            lmp_event_cv.wait(lock, [&]() { return status_recv == true; });
+        } else {
+            lmp_event_cv.wait_for(lock, kEventTimeoutMs,
+                    [&](){ return event_recv == true; });
+        }
+
+    }
+
+    std::shared_ptr<IBluetoothLmpEvent> ibt_lmp_event_;
+    std::shared_ptr<IBluetoothLmpEventCallback> ibt_lmp_event_cb_;
+
+    AddressType address_type;
+    std::array<uint8_t, 6> address;
+
+    std::atomic<bool> event_recv;
+    bool status_recv;
+
+    std::mutex lmp_event_mtx;
+    std::condition_variable lmp_event_cv;
+};
+
+TEST_P(BluetoothLmpEventTest, RegisterAndReceive) {
+    address = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+    address_type = AddressType::RANDOM;
+    std::vector<LmpEventId> lmp_event_ids{LmpEventId::CONNECT_IND, LmpEventId::LL_PHY_UPDATE_IND};
+
+    ibt_lmp_event_->registerForLmpEvents(ibt_lmp_event_cb_, address_type, address, lmp_event_ids);
+    wait(true);
+    EXPECT_EQ(true, status_recv);
+
+    /* Wait for event generated here */
+    wait(false);
+    EXPECT_EQ(true, event_recv);
+
+    ibt_lmp_event_->unregisterLmpEvents(address_type, address);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BluetoothLmpEventTest);
+INSTANTIATE_TEST_SUITE_P(BluetoothLmpEvent, BluetoothLmpEventTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IBluetoothLmpEvent::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/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl
index e7fad4d..8fc77ae 100644
--- a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl
@@ -35,6 +35,7 @@
 @VintfStability
 parcelable ChannelSoudingRawData {
   int procedureCounter;
+  int[] frequencyCompensation;
   boolean aborted;
   android.hardware.bluetooth.ranging.ChannelSoundingSingleSideData initiatorData;
   android.hardware.bluetooth.ranging.ChannelSoundingSingleSideData reflectorData;
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl
index 9fe85da..ddaba72 100644
--- a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl
@@ -38,6 +38,7 @@
   @nullable byte[] packetQuality;
   @nullable byte[] packetRssiDbm;
   @nullable android.hardware.bluetooth.ranging.Nadm[] packetNadm;
+  @nullable int[] measuredFreqOffset;
   @nullable List<android.hardware.bluetooth.ranging.ComplexNumber> packetPct1;
   @nullable List<android.hardware.bluetooth.ranging.ComplexNumber> packetPct2;
   byte referencePowerDbm;
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/StepTonePct.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/StepTonePct.aidl
index a51ba37..4125748 100644
--- a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/StepTonePct.aidl
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/StepTonePct.aidl
@@ -36,6 +36,7 @@
 parcelable StepTonePct {
   List<android.hardware.bluetooth.ranging.ComplexNumber> tonePcts;
   byte[] toneQualityIndicator;
+  byte toneExtensionAntennaIndex;
   const int TONE_QUALITY_GOOD = 0;
   const int TONE_QUALITY_MEDIUM = 1;
   const int TONE_QUALITY_LOW = 2;
@@ -44,4 +45,9 @@
   const int EXTENSION_SLOT_TONE_NOT_EXPECTED_TO_BE_PRESENT = 1;
   const int EXTENSION_SLOT_TONE_EXPECTED_TO_BE_PRESENT = 2;
   const int EXTENSION_SLOT_SHIFT_AMOUNT = 4;
+  const byte TONE_EXTENSION_ANTENNA_1 = 0x0;
+  const byte TONE_EXTENSION_ANTENNA_2 = 0x1;
+  const byte TONE_EXTENSION_ANTENNA_3 = 0x2;
+  const byte TONE_EXTENSION_ANTENNA_4 = 0x3;
+  const byte TONE_EXTENSION_UNUSED = 0xFFu8;
 }
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl
index 3c8a62f..0106865 100644
--- a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl
@@ -29,6 +29,11 @@
      */
     int procedureCounter;
     /**
+     * Frequency Compensation indicates fractional frequency
+     * offset (FFO) value of initiator, in 0.01ppm
+     */
+    int[] frequencyCompensation;
+    /**
      * Indicate if the procedure aborted.
      */
     boolean aborted;
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl
index 2c3f201..942fc0d 100644
--- a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl
@@ -42,6 +42,10 @@
      */
     @nullable Nadm[] packetNadm;
     /**
+     * Measured Frequency Offset from mode 0, relative to the remote device, in 0.01ppm
+     */
+    @nullable int[] measuredFreqOffset;
+    /**
      * Packet_PCT1 or packet_PCT2 of mode-1 or mode-3, if sounding sequence is used and sounding
      * phase-based ranging is supported.
      */
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/StepTonePct.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/StepTonePct.aidl
index 99c6d65..4650861 100644
--- a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/StepTonePct.aidl
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/StepTonePct.aidl
@@ -23,6 +23,10 @@
  */
 @VintfStability
 parcelable StepTonePct {
+    /**
+     * PCT measured from mode-2 or mode-3 steps
+     * (in ascending order of antenna position with tone extension data at the end).
+     */
     List<ComplexNumber> tonePcts;
     const int TONE_QUALITY_GOOD = 0;
     const int TONE_QUALITY_MEDIUM = 1;
@@ -52,4 +56,20 @@
      * See: https://bluetooth.com/specifications/specs/channel-sounding-cr-pr/
      */
     byte[] toneQualityIndicator;
+
+    const byte TONE_EXTENSION_ANTENNA_1 = 0x0;
+    const byte TONE_EXTENSION_ANTENNA_2 = 0x1;
+    const byte TONE_EXTENSION_ANTENNA_3 = 0x2;
+    const byte TONE_EXTENSION_ANTENNA_4 = 0x3;
+    const byte TONE_EXTENSION_UNUSED = 0xFFu8;
+    /**
+     * Tone Extension Antenna Index indicates the Antenna position used in tone extension slot
+     *
+     * 0x00 = A1
+     * 0x01 = A2
+     * 0x02 = A3
+     * 0x03 = A4
+     * 0xFF = Tone extension not used
+     */
+    byte toneExtensionAntennaIndex;
 }
diff --git a/camera/device/aidl/android/hardware/camera/device/ICameraDevice.aidl b/camera/device/aidl/android/hardware/camera/device/ICameraDevice.aidl
index 3a1d762..01009ad 100644
--- a/camera/device/aidl/android/hardware/camera/device/ICameraDevice.aidl
+++ b/camera/device/aidl/android/hardware/camera/device/ICameraDevice.aidl
@@ -444,6 +444,7 @@
      *
      * For Android 15, the characteristics which need to be set are:
      *   - ANDROID_CONTROL_ZOOM_RATIO_RANGE
+     *   - SCALER_AVAILABLE_MAX_DIGITAL_ZOOM
      *
      * A service specific error will be returned on the following conditions
      *     INTERNAL_ERROR:
diff --git a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
index e335853..489bdc9 100644
--- a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
+++ b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
@@ -283,6 +283,64 @@
     }
 }
 
+TEST_P(CameraAidlTest, getSessionCharacteristics) {
+    if (flags::feature_combination_query()) {
+        std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+
+        for (const auto& name : cameraDeviceNames) {
+            std::shared_ptr<ICameraDevice> device;
+            ALOGI("getSessionCharacteristics: Testing camera device %s", name.c_str());
+            ndk::ScopedAStatus ret = mProvider->getCameraDeviceInterface(name, &device);
+            ALOGI("getCameraDeviceInterface returns: %d:%d", ret.getExceptionCode(),
+                  ret.getServiceSpecificError());
+            ASSERT_TRUE(ret.isOk());
+            ASSERT_NE(device, nullptr);
+
+            CameraMetadata meta;
+            openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
+                                   &device /*out*/);
+
+            std::vector<AvailableStream> outputStreams;
+            camera_metadata_t* staticMeta =
+                    reinterpret_cast<camera_metadata_t*>(meta.metadata.data());
+            outputStreams.clear();
+            ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
+            ASSERT_NE(0u, outputStreams.size());
+
+            AvailableStream sampleStream = outputStreams[0];
+
+            int32_t streamId = 0;
+            Stream stream = {streamId,
+                             StreamType::OUTPUT,
+                             sampleStream.width,
+                             sampleStream.height,
+                             static_cast<PixelFormat>(sampleStream.format),
+                             static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                                     GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER),
+                             Dataspace::UNKNOWN,
+                             StreamRotation::ROTATION_0,
+                             std::string(),
+                             /*bufferSize*/ 0,
+                             /*groupId*/ -1,
+                             {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                             RequestAvailableDynamicRangeProfilesMap::
+                                     ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+
+            std::vector<Stream> streams = {stream};
+            StreamConfiguration config;
+            createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &config);
+
+            CameraMetadata chars;
+            ret = device->getSessionCharacteristics(config, &chars);
+            ASSERT_TRUE(ret.isOk());
+            verifySessionCharacteristics(chars);
+        }
+    } else {
+        ALOGI("getSessionCharacteristics: Test skipped.\n");
+        GTEST_SKIP();
+    }
+}
+
 // Verify that the torch strength level can be set and retrieved successfully.
 TEST_P(CameraAidlTest, turnOnTorchWithStrengthLevel) {
     std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
@@ -531,11 +589,7 @@
             }
 
             if (ret.isOk()) {
-                const camera_metadata_t* metadata = (camera_metadata_t*)rawMetadata.metadata.data();
-                size_t expectedSize = rawMetadata.metadata.size();
-                int result = validate_camera_metadata_structure(metadata, &expectedSize);
-                ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED));
-                verifyRequestTemplate(metadata, reqTemplate);
+                validateDefaultRequestMetadata(reqTemplate, rawMetadata);
             } else {
                 ASSERT_EQ(0u, rawMetadata.metadata.size());
             }
@@ -546,24 +600,12 @@
                     ndk::ScopedAStatus ret2 =
                             device->constructDefaultRequestSettings(reqTemplate, &rawMetadata2);
 
-                    // TODO: Do not allow OPERATION_NOT_SUPPORTED once HAL
-                    // implementation is in place.
-                    if (static_cast<Status>(ret2.getServiceSpecificError()) !=
-                        Status::OPERATION_NOT_SUPPORTED) {
-                        ASSERT_EQ(ret.isOk(), ret2.isOk());
-                        ASSERT_EQ(ret.getStatus(), ret2.getStatus());
+                    ASSERT_EQ(ret.isOk(), ret2.isOk());
+                    ASSERT_EQ(ret.getStatus(), ret2.getStatus());
 
-                        ASSERT_EQ(rawMetadata.metadata.size(), rawMetadata2.metadata.size());
-                        if (ret2.isOk()) {
-                            const camera_metadata_t* metadata =
-                                    (camera_metadata_t*)rawMetadata2.metadata.data();
-                            size_t expectedSize = rawMetadata2.metadata.size();
-                            int result =
-                                    validate_camera_metadata_structure(metadata, &expectedSize);
-                            ASSERT_TRUE((result == 0) ||
-                                        (result == CAMERA_METADATA_VALIDATION_SHIFTED));
-                            verifyRequestTemplate(metadata, reqTemplate);
-                        }
+                    ASSERT_EQ(rawMetadata.metadata.size(), rawMetadata2.metadata.size());
+                    if (ret2.isOk()) {
+                        validateDefaultRequestMetadata(reqTemplate, rawMetadata2);
                     }
                 }
             }
diff --git a/camera/provider/aidl/vts/camera_aidl_test.cpp b/camera/provider/aidl/vts/camera_aidl_test.cpp
index 8e72b3f..6a08f58 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.cpp
+++ b/camera/provider/aidl/vts/camera_aidl_test.cpp
@@ -1931,6 +1931,55 @@
     }
 }
 
+void CameraAidlTest::verifySessionCharacteristics(const CameraMetadata& chars) {
+    if (flags::feature_combination_query()) {
+        const camera_metadata_t* metadata =
+                reinterpret_cast<const camera_metadata_t*>(chars.metadata.data());
+
+        size_t expectedSize = chars.metadata.size();
+        int result = validate_camera_metadata_structure(metadata, &expectedSize);
+        ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED));
+        size_t entryCount = get_camera_metadata_entry_count(metadata);
+        ASSERT_GT(entryCount, 0u);
+
+        camera_metadata_ro_entry entry;
+        int retcode = 0;
+        float maxDigitalZoom = 1.0;
+
+        retcode = find_camera_metadata_ro_entry(metadata, ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
+                                                &entry);
+        // ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM should always be present.
+        if ((0 == retcode) && (entry.count == 1)) {
+            maxDigitalZoom = entry.data.f[0];
+        } else {
+            ADD_FAILURE() << "Get camera scalerAvailableMaxDigitalZoom failed!";
+        }
+
+        retcode = find_camera_metadata_ro_entry(metadata, ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
+        bool hasZoomRatioRange = (0 == retcode && entry.count == 2);
+        if (!hasZoomRatioRange) {
+            return;
+        }
+        float minZoomRatio = entry.data.f[0];
+        float maxZoomRatio = entry.data.f[1];
+        constexpr float FLOATING_POINT_THRESHOLD = 0.00001f;
+        if (abs(maxDigitalZoom - maxZoomRatio) > FLOATING_POINT_THRESHOLD) {
+            ADD_FAILURE() << "Difference between maximum digital zoom " << maxDigitalZoom
+                          << " and maximum zoom ratio " << maxZoomRatio
+                          << " is greater than the threshold " << FLOATING_POINT_THRESHOLD << "!";
+        }
+        if (minZoomRatio > maxZoomRatio) {
+            ADD_FAILURE() << "Maximum zoom ratio is less than minimum zoom ratio!";
+        }
+        if (minZoomRatio > 1.0f) {
+            ADD_FAILURE() << "Minimum zoom ratio is more than 1.0!";
+        }
+        if (maxZoomRatio < 1.0f) {
+            ADD_FAILURE() << "Maximum zoom ratio is less than 1.0!";
+        }
+    }
+}
+
 std::vector<ConcurrentCameraIdCombination> CameraAidlTest::getConcurrentDeviceCombinations(
         std::shared_ptr<ICameraProvider>& provider) {
     std::vector<ConcurrentCameraIdCombination> combinations;
@@ -4026,3 +4075,12 @@
         }
     }
 }
+
+void CameraAidlTest::validateDefaultRequestMetadata(RequestTemplate reqTemplate,
+                                                    const CameraMetadata& rawMetadata) {
+    const camera_metadata_t* metadata = (camera_metadata_t*)rawMetadata.metadata.data();
+    size_t expectedSize = rawMetadata.metadata.size();
+    int result = validate_camera_metadata_structure(metadata, &expectedSize);
+    ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED));
+    verifyRequestTemplate(metadata, reqTemplate);
+}
diff --git a/camera/provider/aidl/vts/camera_aidl_test.h b/camera/provider/aidl/vts/camera_aidl_test.h
index b51544f..e3b0820 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.h
+++ b/camera/provider/aidl/vts/camera_aidl_test.h
@@ -281,6 +281,8 @@
     static void verifyStreamCombination(const std::shared_ptr<ICameraDevice>& device,
                                         const StreamConfiguration& config, bool expectedStatus);
 
+    static void verifySessionCharacteristics(const CameraMetadata& chars);
+
     static void verifyLogicalCameraResult(const camera_metadata_t* staticMetadata,
                                           const std::vector<uint8_t>& resultMetadata);
 
@@ -588,6 +590,9 @@
     static void waitForReleaseFence(
             std::vector<InFlightRequest::StreamBufferAndTimestamp>& resultOutputBuffers);
 
+    static void validateDefaultRequestMetadata(RequestTemplate reqTemplate,
+                                               const CameraMetadata& rawMetadata);
+
     // Map from frame number to the in-flight request state
     typedef std::unordered_map<uint32_t, std::shared_ptr<InFlightRequest>> InFlightMap;
 
diff --git a/compatibility_matrices/compatibility_matrix.9.xml b/compatibility_matrices/compatibility_matrix.9.xml
index 328f1c8..cbeb18e 100644
--- a/compatibility_matrices/compatibility_matrix.9.xml
+++ b/compatibility_matrices/compatibility_matrix.9.xml
@@ -173,6 +173,14 @@
         </interface>
     </hal>
     <hal format="aidl" optional="true">
+        <name>android.hardware.bluetooth.lmp_event</name>
+        <version>1</version>
+        <interface>
+            <name>IBluetoothLmpEvent</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
         <name>android.hardware.boot</name>
         <interface>
             <name>IBootControl</name>
@@ -325,6 +333,7 @@
         <version>1</version>
         <interface>
             <name>ISecretkeeper</name>
+            <instance>default</instance>
             <instance>nonsecure</instance>
         </interface>
     </hal>
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/VrrConfig.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/VrrConfig.aidl
index bb2569f..7377b4b 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/VrrConfig.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/VrrConfig.aidl
@@ -42,7 +42,7 @@
     int averageRefreshPeriodNs;
   }
   parcelable NotifyExpectedPresentConfig {
-    int notifyExpectedPresentHeadsUpNs;
-    int notifyExpectedPresentTimeoutNs;
+    int headsUpNs;
+    int timeoutNs;
   }
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
index 725c947..213e8e9 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
@@ -895,9 +895,9 @@
      *
      * The framework will call this function based on the parameters specified in
      * DisplayConfiguration.VrrConfig:
-     * - notifyExpectedPresentTimeoutNs specifies the idle time from the previous present command
-     * where the framework must send the early hint for the next frame.
-     * - notifyExpectedPresentHeadsUpNs specifies minimal time that framework must send
+     * - notifyExpectedPresentConfig.timeoutNs specifies the idle time from the previous
+     * present command where the framework must send the early hint for the next frame.
+     * - notifyExpectedPresentConfig.headsUpNs specifies minimal time that framework must send
      * the early hint before the next frame.
      *
      * The framework can omit calling this API when the next present command matches
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/VrrConfig.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/VrrConfig.aidl
index 3b241ba..99c1c62 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/VrrConfig.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/VrrConfig.aidl
@@ -45,15 +45,16 @@
          * The minimal time in nanoseconds that IComposerClient.notifyExpectedPresent needs to be
          * called ahead of an expectedPresentTime provided on a presentDisplay command.
          */
-        int notifyExpectedPresentHeadsUpNs;
+        int headsUpNs;
 
         /**
          * The time in nanoseconds that represents a timeout from the previous presentDisplay, which
          * after this point the display needs a call to IComposerClient.notifyExpectedPresent before
-         * sending the next frame. If set to 0, there is no need to call
+         * sending the next frame.
+         * If set to 0, hint is sent for every frame.
          * IComposerClient.notifyExpectedPresent for timeout.
          */
-        int notifyExpectedPresentTimeoutNs;
+        int timeoutNs;
     }
 
     /**
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
index 2bbaf29..2b755c2 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
@@ -1275,8 +1275,8 @@
                 if (vrrConfig.notifyExpectedPresentConfig) {
                     const auto& notifyExpectedPresentConfig =
                             *vrrConfig.notifyExpectedPresentConfig;
-                    EXPECT_GT(0, notifyExpectedPresentConfig.notifyExpectedPresentHeadsUpNs);
-                    EXPECT_GE(0, notifyExpectedPresentConfig.notifyExpectedPresentTimeoutNs);
+                    EXPECT_GE(notifyExpectedPresentConfig.headsUpNs, 0);
+                    EXPECT_GE(notifyExpectedPresentConfig.timeoutNs, 0);
                 }
             }
         }
@@ -1773,6 +1773,7 @@
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, SetDisplayBrightness) {
+    EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::ON).isOk());
     const auto& [status, capabilities] =
             mComposerClient->getDisplayCapabilities(getPrimaryDisplayId());
     ASSERT_TRUE(status.isOk());
diff --git a/media/bufferpool/aidl/default/BufferPoolClient.cpp b/media/bufferpool/aidl/default/BufferPoolClient.cpp
index e9777d8..0e249d5 100644
--- a/media/bufferpool/aidl/default/BufferPoolClient.cpp
+++ b/media/bufferpool/aidl/default/BufferPoolClient.cpp
@@ -297,7 +297,7 @@
       mLastEvictCacheMs(::android::elapsedRealtime()) {
     IAccessor::ConnectionInfo conInfo;
     bool valid = false;
-    if(accessor->connect(observer, &conInfo).isOk()) {
+    if (accessor && accessor->connect(observer, &conInfo).isOk()) {
         auto channel = std::make_unique<BufferStatusChannel>(conInfo.toFmqDesc);
         auto observer = std::make_unique<BufferInvalidationListener>(conInfo.fromFmqDesc);
 
diff --git a/media/c2/aidl/Android.bp b/media/c2/aidl/Android.bp
index 3c0915d..84cb382 100644
--- a/media/c2/aidl/Android.bp
+++ b/media/c2/aidl/Android.bp
@@ -42,11 +42,8 @@
             ],
         },
         rust: {
-            min_sdk_version: "31",
-            enabled: true,
-            additional_rustlibs: [
-                "libnativewindow_rs",
-            ],
+            // No users, and no rust implementation of android.os.Surface yet
+            enabled: false,
         },
     },
 }
diff --git a/power/aidl/Android.bp b/power/aidl/Android.bp
index 7643926..8900fb8 100644
--- a/power/aidl/Android.bp
+++ b/power/aidl/Android.bp
@@ -28,11 +28,20 @@
         "android/hardware/power/*.aidl",
     ],
     stability: "vintf",
+    imports: [
+        "android.hardware.common.fmq-V1",
+        "android.hardware.common-V2",
+    ],
     backend: {
         cpp: {
+            enabled: false,
+        },
+        ndk: {
             enabled: true,
         },
         java: {
+            sdk_version: "module_current",
+            enabled: true,
             platform_apis: true,
         },
     },
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/ChannelConfig.aidl
similarity index 80%
copy from security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
copy to power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/ChannelConfig.aidl
index cc07f9b..d3caca4 100644
--- a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/ChannelConfig.aidl
@@ -31,12 +31,11 @@
 // 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.security.secretkeeper;
-/* @hide */
-@Backing(type="int") @VintfStability
-enum ErrorCode {
-  OK = 0,
-  UNKNOWN_KEY_ID = 1,
-  INTERNAL_ERROR = 2,
-  REQUEST_MALFORMED = 3,
+package android.hardware.power;
+@VintfStability
+parcelable ChannelConfig {
+  android.hardware.common.fmq.MQDescriptor<android.hardware.power.ChannelMessage,android.hardware.common.fmq.SynchronizedReadWrite> channelDescriptor;
+  @nullable android.hardware.common.fmq.MQDescriptor<byte,android.hardware.common.fmq.SynchronizedReadWrite> eventFlagDescriptor;
+  int readFlagBitmask;
+  int writeFlagBitmask;
 }
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/ChannelMessage.aidl
similarity index 64%
copy from security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
copy to power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/ChannelMessage.aidl
index cc07f9b..25f01c0 100644
--- a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/ChannelMessage.aidl
@@ -31,12 +31,22 @@
 // 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.security.secretkeeper;
-/* @hide */
-@Backing(type="int") @VintfStability
-enum ErrorCode {
-  OK = 0,
-  UNKNOWN_KEY_ID = 1,
-  INTERNAL_ERROR = 2,
-  REQUEST_MALFORMED = 3,
+package android.hardware.power;
+@FixedSize @VintfStability
+parcelable ChannelMessage {
+  int sessionID;
+  android.hardware.power.ChannelMessage.ChannelMessageContents data;
+  @FixedSize @VintfStability
+  union ChannelMessageContents {
+    int[20] tids = {(-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */};
+    long targetDuration;
+    android.hardware.power.SessionHint hint;
+    android.hardware.power.ChannelMessage.ChannelMessageContents.SessionModeSetter mode;
+    android.hardware.power.WorkDurationFixedV1 workDuration;
+    @FixedSize @VintfStability
+    parcelable SessionModeSetter {
+      android.hardware.power.SessionMode modeInt;
+      boolean enabled;
+    }
+  }
 }
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPower.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPower.aidl
index ae03313..8acdaf2 100644
--- a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPower.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPower.aidl
@@ -40,4 +40,7 @@
   boolean isBoostSupported(in android.hardware.power.Boost type);
   android.hardware.power.IPowerHintSession createHintSession(in int tgid, in int uid, in int[] threadIds, in long durationNanos);
   long getHintSessionPreferredRate();
+  android.hardware.power.IPowerHintSession createHintSessionWithConfig(in int tgid, in int uid, in int[] threadIds, in long durationNanos, in android.hardware.power.SessionTag tag, out android.hardware.power.SessionConfig config);
+  android.hardware.power.ChannelConfig getSessionChannel(in int tgid, in int uid);
+  oneway void closeSessionChannel(in int tgid, in int uid);
 }
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPowerHintSession.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPowerHintSession.aidl
index 6bc663e..010f815 100644
--- a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPowerHintSession.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPowerHintSession.aidl
@@ -42,4 +42,5 @@
   oneway void sendHint(android.hardware.power.SessionHint hint);
   void setThreads(in int[] threadIds);
   oneway void setMode(android.hardware.power.SessionMode type, boolean enabled);
+  android.hardware.power.SessionConfig getSessionConfig();
 }
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionConfig.aidl
similarity index 89%
copy from security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
copy to power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionConfig.aidl
index cc07f9b..b03cfb2 100644
--- a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionConfig.aidl
@@ -31,12 +31,8 @@
 // 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.security.secretkeeper;
-/* @hide */
-@Backing(type="int") @VintfStability
-enum ErrorCode {
-  OK = 0,
-  UNKNOWN_KEY_ID = 1,
-  INTERNAL_ERROR = 2,
-  REQUEST_MALFORMED = 3,
+package android.hardware.power;
+@VintfStability
+parcelable SessionConfig {
+  long id;
 }
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionTag.aidl
similarity index 91%
copy from security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
copy to power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionTag.aidl
index cc07f9b..80848a4 100644
--- a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionTag.aidl
@@ -31,12 +31,11 @@
 // 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.security.secretkeeper;
-/* @hide */
+package android.hardware.power;
 @Backing(type="int") @VintfStability
-enum ErrorCode {
-  OK = 0,
-  UNKNOWN_KEY_ID = 1,
-  INTERNAL_ERROR = 2,
-  REQUEST_MALFORMED = 3,
+enum SessionTag {
+  OTHER,
+  SURFACEFLINGER,
+  HWUI,
+  GAME,
 }
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/WorkDurationFixedV1.aidl
similarity index 87%
copy from security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
copy to power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/WorkDurationFixedV1.aidl
index cc07f9b..8cd246d 100644
--- a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/WorkDurationFixedV1.aidl
@@ -31,12 +31,12 @@
 // 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.security.secretkeeper;
-/* @hide */
-@Backing(type="int") @VintfStability
-enum ErrorCode {
-  OK = 0,
-  UNKNOWN_KEY_ID = 1,
-  INTERNAL_ERROR = 2,
-  REQUEST_MALFORMED = 3,
+package android.hardware.power;
+@FixedSize @VintfStability
+parcelable WorkDurationFixedV1 {
+  long timeStampNanos;
+  long durationNanos;
+  long workPeriodStartTimestampNanos;
+  long cpuDurationNanos;
+  long gpuDurationNanos;
 }
diff --git a/power/aidl/android/hardware/power/ChannelConfig.aidl b/power/aidl/android/hardware/power/ChannelConfig.aidl
new file mode 100644
index 0000000..4da292e
--- /dev/null
+++ b/power/aidl/android/hardware/power/ChannelConfig.aidl
@@ -0,0 +1,52 @@
+
+/*
+ * Copyright (C) 2023 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.power;
+
+import android.hardware.common.fmq.MQDescriptor;
+import android.hardware.common.fmq.SynchronizedReadWrite;
+import android.hardware.power.ChannelMessage;
+
+@VintfStability
+parcelable ChannelConfig {
+    /**
+     * The message queue descriptor that provides the information necessary for
+     * a client to write to this channel.
+     */
+    MQDescriptor<ChannelMessage, SynchronizedReadWrite> channelDescriptor;
+
+    /**
+     * A message queue descriptor used to pass an optional event flag to clients,
+     * used to synchronize multiple message queues using the same flag. If not
+     * defined, the flag from the channelDescriptor should be used.
+     */
+    @nullable MQDescriptor<byte, SynchronizedReadWrite> eventFlagDescriptor;
+
+    /**
+     * The read flag bitmask to be used with the event flag, specifying the
+     * bits used by this channel to mark that the buffer has been read from.
+     * If set to 0, the default bitmask will be used.
+     */
+    int readFlagBitmask;
+
+    /**
+     * The write flag bitmask to be used with the event flag, specifying the
+     * bits used by this channel to mark that the buffer has been written to.
+     * If set to 0, the default bitmask will be used.
+     */
+    int writeFlagBitmask;
+}
diff --git a/power/aidl/android/hardware/power/ChannelMessage.aidl b/power/aidl/android/hardware/power/ChannelMessage.aidl
new file mode 100644
index 0000000..4747d90
--- /dev/null
+++ b/power/aidl/android/hardware/power/ChannelMessage.aidl
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2023 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.power;
+
+import android.hardware.power.SessionHint;
+import android.hardware.power.SessionMode;
+import android.hardware.power.WorkDurationFixedV1;
+
+/**
+ * Data sent through the FMQ must follow this structure. It's important to note
+ * that such data may come from the app itself, so the HAL must validate all
+ * data received through this interface, and reject any calls not guaranteed to be
+ * valid. Each of the types defined in the inner union maps to an equivalent call
+ * on IPowerHintSession, and is merely being used to expedite the use of that API
+ * in cases where it is safe to bypass the HintManagerService.
+ */
+@FixedSize
+@VintfStability
+parcelable ChannelMessage {
+    /**
+     * The ID of the specific session sending the hint, used to enable a single
+     * channel to be multiplexed across all sessions in a single process.
+     */
+    int sessionID;
+
+    /**
+     * A union defining the different messages that can be passed through the
+     * channel. Each type corresponds to a different call in IPowerHintSession.
+     */
+    ChannelMessageContents data;
+
+    @FixedSize
+    @VintfStability
+    union ChannelMessageContents {
+        /**
+         * List of TIDs for this session to change to. Can be used in cases
+         * where HintManagerService is not needed to validate the TIDs, such as
+         * when all TIDs directly belong to the process that owns the session.
+         */
+        int[20] tids = {
+                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
+
+        /**
+         * Setting this field will update the session’s target duration, equivalent
+         * to calling updateTargetWorkDuration(targetDuration).
+         */
+        long targetDuration;
+
+        /**
+         * Setting this field will send a hint to the session, equivalent to
+         * calling sendHint(hint).
+         */
+        SessionHint hint;
+
+        /**
+         * Setting this field will send a hint to the session, equivalent to
+         * calling setMode(mode.modeInt, mode.enabled).
+         */
+        SessionModeSetter mode;
+
+        /**
+         * Setting this field will update the session’s actual duration, equivalent
+         * to calling reportActualWorkDuration([workDuration]). Only one duration
+         * can be passed at a time; this API expects durations to be reported
+         * immediately each frame, since the overhead of this call is much lower.
+         */
+        WorkDurationFixedV1 workDuration;
+
+        /**
+         * This structure is used to fit both the mode and the state within one
+         * entry in the union.
+         */
+        @FixedSize
+        @VintfStability
+        parcelable SessionModeSetter {
+            SessionMode modeInt;
+            boolean enabled;
+        }
+    }
+}
diff --git a/power/aidl/android/hardware/power/IPower.aidl b/power/aidl/android/hardware/power/IPower.aidl
index ee8e5a3..e25714f 100644
--- a/power/aidl/android/hardware/power/IPower.aidl
+++ b/power/aidl/android/hardware/power/IPower.aidl
@@ -17,8 +17,11 @@
 package android.hardware.power;
 
 import android.hardware.power.Boost;
+import android.hardware.power.ChannelConfig;
 import android.hardware.power.IPowerHintSession;
 import android.hardware.power.Mode;
+import android.hardware.power.SessionConfig;
+import android.hardware.power.SessionTag;
 
 @VintfStability
 interface IPower {
@@ -103,4 +106,42 @@
      *         EX_UNSUPPORTED_OPERATION if hint session is not supported.
      */
     long getHintSessionPreferredRate();
+
+    /**
+     * A version of createHintSession that returns an additional bundle of session
+     * data, useful to help the session immediately communicate via an FMQ channel
+     * for more efficient updates.
+     *
+     * @return  the new session if it is supported on this device, otherwise return
+     *          with EX_UNSUPPORTED_OPERATION error if hint session is not
+     *          supported on this device.
+     * @param   tgid The TGID to be associated with this session.
+     * @param   uid The UID to be associated with this session.
+     * @param   threadIds The list of threads to be associated with this session.
+     * @param   durationNanos The desired duration in nanoseconds for this session.
+     * @param   config Extra session metadata to be returned to the caller.
+     */
+    IPowerHintSession createHintSessionWithConfig(in int tgid, in int uid, in int[] threadIds,
+            in long durationNanos, in SessionTag tag, out SessionConfig config);
+
+    /**
+     * Used to get an FMQ channel, per-process. The channel should be unique to
+     * that process, and should return the same ChannelConfig if called multiple
+     * times from that same process.
+     *
+     * @return  the channel config if hint sessions are supported on this device,
+     *          otherwise return with EX_UNSUPPORTED_OPERATION.
+     * @param   tgid The TGID to be associated with this channel.
+     * @param   uid The UID to be associated with this channel.
+     */
+    ChannelConfig getSessionChannel(in int tgid, in int uid);
+
+    /**
+     * Used to close a channel once it is no longer needed by a process, or that
+     * process dies.
+     *
+     * @param   tgid The TGID to be associated with this channel.
+     * @param   uid The UID to be associated with this channel.
+     */
+    oneway void closeSessionChannel(in int tgid, in int uid);
 }
diff --git a/power/aidl/android/hardware/power/IPowerHintSession.aidl b/power/aidl/android/hardware/power/IPowerHintSession.aidl
index 62263c8..9dd251f 100644
--- a/power/aidl/android/hardware/power/IPowerHintSession.aidl
+++ b/power/aidl/android/hardware/power/IPowerHintSession.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.power;
 
+import android.hardware.power.SessionConfig;
 import android.hardware.power.SessionHint;
 import android.hardware.power.SessionMode;
 import android.hardware.power.WorkDuration;
@@ -91,4 +92,11 @@
      * @param enabled True to enable the mode, false to disable it
      */
     oneway void setMode(SessionMode type, boolean enabled);
+
+    /**
+     * This method provides direct access to a session's config data.
+     *
+     * @return  the config data for this session
+     */
+    SessionConfig getSessionConfig();
 }
diff --git a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ErrorCode.aidl b/power/aidl/android/hardware/power/SessionConfig.aidl
similarity index 63%
copy from security/secretkeeper/aidl/android/hardware/security/secretkeeper/ErrorCode.aidl
copy to power/aidl/android/hardware/power/SessionConfig.aidl
index e9cce09..93dc9a2 100644
--- a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ErrorCode.aidl
+++ b/power/aidl/android/hardware/power/SessionConfig.aidl
@@ -14,20 +14,17 @@
  * limitations under the License.
  */
 
-package android.hardware.security.secretkeeper;
+package android.hardware.power;
 
 /**
- * Secretkeeper unencrypted error code, returned via AIDL as service specific errors in
- * EX_SERVICE_SPECIFIC.
- * @hide
+ * Additional session to be passed to the hint session during creation, or acquired
+ * after creation from the session directly.
  */
 @VintfStability
-@Backing(type="int")
-enum ErrorCode {
-    OK = 0,
-    UNKNOWN_KEY_ID = 1,
-    INTERNAL_ERROR = 2,
-    REQUEST_MALFORMED = 3,
-
-    // TODO(b/291224769): Create a more exhaustive set of error code values.
+parcelable SessionConfig {
+    /**
+     * The session's unique ID, used to identify the session for debugging and
+     * for multiplexing on the per-process FMQ channel.
+     */
+    long id;
 }
diff --git a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ErrorCode.aidl b/power/aidl/android/hardware/power/SessionTag.aidl
similarity index 62%
copy from security/secretkeeper/aidl/android/hardware/security/secretkeeper/ErrorCode.aidl
copy to power/aidl/android/hardware/power/SessionTag.aidl
index e9cce09..c1d48e4 100644
--- a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ErrorCode.aidl
+++ b/power/aidl/android/hardware/power/SessionTag.aidl
@@ -14,20 +14,28 @@
  * limitations under the License.
  */
 
-package android.hardware.security.secretkeeper;
+package android.hardware.power;
 
-/**
- * Secretkeeper unencrypted error code, returned via AIDL as service specific errors in
- * EX_SERVICE_SPECIFIC.
- * @hide
- */
 @VintfStability
 @Backing(type="int")
-enum ErrorCode {
-    OK = 0,
-    UNKNOWN_KEY_ID = 1,
-    INTERNAL_ERROR = 2,
-    REQUEST_MALFORMED = 3,
+enum SessionTag {
+    /**
+     * This tag is used to mark uncategorized hint sessions.
+     */
+    OTHER,
 
-    // TODO(b/291224769): Create a more exhaustive set of error code values.
+    /**
+     * This tag is used to mark the SurfaceFlinger hint session.
+     */
+    SURFACEFLINGER,
+
+    /**
+     * This tag is used to mark HWUI hint sessions.
+     */
+    HWUI,
+
+    /**
+     * This tag is used to mark Game hint sessions.
+     */
+    GAME,
 }
diff --git a/power/aidl/android/hardware/power/WorkDurationFixedV1.aidl b/power/aidl/android/hardware/power/WorkDurationFixedV1.aidl
new file mode 100644
index 0000000..2d202ff
--- /dev/null
+++ b/power/aidl/android/hardware/power/WorkDurationFixedV1.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 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.power;
+
+@FixedSize
+@VintfStability
+parcelable WorkDurationFixedV1 {
+    /**
+     * Timestamp in nanoseconds based on CLOCK_MONOTONIC when the duration
+     * sample was measured.
+     */
+    long timeStampNanos;
+
+    /**
+     * Total work duration in nanoseconds.
+     */
+    long durationNanos;
+
+    /**
+     * Timestamp in nanoseconds based on CLOCK_MONOTONIC when the work starts.
+     * The work period start timestamp could be zero if the call is from
+     * the legacy SDK/NDK reportActualWorkDuration API.
+     */
+    long workPeriodStartTimestampNanos;
+
+    /**
+     * CPU work duration in nanoseconds.
+     * The CPU work duration could be the same as the total work duration if
+     * the call is from the legacy SDK/NDK reportActualWorkDuration API.
+     */
+    long cpuDurationNanos;
+
+    /**
+     * GPU work duration in nanoseconds.
+     * The GPU work duration could be zero if the call is from the legacy
+     * SDK/NDK reportActualWorkDuration API.
+     */
+    long gpuDurationNanos;
+}
diff --git a/power/aidl/default/Android.bp b/power/aidl/default/Android.bp
index e3af179..b4ccc7d 100644
--- a/power/aidl/default/Android.bp
+++ b/power/aidl/default/Android.bp
@@ -29,8 +29,12 @@
     vintf_fragments: [":android.hardware.power.xml"],
     vendor: true,
     shared_libs: [
+        "android.hardware.common-V2-ndk",
+        "android.hardware.common.fmq-V1-ndk",
         "libbase",
         "libbinder_ndk",
+        "libcutils",
+        "libfmq",
     ],
     srcs: [
         "main.cpp",
diff --git a/power/aidl/default/Power.cpp b/power/aidl/default/Power.cpp
index 8fe370c..8f15663 100644
--- a/power/aidl/default/Power.cpp
+++ b/power/aidl/default/Power.cpp
@@ -18,6 +18,8 @@
 #include "PowerHintSession.h"
 
 #include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+#include <fmq/EventFlag.h>
 
 namespace aidl {
 namespace android {
@@ -27,6 +29,10 @@
 namespace example {
 
 using namespace std::chrono_literals;
+using ::aidl::android::hardware::common::fmq::MQDescriptor;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::aidl::android::hardware::power::ChannelMessage;
+using ::android::AidlMessageQueue;
 
 using ndk::ScopedAStatus;
 
@@ -70,6 +76,27 @@
     return ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Power::createHintSessionWithConfig(
+        int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos,
+        SessionTag, SessionConfig* config, std::shared_ptr<IPowerHintSession>* _aidl_return) {
+    auto out = createHintSession(tgid, uid, threadIds, durationNanos, _aidl_return);
+    static_cast<PowerHintSession*>(_aidl_return->get())->getSessionConfig(config);
+    return out;
+}
+
+ndk::ScopedAStatus Power::getSessionChannel(int32_t, int32_t, ChannelConfig* _aidl_return) {
+    static AidlMessageQueue<ChannelMessage, SynchronizedReadWrite> stubQueue{1, true};
+    _aidl_return->channelDescriptor = stubQueue.dupeDesc();
+    _aidl_return->readFlagBitmask = 0;
+    _aidl_return->writeFlagBitmask = 0;
+    _aidl_return->eventFlagDescriptor = std::nullopt;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Power::closeSessionChannel(int32_t, int32_t) {
+    return ndk::ScopedAStatus::ok();
+}
+
 ScopedAStatus Power::getHintSessionPreferredRate(int64_t* outNanoseconds) {
     *outNanoseconds = std::chrono::nanoseconds(1ms).count();
     return ScopedAStatus::ok();
diff --git a/power/aidl/default/Power.h b/power/aidl/default/Power.h
index 7f8405e..baabaa7 100644
--- a/power/aidl/default/Power.h
+++ b/power/aidl/default/Power.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <aidl/android/hardware/power/BnPower.h>
+#include "aidl/android/hardware/power/SessionTag.h"
 
 namespace aidl {
 namespace android {
@@ -35,7 +36,14 @@
                                          const std::vector<int32_t>& threadIds,
                                          int64_t durationNanos,
                                          std::shared_ptr<IPowerHintSession>* _aidl_return) override;
+    ndk::ScopedAStatus createHintSessionWithConfig(
+            int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos,
+            SessionTag tag, SessionConfig* config,
+            std::shared_ptr<IPowerHintSession>* _aidl_return) override;
     ndk::ScopedAStatus getHintSessionPreferredRate(int64_t* outNanoseconds) override;
+    ndk::ScopedAStatus getSessionChannel(int32_t tgid, int32_t uid,
+                                         ChannelConfig* _aidl_return) override;
+    ndk::ScopedAStatus closeSessionChannel(int32_t tgid, int32_t uid) override;
 
   private:
     std::vector<std::shared_ptr<IPowerHintSession>> mPowerHintSessions;
diff --git a/power/aidl/default/PowerHintSession.cpp b/power/aidl/default/PowerHintSession.cpp
index 452e435..847a42e 100644
--- a/power/aidl/default/PowerHintSession.cpp
+++ b/power/aidl/default/PowerHintSession.cpp
@@ -17,6 +17,7 @@
 #include "PowerHintSession.h"
 
 #include <android-base/logging.h>
+#include "android/binder_auto_utils.h"
 
 namespace aidl::android::hardware::power::impl::example {
 
@@ -63,4 +64,9 @@
     return ScopedAStatus::ok();
 }
 
+ScopedAStatus PowerHintSession::getSessionConfig(SessionConfig* _aidl_return) {
+    _aidl_return->id = 1;
+    return ScopedAStatus::ok();
+}
+
 }  // namespace aidl::android::hardware::power::impl::example
diff --git a/power/aidl/default/PowerHintSession.h b/power/aidl/default/PowerHintSession.h
index b488bf1..2ed5588 100644
--- a/power/aidl/default/PowerHintSession.h
+++ b/power/aidl/default/PowerHintSession.h
@@ -35,6 +35,7 @@
     ndk::ScopedAStatus sendHint(SessionHint hint) override;
     ndk::ScopedAStatus setThreads(const std::vector<int32_t>& threadIds) override;
     ndk::ScopedAStatus setMode(SessionMode mode, bool enabled) override;
+    ndk::ScopedAStatus getSessionConfig(SessionConfig* _aidl_return) override;
 };
 
 }  // namespace aidl::android::hardware::power::impl::example
diff --git a/power/aidl/vts/Android.bp b/power/aidl/vts/Android.bp
index eb98b8b..c9285f4 100644
--- a/power/aidl/vts/Android.bp
+++ b/power/aidl/vts/Android.bp
@@ -31,6 +31,11 @@
     srcs: ["VtsHalPowerTargetTest.cpp"],
     shared_libs: [
         "libbinder_ndk",
+        "libfmq",
+    ],
+    static_libs: [
+        "android.hardware.common.fmq-V1-ndk",
+        "android.hardware.common-V2-ndk",
     ],
     test_suites: [
         "general-tests",
diff --git a/power/aidl/vts/VtsHalPowerTargetTest.cpp b/power/aidl/vts/VtsHalPowerTargetTest.cpp
index 96995a0..11d44b8 100644
--- a/power/aidl/vts/VtsHalPowerTargetTest.cpp
+++ b/power/aidl/vts/VtsHalPowerTargetTest.cpp
@@ -24,12 +24,22 @@
 #include <android/binder_process.h>
 #include <android/binder_status.h>
 
+#include <fmq/AidlMessageQueue.h>
+#include <fmq/EventFlag.h>
+
 #include <unistd.h>
+#include <cstdint>
+#include "aidl/android/hardware/common/fmq/SynchronizedReadWrite.h"
+#include "fmq/EventFlag.h"
 
 namespace aidl::android::hardware::power {
 namespace {
 
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::android::AidlMessageQueue;
 using android::hardware::power::Boost;
+using android::hardware::power::ChannelConfig;
+using android::hardware::power::ChannelMessage;
 using android::hardware::power::IPower;
 using android::hardware::power::IPowerHintSession;
 using android::hardware::power::Mode;
@@ -37,6 +47,8 @@
 using android::hardware::power::SessionMode;
 using android::hardware::power::WorkDuration;
 
+using SessionMessageQueue = AidlMessageQueue<ChannelMessage, SynchronizedReadWrite>;
+
 const std::vector<Boost> kBoosts{ndk::enum_range<Boost>().begin(), ndk::enum_range<Boost>().end()};
 
 const std::vector<Mode> kModes{ndk::enum_range<Mode>().begin(), ndk::enum_range<Mode>().end()};
@@ -190,6 +202,31 @@
     ASSERT_GE(rate, 1000000);
 }
 
+TEST_P(PowerAidl, createHintSessionWithConfig) {
+    if (mServiceVersion < 5) {
+        GTEST_SKIP() << "DEVICE not launching with Power V5 and beyond.";
+    }
+    std::shared_ptr<IPowerHintSession> session;
+    SessionConfig config;
+
+    auto status = power->createHintSessionWithConfig(getpid(), getuid(), kSelfTids, 16666666L,
+                                                     SessionTag::OTHER, &config, &session);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_NE(nullptr, session);
+}
+
+TEST_P(PowerAidl, getAndCloseSessionChannel) {
+    if (mServiceVersion < 5) {
+        GTEST_SKIP() << "DEVICE not launching with Power V5 and beyond.";
+    }
+    ChannelConfig config;
+    auto status = power->getSessionChannel(getpid(), getuid(), &config);
+    ASSERT_TRUE(status.isOk());
+    auto messageQueue = std::make_shared<SessionMessageQueue>(config.channelDescriptor, true);
+    ASSERT_TRUE(messageQueue->isValid());
+    ASSERT_TRUE(power->closeSessionChannel(getpid(), getuid()).isOk());
+}
+
 TEST_P(HintSessionAidl, createAndCloseHintSession) {
     ASSERT_TRUE(mSession->pause().isOk());
     ASSERT_TRUE(mSession->resume().isOk());
@@ -252,6 +289,14 @@
     }
 }
 
+TEST_P(HintSessionAidl, getSessionConfig) {
+    if (mServiceVersion < 5) {
+        GTEST_SKIP() << "DEVICE not launching with Power V5 and beyond.";
+    }
+    SessionConfig config;
+    ASSERT_TRUE(mSession->getSessionConfig(&config).isOk());
+}
+
 // FIXED_PERFORMANCE mode is required for all devices which ship on Android 11
 // or later
 TEST_P(PowerAidl, hasFixedPerformance) {
diff --git a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/IRadioConfig.aidl b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/IRadioConfig.aidl
index 0f5e7e4..bc1c292 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/IRadioConfig.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/IRadioConfig.aidl
@@ -51,4 +51,5 @@
   oneway void setPreferredDataModem(in int serial, in byte modemId);
   oneway void setResponseFunctions(in android.hardware.radio.config.IRadioConfigResponse radioConfigResponse, in android.hardware.radio.config.IRadioConfigIndication radioConfigIndication);
   oneway void setSimSlotsMapping(in int serial, in android.hardware.radio.config.SlotPortMapping[] slotMap);
+  oneway void getSimultaneousCallingSupport(in int serial);
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/IRadioConfigIndication.aidl b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/IRadioConfigIndication.aidl
index 9189f90..f786373 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/IRadioConfigIndication.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/IRadioConfigIndication.aidl
@@ -36,4 +36,5 @@
 @VintfStability
 interface IRadioConfigIndication {
   oneway void simSlotsStatusChanged(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.config.SimSlotStatus[] slotStatus);
+  oneway void onSimultaneousCallingSupportChanged(in int[] enabledLogicalSlots);
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/IRadioConfigResponse.aidl b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/IRadioConfigResponse.aidl
index 348aa34..6ff7bd0 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/IRadioConfigResponse.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/IRadioConfigResponse.aidl
@@ -42,4 +42,5 @@
   oneway void setNumOfLiveModemsResponse(in android.hardware.radio.RadioResponseInfo info);
   oneway void setPreferredDataModemResponse(in android.hardware.radio.RadioResponseInfo info);
   oneway void setSimSlotsMappingResponse(in android.hardware.radio.RadioResponseInfo info);
+  oneway void getSimultaneousCallingSupportResponse(in android.hardware.radio.RadioResponseInfo info, in int[] enabledLogicalSlots);
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/PhoneCapability.aidl b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/PhoneCapability.aidl
index 3648866..2c66abd 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/PhoneCapability.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/PhoneCapability.aidl
@@ -39,4 +39,6 @@
   byte maxActiveInternetData;
   boolean isInternetLingeringSupported;
   byte[] logicalModemIds;
+  byte maxActiveVoice = UNKNOWN /* -1 */;
+  const byte UNKNOWN = (-1) /* -1 */;
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/SuggestedAction.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/SuggestedAction.aidl
index 6dbf09d..9846006 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/SuggestedAction.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/SuggestedAction.aidl
@@ -39,5 +39,5 @@
   TRIGGER_PLMN_BLOCK,
   TRIGGER_PLMN_BLOCK_WITH_TIMEOUT,
   TRIGGER_RAT_BLOCK,
-  TRIGGER_CLEAR_RAT_BLOCK,
+  TRIGGER_CLEAR_RAT_BLOCKS,
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/SecurityAlgorithm.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/SecurityAlgorithm.aidl
index 1664501..3eb51e7 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/SecurityAlgorithm.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/SecurityAlgorithm.aidl
@@ -64,9 +64,9 @@
   DES_EDE3_CBC = 72,
   AES_EDE3_CBC = 73,
   HMAC_SHA1_96 = 74,
-  HMAC_SHA1_96_null = 75,
+  HMAC_SHA1_96_NULL = 75,
   HMAC_MD5_96 = 76,
-  HMAC_MD5_96_null = 77,
+  HMAC_MD5_96_NULL = 77,
   SRTP_AES_COUNTER = 87,
   SRTP_AES_F8 = 88,
   SRTP_HMAC_SHA1 = 89,
diff --git a/radio/aidl/android/hardware/radio/config/IRadioConfig.aidl b/radio/aidl/android/hardware/radio/config/IRadioConfig.aidl
index 9058d9d..8f4dff4 100644
--- a/radio/aidl/android/hardware/radio/config/IRadioConfig.aidl
+++ b/radio/aidl/android/hardware/radio/config/IRadioConfig.aidl
@@ -191,4 +191,20 @@
      * This is available when android.hardware.telephony.subscription is defined.
      */
     void setSimSlotsMapping(in int serial, in SlotPortMapping[] slotMap);
+
+    /**
+     * Get the set of logical slots where simultaneous cellular calling is currently possible. This
+     * does not include simultaneous calling availability over other non-cellular transports, such
+     * as IWLAN.
+     *
+     * Get the set of slots that currently support simultaneous cellular calling. When a new
+     * cellular call is placed/received, if another slot is active and handing a call, both the
+     * active slot and proposed slot must be in this list in order to support simultaneous cellular
+     * calling for both of those slots.
+     *
+     * @param serial Serial number of request
+     *
+     * This is available when android.hardware.telephony is defined.
+     */
+    void getSimultaneousCallingSupport(in int serial);
 }
diff --git a/radio/aidl/android/hardware/radio/config/IRadioConfigIndication.aidl b/radio/aidl/android/hardware/radio/config/IRadioConfigIndication.aidl
index ed2366b..9eacb8e 100644
--- a/radio/aidl/android/hardware/radio/config/IRadioConfigIndication.aidl
+++ b/radio/aidl/android/hardware/radio/config/IRadioConfigIndication.aidl
@@ -37,4 +37,15 @@
      */
     void simSlotsStatusChanged(
             in android.hardware.radio.RadioIndicationType type, in SimSlotStatus[] slotStatus);
+
+    /**
+     * The logical slots supporting simultaneous cellular calling has changed.
+     *
+     * @param enabledLogicalSlots The slots that have simultaneous cellular calling enabled. If
+     * there is a call active on logical slot X, then a simultaneous cellular call is only possible
+     * on logical slot Y if BOTH slot X and slot Y are in enabledLogicalSlots. If simultaneous
+     * cellular calling is not currently supported, the expected value of enabledLogicalSLots is an
+     * empty int array. Sending only one radio slot is not acceptable in any case.
+     */
+    void onSimultaneousCallingSupportChanged(in int[] enabledLogicalSlots);
 }
diff --git a/radio/aidl/android/hardware/radio/config/IRadioConfigResponse.aidl b/radio/aidl/android/hardware/radio/config/IRadioConfigResponse.aidl
index df93e3c..33b0ff0 100644
--- a/radio/aidl/android/hardware/radio/config/IRadioConfigResponse.aidl
+++ b/radio/aidl/android/hardware/radio/config/IRadioConfigResponse.aidl
@@ -129,4 +129,27 @@
      *   RadioError:INVALID_ARGUMENTS
      */
     void setSimSlotsMappingResponse(in android.hardware.radio.RadioResponseInfo info);
+
+    /**
+     * Response to the asynchronous
+     * {@link IRadioConfig#getSimultaneousCallingSupport} request.
+     *
+     * @param info Response info struct containing response type, serial no. and error
+     * @param enabledLogicalSlots The slots that have simultaneous cellular calling enabled. If
+     * there is a call active on logical slot X, then a simultaneous cellular call is only possible
+     * on logical slot Y if BOTH slot X and slot Y are in enabledLogicalSlots. If simultaneous
+     * cellular calling is not currently supported, the expected value of enabledLogicalSLots is an
+     * empty int array. Sending only one radio slot is not acceptable in any case.
+     *
+     * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony is not defined
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:MODEM_ERR
+     *
+     * @see IRadioConfig#getSimultaneousCallingSupport for more information.
+     */
+    void getSimultaneousCallingSupportResponse(
+            in android.hardware.radio.RadioResponseInfo info, in int[] enabledLogicalSlots);
 }
diff --git a/radio/aidl/android/hardware/radio/config/PhoneCapability.aidl b/radio/aidl/android/hardware/radio/config/PhoneCapability.aidl
index 35d6b5d..7936eb6 100644
--- a/radio/aidl/android/hardware/radio/config/PhoneCapability.aidl
+++ b/radio/aidl/android/hardware/radio/config/PhoneCapability.aidl
@@ -25,6 +25,7 @@
 @VintfStability
 @JavaDerive(toString=true)
 parcelable PhoneCapability {
+    const byte UNKNOWN = -1;
     /**
      * maxActiveData defines how many logical modems can have
      * PS attached simultaneously. For example, for L+L modem it
@@ -47,4 +48,10 @@
      * List of logical modem IDs.
      */
     byte[] logicalModemIds;
+    /**
+     * maxActiveVoice defines how many logical modems can have
+     * cellular voice calls simultaneously. For example, for cellular DSDA
+     * with simultaneous calling support, it should be 2.
+     */
+    byte maxActiveVoice = UNKNOWN;
 }
diff --git a/radio/aidl/android/hardware/radio/ims/SuggestedAction.aidl b/radio/aidl/android/hardware/radio/ims/SuggestedAction.aidl
index f0e28fc..73c57fa 100644
--- a/radio/aidl/android/hardware/radio/ims/SuggestedAction.aidl
+++ b/radio/aidl/android/hardware/radio/ims/SuggestedAction.aidl
@@ -37,9 +37,10 @@
     TRIGGER_PLMN_BLOCK_WITH_TIMEOUT,
     /**
      * Indicates that the IMS registration on current RAT failed multiple times.
-     * The radio shall block the current RAT and search for other available RATs in the
-     * background. If no other RAT is available that meets the carrier requirements, the
-     * radio may remain on the current RAT for internet service. The radio clears all
+     * The radio shall block the {@link AccessNetwork} included with this and
+     * search for other available RATs in the background.
+     * If no other RAT is available that meets the carrier requirements, the
+     * radio may remain on the blocked RAT for internet service. The radio clears all
      * RATs marked as unavailable if {@link IRadioIms#updateImsRegistrationInfo()} API
      * with REGISTERED state is invoked.
      */
@@ -48,5 +49,5 @@
      * Indicates that the radio clears all RATs marked as unavailable and tries to find
      * an available RAT that meets the carrier requirements.
      */
-    TRIGGER_CLEAR_RAT_BLOCK,
+    TRIGGER_CLEAR_RAT_BLOCKS,
 }
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl
index 9c2502d..dde4128 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl
@@ -234,10 +234,10 @@
      * signaling, or data connection attempt for a given PLMN and/or access network. Due to
      * power concerns, once a connection type has been reported on, follow-up reports about that
      * connection type are only generated if there is any change to the previously reported
-     * encryption or integrity. Thus the AP is only to be notified when there is new information.
-     * List is reset upon rebooting thus info about initial connections is always passed to the
-     * AP after a reboot. List is also reset if the SIM is changed or if there has been a change
-     * in the access network.
+     * encryption or integrity, or if the value of SecurityAlgorithmUpdate#isUnprotectedEmergency
+     * changes. Thus the AP is only to be notified when there is new information. List is reset upon
+     * rebooting thus info about initial connections is always passed to the AP after a reboot.
+     * List is also reset if the SIM is changed or if there has been a change in the access network.
      *
      * Note: a change only in cell ID should not trigger an update, as the design is intended to
      * be agnostic to dual connectivity ("secondary serving cells").
diff --git a/radio/aidl/android/hardware/radio/network/SecurityAlgorithm.aidl b/radio/aidl/android/hardware/radio/network/SecurityAlgorithm.aidl
index 71c654c..fefa26e 100644
--- a/radio/aidl/android/hardware/radio/network/SecurityAlgorithm.aidl
+++ b/radio/aidl/android/hardware/radio/network/SecurityAlgorithm.aidl
@@ -67,9 +67,9 @@
     DES_EDE3_CBC = 72,
     AES_EDE3_CBC = 73,
     HMAC_SHA1_96 = 74,
-    HMAC_SHA1_96_null = 75,
+    HMAC_SHA1_96_NULL = 75,
     HMAC_MD5_96 = 76,
-    HMAC_MD5_96_null = 77,
+    HMAC_MD5_96_NULL = 77,
 
     // RTP (see 3GPP TS 33.328)
     SRTP_AES_COUNTER = 87,
diff --git a/radio/aidl/compat/libradiocompat/config/RadioConfig.cpp b/radio/aidl/compat/libradiocompat/config/RadioConfig.cpp
index b450418..837c626 100644
--- a/radio/aidl/compat/libradiocompat/config/RadioConfig.cpp
+++ b/radio/aidl/compat/libradiocompat/config/RadioConfig.cpp
@@ -62,6 +62,13 @@
     return ok();
 }
 
+ScopedAStatus RadioConfig::getSimultaneousCallingSupport(int32_t serial) {
+    LOG_CALL << serial;
+    LOG(ERROR) << " getSimultaneousCallingSupport is unsupported by HIDL HALs";
+    respond()->getSimultaneousCallingSupportResponse(notSupported(serial), {});
+    return ok();
+}
+
 ScopedAStatus RadioConfig::getSimSlotsStatus(int32_t serial) {
     LOG_CALL << serial;
     mHal1_1->getSimSlotsStatus(serial);
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioConfig.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioConfig.h
index 89ddea0..17d5985 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioConfig.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioConfig.h
@@ -42,6 +42,7 @@
     ::ndk::ScopedAStatus getHalDeviceCapabilities(int32_t serial) override;
     ::ndk::ScopedAStatus getNumOfLiveModems(int32_t serial) override;
     ::ndk::ScopedAStatus getPhoneCapability(int32_t serial) override;
+    ::ndk::ScopedAStatus getSimultaneousCallingSupport(int32_t serial) override;
     ::ndk::ScopedAStatus getSimSlotsStatus(int32_t serial) override;
     ::ndk::ScopedAStatus setNumOfLiveModems(int32_t serial, int8_t numOfLiveModems) override;
     ::ndk::ScopedAStatus setPreferredDataModem(int32_t serial, int8_t modemId) override;
diff --git a/radio/aidl/vts/radio_config_indication.cpp b/radio/aidl/vts/radio_config_indication.cpp
index a84c20b..c707663 100644
--- a/radio/aidl/vts/radio_config_indication.cpp
+++ b/radio/aidl/vts/radio_config_indication.cpp
@@ -22,3 +22,8 @@
         RadioIndicationType /*type*/, const std::vector<SimSlotStatus>& /*slotStatus*/) {
     return ndk::ScopedAStatus::ok();
 }
+
+ndk::ScopedAStatus RadioConfigIndication::onSimultaneousCallingSupportChanged(
+        const std::vector<int32_t>& /*enabledLogicalSlots*/) {
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_config_response.cpp b/radio/aidl/vts/radio_config_response.cpp
index 7384f87..dccbd0e 100644
--- a/radio/aidl/vts/radio_config_response.cpp
+++ b/radio/aidl/vts/radio_config_response.cpp
@@ -40,6 +40,13 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus RadioConfigResponse::getSimultaneousCallingSupportResponse(
+        const RadioResponseInfo& info, const std::vector<int32_t>& /* enabledLogicalSlots */) {
+    rspInfo = info;
+    parent_config.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus RadioConfigResponse::setPreferredDataModemResponse(
         const RadioResponseInfo& info) {
     rspInfo = info;
diff --git a/radio/aidl/vts/radio_config_test.cpp b/radio/aidl/vts/radio_config_test.cpp
index d8c0142..f725136 100644
--- a/radio/aidl/vts/radio_config_test.cpp
+++ b/radio/aidl/vts/radio_config_test.cpp
@@ -122,6 +122,41 @@
 }
 
 /*
+ * Test IRadioConfig.getSimultaneousCallingSupport() for the response returned.
+ */
+TEST_P(RadioConfigTest, getSimultaneousCallingSupport) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY)) {
+            GTEST_SKIP() << "Skipping getSimultaneousCallingSupport "
+                            "due to undefined FEATURE_TELEPHONY";
+        }
+    }
+
+    int32_t aidl_version;
+    ndk::ScopedAStatus aidl_status = radio_config->getInterfaceVersion(&aidl_version);
+    ASSERT_OK(aidl_status);
+    if (aidl_version < 3) {
+        ALOGI("Skipped the test since"
+                " getSimultaneousCallingSupport is not supported on version < 3.");
+        GTEST_SKIP();
+    }
+
+    serial = GetRandomSerialNumber();
+    ndk::ScopedAStatus res = radio_config->getSimultaneousCallingSupport(serial);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_config->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_config->rspInfo.serial);
+    ALOGI("getSimultaneousCallingSupport, rspInfo.error = %s\n",
+          toString(radioRsp_config->rspInfo.error).c_str());
+
+    ASSERT_TRUE(CheckAnyOfErrors(
+            radioRsp_config->rspInfo.error,
+            {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INTERNAL_ERR,
+            RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
+}
+
+/*
  * Test IRadioConfig.setPreferredDataModem() for the response returned.
  */
 TEST_P(RadioConfigTest, setPreferredDataModem) {
diff --git a/radio/aidl/vts/radio_config_utils.h b/radio/aidl/vts/radio_config_utils.h
index f79aedb..9e809ff 100644
--- a/radio/aidl/vts/radio_config_utils.h
+++ b/radio/aidl/vts/radio_config_utils.h
@@ -48,6 +48,9 @@
     virtual ndk::ScopedAStatus getPhoneCapabilityResponse(
             const RadioResponseInfo& info, const PhoneCapability& phoneCapability) override;
 
+    virtual ndk::ScopedAStatus getSimultaneousCallingSupportResponse(
+            const RadioResponseInfo& info, const std::vector<int32_t>& enabledLogicalSlots) override;
+
     virtual ndk::ScopedAStatus setPreferredDataModemResponse(
             const RadioResponseInfo& info) override;
 
@@ -71,6 +74,9 @@
 
     virtual ndk::ScopedAStatus simSlotsStatusChanged(
             RadioIndicationType type, const std::vector<SimSlotStatus>& slotStatus) override;
+
+    virtual ndk::ScopedAStatus onSimultaneousCallingSupportChanged(
+            const std::vector<int32_t>& /*enabledLogicalSlots*/) override;
 };
 
 // The main test class for Radio AIDL Config.
diff --git a/security/authgraph/default/src/lib.rs b/security/authgraph/default/src/lib.rs
index 1f851b2..1d6ffb3 100644
--- a/security/authgraph/default/src/lib.rs
+++ b/security/authgraph/default/src/lib.rs
@@ -22,6 +22,7 @@
     ta::{AuthGraphTa, Role},
 };
 use authgraph_hal::channel::SerializedChannel;
+use log::error;
 use std::cell::RefCell;
 use std::rc::Rc;
 use std::sync::{mpsc, Mutex};
@@ -57,10 +58,23 @@
             );
             // Loop forever processing request messages.
             loop {
-                let req_data: Vec<u8> = in_rx.recv().expect("failed to receive next req");
+                let req_data: Vec<u8> = match in_rx.recv() {
+                    Ok(data) => data,
+                    Err(_) => {
+                        error!("local TA failed to receive request!");
+                        break;
+                    }
+                };
                 let rsp_data = ta.process(&req_data);
-                out_tx.send(rsp_data).expect("failed to send out rsp");
+                match out_tx.send(rsp_data) {
+                    Ok(_) => {}
+                    Err(_) => {
+                        error!("local TA failed to send out response");
+                        break;
+                    }
+                }
             }
+            error!("local TA terminating!");
         });
         Ok(Self {
             channels: Mutex::new(Channels { in_tx, out_rx }),
diff --git a/security/rkp/README.md b/security/rkp/README.md
index 2180d0f..2d00b83 100644
--- a/security/rkp/README.md
+++ b/security/rkp/README.md
@@ -210,10 +210,10 @@
    describes an RKP VM. If there are further certificates without the RKP VM
    marker, then the chain does not describe an RKP VM.
 
-   Implementations must include the first RPK VM marker as early as possible
+   Implementations must include the first RKP VM marker as early as possible
    after the point of divergence between TEE and non-TEE components in the DICE
    chain, prior to loading the Android Bootloader (ABL).
 2. "widevine" or "keymint": If there are no certificates with the RKP VM
    marker then it describes a TEE component.
 3. None: Any component described by a DICE chain that does not match the above
-   two categories.
\ No newline at end of file
+   two categories.
diff --git a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index a1de93e..68b966c 100644
--- a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -402,7 +402,7 @@
         for (auto& key : keysToSign_) {
             bytevec privateKeyBlob;
             auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &key, &privateKeyBlob);
-            ASSERT_TRUE(status.isOk()) << status.getMessage();
+            ASSERT_TRUE(status.isOk()) << status.getDescription();
 
             vector<uint8_t> payload_value;
             check_maced_pubkey(key, testMode, &payload_value);
@@ -447,7 +447,7 @@
         auto status = provisionable_->generateCertificateRequest(
                 testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
                 &protectedData, &keysToSignMac);
-        ASSERT_TRUE(status.isOk()) << status.getMessage();
+        ASSERT_TRUE(status.isOk()) << status.getDescription();
 
         auto result = verifyProductionProtectedData(
                 deviceInfo, cppbor::Array(), keysToSignMac, protectedData, testEekChain_, eekId_,
@@ -472,7 +472,7 @@
     auto status = provisionable_->generateCertificateRequest(
             testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
             &protectedData, &keysToSignMac);
-    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    ASSERT_TRUE(status.isOk()) << status.getDescription();
 
     auto firstBcc = verifyProductionProtectedData(
             deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData, testEekChain_,
@@ -482,7 +482,7 @@
     status = provisionable_->generateCertificateRequest(
             testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
             &protectedData, &keysToSignMac);
-    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    ASSERT_TRUE(status.isOk()) << status.getDescription();
 
     auto secondBcc = verifyProductionProtectedData(
             deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData, testEekChain_,
@@ -532,7 +532,7 @@
         auto status = provisionable_->generateCertificateRequest(
                 testMode, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo, &protectedData,
                 &keysToSignMac);
-        ASSERT_TRUE(status.isOk()) << status.getMessage();
+        ASSERT_TRUE(status.isOk()) << status.getDescription();
 
         auto result = verifyProductionProtectedData(
                 deviceInfo, cborKeysToSign_, keysToSignMac, protectedData, testEekChain_, eekId_,
@@ -576,7 +576,7 @@
     auto status = provisionable_->generateCertificateRequest(
             testMode, {keyWithCorruptMac}, testEekChain_.chain, challenge_, &deviceInfo,
             &protectedData, &keysToSignMac);
-    ASSERT_FALSE(status.isOk()) << status.getMessage();
+    ASSERT_FALSE(status.isOk()) << status.getDescription();
     EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
 }
 
@@ -596,7 +596,7 @@
     auto status = provisionable_->generateCertificateRequest(
             testMode, {keyWithCorruptMac}, getProdEekChain(rpcHardwareInfo.supportedEekCurve),
             challenge_, &deviceInfo, &protectedData, &keysToSignMac);
-    ASSERT_FALSE(status.isOk()) << status.getMessage();
+    ASSERT_FALSE(status.isOk()) << status.getDescription();
     EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
 }
 
@@ -722,7 +722,7 @@
         auto challenge = randomBytes(size);
         auto status =
                 provisionable_->generateCertificateRequestV2({} /* keysToSign */, challenge, &csr);
-        ASSERT_TRUE(status.isOk()) << status.getMessage();
+        ASSERT_TRUE(status.isOk()) << status.getDescription();
 
         auto result = verifyProductionCsr(cppbor::Array(), csr, provisionable_.get(), challenge);
         ASSERT_TRUE(result) << result.message();
@@ -743,7 +743,7 @@
         SCOPED_TRACE(testing::Message() << "challenge[" << size << "]");
         auto challenge = randomBytes(size);
         auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge, &csr);
-        ASSERT_TRUE(status.isOk()) << status.getMessage();
+        ASSERT_TRUE(status.isOk()) << status.getDescription();
 
         auto result = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge);
         ASSERT_TRUE(result) << result.message();
@@ -758,7 +758,7 @@
 
     auto status = provisionable_->generateCertificateRequestV2(
             /* keysToSign */ {}, randomBytes(MAX_CHALLENGE_SIZE + 1), &csr);
-    EXPECT_FALSE(status.isOk()) << status.getMessage();
+    EXPECT_FALSE(status.isOk()) << status.getDescription();
     EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_FAILED);
 }
 
@@ -773,13 +773,13 @@
     bytevec csr;
 
     auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
-    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    ASSERT_TRUE(status.isOk()) << status.getDescription();
 
     auto firstCsr = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
     ASSERT_TRUE(firstCsr) << firstCsr.message();
 
     status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
-    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    ASSERT_TRUE(status.isOk()) << status.getDescription();
 
     auto secondCsr = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
     ASSERT_TRUE(secondCsr) << secondCsr.message();
@@ -797,7 +797,7 @@
     bytevec csr;
 
     auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
-    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    ASSERT_TRUE(status.isOk()) << status.getDescription();
 
     auto result = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
     ASSERT_TRUE(result) << result.message();
@@ -815,7 +815,7 @@
     bytevec csr;
     auto status =
             provisionable_->generateCertificateRequestV2({keyWithCorruptMac}, challenge_, &csr);
-    ASSERT_FALSE(status.isOk()) << status.getMessage();
+    ASSERT_FALSE(status.isOk()) << status.getDescription();
     EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
 }
 
@@ -829,7 +829,7 @@
     auto status = provisionable_->generateCertificateRequest(
             false /* testMode */, {} /* keysToSign */, {} /* EEK chain */, challenge_, &deviceInfo,
             &protectedData, &keysToSignMac);
-    ASSERT_FALSE(status.isOk()) << status.getMessage();
+    ASSERT_FALSE(status.isOk()) << status.getDescription();
     EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_REMOVED);
 }
 
@@ -843,7 +843,7 @@
     auto status = provisionable_->generateCertificateRequest(
             true /* testMode */, {} /* keysToSign */, {} /* EEK chain */, challenge_, &deviceInfo,
             &protectedData, &keysToSignMac);
-    ASSERT_FALSE(status.isOk()) << status.getMessage();
+    ASSERT_FALSE(status.isOk()) << status.getDescription();
     EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_REMOVED);
 }
 
@@ -927,7 +927,7 @@
     bytevec csr;
     irpcStatus =
             provisionable_->generateCertificateRequestV2({} /* keysToSign */, challenge_, &csr);
-    ASSERT_TRUE(irpcStatus.isOk()) << irpcStatus.getMessage();
+    ASSERT_TRUE(irpcStatus.isOk()) << irpcStatus.getDescription();
 
     auto result = verifyProductionCsr(cppbor::Array(), csr, provisionable_.get(), challenge_);
     ASSERT_TRUE(result) << result.message();
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ISecretkeeper.aidl b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ISecretkeeper.aidl
index 023fc8f..8ce37cd 100644
--- a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ISecretkeeper.aidl
+++ b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ISecretkeeper.aidl
@@ -36,4 +36,9 @@
 interface ISecretkeeper {
   android.hardware.security.authgraph.IAuthGraphKeyExchange getAuthGraphKe();
   byte[] processSecretManagementRequest(in byte[] request);
+  void deleteIds(in android.hardware.security.secretkeeper.SecretId[] ids);
+  void deleteAll();
+  const int ERROR_UNKNOWN_KEY_ID = 1;
+  const int ERROR_INTERNAL_ERROR = 2;
+  const int ERROR_REQUEST_MALFORMED = 3;
 }
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/SecretId.aidl
similarity index 92%
rename from security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
rename to security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/SecretId.aidl
index cc07f9b..9887066 100644
--- a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
+++ b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/SecretId.aidl
@@ -33,10 +33,7 @@
 
 package android.hardware.security.secretkeeper;
 /* @hide */
-@Backing(type="int") @VintfStability
-enum ErrorCode {
-  OK = 0,
-  UNKNOWN_KEY_ID = 1,
-  INTERNAL_ERROR = 2,
-  REQUEST_MALFORMED = 3,
+@VintfStability
+parcelable SecretId {
+  byte[64] id;
 }
diff --git a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl
index cb3e9b9..b07dba8 100644
--- a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl
@@ -17,6 +17,7 @@
 package android.hardware.security.secretkeeper;
 
 import android.hardware.security.authgraph.IAuthGraphKeyExchange;
+import android.hardware.security.secretkeeper.SecretId;
 
 @VintfStability
 /**
@@ -30,19 +31,22 @@
  * - A trusted execution environment such as ARM TrustZone.
  * - A completely separate, purpose-built and certified secure CPU.
  *
- * TODO(b/291224769): Extend the HAL interface to include:
- * 1. Dice policy operation - These allow sealing of the secrets with a class of Dice chains.
- * Typical operations are (securely) updating the dice policy sealing the Secrets above. These
- * operations are core to AntiRollback protected secrets - ie, ensuring secrets of a pVM are only
- * accessible to same or higher versions of the images.
- * 2. Maintenance API: This is required for removing the Secretkeeper entries for obsolete pVMs.
  */
 interface ISecretkeeper {
+    const int ERROR_UNKNOWN_KEY_ID = 1;
+    const int ERROR_INTERNAL_ERROR = 2;
+    const int ERROR_REQUEST_MALFORMED = 3;
+
     /**
      * Retrieve the instance of the `IAuthGraphKeyExchange` HAL that should be used for shared
-     * session key establishment.  These keys are used to perform encryption of messages as
+     * session key establishment. These keys are used to perform encryption of messages as
      * described in SecretManagement.cddl, allowing the client and Secretkeeper to have a
-     * cryptographically secure channel.
+     * cryptographically secure channel. In the key exchange protocol the client acts as P1
+     * (source) and Secretkeeper as P2 (sink). The interface returned here can be used to invoke
+     * methods on the sink.
+     *
+     * The client's identity is its DICE chain; Secretkeeper's identity is a
+     * per-boot key pair.
      */
     IAuthGraphKeyExchange getAuthGraphKe();
 
@@ -57,11 +61,11 @@
      * ProtectedRequestPacket & ProtectedResponsePacket using symmetric keys agreed between
      * the client & service. This cryptographic protection is required because the messages are
      * ferried via Android, which is allowed to be outside the TCB of clients (for example protected
-     * Virtual Machines). For this, service (& client) must implement a key exchange protocol, which
-     * is critical for establishing the secure channel.
+     * Virtual Machines). For this, service (& client) must implement the AuthGraph key exchange
+     * protocol to establish a secure channel between them.
      *
-     * If an encrypted response cannot be generated, then a service-specific Binder error using an
-     * error code from ErrorCode.aidl will be returned.
+     * If an encrypted response cannot be generated, then a service-specific Binder error using one
+     * of the ERROR_ codes above will be returned.
      *
      * Secretkeeper database should guarantee the following properties:
      *
@@ -82,4 +86,19 @@
      * @return CBOR-encoded ProtectedResponsePacket. See SecretManagement.cddl for its definition
      */
     byte[] processSecretManagementRequest(in byte[] request);
+
+    /**
+     * Delete the data corresponding to a collection of IDs.
+     *
+     * Note that unlike `processSecretManagementRequest`, the contents of this method are in
+     * plaintext, and no client authentication is required.
+     *
+     * @param Secret identifiers to delete.
+     */
+    void deleteIds(in SecretId[] ids);
+
+    /**
+     * Delete data of all clients.
+     */
+    void deleteAll();
 }
diff --git a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ErrorCode.aidl b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretId.aidl
similarity index 69%
rename from security/secretkeeper/aidl/android/hardware/security/secretkeeper/ErrorCode.aidl
rename to security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretId.aidl
index e9cce09..b17917f 100644
--- a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ErrorCode.aidl
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretId.aidl
@@ -17,17 +17,13 @@
 package android.hardware.security.secretkeeper;
 
 /**
- * Secretkeeper unencrypted error code, returned via AIDL as service specific errors in
- * EX_SERVICE_SPECIFIC.
+ * SecretId contains an identifier for a secret held by Secretkeeper.
  * @hide
  */
 @VintfStability
-@Backing(type="int")
-enum ErrorCode {
-    OK = 0,
-    UNKNOWN_KEY_ID = 1,
-    INTERNAL_ERROR = 2,
-    REQUEST_MALFORMED = 3,
-
-    // TODO(b/291224769): Create a more exhaustive set of error code values.
+parcelable SecretId {
+    /**
+     * 64-byte identifier for a secret.
+     */
+    byte[64] id;
 }
diff --git a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl
index 66ca8ed..6a824c9 100644
--- a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl
@@ -3,21 +3,22 @@
 ; The input parameter to the `processSecretManagementRequest` operation in
 ; `ISecretkeeper.aidl` is always an encrypted request message, CBOR-encoded as a
 ; COSE_Encrypt0 object.  The encryption uses the first of the keys agreed using
-; the associated AuthGraph instance, referred to as `KeySourceToSink`.
-ProtectedRequestPacket = CryptoPayload<RequestPacket, KeySourceToSink>
+; the associated AuthGraph instance, referred to as `KeySourceToSink`. Additionally,
+; an external aad is used - RequestSeqNum.
+ProtectedRequestPacket = CryptoPayload<RequestPacket, KeySourceToSink, RequestSeqNum>
 
-CryptoPayload<Payload, Key> = [ ; COSE_Encrypt0 (untagged), [RFC 9052 s5.2]
+CryptoPayload<Payload, Key, SeqNum> = [ ; COSE_Encrypt0 (untagged), [RFC 9052 s5.2]
     protected: bstr .cbor {
         1 : 3,                  ; Algorithm: AES-GCM mode w/ 256-bit key, 128-bit tag
-        4 : bstr                ; key identifier, uniquely identifies the session
-                                ; TODO(b/291228560): Refer to the Key Exchange spec.
+        4 : bstr                ; key identifier set to session ID produced
+                                ; by AuthGraph key exchange.
     },
     unprotected: {
         5 : bstr .size 12       ; IV
     },
     ciphertext : bstr           ; AES-GCM-256(Key, bstr .cbor Payload)
                                 ; AAD for the encryption is CBOR-serialized
-                                ; Enc_structure (RFC 9052 s5.3) with empty external_aad.
+                                ; Enc_structure (RFC 9052 s5.3) with SeqNum as the external_aad.
 ]
 
 ; Once decrypted, the request packet is an encoded CBOR array holding:
@@ -32,8 +33,11 @@
 StoreSecretOpcode = 2           ; Store a secret
 GetSecretOpcode = 3             ; Get the secret
 
+; Retrieve Secretkeeper version.
 GetVersionParams = ()
 
+; Store a secret identified by the given ID, with access to the secret policed
+; by the associated sealing policy.
 StoreSecretParams = (
     id : SecretId,
     secret : Secret,
@@ -42,6 +46,9 @@
 
 ; INCLUDE DicePolicy.cddl for: DicePolicy
 
+; Retrieve a secret identified by the given ID, policed according to the sealing
+; policy that was associated with the secret.  If successful, optionally also
+; update the sealing policy for the secret.
 GetSecretParams = (
     id : SecretId,
     ; Retrieving the value of a secret may optionally also update the sealing
@@ -52,10 +59,18 @@
 SecretId = bstr .size 64        ; Unique identifier of the secret.
 Secret = bstr .size 32          ; The secret value.
 
+; A monotonically incrementing number is associated with each RequestPacket to prevent replay
+; of messages within a session. This starts with 0 and is incremented (by 1) for each request
+; in a session. Secretkeeper implementation must maintain an expected RequestSeqNum for each
+; session (increasing it by 1 for each SecretManagement request received). This will be used in
+; in decryption (external_aad).
+RequestSeqNum = bstr .cbor uint     ; Encoded in accordance with Core Deterministic Encoding
+                                    ; Requirements [RFC 8949 s4.2.1]
+
 ; The return value from a successful `processSecretManagementRequest` operation is a
 ; response message encrypted with the second of the keys agreed using the associated
 ; AuthGraph instance, referred to as `KeySinkToSource`.
-ProtectedResponsePacket = CryptoPayload<ResponsePacket, KeySinkToSource>
+ProtectedResponsePacket = CryptoPayload<ResponsePacket, KeySinkToSource, ResponseSeqNum>
 
 ; Once decrypted, the inner response message is encoded as a CBOR array holding:
 ; - An initial integer return code value.
@@ -68,7 +83,6 @@
 
 ; An error code in the inner response message indicates a failure in
 ; secret management processing.
-; TODO(b/291224769): Create a more exhaustive set of ErrorCodes
 ErrorCode = &(
     ; Use this as if no other error code can be used.
     ErrorCode_UnexpectedServerError: 1,
@@ -77,7 +91,7 @@
     ; Requested Entry not found.
     ErrorCode_EntryNotFound: 3,
     ; Error happened while serialization or deserialization.
-    SerializationError: 4,
+    ErrorCode_SerializationError: 4,
     ; Indicates that Dice Policy matching did not succeed & hence access not granted.
     ErrorCode_DicePolicyError: 5,
 )
@@ -90,8 +104,13 @@
     GetSecretResult,
 )
 
-GetVersionResult = (version : uint)
+GetVersionResult = (1)
 
 StoreSecretResult = ()
 
 GetSecretResult = (secret : Secret)
+
+; Analogous to RequestSeqNum, Secretkeeper must maintain ResponseSeqNum for each session.
+; This will be input to the encryption (ProtectedResponsePacket) as external_aad.
+ResponseSeqNum = bstr .cbor uint    ; Encoded in accordance with Core Deterministic Encoding
+                                    ; Requirements [RFC 8949 s4.2.1]
diff --git a/security/secretkeeper/aidl/vts/Android.bp b/security/secretkeeper/aidl/vts/Android.bp
index c130a3a..7de9d6a 100644
--- a/security/secretkeeper/aidl/vts/Android.bp
+++ b/security/secretkeeper/aidl/vts/Android.bp
@@ -25,7 +25,9 @@
         "general-tests",
         "vts",
     ],
+    test_config: "AndroidTest.xml",
     rustlibs: [
+        "libsecretkeeper_client",
         "libsecretkeeper_comm_nostd",
         "libsecretkeeper_core_nostd",
         "android.hardware.security.secretkeeper-V1-rust",
@@ -36,6 +38,7 @@
         "libbinder_rs",
         "libcoset",
         "liblog_rust",
+        "liblogger",
     ],
     require_root: true,
 }
diff --git a/security/secretkeeper/aidl/vts/AndroidTest.xml b/security/secretkeeper/aidl/vts/AndroidTest.xml
new file mode 100644
index 0000000..4fee78f
--- /dev/null
+++ b/security/secretkeeper/aidl/vts/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 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.
+-->
+<configuration description="Config for Secretkeeper VTS tests.">
+  <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+  <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+    <option name="push-file" key="VtsSecretkeeperTargetTest" value="/data/local/tmp/VtsSecretkeeperTargetTest" />
+  </target_preparer>
+
+  <test class="com.android.tradefed.testtype.rust.RustBinaryTest" >
+    <option name="test-device-path" value="/data/local/tmp" />
+    <option name="module-name" value="VtsSecretkeeperTargetTest" />
+    <!-- Rust tests are run in parallel by default. Run these ones
+         single-threaded, so that one test's secrets don't affect
+         the behaviour of a different test. -->
+    <option name="native-test-flag" value="--test-threads=1" />
+  </test>
+</configuration>
diff --git a/security/secretkeeper/aidl/vts/rustfmt.toml b/security/secretkeeper/aidl/vts/rustfmt.toml
new file mode 120000
index 0000000..ed2086b
--- /dev/null
+++ b/security/secretkeeper/aidl/vts/rustfmt.toml
@@ -0,0 +1 @@
+../../../../../../build/soong/scripts/rustfmt.toml
\ No newline at end of file
diff --git a/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs b/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
index a473bd0..c457d24 100644
--- a/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
+++ b/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
@@ -14,26 +14,29 @@
  * limitations under the License.
  */
 
-#[cfg(test)]
+#![cfg(test)]
+
+use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::ISecretkeeper::ISecretkeeper;
+use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::SecretId::SecretId;
+use authgraph_vts_test as ag_vts;
+use authgraph_boringssl as boring;
+use authgraph_core::key;
 use binder::StatusCode;
 use coset::{CborSerializable, CoseEncrypt0};
-use log::warn;
+use log::{info, warn};
+use secretkeeper_client::SkSession;
 use secretkeeper_core::cipher;
 use secretkeeper_comm::data_types::error::SecretkeeperError;
 use secretkeeper_comm::data_types::request::Request;
 use secretkeeper_comm::data_types::request_response_impl::{
     GetVersionRequest, GetVersionResponse, GetSecretRequest, GetSecretResponse, StoreSecretRequest,
     StoreSecretResponse };
-use secretkeeper_comm::data_types::{Id, ID_SIZE, Secret, SECRET_SIZE};
+use secretkeeper_comm::data_types::{Id, Secret, SeqNum};
 use secretkeeper_comm::data_types::response::Response;
 use secretkeeper_comm::data_types::packet::{ResponsePacket, ResponseType};
-use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::ISecretkeeper::ISecretkeeper;
-use authgraph_vts_test as ag_vts;
-use authgraph_boringssl as boring;
-use authgraph_core::key;
 
-const SECRETKEEPER_IDENTIFIER: &str =
-    "android.hardware.security.secretkeeper.ISecretkeeper/nonsecure";
+const SECRETKEEPER_SERVICE: &str = "android.hardware.security.secretkeeper.ISecretkeeper";
+const SECRETKEEPER_INSTANCES: [&'static str; 2] = ["default", "nonsecure"];
 const CURRENT_VERSION: u64 = 1;
 
 // TODO(b/291238565): This will change once libdice_policy switches to Explicit-key DiceCertChain
@@ -46,32 +49,73 @@
 ];
 
 // Random bytes (of ID_SIZE/SECRET_SIZE) generated for tests.
-const ID_EXAMPLE: [u8; ID_SIZE] = [
+const ID_EXAMPLE: Id = Id([
     0xF1, 0xB2, 0xED, 0x3B, 0xD1, 0xBD, 0xF0, 0x7D, 0xE1, 0xF0, 0x01, 0xFC, 0x61, 0x71, 0xD3, 0x42,
     0xE5, 0x8A, 0xAF, 0x33, 0x6C, 0x11, 0xDC, 0xC8, 0x6F, 0xAE, 0x12, 0x5C, 0x26, 0x44, 0x6B, 0x86,
     0xCC, 0x24, 0xFD, 0xBF, 0x91, 0x4A, 0x54, 0x84, 0xF9, 0x01, 0x59, 0x25, 0x70, 0x89, 0x38, 0x8D,
     0x5E, 0xE6, 0x91, 0xDF, 0x68, 0x60, 0x69, 0x26, 0xBE, 0xFE, 0x79, 0x58, 0xF7, 0xEA, 0x81, 0x7D,
-];
-const ID_NOT_STORED: [u8; ID_SIZE] = [
+]);
+const ID_EXAMPLE_2: Id = Id([
+    0x6A, 0xCC, 0xB1, 0xEB, 0xBB, 0xAB, 0xE3, 0xEA, 0x44, 0xBD, 0xDC, 0x75, 0x75, 0x7D, 0xC0, 0xE5,
+    0xC7, 0x86, 0x41, 0x56, 0x39, 0x66, 0x96, 0x10, 0xCB, 0x43, 0x10, 0x79, 0x03, 0xDC, 0xE6, 0x9F,
+    0x12, 0x2B, 0xEF, 0x28, 0x9C, 0x1E, 0x32, 0x46, 0x5F, 0xA3, 0xE7, 0x8D, 0x53, 0x63, 0xE8, 0x30,
+    0x5A, 0x17, 0x6F, 0xEF, 0x42, 0xD6, 0x58, 0x7A, 0xF0, 0xCB, 0xD4, 0x40, 0x58, 0x96, 0x32, 0xF4,
+]);
+const ID_NOT_STORED: Id = Id([
     0x56, 0xD0, 0x4E, 0xAA, 0xC1, 0x7B, 0x55, 0x6B, 0xA0, 0x2C, 0x65, 0x43, 0x39, 0x0A, 0x6C, 0xE9,
     0x1F, 0xD0, 0x0E, 0x20, 0x3E, 0xFB, 0xF5, 0xF9, 0x3F, 0x5B, 0x11, 0x1B, 0x18, 0x73, 0xF6, 0xBB,
     0xAB, 0x9F, 0xF2, 0xD6, 0xBD, 0xBA, 0x25, 0x68, 0x22, 0x30, 0xF2, 0x1F, 0x90, 0x05, 0xF3, 0x64,
     0xE7, 0xEF, 0xC6, 0xB6, 0xA0, 0x85, 0xC9, 0x40, 0x40, 0xF0, 0xB4, 0xB9, 0xD8, 0x28, 0xEE, 0x9C,
-];
-const SECRET_EXAMPLE: [u8; SECRET_SIZE] = [
+]);
+const SECRET_EXAMPLE: Secret = Secret([
     0xA9, 0x89, 0x97, 0xFE, 0xAE, 0x97, 0x55, 0x4B, 0x32, 0x35, 0xF0, 0xE8, 0x93, 0xDA, 0xEA, 0x24,
     0x06, 0xAC, 0x36, 0x8B, 0x3C, 0x95, 0x50, 0x16, 0x67, 0x71, 0x65, 0x26, 0xEB, 0xD0, 0xC3, 0x98,
-];
+]);
 
-fn get_connection() -> Option<binder::Strong<dyn ISecretkeeper>> {
-    match binder::get_interface(SECRETKEEPER_IDENTIFIER) {
-        Ok(sk) => Some(sk),
-        Err(StatusCode::NAME_NOT_FOUND) => None,
-        Err(e) => {
-            panic!(
-                "unexpected error while fetching connection to Secretkeeper {:?}",
-                e
-            );
+fn get_connection() -> Option<(binder::Strong<dyn ISecretkeeper>, String)> {
+    // Initialize logging (which is OK to call multiple times).
+    logger::init(logger::Config::default().with_min_level(log::Level::Debug));
+
+    // Determine which instances are available.
+    let available = binder::get_declared_instances(SECRETKEEPER_SERVICE).unwrap_or_default();
+
+    // TODO: replace this with a parameterized set of tests that run for each available instance of
+    // ISecretkeeper (rather than having a fixed set of instance names to look for).
+    for instance in &SECRETKEEPER_INSTANCES {
+        if available.iter().find(|s| s == instance).is_none() {
+            // Skip undeclared instances.
+            continue;
+        }
+        let name = format!("{SECRETKEEPER_SERVICE}/{instance}");
+        match binder::get_interface(&name) {
+            Ok(sk) => {
+                info!("Running test against /{instance}");
+                return Some((sk, name));
+            }
+            Err(StatusCode::NAME_NOT_FOUND) => {
+                info!("No /{instance} instance of ISecretkeeper present");
+            }
+            Err(e) => {
+                panic!(
+                    "unexpected error while fetching connection to Secretkeeper {:?}",
+                    e
+                );
+            }
+        }
+    }
+    info!("no Secretkeeper instances in {SECRETKEEPER_INSTANCES:?} are declared and present");
+    None
+}
+
+/// Macro to perform test setup. Invokes `return` if no Secretkeeper instance available.
+macro_rules! setup_client {
+    {} => {
+        match SkClient::new() {
+            Some(sk) => sk,
+            None => {
+                warn!("Secretkeeper HAL is unavailable, skipping test");
+                return;
+            }
         }
     }
 }
@@ -79,41 +123,124 @@
 /// Secretkeeper client information.
 struct SkClient {
     sk: binder::Strong<dyn ISecretkeeper>,
-    aes_keys: [key::AesKey; 2],
-    session_id: Vec<u8>,
+    name: String,
+    session: SkSession,
+}
+
+impl Drop for SkClient {
+    fn drop(&mut self) {
+        // Delete any IDs that may be left over.
+        self.delete(&[&ID_EXAMPLE, &ID_EXAMPLE_2]);
+    }
 }
 
 impl SkClient {
     fn new() -> Option<Self> {
-        let sk = get_connection()?;
-        let (aes_keys, session_id) = authgraph_key_exchange(sk.clone());
+        let (sk, name) = get_connection()?;
         Some(Self {
-            sk,
-            aes_keys,
-            session_id,
+            sk: sk.clone(),
+            name,
+            session: SkSession::new(sk).unwrap(),
         })
     }
-    /// Wrapper around `ISecretkeeper::processSecretManagementRequest` that handles
+
+    /// This method is wrapper that use `SkSession::secret_management_request` which handles
     /// encryption and decryption.
-    fn secret_management_request(&self, req_data: &[u8]) -> Vec<u8> {
+    fn secret_management_request(&mut self, req_data: &[u8]) -> Vec<u8> {
+        self.session.secret_management_request(req_data).unwrap()
+    }
+
+    /// Unlike the method [`secret_management_request`], this method directly uses
+    /// `cipher::encrypt_message` & `cipher::decrypt_message`, allowing finer control of request
+    /// & response aad.
+    fn secret_management_request_custom_aad(
+        &self,
+        req_data: &[u8],
+        req_aad: &[u8],
+        expected_res_aad: &[u8],
+    ) -> Vec<u8> {
         let aes_gcm = boring::BoringAes;
         let rng = boring::BoringRng;
         let request_bytes = cipher::encrypt_message(
             &aes_gcm,
             &rng,
-            &self.aes_keys[0],
-            &self.session_id,
+            self.session.encryption_key(),
+            self.session.session_id(),
             &req_data,
+            req_aad,
         )
         .unwrap();
 
+        // Binder call!
         let response_bytes = self
             .sk
             .processSecretManagementRequest(&request_bytes)
             .unwrap();
 
         let response_encrypt0 = CoseEncrypt0::from_slice(&response_bytes).unwrap();
-        cipher::decrypt_message(&aes_gcm, &self.aes_keys[1], &response_encrypt0).unwrap()
+        cipher::decrypt_message(
+            &aes_gcm,
+            self.session.decryption_key(),
+            &response_encrypt0,
+            expected_res_aad,
+        )
+        .unwrap()
+    }
+
+    /// Helper method to store a secret.
+    fn store(&mut self, id: &Id, secret: &Secret) {
+        let store_request = StoreSecretRequest {
+            id: id.clone(),
+            secret: secret.clone(),
+            sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
+        };
+        let store_request = store_request.serialize_to_packet().to_vec().unwrap();
+
+        let store_response = self.secret_management_request(&store_request);
+        let store_response = ResponsePacket::from_slice(&store_response).unwrap();
+
+        assert_eq!(
+            store_response.response_type().unwrap(),
+            ResponseType::Success
+        );
+        // Really just checking that the response is indeed StoreSecretResponse
+        let _ = StoreSecretResponse::deserialize_from_packet(store_response).unwrap();
+    }
+
+    /// Helper method to get a secret.
+    fn get(&mut self, id: &Id) -> Option<Secret> {
+        let get_request = GetSecretRequest {
+            id: id.clone(),
+            updated_sealing_policy: None,
+        };
+        let get_request = get_request.serialize_to_packet().to_vec().unwrap();
+
+        let get_response = self.secret_management_request(&get_request);
+        let get_response = ResponsePacket::from_slice(&get_response).unwrap();
+
+        if get_response.response_type().unwrap() == ResponseType::Success {
+            let get_response = *GetSecretResponse::deserialize_from_packet(get_response).unwrap();
+            Some(Secret(get_response.secret.0))
+        } else {
+            // Only expect a not-found failure.
+            let err = *SecretkeeperError::deserialize_from_packet(get_response).unwrap();
+            assert_eq!(err, SecretkeeperError::EntryNotFound);
+            None
+        }
+    }
+
+    /// Helper method to delete secrets.
+    fn delete(&self, ids: &[&Id]) {
+        let ids: Vec<SecretId> = ids
+            .iter()
+            .map(|id| SecretId { id: id.0 })
+            .collect();
+        self.sk.deleteIds(&ids).unwrap();
+    }
+
+    /// Helper method to delete everything.
+    fn delete_all(&self) {
+        self.sk.deleteAll().unwrap();
     }
 }
 
@@ -128,7 +255,7 @@
 /// mainline key exchange against a local source implementation.
 #[test]
 fn authgraph_mainline() {
-    let sk = match get_connection() {
+    let (sk, _) = match get_connection() {
         Some(sk) => sk,
         None => {
             warn!("Secretkeeper HAL is unavailable, skipping test");
@@ -142,7 +269,7 @@
 /// a corrupted session ID signature.
 #[test]
 fn authgraph_corrupt_sig() {
-    let sk = match get_connection() {
+    let (sk, _) = match get_connection() {
         Some(sk) => sk,
         None => {
             warn!("Secretkeeper HAL is unavailable, skipping test");
@@ -158,7 +285,7 @@
 /// when corrupted keys are returned to it.
 #[test]
 fn authgraph_corrupt_keys() {
-    let sk = match get_connection() {
+    let (sk, _) = match get_connection() {
         Some(sk) => sk,
         None => {
             warn!("Secretkeeper HAL is unavailable, skipping test");
@@ -175,13 +302,7 @@
 
 #[test]
 fn secret_management_get_version() {
-    let sk_client = match SkClient::new() {
-        Some(sk) => sk,
-        None => {
-            warn!("Secretkeeper HAL is unavailable, skipping test");
-            return;
-        }
-    };
+    let mut sk_client = setup_client!();
 
     let request = GetVersionRequest {};
     let request_packet = request.serialize_to_packet();
@@ -201,13 +322,7 @@
 
 #[test]
 fn secret_management_malformed_request() {
-    let sk_client = match SkClient::new() {
-        Some(sk) => sk,
-        None => {
-            warn!("Secretkeeper HAL is unavailable, skipping test");
-            return;
-        }
-    };
+    let mut sk_client = setup_client!();
 
     let request = GetVersionRequest {};
     let request_packet = request.serialize_to_packet();
@@ -229,83 +344,209 @@
 
 #[test]
 fn secret_management_store_get_secret_found() {
-    let sk_client = match SkClient::new() {
-        Some(sk) => sk,
-        None => {
-            warn!("Secretkeeper HAL is unavailable, skipping test");
-            return;
-        }
-    };
+    let mut sk_client = setup_client!();
 
-    let store_request = StoreSecretRequest {
-        id: Id(ID_EXAMPLE),
-        secret: Secret(SECRET_EXAMPLE),
-        sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
-    };
-
-    let store_request = store_request.serialize_to_packet().to_vec().unwrap();
-
-    let store_response = sk_client.secret_management_request(&store_request);
-    let store_response = ResponsePacket::from_slice(&store_response).unwrap();
-
-    assert_eq!(
-        store_response.response_type().unwrap(),
-        ResponseType::Success
-    );
-    // Really just checking that the response is indeed StoreSecretResponse
-    let _ = StoreSecretResponse::deserialize_from_packet(store_response).unwrap();
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
 
     // Get the secret that was just stored
-    let get_request = GetSecretRequest {
-        id: Id(ID_EXAMPLE),
-        updated_sealing_policy: None,
-    };
-    let get_request = get_request.serialize_to_packet().to_vec().unwrap();
-
-    let get_response = sk_client.secret_management_request(&get_request);
-    let get_response = ResponsePacket::from_slice(&get_response).unwrap();
-    assert_eq!(get_response.response_type().unwrap(), ResponseType::Success);
-    let get_response = *GetSecretResponse::deserialize_from_packet(get_response).unwrap();
-    assert_eq!(get_response.secret.0, SECRET_EXAMPLE);
+    assert_eq!(sk_client.get(&ID_EXAMPLE), Some(SECRET_EXAMPLE));
 }
 
 #[test]
 fn secret_management_store_get_secret_not_found() {
-    let sk_client = match SkClient::new() {
-        Some(sk) => sk,
-        None => {
-            warn!("Secretkeeper HAL is unavailable, skipping test");
-            return;
-        }
-    };
+    let mut sk_client = setup_client!();
 
     // Store a secret (corresponding to an id).
-    let store_request = StoreSecretRequest {
-        id: Id(ID_EXAMPLE),
-        secret: Secret(SECRET_EXAMPLE),
-        sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
-    };
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
 
-    let store_request = store_request.serialize_to_packet().to_vec().unwrap();
-    let store_response = sk_client.secret_management_request(&store_request);
-    let store_response = ResponsePacket::from_slice(&store_response).unwrap();
+    // Get the secret that was never stored
+    assert_eq!(sk_client.get(&ID_NOT_STORED), None);
+}
 
-    assert_eq!(
-        store_response.response_type().unwrap(),
-        ResponseType::Success
-    );
+#[test]
+fn secretkeeper_store_delete_ids() {
+    let mut sk_client = setup_client!();
+
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
+    sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE);
+    sk_client.delete(&[&ID_EXAMPLE]);
+
+    assert_eq!(sk_client.get(&ID_EXAMPLE), None);
+    assert_eq!(sk_client.get(&ID_EXAMPLE_2), Some(SECRET_EXAMPLE));
+
+    sk_client.delete(&[&ID_EXAMPLE_2]);
+
+    assert_eq!(sk_client.get(&ID_EXAMPLE), None);
+    assert_eq!(sk_client.get(&ID_EXAMPLE_2), None);
+}
+
+#[test]
+fn secretkeeper_store_delete_multiple_ids() {
+    let mut sk_client = setup_client!();
+
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
+    sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE);
+    sk_client.delete(&[&ID_EXAMPLE, &ID_EXAMPLE_2]);
+
+    assert_eq!(sk_client.get(&ID_EXAMPLE), None);
+    assert_eq!(sk_client.get(&ID_EXAMPLE_2), None);
+}
+
+#[test]
+fn secretkeeper_store_delete_duplicate_ids() {
+    let mut sk_client = setup_client!();
+
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
+    sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE);
+    // Delete the same secret twice.
+    sk_client.delete(&[&ID_EXAMPLE, &ID_EXAMPLE]);
+
+    assert_eq!(sk_client.get(&ID_EXAMPLE), None);
+    assert_eq!(sk_client.get(&ID_EXAMPLE_2), Some(SECRET_EXAMPLE));
+}
+
+#[test]
+fn secretkeeper_store_delete_nonexistent() {
+    let mut sk_client = setup_client!();
+
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
+    sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE);
+    sk_client.delete(&[&ID_NOT_STORED]);
+
+    assert_eq!(sk_client.get(&ID_EXAMPLE), Some(SECRET_EXAMPLE));
+    assert_eq!(sk_client.get(&ID_EXAMPLE_2), Some(SECRET_EXAMPLE));
+    assert_eq!(sk_client.get(&ID_NOT_STORED), None);
+}
+
+#[test]
+fn secretkeeper_store_delete_all() {
+    let mut sk_client = setup_client!();
+
+    if sk_client.name != "nonsecure" {
+        // Don't run deleteAll() on a secure device, as it might affect
+        // real secrets.
+        warn!("skipping deleteAll test due to real impl");
+        return;
+    }
+
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
+    sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE);
+
+    sk_client.delete_all();
+
+    assert_eq!(sk_client.get(&ID_EXAMPLE), None);
+    assert_eq!(sk_client.get(&ID_EXAMPLE_2), None);
+
+    // Store a new secret (corresponding to an id).
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
+
+    // Get the restored secret.
+    assert_eq!(sk_client.get(&ID_EXAMPLE), Some(SECRET_EXAMPLE));
 
     // (Try to) Get the secret that was never stored
+    assert_eq!(sk_client.get(&ID_NOT_STORED), None);
+}
+
+// This test checks that Secretkeeper uses the expected [`RequestSeqNum`] as aad while
+// decrypting requests and the responses are encrypted with correct [`ResponseSeqNum`] for the
+// first few messages.
+#[test]
+fn secret_management_replay_protection_seq_num() {
+    let sk_client = setup_client!();
+    // Construct encoded request packets for the test
+    let (req_1, req_2, req_3) = construct_secret_management_requests();
+
+    // Lets now construct the seq_numbers(in request & expected in response)
+    let mut seq_a = SeqNum::new();
+    let [seq_0, seq_1, seq_2] = std::array::from_fn(|_| seq_a.get_then_increment().unwrap());
+
+    // Check first request/response is successful
+    let res = ResponsePacket::from_slice(
+        &sk_client.secret_management_request_custom_aad(&req_1, &seq_0, &seq_0),
+    )
+    .unwrap();
+    assert_eq!(res.response_type().unwrap(), ResponseType::Success);
+
+    // Check 2nd request/response is successful
+    let res = ResponsePacket::from_slice(
+        &sk_client.secret_management_request_custom_aad(&req_2, &seq_1, &seq_1),
+    )
+    .unwrap();
+    assert_eq!(res.response_type().unwrap(), ResponseType::Success);
+
+    // Check 3rd request/response is successful
+    let res = ResponsePacket::from_slice(
+        &sk_client.secret_management_request_custom_aad(&req_3, &seq_2, &seq_2),
+    )
+    .unwrap();
+    assert_eq!(res.response_type().unwrap(), ResponseType::Success);
+}
+
+// This test checks that Secretkeeper uses fresh [`RequestSeqNum`] & [`ResponseSeqNum`]
+// for new sessions.
+#[test]
+fn secret_management_replay_protection_seq_num_per_session() {
+    let sk_client = setup_client!();
+
+    // Construct encoded request packets for the test
+    let (req_1, _, _) = construct_secret_management_requests();
+
+    // Lets now construct the seq_number (in request & expected in response)
+    let mut seq_a = SeqNum::new();
+    let seq_0 = seq_a.get_then_increment().unwrap();
+    // Check first request/response is successful
+    let res = ResponsePacket::from_slice(
+        &sk_client.secret_management_request_custom_aad(&req_1, &seq_0, &seq_0),
+    )
+    .unwrap();
+    assert_eq!(res.response_type().unwrap(), ResponseType::Success);
+
+    // Start another session
+    let sk_client_diff = setup_client!();
+    // Check first request/response is with seq_0 is successful
+    let res = ResponsePacket::from_slice(
+        &sk_client_diff.secret_management_request_custom_aad(&req_1, &seq_0, &seq_0),
+    )
+    .unwrap();
+    assert_eq!(res.response_type().unwrap(), ResponseType::Success);
+}
+
+// This test checks that Secretkeeper rejects requests with out of order [`RequestSeqNum`]
+#[test]
+// TODO(b/317416663): This test fails, when HAL is not present in the device. Refactor to fix this.
+#[ignore]
+#[should_panic]
+fn secret_management_replay_protection_out_of_seq_req_not_accepted() {
+    let sk_client = setup_client!();
+
+    // Construct encoded request packets for the test
+    let (req_1, req_2, _) = construct_secret_management_requests();
+
+    // Lets now construct the seq_numbers(in request & expected in response)
+    let mut seq_a = SeqNum::new();
+    let [seq_0, seq_1, seq_2] = std::array::from_fn(|_| seq_a.get_then_increment().unwrap());
+
+    // Assume First request/response is successful
+    sk_client.secret_management_request_custom_aad(&req_1, &seq_0, &seq_0);
+
+    // Check 2nd request/response with skipped seq_num in request is a binder error
+    // This should panic!
+    sk_client.secret_management_request_custom_aad(&req_2, /*Skipping seq_1*/ &seq_2, &seq_1);
+}
+
+fn construct_secret_management_requests() -> (Vec<u8>, Vec<u8>, Vec<u8>) {
+    let version_request = GetVersionRequest {};
+    let version_request = version_request.serialize_to_packet().to_vec().unwrap();
+    let store_request = StoreSecretRequest {
+        id: ID_EXAMPLE,
+        secret: SECRET_EXAMPLE,
+        sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
+    };
+    let store_request = store_request.serialize_to_packet().to_vec().unwrap();
     let get_request = GetSecretRequest {
-        id: Id(ID_NOT_STORED),
+        id: ID_EXAMPLE,
         updated_sealing_policy: None,
     };
     let get_request = get_request.serialize_to_packet().to_vec().unwrap();
-    let get_response = sk_client.secret_management_request(&get_request);
-
-    // Check that response is `SecretkeeperError::EntryNotFound`
-    let get_response = ResponsePacket::from_slice(&get_response).unwrap();
-    assert_eq!(get_response.response_type().unwrap(), ResponseType::Error);
-    let err = *SecretkeeperError::deserialize_from_packet(get_response).unwrap();
-    assert_eq!(err, SecretkeeperError::EntryNotFound);
+    (version_request, store_request, get_request)
 }
diff --git a/security/secretkeeper/default/Android.bp b/security/secretkeeper/default/Android.bp
index 08cc67a..1d75c74 100644
--- a/security/secretkeeper/default/Android.bp
+++ b/security/secretkeeper/default/Android.bp
@@ -18,6 +18,28 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
+rust_library {
+    name: "libsecretkeeper_nonsecure",
+    crate_name: "secretkeeper_nonsecure",
+    srcs: [
+        "src/lib.rs",
+    ],
+    vendor_available: true,
+    defaults: [
+        "authgraph_use_latest_hal_aidl_rust",
+    ],
+    rustlibs: [
+        "android.hardware.security.secretkeeper-V1-rust",
+        "libauthgraph_boringssl",
+        "libauthgraph_core",
+        "libauthgraph_hal",
+        "libbinder_rs",
+        "liblog_rust",
+        "libsecretkeeper_core_nostd",
+        "libsecretkeeper_comm_nostd",
+    ],
+}
+
 rust_binary {
     name: "android.hardware.security.secretkeeper-service.nonsecure",
     relative_install_path: "hw",
@@ -30,20 +52,34 @@
     rustlibs: [
         "android.hardware.security.secretkeeper-V1-rust",
         "libandroid_logger",
-        "libauthgraph_boringssl",
-        "libauthgraph_core",
-        "libauthgraph_hal",
         "libbinder_rs",
         "liblog_rust",
-        "libsecretkeeper_comm_nostd",
-        "libsecretkeeper_core_nostd",
         "libsecretkeeper_hal",
+        "libsecretkeeper_nonsecure",
     ],
     srcs: [
         "src/main.rs",
     ],
 }
 
+rust_fuzz {
+    name: "android.hardware.security.secretkeeper-service.nonsecure_fuzzer",
+    rustlibs: [
+        "libsecretkeeper_hal",
+        "libsecretkeeper_nonsecure",
+        "libbinder_random_parcel_rs",
+        "libbinder_rs",
+    ],
+    srcs: ["src/fuzzer.rs"],
+    fuzz_config: {
+        cc: [
+            "alanstokes@google.com",
+            "drysdale@google.com",
+            "shikhapanwar@google.com",
+        ],
+    },
+}
+
 prebuilt_etc {
     name: "secretkeeper.rc",
     src: "secretkeeper.rc",
diff --git a/security/secretkeeper/default/src/fuzzer.rs b/security/secretkeeper/default/src/fuzzer.rs
new file mode 100644
index 0000000..914ebe6
--- /dev/null
+++ b/security/secretkeeper/default/src/fuzzer.rs
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#![allow(missing_docs)]
+#![no_main]
+extern crate libfuzzer_sys;
+
+use binder_random_parcel_rs::fuzz_service;
+use libfuzzer_sys::fuzz_target;
+use secretkeeper_hal::SecretkeeperService;
+use secretkeeper_nonsecure::{AuthGraphChannel, LocalTa, SecretkeeperChannel};
+use std::sync::{Arc, Mutex};
+
+fuzz_target!(|data: &[u8]| {
+    let ta = Arc::new(Mutex::new(LocalTa::new()));
+    let ag_channel = AuthGraphChannel(ta.clone());
+    let sk_channel = SecretkeeperChannel(ta.clone());
+
+    let service = SecretkeeperService::new_as_binder(sk_channel, ag_channel);
+    fuzz_service(&mut service.as_binder(), data);
+});
diff --git a/security/secretkeeper/default/src/lib.rs b/security/secretkeeper/default/src/lib.rs
new file mode 100644
index 0000000..412ad45
--- /dev/null
+++ b/security/secretkeeper/default/src/lib.rs
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+//! Non-secure implementation of a local Secretkeeper TA.
+
+use authgraph_boringssl as boring;
+use authgraph_core::keyexchange::{AuthGraphParticipant, MAX_OPENED_SESSIONS};
+use authgraph_core::ta::{AuthGraphTa, Role};
+use authgraph_hal::channel::SerializedChannel;
+use log::error;
+use secretkeeper_core::ta::SecretkeeperTa;
+use std::cell::RefCell;
+use std::rc::Rc;
+use std::sync::mpsc;
+use std::sync::{Arc, Mutex};
+
+mod store;
+
+/// Implementation of the Secrekeeper TA that runs locally in-process (and which is therefore
+/// insecure).
+pub struct LocalTa {
+    in_tx: mpsc::Sender<Vec<u8>>,
+    out_rx: mpsc::Receiver<Vec<u8>>,
+}
+
+/// Prefix byte for messages intended for the AuthGraph TA.
+const AG_MESSAGE_PREFIX: u8 = 0x00;
+/// Prefix byte for messages intended for the Secretkeeper TA.
+const SK_MESSAGE_PREFIX: u8 = 0x01;
+
+impl LocalTa {
+    /// Create a new instance.
+    pub fn new() -> Self {
+        // Create a pair of channels to communicate with the TA thread.
+        let (in_tx, in_rx) = mpsc::channel();
+        let (out_tx, out_rx) = mpsc::channel();
+
+        // The TA code expects to run single threaded, so spawn a thread to run it in.
+        std::thread::spawn(move || {
+            let mut crypto_impls = boring::crypto_trait_impls();
+            let storage_impl = Box::new(store::InMemoryStore::default());
+            let sk_ta = Rc::new(RefCell::new(
+                SecretkeeperTa::new(&mut crypto_impls, storage_impl)
+                    .expect("Failed to create local Secretkeeper TA"),
+            ));
+            let mut ag_ta = AuthGraphTa::new(
+                AuthGraphParticipant::new(crypto_impls, sk_ta.clone(), MAX_OPENED_SESSIONS)
+                    .expect("Failed to create local AuthGraph TA"),
+                Role::Sink,
+            );
+
+            // Loop forever processing request messages.
+            loop {
+                let req_data: Vec<u8> = match in_rx.recv() {
+                    Ok(data) => data,
+                    Err(_) => {
+                        error!("local TA failed to receive request!");
+                        break;
+                    }
+                };
+                let rsp_data = match req_data[0] {
+                    AG_MESSAGE_PREFIX => ag_ta.process(&req_data[1..]),
+                    SK_MESSAGE_PREFIX => {
+                        // It's safe to `borrow_mut()` because this code is not a callback
+                        // from AuthGraph (the only other holder of an `Rc`), and so there
+                        // can be no live `borrow()`s in this (single) thread.
+                        sk_ta.borrow_mut().process(&req_data[1..])
+                    }
+                    prefix => panic!("unexpected messageprefix {prefix}!"),
+                };
+                match out_tx.send(rsp_data) {
+                    Ok(_) => {}
+                    Err(_) => {
+                        error!("local TA failed to send out response");
+                        break;
+                    }
+                }
+            }
+            error!("local TA terminating!");
+        });
+        Self { in_tx, out_rx }
+    }
+
+    fn execute_for(&mut self, prefix: u8, req_data: &[u8]) -> Vec<u8> {
+        let mut prefixed_req = Vec::with_capacity(req_data.len() + 1);
+        prefixed_req.push(prefix);
+        prefixed_req.extend_from_slice(req_data);
+        self.in_tx
+            .send(prefixed_req)
+            .expect("failed to send in request");
+        self.out_rx.recv().expect("failed to receive response")
+    }
+}
+
+pub struct AuthGraphChannel(pub Arc<Mutex<LocalTa>>);
+
+impl SerializedChannel for AuthGraphChannel {
+    const MAX_SIZE: usize = usize::MAX;
+    fn execute(&self, req_data: &[u8]) -> binder::Result<Vec<u8>> {
+        Ok(self
+            .0
+            .lock()
+            .unwrap()
+            .execute_for(AG_MESSAGE_PREFIX, req_data))
+    }
+}
+
+pub struct SecretkeeperChannel(pub Arc<Mutex<LocalTa>>);
+
+impl SerializedChannel for SecretkeeperChannel {
+    const MAX_SIZE: usize = usize::MAX;
+    fn execute(&self, req_data: &[u8]) -> binder::Result<Vec<u8>> {
+        Ok(self
+            .0
+            .lock()
+            .unwrap()
+            .execute_for(SK_MESSAGE_PREFIX, req_data))
+    }
+}
diff --git a/security/secretkeeper/default/src/main.rs b/security/secretkeeper/default/src/main.rs
index c8c1521..436f9a7 100644
--- a/security/secretkeeper/default/src/main.rs
+++ b/security/secretkeeper/default/src/main.rs
@@ -15,112 +15,14 @@
  */
 
 //! Non-secure implementation of the Secretkeeper HAL.
-mod store;
 
-use authgraph_boringssl as boring;
-use authgraph_core::keyexchange::{AuthGraphParticipant, MAX_OPENED_SESSIONS};
-use authgraph_core::ta::{AuthGraphTa, Role};
-use authgraph_hal::channel::SerializedChannel;
 use log::{error, info, Level};
-use secretkeeper_core::ta::SecretkeeperTa;
 use secretkeeper_hal::SecretkeeperService;
-use std::sync::Arc;
-use std::sync::Mutex;
-use store::InMemoryStore;
-
+use secretkeeper_nonsecure::{AuthGraphChannel, SecretkeeperChannel, LocalTa};
+use std::sync::{Arc, Mutex};
 use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::ISecretkeeper::{
     BpSecretkeeper, ISecretkeeper,
 };
-use std::cell::RefCell;
-use std::rc::Rc;
-use std::sync::mpsc;
-
-/// Implementation of the Secrekeeper TA that runs locally in-process (and which is therefore
-/// insecure).
-pub struct LocalTa {
-    in_tx: mpsc::Sender<Vec<u8>>,
-    out_rx: mpsc::Receiver<Vec<u8>>,
-}
-
-/// Prefix byte for messages intended for the AuthGraph TA.
-const AG_MESSAGE_PREFIX: u8 = 0x00;
-/// Prefix byte for messages intended for the Secretkeeper TA.
-const SK_MESSAGE_PREFIX: u8 = 0x01;
-
-impl LocalTa {
-    /// Create a new instance.
-    pub fn new() -> Self {
-        // Create a pair of channels to communicate with the TA thread.
-        let (in_tx, in_rx) = mpsc::channel();
-        let (out_tx, out_rx) = mpsc::channel();
-
-        // The TA code expects to run single threaded, so spawn a thread to run it in.
-        std::thread::spawn(move || {
-            let mut crypto_impls = boring::crypto_trait_impls();
-            let storage_impl = Box::new(InMemoryStore::default());
-            let sk_ta = Rc::new(RefCell::new(
-                SecretkeeperTa::new(&mut crypto_impls, storage_impl)
-                    .expect("Failed to create local Secretkeeper TA"),
-            ));
-            let mut ag_ta = AuthGraphTa::new(
-                AuthGraphParticipant::new(crypto_impls, sk_ta.clone(), MAX_OPENED_SESSIONS)
-                    .expect("Failed to create local AuthGraph TA"),
-                Role::Sink,
-            );
-
-            // Loop forever processing request messages.
-            loop {
-                let req_data: Vec<u8> = in_rx.recv().expect("failed to receive next req");
-                let rsp_data = match req_data[0] {
-                    AG_MESSAGE_PREFIX => ag_ta.process(&req_data[1..]),
-                    SK_MESSAGE_PREFIX => {
-                        // It's safe to `borrow_mut()` because this code is not a callback
-                        // from AuthGraph (the only other holder of an `Rc`), and so there
-                        // can be no live `borrow()`s in this (single) thread.
-                        sk_ta.borrow_mut().process(&req_data[1..])
-                    }
-                    prefix => panic!("unexpected messageprefix {prefix}!"),
-                };
-                out_tx.send(rsp_data).expect("failed to send out rsp");
-            }
-        });
-        Self { in_tx, out_rx }
-    }
-
-    fn execute_for(&mut self, prefix: u8, req_data: &[u8]) -> Vec<u8> {
-        let mut prefixed_req = Vec::with_capacity(req_data.len() + 1);
-        prefixed_req.push(prefix);
-        prefixed_req.extend_from_slice(req_data);
-        self.in_tx
-            .send(prefixed_req)
-            .expect("failed to send in request");
-        self.out_rx.recv().expect("failed to receive response")
-    }
-}
-
-pub struct AuthGraphChannel(Arc<Mutex<LocalTa>>);
-impl SerializedChannel for AuthGraphChannel {
-    const MAX_SIZE: usize = usize::MAX;
-    fn execute(&self, req_data: &[u8]) -> binder::Result<Vec<u8>> {
-        Ok(self
-            .0
-            .lock()
-            .unwrap()
-            .execute_for(AG_MESSAGE_PREFIX, req_data))
-    }
-}
-
-pub struct SecretkeeperChannel(Arc<Mutex<LocalTa>>);
-impl SerializedChannel for SecretkeeperChannel {
-    const MAX_SIZE: usize = usize::MAX;
-    fn execute(&self, req_data: &[u8]) -> binder::Result<Vec<u8>> {
-        Ok(self
-            .0
-            .lock()
-            .unwrap()
-            .execute_for(SK_MESSAGE_PREFIX, req_data))
-    }
-}
 
 fn main() {
     // Initialize Android logging.
diff --git a/security/secretkeeper/default/src/store.rs b/security/secretkeeper/default/src/store.rs
index 7b2d0b9..6c7dba1 100644
--- a/security/secretkeeper/default/src/store.rs
+++ b/security/secretkeeper/default/src/store.rs
@@ -13,12 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+//! In-memory store for nonsecure Secretkeeper.
+
 use secretkeeper_comm::data_types::error::Error;
 use secretkeeper_core::store::KeyValueStore;
 use std::collections::HashMap;
 
-/// An in-memory implementation of KeyValueStore. Please note that this is entirely for
-/// testing purposes. Refer to the documentation of `PolicyGatedStorage` & Secretkeeper HAL for
+/// An in-memory implementation of [`KeyValueStore`]. Please note that this is entirely for testing
+/// purposes. Refer to the documentation of `PolicyGatedStorage` and Secretkeeper HAL for
 /// persistence requirements.
 #[derive(Default)]
 pub struct InMemoryStore(HashMap<Vec<u8>, Vec<u8>>);
@@ -33,4 +36,14 @@
         let optional_val = self.0.get(key);
         Ok(optional_val.cloned())
     }
+
+    fn delete(&mut self, key: &[u8]) -> Result<(), Error> {
+        self.0.remove(key);
+        Ok(())
+    }
+
+    fn delete_all(&mut self) -> Result<(), Error> {
+        self.0.clear();
+        Ok(())
+    }
 }
diff --git a/sensors/aidl/default/Android.bp b/sensors/aidl/default/Android.bp
index 08ee773..e93c391 100644
--- a/sensors/aidl/default/Android.bp
+++ b/sensors/aidl/default/Android.bp
@@ -97,12 +97,5 @@
     prebuilts: [
         "sensors-default.rc", // init rc
         "sensors-default.xml", // vintf fragment
-        "android.hardware.sensor.ambient_temperature.prebuilt.xml",
-        "android.hardware.sensor.barometer.prebuilt.xml",
-        "android.hardware.sensor.gyroscope.prebuilt.xml",
-        "android.hardware.sensor.hinge_angle.prebuilt.xml",
-        "android.hardware.sensor.light.prebuilt.xml",
-        "android.hardware.sensor.proximity.prebuilt.xml",
-        "android.hardware.sensor.relative_humidity.prebuilt.xml",
     ],
 }
diff --git a/sensors/aidl/default/multihal/Android.bp b/sensors/aidl/default/multihal/Android.bp
index a20d6d7..40cb2d9 100644
--- a/sensors/aidl/default/multihal/Android.bp
+++ b/sensors/aidl/default/multihal/Android.bp
@@ -45,11 +45,6 @@
         "HalProxyAidl.cpp",
         "ConvertUtils.cpp",
     ],
-    visibility: [
-        ":__subpackages__",
-        "//hardware/interfaces/sensors/aidl/multihal:__subpackages__",
-        "//hardware/interfaces/tests/extension/sensors:__subpackages__",
-    ],
     static_libs: [
         "android.hardware.sensors@1.0-convert",
         "android.hardware.sensors@2.X-multihal",
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingDevice.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingDevice.aidl
index dff3c4c..7e1aed7 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingDevice.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingDevice.aidl
@@ -38,4 +38,7 @@
   android.hardware.thermal.CoolingType type;
   String name;
   long value;
+  long powerLimitMw;
+  long powerMw;
+  long timeWindowMs;
 }
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/ICoolingDeviceChangedCallback.aidl
similarity index 89%
copy from security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
copy to thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/ICoolingDeviceChangedCallback.aidl
index cc07f9b..ea75b1c 100644
--- a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/ICoolingDeviceChangedCallback.aidl
@@ -31,12 +31,9 @@
 // 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.security.secretkeeper;
+package android.hardware.thermal;
 /* @hide */
-@Backing(type="int") @VintfStability
-enum ErrorCode {
-  OK = 0,
-  UNKNOWN_KEY_ID = 1,
-  INTERNAL_ERROR = 2,
-  REQUEST_MALFORMED = 3,
+@VintfStability
+interface ICoolingDeviceChangedCallback {
+  oneway void notifyCoolingDeviceChanged(in android.hardware.thermal.CoolingDevice coolingDevice);
 }
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermal.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermal.aidl
index c9b6cab..904496c 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermal.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermal.aidl
@@ -44,4 +44,6 @@
   void registerThermalChangedCallback(in android.hardware.thermal.IThermalChangedCallback callback);
   void registerThermalChangedCallbackWithType(in android.hardware.thermal.IThermalChangedCallback callback, in android.hardware.thermal.TemperatureType type);
   void unregisterThermalChangedCallback(in android.hardware.thermal.IThermalChangedCallback callback);
+  void registerCoolingDeviceChangedCallbackWithType(in android.hardware.thermal.ICoolingDeviceChangedCallback callback, in android.hardware.thermal.CoolingType type);
+  void unregisterCoolingDeviceChangedCallback(in android.hardware.thermal.ICoolingDeviceChangedCallback callback);
 }
diff --git a/thermal/aidl/android/hardware/thermal/CoolingDevice.aidl b/thermal/aidl/android/hardware/thermal/CoolingDevice.aidl
index 0c5c17d..406733b 100644
--- a/thermal/aidl/android/hardware/thermal/CoolingDevice.aidl
+++ b/thermal/aidl/android/hardware/thermal/CoolingDevice.aidl
@@ -40,4 +40,16 @@
      * means deeper throttling.
      */
     long value;
+    /**
+     * Power budget (mW) of the cooling device.
+     */
+    long powerLimitMw;
+    /**
+     * Target cooling device's AVG power for the last time_window_ms.
+     */
+    long powerMw;
+    /**
+     * The time window (millisecond) to calculate the power consumption
+     */
+    long timeWindowMs;
 }
diff --git a/thermal/aidl/android/hardware/thermal/ICoolingDeviceChangedCallback.aidl b/thermal/aidl/android/hardware/thermal/ICoolingDeviceChangedCallback.aidl
new file mode 100644
index 0000000..e6bb9fe
--- /dev/null
+++ b/thermal/aidl/android/hardware/thermal/ICoolingDeviceChangedCallback.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 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.thermal;
+
+import android.hardware.thermal.CoolingDevice;
+import android.hardware.thermal.Temperature;
+
+/**
+ * ICoolingDeviceChangedCallback send cooling device change notification to clients.
+ * @hide
+ */
+@VintfStability
+interface ICoolingDeviceChangedCallback {
+    /**
+     * Send a cooling device change event to all ThermalHAL
+     * cooling device event listeners.
+     *
+     * @param cooling_device The cooling device information associated with the
+     *     change event.
+     */
+    oneway void notifyCoolingDeviceChanged(in CoolingDevice coolingDevice);
+}
diff --git a/thermal/aidl/android/hardware/thermal/IThermal.aidl b/thermal/aidl/android/hardware/thermal/IThermal.aidl
index c94edcd..4aa4090 100644
--- a/thermal/aidl/android/hardware/thermal/IThermal.aidl
+++ b/thermal/aidl/android/hardware/thermal/IThermal.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.thermal.CoolingDevice;
 import android.hardware.thermal.CoolingType;
+import android.hardware.thermal.ICoolingDeviceChangedCallback;
 import android.hardware.thermal.IThermalChangedCallback;
 import android.hardware.thermal.Temperature;
 import android.hardware.thermal.TemperatureThreshold;
@@ -188,4 +189,40 @@
      *         getMessage() must be populated with human-readable error message.
      */
     void unregisterThermalChangedCallback(in IThermalChangedCallback callback);
+
+    /**
+     * Register an ICoolingDeviceChangedCallback for a given CoolingType, used by
+     * the Thermal HAL to receive CDEV events when cooling device status
+     * changed.
+     * Multiple registrations with different ICoolingDeviceChangedCallback must be allowed.
+     * Multiple registrations with same ICoolingDeviceChangedCallback is not allowed, client
+     * should unregister the given ICoolingDeviceChangedCallback first.
+     *
+     * @param callback the ICoolingChangedCallback to use for receiving
+     *    cooling device events. If nullptr callback is given, the status code will be
+     *    STATUS_BAD_VALUE and the operation will fail.
+     * @param type the type to be filtered.
+     *
+     * @throws EX_ILLEGAL_ARGUMENT If the callback is given nullptr or already registered. And the
+     *         getMessage() must be populated with human-readable error message.
+     * @throws EX_ILLEGAL_STATE If the Thermal HAL is not initialized successfully. And the
+     *         getMessage() must be populated with human-readable error message.
+     */
+    void registerCoolingDeviceChangedCallbackWithType(
+            in ICoolingDeviceChangedCallback callback, in CoolingType type);
+
+    /**
+     * Unregister an ICoolingDeviceChangedCallback, used by the Thermal HAL
+     * to receive CDEV events when cooling device status changed.
+     *
+     * @param callback the ICoolingDeviceChangedCallback to use for receiving
+     *    cooling device events. if nullptr callback is given, the status code will be
+     *    STATUS_BAD_VALUE and the operation will fail.
+     *
+     * @throws EX_ILLEGAL_ARGUMENT If the callback is given nullptr or not previously registered.
+     *         And the getMessage() must be populated with human-readable error message.
+     * @throws EX_ILLEGAL_STATE If the Thermal HAL is not initialized successfully. And the
+     *         getMessage() must be populated with human-readable error message.
+     */
+    void unregisterCoolingDeviceChangedCallback(in ICoolingDeviceChangedCallback callback);
 }
diff --git a/thermal/aidl/default/Thermal.cpp b/thermal/aidl/default/Thermal.cpp
index f643d22..41d0be8 100644
--- a/thermal/aidl/default/Thermal.cpp
+++ b/thermal/aidl/default/Thermal.cpp
@@ -142,4 +142,53 @@
     return ScopedAStatus::ok();
 }
 
+ScopedAStatus Thermal::registerCoolingDeviceChangedCallbackWithType(
+        const std::shared_ptr<ICoolingDeviceChangedCallback>& in_callback, CoolingType in_type) {
+    LOG(VERBOSE) << __func__ << " ICoolingDeviceChangedCallback: " << in_callback
+                 << ", CoolingType: " << static_cast<int32_t>(in_type);
+    if (in_callback == nullptr) {
+        return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                "Invalid nullptr callback");
+    }
+    {
+        std::lock_guard<std::mutex> _lock(cdev_callback_mutex_);
+        if (std::any_of(cdev_callbacks_.begin(), cdev_callbacks_.end(),
+                        [&](const std::shared_ptr<ICoolingDeviceChangedCallback>& c) {
+                            return interfacesEqual(c, in_callback);
+                        })) {
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "Callback already registered");
+        }
+        cdev_callbacks_.push_back(in_callback);
+    }
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Thermal::unregisterCoolingDeviceChangedCallback(
+        const std::shared_ptr<ICoolingDeviceChangedCallback>& in_callback) {
+    LOG(VERBOSE) << __func__ << " ICoolingDeviceChangedCallback: " << in_callback;
+    if (in_callback == nullptr) {
+        return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                "Invalid nullptr callback");
+    }
+    {
+        std::lock_guard<std::mutex> _lock(cdev_callback_mutex_);
+        bool removed = false;
+        cdev_callbacks_.erase(
+                std::remove_if(cdev_callbacks_.begin(), cdev_callbacks_.end(),
+                               [&](const std::shared_ptr<ICoolingDeviceChangedCallback>& c) {
+                                   if (interfacesEqual(c, in_callback)) {
+                                       removed = true;
+                                       return true;
+                                   }
+                                   return false;
+                               }),
+                cdev_callbacks_.end());
+        if (!removed) {
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "Callback wasn't registered");
+        }
+    }
+    return ScopedAStatus::ok();
+}
 }  // namespace aidl::android::hardware::thermal::impl::example
diff --git a/thermal/aidl/default/Thermal.h b/thermal/aidl/default/Thermal.h
index 8885e63..d3d8874 100644
--- a/thermal/aidl/default/Thermal.h
+++ b/thermal/aidl/default/Thermal.h
@@ -46,6 +46,7 @@
 
     ndk::ScopedAStatus registerThermalChangedCallback(
             const std::shared_ptr<IThermalChangedCallback>& in_callback) override;
+
     ndk::ScopedAStatus registerThermalChangedCallbackWithType(
             const std::shared_ptr<IThermalChangedCallback>& in_callback,
             TemperatureType in_type) override;
@@ -53,9 +54,18 @@
     ndk::ScopedAStatus unregisterThermalChangedCallback(
             const std::shared_ptr<IThermalChangedCallback>& in_callback) override;
 
+    ndk::ScopedAStatus registerCoolingDeviceChangedCallbackWithType(
+            const std::shared_ptr<ICoolingDeviceChangedCallback>& in_callback,
+            CoolingType in_type) override;
+
+    ndk::ScopedAStatus unregisterCoolingDeviceChangedCallback(
+            const std::shared_ptr<ICoolingDeviceChangedCallback>& in_callback) override;
+
   private:
     std::mutex thermal_callback_mutex_;
     std::vector<std::shared_ptr<IThermalChangedCallback>> thermal_callbacks_;
+    std::mutex cdev_callback_mutex_;
+    std::vector<std::shared_ptr<ICoolingDeviceChangedCallback>> cdev_callbacks_;
 };
 
 }  // namespace example
diff --git a/thermal/aidl/vts/VtsHalThermalTargetTest.cpp b/thermal/aidl/vts/VtsHalThermalTargetTest.cpp
index 4b0eb65..403c6c8 100644
--- a/thermal/aidl/vts/VtsHalThermalTargetTest.cpp
+++ b/thermal/aidl/vts/VtsHalThermalTargetTest.cpp
@@ -26,6 +26,7 @@
 
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
+#include <aidl/android/hardware/thermal/BnCoolingDeviceChangedCallback.h>
 #include <aidl/android/hardware/thermal/BnThermal.h>
 #include <aidl/android/hardware/thermal/BnThermalChangedCallback.h>
 #include <android-base/logging.h>
@@ -59,6 +60,15 @@
         .throttlingStatus = ThrottlingSeverity::CRITICAL,
 };
 
+static const CoolingDevice kCoolingDevice = {
+        .type = CoolingType::CPU,
+        .name = "test cooling device",
+        .value = 1,
+        .powerLimitMw = 300,
+        .powerMw = 500,
+        .timeWindowMs = 7000,
+};
+
 // Callback class for receiving thermal event notifications from main class
 class ThermalCallback : public BnThermalChangedCallback {
   public:
@@ -85,6 +95,33 @@
     bool mInvoke = false;
 };
 
+// Callback class for receiving cooling device event notifications from main class
+class CoolingDeviceCallback : public BnCoolingDeviceChangedCallback {
+  public:
+    ndk::ScopedAStatus notifyCoolingDeviceChanged(const CoolingDevice&) override {
+        {
+            std::lock_guard<std::mutex> lock(mMutex);
+            mInvoke = true;
+        }
+        mNotifyCoolingDeviceChanged.notify_all();
+        return ndk::ScopedAStatus::ok();
+    }
+
+    template <typename R, typename P>
+    [[nodiscard]] bool waitForCallback(std::chrono::duration<R, P> duration) {
+        std::unique_lock<std::mutex> lock(mMutex);
+        bool r = mNotifyCoolingDeviceChanged.wait_for(lock, duration,
+                                                      [this] { return this->mInvoke; });
+        mInvoke = false;
+        return r;
+    }
+
+  private:
+    std::mutex mMutex;
+    std::condition_variable mNotifyCoolingDeviceChanged;
+    bool mInvoke = false;
+};
+
 // The main test class for THERMAL HIDL HAL.
 class ThermalAidlTest : public testing::TestWithParam<std::string> {
   public:
@@ -97,19 +134,42 @@
         ASSERT_NE(mThermalCallback, nullptr);
         ::ndk::ScopedAStatus status = mThermal->registerThermalChangedCallback(mThermalCallback);
         ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+        auto ret = mThermal->getInterfaceVersion(&thermal_version);
+        ASSERT_TRUE(ret.isOk()) << ret;
+        if (thermal_version > 1) {
+            mCoolingDeviceCallback = ndk::SharedRefBase::make<CoolingDeviceCallback>();
+            ASSERT_NE(mCoolingDeviceCallback, nullptr);
+            status = mThermal->registerCoolingDeviceChangedCallbackWithType(mCoolingDeviceCallback,
+                                                                            kCoolingDevice.type);
+            ASSERT_TRUE(status.isOk()) << status.getMessage();
+        }
     }
 
     void TearDown() override {
         ::ndk::ScopedAStatus status = mThermal->unregisterThermalChangedCallback(mThermalCallback);
         ASSERT_TRUE(status.isOk()) << status.getMessage();
+
         // Expect to fail if unregister again
         status = mThermal->unregisterThermalChangedCallback(mThermalCallback);
         ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
+
+        auto ret = mThermal->getInterfaceVersion(&thermal_version);
+        ASSERT_TRUE(ret.isOk()) << ret;
+        if (thermal_version > 1) {
+            status = mThermal->unregisterCoolingDeviceChangedCallback(mCoolingDeviceCallback);
+            ASSERT_TRUE(status.isOk()) << status.getMessage();
+            status = mThermal->unregisterCoolingDeviceChangedCallback(mCoolingDeviceCallback);
+            ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
+        }
     }
+    // Stores thermal version
+    int32_t thermal_version;
 
   protected:
     std::shared_ptr<IThermal> mThermal;
     std::shared_ptr<ThermalCallback> mThermalCallback;
+    std::shared_ptr<CoolingDeviceCallback> mCoolingDeviceCallback;
 };
 
 // Test ThermalChangedCallback::notifyThrottling().
@@ -121,6 +181,21 @@
     ASSERT_TRUE(thermalCallback->waitForCallback(200ms));
 }
 
+// Test CoolingDeviceChangedCallback::notifyCoolingDeviceChanged().
+// This just calls into and back from our local CoolingDeviceChangedCallback impl.
+TEST_P(ThermalAidlTest, NotifyCoolingDeviceChangedTest) {
+    auto ret = mThermal->getInterfaceVersion(&thermal_version);
+    ASSERT_TRUE(ret.isOk()) << ret;
+    if (thermal_version < 2) {
+        return;
+    }
+    std::shared_ptr<CoolingDeviceCallback> cdevCallback =
+            ndk::SharedRefBase::make<CoolingDeviceCallback>();
+    ::ndk::ScopedAStatus status = cdevCallback->notifyCoolingDeviceChanged(kCoolingDevice);
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    ASSERT_TRUE(cdevCallback->waitForCallback(200ms));
+}
+
 // Test Thermal->registerThermalChangedCallback.
 TEST_P(ThermalAidlTest, RegisterThermalChangedCallbackTest) {
     // Expect to fail with same callback
@@ -169,6 +244,37 @@
         || status.getExceptionCode() == EX_NULL_POINTER);
 }
 
+// Test Thermal->registerCoolingDeviceChangedCallbackWithType.
+TEST_P(ThermalAidlTest, RegisterCoolingDeviceChangedCallbackWithTypeTest) {
+    auto ret = mThermal->getInterfaceVersion(&thermal_version);
+    ASSERT_TRUE(ret.isOk()) << ret;
+    if (thermal_version < 2) {
+        return;
+    }
+
+    // Expect to fail with same callback
+    ::ndk::ScopedAStatus status = mThermal->registerCoolingDeviceChangedCallbackWithType(
+            mCoolingDeviceCallback, CoolingType::CPU);
+    ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
+    // Expect to fail with null callback
+    status = mThermal->registerCoolingDeviceChangedCallbackWithType(nullptr, CoolingType::CPU);
+    ASSERT_TRUE(status.getExceptionCode() == EX_ILLEGAL_ARGUMENT ||
+                status.getExceptionCode() == EX_NULL_POINTER);
+    std::shared_ptr<CoolingDeviceCallback> localCoolingDeviceCallback =
+            ndk::SharedRefBase::make<CoolingDeviceCallback>();
+    // Expect to succeed with different callback
+    status = mThermal->registerCoolingDeviceChangedCallbackWithType(localCoolingDeviceCallback,
+                                                                    CoolingType::CPU);
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    // Remove the local callback
+    status = mThermal->unregisterCoolingDeviceChangedCallback(localCoolingDeviceCallback);
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    // Expect to fail with null callback
+    status = mThermal->unregisterCoolingDeviceChangedCallback(nullptr);
+    ASSERT_TRUE(status.getExceptionCode() == EX_ILLEGAL_ARGUMENT ||
+                status.getExceptionCode() == EX_NULL_POINTER);
+}
+
 // Test Thermal->getCurrentTemperatures().
 TEST_P(ThermalAidlTest, TemperatureTest) {
     std::vector<Temperature> ret;
diff --git a/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.cpp b/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.cpp
index 746ae1e..7e095f1 100644
--- a/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.cpp
+++ b/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "tv_input_aidl_hal_test"
+
 #include "VtsHalTvInputTargetTest.h"
 
 #include <android-base/properties.h>
@@ -181,7 +183,9 @@
             ALOGD("OpenAndCloseStreamTest: open stream, device_id=%d, stream_id=%d", device_id,
                   stream_id);
             ASSERT_TRUE(tv_input_->openStream(device_id, stream_id, &handle).isOk());
-            ASSERT_TRUE(isValidHandle(handle));
+            if (VERIFY_SIDEBAND_STREAM_HANDLE) {
+                ASSERT_TRUE(isValidHandle(handle));
+            }
 
             ALOGD("OpenAndCloseStreamTest: close stream, device_id=%d, stream_id=%d", device_id,
                   stream_id);
@@ -283,7 +287,9 @@
 
     ALOGD("OpenAnOpenedStreamsTest: open stream, device_id=%d, stream_id=%d", device_id, stream_id);
     ASSERT_TRUE(tv_input_->openStream(device_id, stream_id, &handle).isOk());
-    ASSERT_TRUE(isValidHandle(handle));
+    if (VERIFY_SIDEBAND_STREAM_HANDLE) {
+        ASSERT_TRUE(isValidHandle(handle));
+    }
 
     ALOGD("OpenAnOpenedStreamsTest: open stream, device_id=%d, stream_id=%d", device_id, stream_id);
     ASSERT_TRUE(tv_input_->openStream(device_id, stream_id, &handle).getServiceSpecificError() ==
diff --git a/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.h b/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.h
index 7e66a88..fd98a18 100644
--- a/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.h
+++ b/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.h
@@ -43,6 +43,7 @@
 
 #define WAIT_FOR_EVENT_TIMEOUT 5
 #define DEFAULT_ID INT32_MIN
+#define VERIFY_SIDEBAND_STREAM_HANDLE 1
 
 namespace VtsHalTvInputTargetTest {
 
diff --git a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
index fccd2ed..3d60e89 100644
--- a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
+++ b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
@@ -35,6 +35,7 @@
     ASSERT_TRUE(mFrontendTests.setFrontendCallback());
     ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
     ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+    mFrontendTests.setDemux(demux);
     mFilterTests.setDemux(demux);
     ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.config1_0.type,
                                                filterConf.config1_0.bufferSize));
diff --git a/tv/tuner/aidl/vts/functional/Android.bp b/tv/tuner/aidl/vts/functional/Android.bp
index 513007b..09e63fc 100644
--- a/tv/tuner/aidl/vts/functional/Android.bp
+++ b/tv/tuner/aidl/vts/functional/Android.bp
@@ -37,6 +37,7 @@
         "FrontendTests.cpp",
         "LnbTests.cpp",
         "VtsHalTvTunerTargetTest.cpp",
+        "utils/IpStreamer.cpp",
     ],
     generated_headers: [
         "tuner_testing_dynamic_configuration_V1_0_enums",
diff --git a/tv/tuner/aidl/vts/functional/FrontendTests.cpp b/tv/tuner/aidl/vts/functional/FrontendTests.cpp
index b0f614e..b7b0185 100644
--- a/tv/tuner/aidl/vts/functional/FrontendTests.cpp
+++ b/tv/tuner/aidl/vts/functional/FrontendTests.cpp
@@ -475,6 +475,10 @@
             << "FrontendConfig does not match the frontend info of the given id.";
 
     mIsSoftwareFe = config.isSoftwareFe;
+    std::unique_ptr<IpStreamer> ipThread = std::make_unique<IpStreamer>();
+    if (config.type == FrontendType::IPTV) {
+        ipThread->startIpStream();
+    }
     if (mIsSoftwareFe && testWithDemux) {
         if (getDvrTests()->openDvrInDemux(mDvrConfig.type, mDvrConfig.bufferSize) != success()) {
             ALOGW("[vts] Software frontend dvr configure openDvr failed.");
@@ -494,6 +498,9 @@
         getDvrTests()->startDvrPlayback();
     }
     mFrontendCallback->tuneTestOnLock(mFrontend, config.settings);
+    if (config.type == FrontendType::IPTV) {
+        ipThread->stopIpStream();
+    }
     return AssertionResult(true);
 }
 
diff --git a/tv/tuner/aidl/vts/functional/FrontendTests.h b/tv/tuner/aidl/vts/functional/FrontendTests.h
index 1746c8e..9c2ffc0 100644
--- a/tv/tuner/aidl/vts/functional/FrontendTests.h
+++ b/tv/tuner/aidl/vts/functional/FrontendTests.h
@@ -27,6 +27,7 @@
 
 #include "DvrTests.h"
 #include "VtsHalTvTunerTestConfigurations.h"
+#include "utils/IpStreamer.h"
 
 #define WAIT_TIMEOUT 3000000000
 #define INVALID_ID -1
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
index 3664b6c..671d079 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
@@ -48,6 +48,7 @@
     ASSERT_TRUE(mFrontendTests.setFrontendCallback());
     ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
     ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+    mFrontendTests.setDemux(demux);
     mFilterTests.setDemux(demux);
     ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize));
     ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId_64bit(filterId));
@@ -683,6 +684,10 @@
     if (!live.hasFrontendConnection) {
         return;
     }
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     auto live_configs = generateLiveConfigurations();
     for (auto& configuration : live_configs) {
         live = configuration;
@@ -779,6 +784,10 @@
     if (!live.hasFrontendConnection) {
         return;
     }
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     // TODO use parameterized tests
     auto live_configs = generateLiveConfigurations();
     for (auto& configuration : live_configs) {
@@ -793,6 +802,10 @@
     if (!live.hasFrontendConnection) {
         return;
     }
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     auto live_configs = generateLiveConfigurations();
     for (auto& configuration : live_configs) {
         live = configuration;
@@ -808,6 +821,10 @@
     if (!live.hasFrontendConnection) {
         return;
     }
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     // TODO use parameterized tests
     auto live_configs = generateLiveConfigurations();
     for (auto& configuration : live_configs) {
@@ -1111,6 +1128,10 @@
     if (!record.support) {
         return;
     }
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     auto record_configs = generateRecordConfigurations();
     for (auto& configuration : record_configs) {
         record = configuration;
@@ -1125,6 +1146,10 @@
     if (!record.support) {
         return;
     }
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     auto record_configs = generateRecordConfigurations();
     for (auto& configuration : record_configs) {
         record = configuration;
@@ -1157,6 +1182,10 @@
     if (!record.support) {
         return;
     }
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     auto record_configs = generateRecordConfigurations();
     for (auto& configuration : record_configs) {
         record = configuration;
@@ -1194,9 +1223,17 @@
     if (!scan.hasFrontendConnection) {
         return;
     }
+    // Blind scan is not applicable for IPTV frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     vector<ScanHardwareConnections> scan_configs = generateScanConfigurations();
     for (auto& configuration : scan_configs) {
         scan = configuration;
+        // Skip test if the frontend implementation doesn't support blind scan
+        if (!frontendMap[scan.frontendId].supportBlindScan) {
+            continue;
+        }
         mFrontendTests.scanTest(frontendMap[scan.frontendId], FrontendScanType::SCAN_BLIND);
     }
 }
@@ -1218,9 +1255,17 @@
     if (!scan.hasFrontendConnection) {
         return;
     }
+    // Blind scan is not application for IPTV frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     vector<ScanHardwareConnections> scan_configs = generateScanConfigurations();
     for (auto& configuration : scan_configs) {
         scan = configuration;
+        // Skip test if the frontend implementation doesn't support blind scan
+        if (!frontendMap[scan.frontendId].supportBlindScan) {
+            continue;
+        }
         mFrontendTests.scanTest(frontendMap[scan.frontendId], FrontendScanType::SCAN_BLIND);
     }
 }
@@ -1242,6 +1287,10 @@
 
 TEST_P(TunerFrontendAidlTest, getHardwareInfo) {
     description("Test Frontend get hardware info");
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     if (!live.hasFrontendConnection) {
         return;
     }
@@ -1289,6 +1338,10 @@
     if (!live.hasFrontendConnection) {
         return;
     }
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     auto live_configs = generateLiveConfigurations();
     for (auto& configuration : live_configs) {
         live = configuration;
@@ -1316,6 +1369,10 @@
     if (!live.hasFrontendConnection) {
         return;
     }
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     auto live_configs = generateLiveConfigurations();
     for (auto& configuration : live_configs) {
         live = configuration;
@@ -1345,6 +1402,10 @@
     if (!live.hasFrontendConnection) {
         return;
     }
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     auto live_configs = generateLiveConfigurations();
     for (auto& configuration : live_configs) {
         live = configuration;
@@ -1358,6 +1419,10 @@
     if (!descrambling.support) {
         return;
     }
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     vector<DescramblingHardwareConnections> descrambling_configs =
             generateDescramblingConfigurations();
     if (descrambling_configs.empty()) {
@@ -1394,6 +1459,10 @@
     if (!descrambling.support) {
         return;
     }
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     vector<DescramblingHardwareConnections> descrambling_configs =
             generateDescramblingConfigurations();
     if (descrambling_configs.empty()) {
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
index 516cb62..5c13ed0 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
@@ -612,6 +612,7 @@
     frontendMap[defaultFeId].isSoftwareFe = true;
     frontendMap[defaultFeId].canConnectToCiCam = true;
     frontendMap[defaultFeId].ciCamId = 0;
+    frontendMap[defaultFeId].supportBlindScan = true;
     FrontendDvbtSettings dvbt;
     dvbt.transmissionMode = FrontendDvbtTransmissionMode::MODE_8K_E;
     frontendMap[defaultFeId].settings.set<FrontendSettings::Tag::dvbt>(dvbt);
diff --git a/tv/tuner/aidl/vts/functional/utils/IpStreamer.cpp b/tv/tuner/aidl/vts/functional/utils/IpStreamer.cpp
new file mode 100644
index 0000000..02b2633
--- /dev/null
+++ b/tv/tuner/aidl/vts/functional/utils/IpStreamer.cpp
@@ -0,0 +1,57 @@
+#include "IpStreamer.h"
+
+IpStreamer::IpStreamer() {}
+
+IpStreamer::~IpStreamer() {}
+
+void IpStreamer::startIpStream() {
+    ALOGI("Starting IP Stream thread");
+    mFp = fopen(mFilePath.c_str(), "rb");
+    if (mFp == nullptr) {
+        ALOGE("Failed to open file at path: %s", mFilePath.c_str());
+        return;
+    }
+    mIpStreamerThread = std::thread(&IpStreamer::ipStreamThreadLoop, this, mFp);
+}
+
+void IpStreamer::stopIpStream() {
+    ALOGI("Stopping IP Stream thread");
+    close(mSockfd);
+    if (mFp != nullptr) fclose(mFp);
+    if (mIpStreamerThread.joinable()) {
+        mIpStreamerThread.join();
+    }
+}
+
+void IpStreamer::ipStreamThreadLoop(FILE* fp) {
+    mSockfd = socket(AF_INET, SOCK_DGRAM, 0);
+    if (mSockfd < 0) {
+        ALOGE("IpStreamer::ipStreamThreadLoop: Socket creation failed (%s)", strerror(errno));
+        exit(1);
+    }
+
+    if (mFp == NULL) {
+        ALOGE("IpStreamer::ipStreamThreadLoop: Cannot open file %s: (%s)", mFilePath.c_str(),
+              strerror(errno));
+        exit(1);
+    }
+
+    struct sockaddr_in destaddr;
+    memset(&destaddr, 0, sizeof(destaddr));
+    destaddr.sin_family = mIsIpV4 ? AF_INET : AF_INET6;
+    destaddr.sin_port = htons(mPort);
+    destaddr.sin_addr.s_addr = inet_addr(mIpAddress.c_str());
+
+    char buf[mBufferSize];
+    int n;
+    while (1) {
+        if (fp == nullptr) break;
+        n = fread(buf, 1, mBufferSize, fp);
+        ALOGI("IpStreamer::ipStreamThreadLoop: Bytes read from fread(): %d\n", n);
+        if (n <= 0) {
+            break;
+        }
+        sendto(mSockfd, buf, n, 0, (struct sockaddr*)&destaddr, sizeof(destaddr));
+        sleep(mSleepTime);
+    }
+}
diff --git a/tv/tuner/aidl/vts/functional/utils/IpStreamer.h b/tv/tuner/aidl/vts/functional/utils/IpStreamer.h
new file mode 100644
index 0000000..d073003
--- /dev/null
+++ b/tv/tuner/aidl/vts/functional/utils/IpStreamer.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <log/log.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string>
+#include <thread>
+
+/**
+ * IP Streamer class to send TS data to a specified socket for testing IPTV frontend functions
+ * e.g. tuning and playback.
+ */
+
+class IpStreamer {
+  public:
+    // Constructor for IP Streamer object
+    IpStreamer();
+
+    // Destructor for IP Streamer object
+    ~IpStreamer();
+
+    // Starts a thread to read data from a socket
+    void startIpStream();
+
+    // Stops the reading thread started by startIpStream
+    void stopIpStream();
+
+    // Thread function that consumes data from a socket
+    void ipStreamThreadLoop(FILE* fp);
+
+    std::string getFilePath() { return mFilePath; };
+
+  private:
+    int mSockfd = -1;
+    FILE* mFp;
+    bool mIsIpV4 = true;                                         // By default, set to IPV4
+    int mPort = 12345;                                           // default port
+    int mBufferSize = 188;                                       // bytes
+    int mSleepTime = 1;                                          // second
+    std::string mIpAddress = "127.0.0.1";                        // default IP address
+    std::string mFilePath = "/data/local/tmp/segment000000.ts";  // default path for TS file
+    std::thread mIpStreamerThread;
+};
\ No newline at end of file
diff --git a/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h b/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
index 9517520..5ffb38f 100644
--- a/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
+++ b/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
@@ -114,6 +114,7 @@
     FrontendSettings settings;
     vector<FrontendStatusType> tuneStatusTypes;
     vector<FrontendStatus> expectTuneStatuses;
+    bool supportBlindScan;
 };
 
 struct FilterConfig {
@@ -354,6 +355,11 @@
                 } else {
                     hasHwFe = true;
                 }
+                if (feConfig.hasSupportBlindScan()) {
+                    frontendMap[id].supportBlindScan = feConfig.getSupportBlindScan();
+                } else {
+                    frontendMap[id].supportBlindScan = true;
+                }
                 // TODO: b/182519645 complete the tune status config
                 frontendMap[id].tuneStatusTypes = types;
                 frontendMap[id].expectTuneStatuses = statuses;
diff --git a/tv/tuner/config/api/current.txt b/tv/tuner/config/api/current.txt
index dbd3486..ff2df90 100644
--- a/tv/tuner/config/api/current.txt
+++ b/tv/tuner/config/api/current.txt
@@ -369,6 +369,7 @@
     method @Nullable public android.media.tuner.testing.configuration.V1_0.IsdbsFrontendSettings getIsdbsFrontendSettings_optional();
     method @Nullable public android.media.tuner.testing.configuration.V1_0.IsdbtFrontendSettings getIsdbtFrontendSettings_optional();
     method @Nullable public java.math.BigInteger getRemoveOutputPid();
+    method @Nullable public boolean getSupportBlindScan();
     method @Nullable public android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum getType();
     method public void setAtscFrontendSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.AtscFrontendSettings);
     method public void setConnectToCicamId(@Nullable java.math.BigInteger);
@@ -381,6 +382,7 @@
     method public void setIsdbsFrontendSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.IsdbsFrontendSettings);
     method public void setIsdbtFrontendSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.IsdbtFrontendSettings);
     method public void setRemoveOutputPid(@Nullable java.math.BigInteger);
+    method public void setSupportBlindScan(@Nullable boolean);
     method public void setType(@Nullable android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum);
   }
 
diff --git a/tv/tuner/config/tuner_testing_dynamic_configuration.xsd b/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
index c51ac51..eafaca9 100644
--- a/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
+++ b/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
@@ -162,6 +162,7 @@
         <xs:attribute name="connectToCicamId" type="xs:nonNegativeInteger" use="optional"/>
         <xs:attribute name="removeOutputPid" type="xs:nonNegativeInteger" use="optional"/>
         <xs:attribute name="endFrequency" type="xs:nonNegativeInteger" use="optional"/>
+        <xs:attribute name="supportBlindScan" type="xs:boolean" use="optional"/>
     </xs:complexType>
 
     <!-- FILTER SESSION -->
diff --git a/uwb/aidl/default/Android.bp b/uwb/aidl/default/Android.bp
index f9b79de..8af1678 100644
--- a/uwb/aidl/default/Android.bp
+++ b/uwb/aidl/default/Android.bp
@@ -24,6 +24,8 @@
         "libtokio_util",
         "libnix",
         "libanyhow",
+        "libpdl_runtime",
+        "libuwb_uci_packets",
     ],
     proc_macros: [
         "libasync_trait",
diff --git a/uwb/aidl/default/src/uwb_chip.rs b/uwb/aidl/default/src/uwb_chip.rs
index efb2454..d1c3c67 100644
--- a/uwb/aidl/default/src/uwb_chip.rs
+++ b/uwb/aidl/default/src/uwb_chip.rs
@@ -16,6 +16,9 @@
 use std::io::{self, Read, Write};
 use std::os::unix::fs::OpenOptionsExt;
 
+use pdl_runtime::Packet;
+use uwb_uci_packets::{DeviceResetCmdBuilder, ResetConfig, UciControlPacket, UciControlPacketHal};
+
 enum State {
     Closed,
     Opened {
@@ -46,11 +49,37 @@
 impl State {
     /// Terminate the reader task.
     async fn close(&mut self) -> Result<()> {
-        if let State::Opened { ref mut token, ref callbacks, ref mut death_recipient, ref mut handle, .. } = *self {
+        if let State::Opened {
+            ref mut token,
+            ref callbacks,
+            ref mut death_recipient,
+            ref mut handle,
+            ref mut serial,
+        } = *self
+        {
             log::info!("waiting for task cancellation");
             callbacks.as_binder().unlink_to_death(death_recipient)?;
             token.cancel();
             handle.await.unwrap();
+            let packet: UciControlPacket = DeviceResetCmdBuilder {
+                reset_config: ResetConfig::UwbsReset,
+            }
+            .build()
+            .into();
+            // DeviceResetCmd need to be send to reset the device to stop all running
+            // activities on UWBS.
+            let packet_vec: Vec<UciControlPacketHal> = packet.into();
+            for hal_packet in packet_vec.into_iter() {
+                serial
+                    .write(&hal_packet.to_vec())
+                    .map(|written| written as i32)
+                    .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
+            }
+            consume_device_reset_rsp_and_ntf(
+                &mut serial
+                    .try_clone()
+                    .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?,
+            );
             log::info!("task successfully cancelled");
             callbacks.onHalEvent(UwbEvent::CLOSE_CPLT, UwbStatus::OK)?;
             *self = State::Closed;
@@ -59,6 +88,20 @@
     }
 }
 
+fn consume_device_reset_rsp_and_ntf(reader: &mut File) {
+    // Poll the DeviceResetRsp and DeviceStatusNtf before hal is closed to prevent
+    // the host from getting response and notifications from a 'powered down' UWBS.
+    // Do nothing when these packets are received.
+    const DEVICE_RESET_RSP: [u8; 5] = [64, 0, 0, 1, 0];
+    const DEVICE_STATUS_NTF: [u8; 5] = [96, 1, 0, 1, 1];
+    let mut buffer = vec![0; DEVICE_RESET_RSP.len() + DEVICE_STATUS_NTF.len()];
+    read_exact(reader, &mut buffer).unwrap();
+
+    // Make sure received packets are the expected ones.
+    assert_eq!(&buffer[0..DEVICE_RESET_RSP.len()], &DEVICE_RESET_RSP);
+    assert_eq!(&buffer[DEVICE_RESET_RSP.len()..], &DEVICE_STATUS_NTF);
+}
+
 pub fn makeraw(file: File) -> io::Result<File> {
     // Configure the file descriptor as raw fd.
     use nix::sys::termios::*;
@@ -209,7 +252,7 @@
 
         let mut state = self.state.lock().await;
 
-        if matches!(*state, State::Opened { .. }) {
+        if let State::Opened { .. } = *state {
             state.close().await
         } else {
             Err(binder::ExceptionCode::ILLEGAL_STATE.into())
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttCapabilities.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttCapabilities.aidl
index 56ef2d2..af1647d 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttCapabilities.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttCapabilities.aidl
@@ -42,9 +42,8 @@
   android.hardware.wifi.RttPreamble preambleSupport;
   android.hardware.wifi.RttBw bwSupport;
   byte mcVersion;
-  android.hardware.wifi.RttPreamble azPreambleSupport;
-  android.hardware.wifi.RttBw azBwSupport;
+  int azPreambleSupport;
+  int azBwSupport;
   boolean ntbInitiatorSupported;
   boolean ntbResponderSupported;
-  int maxTxLtfRepetitionCount;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttConfig.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttConfig.aidl
index b7830bd..b53ff9b 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttConfig.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttConfig.aidl
@@ -48,7 +48,6 @@
   int burstDuration;
   android.hardware.wifi.RttPreamble preamble;
   android.hardware.wifi.RttBw bw;
-  int ntbMinMeasurementTimeMillis;
-  int ntbMaxMeasurementTimeMillis;
-  int txLtfRepetitionCount;
+  long ntbMinMeasurementTime;
+  long ntbMaxMeasurementTime;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResult.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResult.aidl
index 30f5f58..9c6ad26 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResult.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResult.aidl
@@ -59,7 +59,8 @@
   android.hardware.wifi.WifiInformationElement lcr;
   int channelFreqMHz;
   android.hardware.wifi.RttBw packetBw;
-  int txLtfRepetitionCount;
-  int ntbMinMeasurementTimeMillis;
-  int ntbMaxMeasurementTimeMillis;
+  byte i2rTxLtfRepetitionCount;
+  byte r2iTxLtfRepetitionCount;
+  long ntbMinMeasurementTime;
+  long ntbMaxMeasurementTime;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtCapabilities.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtCapabilities.aidl
index d8e73fb..75f3e83 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtCapabilities.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtCapabilities.aidl
@@ -38,8 +38,8 @@
   boolean isTwtResponderSupported;
   boolean isBroadcastTwtSupported;
   boolean isFlexibleTwtScheduleSupported;
-  int minWakeDurationMicros;
-  int maxWakeDurationMicros;
-  int minWakeIntervalMicros;
-  int maxWakeIntervalMicros;
+  int minWakeDurationUs;
+  int maxWakeDurationUs;
+  long minWakeIntervalUs;
+  long maxWakeIntervalUs;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtRequest.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtRequest.aidl
index 3051b94..1e1c39a 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtRequest.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtRequest.aidl
@@ -35,8 +35,8 @@
 @VintfStability
 parcelable TwtRequest {
   int mloLinkId;
-  int minWakeDurationMicros;
-  int maxWakeDurationMicros;
-  int minWakeIntervalMicros;
-  int maxWakeIntervalMicros;
+  int minWakeDurationUs;
+  int maxWakeDurationUs;
+  long minWakeIntervalUs;
+  long maxWakeIntervalUs;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtSession.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtSession.aidl
index 92c2533..0b88d8e 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtSession.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtSession.aidl
@@ -36,8 +36,8 @@
 parcelable TwtSession {
   int sessionId;
   int mloLinkId;
-  int wakeDurationMicros;
-  int wakeIntervalMicros;
+  int wakeDurationUs;
+  long wakeIntervalUs;
   android.hardware.wifi.TwtSession.TwtNegotiationType negotiationType;
   boolean isTriggerEnabled;
   boolean isAnnounced;
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtSessionStats.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtSessionStats.aidl
index 528444a..f62b614 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtSessionStats.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtSessionStats.aidl
@@ -38,6 +38,6 @@
   int avgRxPktCount;
   int avgTxPktSize;
   int avgRxPktSize;
-  int avgEospDurationMicros;
+  int avgEospDurationUs;
   int eospCount;
 }
diff --git a/wifi/aidl/android/hardware/wifi/RttCapabilities.aidl b/wifi/aidl/android/hardware/wifi/RttCapabilities.aidl
index 0352ec8..89b70c9 100644
--- a/wifi/aidl/android/hardware/wifi/RttCapabilities.aidl
+++ b/wifi/aidl/android/hardware/wifi/RttCapabilities.aidl
@@ -64,12 +64,12 @@
      * Bit mask indicating what preamble is supported by IEEE 802.11az initiator.
      * Combination of |RttPreamble| values.
      */
-    RttPreamble azPreambleSupport;
+    int azPreambleSupport;
     /**
      * Bit mask indicating what BW is supported by IEEE 802.11az initiator.
      * Combination of |RttBw| values.
      */
-    RttBw azBwSupport;
+    int azBwSupport;
     /**
      * Whether the initiator supports IEEE 802.11az Non-Trigger-based (non-TB) measurement.
      */
@@ -78,9 +78,4 @@
      * Whether IEEE 802.11az Non-Trigger-based (non-TB) responder mode is supported.
      */
     boolean ntbResponderSupported;
-    /**
-     * Maximum HE LTF repetitions the IEEE 802.11az initiator is capable of transmitting in the
-     * preamble of I2R NDP.
-     */
-    int maxTxLtfRepetitionCount;
 }
diff --git a/wifi/aidl/android/hardware/wifi/RttConfig.aidl b/wifi/aidl/android/hardware/wifi/RttConfig.aidl
index e970656..7b18708 100644
--- a/wifi/aidl/android/hardware/wifi/RttConfig.aidl
+++ b/wifi/aidl/android/hardware/wifi/RttConfig.aidl
@@ -121,16 +121,17 @@
      */
     RttBw bw;
     /**
-     * IEEE 802.11az Non-Trigger-based (non-TB) minimum measurement time in milliseconds.
+     * IEEE 802.11az Non-Trigger-based (non-TB) minimum measurement time in units of 100
+     * microseconds.
+     *
+     * Reference: IEEE Std 802.11az-2022 spec, section 9.4.2.298 Ranging Parameters element.
      */
-    int ntbMinMeasurementTimeMillis;
+    long ntbMinMeasurementTime;
     /**
-     * IEEE 802.11az Non-Trigger-based (non-TB) maximum measurement time in milliseconds.
+     * IEEE 802.11az Non-Trigger-based (non-TB) maximum measurement time in units of 10
+     * milliseconds.
+     *
+     * Reference: IEEE Std 802.11az-2022 spec, section 9.4.2.298 Ranging Parameters element.
      */
-    int ntbMaxMeasurementTimeMillis;
-    /**
-     * Multiple transmissions of HE-LTF symbols in an HE Ranging NDP. A value of 1 indicates no
-     * repetition.
-     */
-    int txLtfRepetitionCount;
+    long ntbMaxMeasurementTime;
 }
diff --git a/wifi/aidl/android/hardware/wifi/RttResult.aidl b/wifi/aidl/android/hardware/wifi/RttResult.aidl
index 2cb0afa..ab9abb5 100644
--- a/wifi/aidl/android/hardware/wifi/RttResult.aidl
+++ b/wifi/aidl/android/hardware/wifi/RttResult.aidl
@@ -146,12 +146,18 @@
      */
     RttBw packetBw;
     /**
-     * IEEE 802.11az Transmit LTF repetitions used to get this result.
+     * Multiple transmissions of HE-LTF symbols in an HE (I2R) Ranging NDP. An HE-LTF repetition
+     * value of 1 indicates no repetitions.
      */
-    int txLtfRepetitionCount;
+    byte i2rTxLtfRepetitionCount;
     /**
-     * Minimum non-trigger based (non-TB) dynamic measurement time in milliseconds assigned by the
-     * IEEE 802.11az responder.
+     * Multiple transmissions of HE-LTF symbols in an HE (R2I) Ranging NDP. An HE-LTF repetition
+     * value of 1 indicates no repetitions.
+     */
+    byte r2iTxLtfRepetitionCount;
+    /**
+     * Minimum non-trigger based (non-TB) dynamic measurement time in units of 100 microseconds
+     * assigned by the IEEE 802.11az responder.
      *
      * After initial non-TB negotiation, if the next ranging request for this peer comes in between
      * [ntbMinMeasurementTime, ntbMaxMeasurementTime], vendor software shall do the NDPA sounding
@@ -160,11 +166,13 @@
      * If the ranging request for this peer comes sooner than minimum measurement time, vendor
      * software shall return the cached result of the last measurement including the time stamp
      * |RttResult.timestamp|.
+     *
+     * Reference: IEEE Std 802.11az-2022 spec, section 9.4.2.298 Ranging Parameters element.
      */
-    int ntbMinMeasurementTimeMillis;
+    long ntbMinMeasurementTime;
     /**
-     * Maximum non-trigger based (non-TB) dynamic measurement time in milliseconds assigned by the
-     * IEEE 802.11az responder.
+     * Maximum non-trigger based (non-TB) dynamic measurement time in units of 10 milliseconds
+     * assigned by the IEEE 802.11az responder.
      *
      * After initial non-TB negotiation, if the next ranging request for this peer comes in between
      * [ntbMinMeasurementTime, ntbMaxMeasurementTime], vendor software shall do the NDPA sounding
@@ -173,6 +181,8 @@
      * If the ranging request for this peer comes later than the maximum measurement time, vendor
      * software shall clean up any existing IEEE 802.11ax non-TB ranging session and re-do the
      * non-TB ranging negotiation.
+     *
+     * Reference: IEEE Std 802.11az-2022 spec, section 9.4.2.298 Ranging Parameters element.
      */
-    int ntbMaxMeasurementTimeMillis;
+    long ntbMaxMeasurementTime;
 }
diff --git a/wifi/aidl/android/hardware/wifi/TwtCapabilities.aidl b/wifi/aidl/android/hardware/wifi/TwtCapabilities.aidl
index 9007d0e..28d16f0 100644
--- a/wifi/aidl/android/hardware/wifi/TwtCapabilities.aidl
+++ b/wifi/aidl/android/hardware/wifi/TwtCapabilities.aidl
@@ -18,6 +18,14 @@
 
 /**
  * Target Wake Time (TWT) Capabilities supported.
+ *
+ * TWT allows Wi-Fi stations to manage activity in a network by scheduling to operate at different
+ * times. This minimizes the contention and reduces the required amount of time that a station
+ * utilizing a power management mode needs to be awake.
+ *
+ * IEEE 802.11ax standard defines two modes of TWT operation:
+ *  - Individual TWT (default mode of operation if TWT requester is supported)
+ *  - Broadcast TWT
  */
 @VintfStability
 parcelable TwtCapabilities {
@@ -40,17 +48,17 @@
     /**
      * Minimum TWT wake duration in microseconds.
      */
-    int minWakeDurationMicros;
+    int minWakeDurationUs;
     /**
      * Maximum TWT wake duration in microseconds.
      */
-    int maxWakeDurationMicros;
+    int maxWakeDurationUs;
     /**
      * Minimum TWT wake interval in microseconds.
      */
-    int minWakeIntervalMicros;
+    long minWakeIntervalUs;
     /**
      * Maximum TWT wake interval in microseconds.
      */
-    int maxWakeIntervalMicros;
+    long maxWakeIntervalUs;
 }
diff --git a/wifi/aidl/android/hardware/wifi/TwtRequest.aidl b/wifi/aidl/android/hardware/wifi/TwtRequest.aidl
index 5191713..6964a39 100644
--- a/wifi/aidl/android/hardware/wifi/TwtRequest.aidl
+++ b/wifi/aidl/android/hardware/wifi/TwtRequest.aidl
@@ -28,17 +28,23 @@
     /**
      * Minimum TWT wake duration in microseconds.
      */
-    int minWakeDurationMicros;
+    int minWakeDurationUs;
     /**
      * Maximum TWT wake duration in microseconds.
+     *
+     * As per IEEE 802.11ax spec, section 9.4.2.199 TWT element, the maximum wake duration is
+     * 65280 microseconds.
      */
-    int maxWakeDurationMicros;
+    int maxWakeDurationUs;
     /**
      * Minimum TWT wake interval in microseconds.
      */
-    int minWakeIntervalMicros;
+    long minWakeIntervalUs;
     /**
      * Maximum TWT wake interval in microseconds.
+     *
+     * As per IEEE 802.11ax spec, section 9.4.2.199 TWT element, the maximum wake interval is
+     * 65535 * 2^31 microseconds.
      */
-    int maxWakeIntervalMicros;
+    long maxWakeIntervalUs;
 }
diff --git a/wifi/aidl/android/hardware/wifi/TwtSession.aidl b/wifi/aidl/android/hardware/wifi/TwtSession.aidl
index 5a7ddb1..2d7e819 100644
--- a/wifi/aidl/android/hardware/wifi/TwtSession.aidl
+++ b/wifi/aidl/android/hardware/wifi/TwtSession.aidl
@@ -41,12 +41,12 @@
     /**
      * TWT service period in microseconds.
      */
-    int wakeDurationMicros;
+    int wakeDurationUs;
 
     /**
      * Time interval in microseconds between two successive TWT service periods.
      */
-    int wakeIntervalMicros;
+    long wakeIntervalUs;
 
     /**
      * TWT negotiation type.
diff --git a/wifi/aidl/android/hardware/wifi/TwtSessionStats.aidl b/wifi/aidl/android/hardware/wifi/TwtSessionStats.aidl
index e2e2d12..ba70426 100644
--- a/wifi/aidl/android/hardware/wifi/TwtSessionStats.aidl
+++ b/wifi/aidl/android/hardware/wifi/TwtSessionStats.aidl
@@ -44,7 +44,7 @@
     /**
      * Average End of Service period in microseconds.
      */
-    int avgEospDurationMicros;
+    int avgEospDurationUs;
 
     /**
      * Count of early terminations.
diff --git a/wifi/aidl/default/aidl_struct_util.cpp b/wifi/aidl/default/aidl_struct_util.cpp
index b62b3a0..836ce1a 100644
--- a/wifi/aidl/default/aidl_struct_util.cpp
+++ b/wifi/aidl/default/aidl_struct_util.cpp
@@ -2741,9 +2741,8 @@
     if (!convertAidlRttConfigToLegacy(aidl_config, &(legacy_config->rtt_config))) {
         return false;
     }
-    legacy_config->tx_ltf_repetition_count = aidl_config.txLtfRepetitionCount;
-    legacy_config->ntb_min_measurement_time_millis = aidl_config.ntbMinMeasurementTimeMillis;
-    legacy_config->ntb_max_measurement_time_millis = aidl_config.ntbMaxMeasurementTimeMillis;
+    legacy_config->ntb_min_measurement_time = aidl_config.ntbMinMeasurementTime;
+    legacy_config->ntb_max_measurement_time = aidl_config.ntbMaxMeasurementTime;
     return true;
 }
 
@@ -2887,11 +2886,10 @@
     aidl_capabilities->bwSupport = convertLegacyRttBwBitmapToAidl(legacy_capabilities.bw_support);
     aidl_capabilities->mcVersion = legacy_capabilities.mc_version;
     // Initialize 11az parameters to default
-    aidl_capabilities->azPreambleSupport = RttPreamble::INVALID;
-    aidl_capabilities->azBwSupport = RttBw::BW_UNSPECIFIED;
+    aidl_capabilities->azPreambleSupport = (int)RttPreamble::INVALID;
+    aidl_capabilities->azBwSupport = (int)RttBw::BW_UNSPECIFIED;
     aidl_capabilities->ntbInitiatorSupported = false;
     aidl_capabilities->ntbResponderSupported = false;
-    aidl_capabilities->maxTxLtfRepetitionCount = 0;
     return true;
 }
 
@@ -2914,12 +2912,11 @@
             convertLegacyRttBwBitmapToAidl(legacy_capabilities_v3.rtt_capab.bw_support);
     aidl_capabilities->mcVersion = legacy_capabilities_v3.rtt_capab.mc_version;
     aidl_capabilities->azPreambleSupport =
-            convertLegacyRttPreambleBitmapToAidl(legacy_capabilities_v3.az_preamble_support);
+            (int)convertLegacyRttPreambleBitmapToAidl(legacy_capabilities_v3.az_preamble_support);
     aidl_capabilities->azBwSupport =
-            convertLegacyRttBwBitmapToAidl(legacy_capabilities_v3.az_bw_support);
+            (int)convertLegacyRttBwBitmapToAidl(legacy_capabilities_v3.az_bw_support);
     aidl_capabilities->ntbInitiatorSupported = legacy_capabilities_v3.ntb_initiator_supported;
     aidl_capabilities->ntbResponderSupported = legacy_capabilities_v3.ntb_responder_supported;
-    aidl_capabilities->maxTxLtfRepetitionCount = legacy_capabilities_v3.max_tx_ltf_repetition_count;
     return true;
 }
 
@@ -2994,9 +2991,10 @@
         }
         aidl_result.channelFreqMHz = 0;
         aidl_result.packetBw = RttBw::BW_UNSPECIFIED;
-        aidl_result.txLtfRepetitionCount = 0;
-        aidl_result.ntbMinMeasurementTimeMillis = 0;
-        aidl_result.ntbMaxMeasurementTimeMillis = 0;
+        aidl_result.i2rTxLtfRepetitionCount = 0;
+        aidl_result.r2iTxLtfRepetitionCount = 0;
+        aidl_result.ntbMinMeasurementTime = 0;
+        aidl_result.ntbMaxMeasurementTime = 0;
         aidl_results->push_back(aidl_result);
     }
     return true;
@@ -3017,9 +3015,10 @@
         aidl_result.channelFreqMHz =
                 legacy_result->frequency != UNSPECIFIED ? legacy_result->frequency : 0;
         aidl_result.packetBw = convertLegacyRttBwToAidl(legacy_result->packet_bw);
-        aidl_result.txLtfRepetitionCount = 0;
-        aidl_result.ntbMinMeasurementTimeMillis = 0;
-        aidl_result.ntbMaxMeasurementTimeMillis = 0;
+        aidl_result.i2rTxLtfRepetitionCount = 0;
+        aidl_result.r2iTxLtfRepetitionCount = 0;
+        aidl_result.ntbMinMeasurementTime = 0;
+        aidl_result.ntbMaxMeasurementTime = 0;
         aidl_results->push_back(aidl_result);
     }
     return true;
@@ -3041,9 +3040,10 @@
                                              ? legacy_result->rtt_result.frequency
                                              : 0;
         aidl_result.packetBw = convertLegacyRttBwToAidl(legacy_result->rtt_result.packet_bw);
-        aidl_result.txLtfRepetitionCount = legacy_result->tx_ltf_repetition_count;
-        aidl_result.ntbMinMeasurementTimeMillis = legacy_result->ntb_min_measurement_time_millis;
-        aidl_result.ntbMaxMeasurementTimeMillis = legacy_result->ntb_max_measurement_time_millis;
+        aidl_result.i2rTxLtfRepetitionCount = legacy_result->i2r_tx_ltf_repetition_count;
+        aidl_result.r2iTxLtfRepetitionCount = legacy_result->r2i_tx_ltf_repetition_count;
+        aidl_result.ntbMinMeasurementTime = legacy_result->ntb_min_measurement_time;
+        aidl_result.ntbMaxMeasurementTime = legacy_result->ntb_max_measurement_time;
         aidl_results->push_back(aidl_result);
     }
     return true;
@@ -3587,13 +3587,13 @@
     if (legacy_twt_capabs.min_wake_duration_micros > legacy_twt_capabs.max_wake_duration_micros) {
         return false;
     }
-    aidl_twt_capabs->minWakeDurationMicros = legacy_twt_capabs.min_wake_duration_micros;
-    aidl_twt_capabs->maxWakeDurationMicros = legacy_twt_capabs.max_wake_duration_micros;
+    aidl_twt_capabs->minWakeDurationUs = legacy_twt_capabs.min_wake_duration_micros;
+    aidl_twt_capabs->maxWakeDurationUs = legacy_twt_capabs.max_wake_duration_micros;
     if (legacy_twt_capabs.min_wake_interval_micros > legacy_twt_capabs.max_wake_interval_micros) {
         return false;
     }
-    aidl_twt_capabs->minWakeIntervalMicros = legacy_twt_capabs.min_wake_interval_micros;
-    aidl_twt_capabs->maxWakeIntervalMicros = legacy_twt_capabs.max_wake_interval_micros;
+    aidl_twt_capabs->minWakeIntervalUs = legacy_twt_capabs.min_wake_interval_micros;
+    aidl_twt_capabs->maxWakeIntervalUs = legacy_twt_capabs.max_wake_interval_micros;
     return true;
 }
 
@@ -3603,16 +3603,16 @@
         return false;
     }
     legacy_twt_request->mlo_link_id = aidl_twt_request.mloLinkId;
-    if (aidl_twt_request.minWakeDurationMicros > aidl_twt_request.maxWakeDurationMicros) {
+    if (aidl_twt_request.minWakeDurationUs > aidl_twt_request.maxWakeDurationUs) {
         return false;
     }
-    legacy_twt_request->min_wake_duration_micros = aidl_twt_request.minWakeDurationMicros;
-    legacy_twt_request->max_wake_duration_micros = aidl_twt_request.maxWakeDurationMicros;
-    if (aidl_twt_request.minWakeIntervalMicros > aidl_twt_request.maxWakeIntervalMicros) {
+    legacy_twt_request->min_wake_duration_micros = aidl_twt_request.minWakeDurationUs;
+    legacy_twt_request->max_wake_duration_micros = aidl_twt_request.maxWakeDurationUs;
+    if (aidl_twt_request.minWakeIntervalUs > aidl_twt_request.maxWakeIntervalUs) {
         return false;
     }
-    legacy_twt_request->min_wake_interval_micros = aidl_twt_request.minWakeIntervalMicros;
-    legacy_twt_request->max_wake_interval_micros = aidl_twt_request.maxWakeIntervalMicros;
+    legacy_twt_request->min_wake_interval_micros = aidl_twt_request.minWakeIntervalUs;
+    legacy_twt_request->max_wake_interval_micros = aidl_twt_request.maxWakeIntervalUs;
     return true;
 }
 
@@ -3664,8 +3664,8 @@
 
     aidl_twt_session->sessionId = twt_session.session_id;
     aidl_twt_session->mloLinkId = twt_session.mlo_link_id;
-    aidl_twt_session->wakeDurationMicros = twt_session.wake_duration_micros;
-    aidl_twt_session->wakeIntervalMicros = twt_session.wake_interval_micros;
+    aidl_twt_session->wakeDurationUs = twt_session.wake_duration_micros;
+    aidl_twt_session->wakeIntervalUs = twt_session.wake_interval_micros;
     switch (twt_session.negotiation_type) {
         case WIFI_TWT_NEGO_TYPE_INDIVIDUAL:
             aidl_twt_session->negotiationType = TwtSession::TwtNegotiationType::INDIVIDUAL;
@@ -3696,7 +3696,7 @@
     aidl_twt_stats->avgRxPktCount = twt_stats.avg_pkt_num_rx;
     aidl_twt_stats->avgTxPktSize = twt_stats.avg_tx_pkt_size;
     aidl_twt_stats->avgRxPktSize = twt_stats.avg_rx_pkt_size;
-    aidl_twt_stats->avgEospDurationMicros = twt_stats.avg_eosp_dur_us;
+    aidl_twt_stats->avgEospDurationUs = twt_stats.avg_eosp_dur_us;
     aidl_twt_stats->eospCount = twt_stats.eosp_count;
 
     return true;
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
index 0729646..05a7548 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
@@ -42,6 +42,9 @@
   void cancelConnect();
   void cancelServiceDiscovery(in long identifier);
   void cancelWps(in String groupIfName);
+  /**
+   * @deprecated This method is deprecated from AIDL v3, newer HALs should use configureExtListenWithParams.
+   */
   void configureExtListen(in int periodInMillis, in int intervalInMillis);
   /**
    * @deprecated This method is deprecated from AIDL v3, newer HALs should use connectWithParams.
@@ -111,4 +114,5 @@
   void configureEapolIpAddressAllocationParams(in int ipAddressGo, in int ipAddressMask, in int ipAddressStart, in int ipAddressEnd);
   String connectWithParams(in android.hardware.wifi.supplicant.P2pConnectInfo connectInfo);
   void findWithParams(in android.hardware.wifi.supplicant.P2pDiscoveryInfo discoveryInfo);
+  void configureExtListenWithParams(in android.hardware.wifi.supplicant.P2pExtListenInfo extListenInfo);
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
index 851e851..4811565 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
@@ -35,7 +35,7 @@
 @VintfStability
 interface ISupplicantP2pIfaceCallback {
   /**
-   * @deprecated This callback is deprecated from AIDL v2, newer HAL should call onDeviceFoundWithParams.
+   * @deprecated This callback is deprecated from AIDL v3, newer HAL should call onDeviceFoundWithParams.
    */
   oneway void onDeviceFound(in byte[] srcAddress, in byte[] p2pDeviceAddress, in byte[] primaryDeviceType, in String deviceName, in android.hardware.wifi.supplicant.WpsConfigMethods configMethods, in byte deviceCapabilities, in android.hardware.wifi.supplicant.P2pGroupCapabilityMask groupCapabilities, in byte[] wfdDeviceInfo);
   oneway void onDeviceLost(in byte[] p2pDeviceAddress);
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 898c2d4..9fa8f56 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
@@ -54,7 +54,7 @@
   oneway void onExtRadioWorkTimeout(in int id);
   oneway void onHs20DeauthImminentNotice(in byte[] bssid, in int reasonCode, in int reAuthDelayInSec, in String url);
   /**
-   * @deprecated No longer in use.
+   * @deprecated This callback is deprecated from AIDL v3.
    */
   oneway void onHs20IconQueryDone(in byte[] bssid, in String fileName, in byte[] data);
   oneway void onHs20SubscriptionRemediation(in byte[] bssid, in android.hardware.wifi.supplicant.OsuMethod osuMethod, in String url);
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pExtListenInfo.aidl
similarity index 88%
copy from security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
copy to wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pExtListenInfo.aidl
index cc07f9b..b4d8e9d 100644
--- a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pExtListenInfo.aidl
@@ -1,4 +1,4 @@
-/*
+/**
  * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,12 +31,10 @@
 // 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.security.secretkeeper;
-/* @hide */
-@Backing(type="int") @VintfStability
-enum ErrorCode {
-  OK = 0,
-  UNKNOWN_KEY_ID = 1,
-  INTERNAL_ERROR = 2,
-  REQUEST_MALFORMED = 3,
+package android.hardware.wifi.supplicant;
+@VintfStability
+parcelable P2pExtListenInfo {
+  int periodMs;
+  int intervalMs;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pProvisionDiscoveryCompletedEventParams.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pProvisionDiscoveryCompletedEventParams.aidl
index 0ff0653..46366cc 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pProvisionDiscoveryCompletedEventParams.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pProvisionDiscoveryCompletedEventParams.aidl
@@ -37,7 +37,7 @@
   byte[6] p2pDeviceAddress;
   boolean isRequest;
   android.hardware.wifi.supplicant.P2pProvDiscStatusCode status;
-  android.hardware.wifi.supplicant.WpsConfigMethods configMethods;
+  int configMethods;
   String generatedPin;
   String groupInterfaceName;
   @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
index 983ed15..8b78a4a 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
@@ -24,6 +24,7 @@
 import android.hardware.wifi.supplicant.MiracastMode;
 import android.hardware.wifi.supplicant.P2pConnectInfo;
 import android.hardware.wifi.supplicant.P2pDiscoveryInfo;
+import android.hardware.wifi.supplicant.P2pExtListenInfo;
 import android.hardware.wifi.supplicant.P2pFrameTypeMask;
 import android.hardware.wifi.supplicant.P2pGroupCapabilityMask;
 import android.hardware.wifi.supplicant.WpsConfigMethods;
@@ -165,6 +166,9 @@
      * (with interval obviously having to be larger than or equal to duration).
      * If the P2P module is not idle at the time the Extended Listen Timing
      * timeout occurs, the Listen State operation must be skipped.
+     * <p>
+     * @deprecated This method is deprecated from AIDL v3, newer HALs should use
+     * configureExtListenWithParams.
      *
      * @param periodInMillis Period in milliseconds.
      * @param intervalInMillis Interval in milliseconds.
@@ -882,4 +886,21 @@
      *         |SupplicantStatusCode.FAILURE_IFACE_DISABLED|
      */
     void findWithParams(in P2pDiscoveryInfo discoveryInfo);
+
+    /**
+     * Configure Extended Listen Timing.
+     *
+     * If enabled, listen state must be entered every |intervalMs| for at
+     * least |periodMs|. Both values have acceptable range of 1-65535
+     * (note that the interval must be larger than or equal to the duration).
+     * If the P2P module is not idle at the time the Extended Listen Timing
+     * timeout occurs, the Listen State operation must be skipped.
+     *
+     * @param extListenInfo Parameters to configure extended listening timing.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void configureExtListenWithParams(in P2pExtListenInfo extListenInfo);
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
index 11cd867..b9273a8 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
@@ -40,7 +40,7 @@
     /**
      * Used to indicate that a P2P device has been found.
      * <p>
-     * @deprecated This callback is deprecated from AIDL v2, newer HAL should call
+     * @deprecated This callback is deprecated from AIDL v3, newer HAL should call
      * onDeviceFoundWithParams.
      *
      * @param srcAddress MAC address of the device found. This must either
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
index 58893eb..172fcda 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
@@ -198,7 +198,7 @@
     /**
      * Used to indicate the result of Hotspot 2.0 Icon query.
      *
-     * @deprecated No longer in use.
+     * @deprecated This callback is deprecated from AIDL v3.
      *
      * @param bssid BSSID of the access point.
      * @param fileName Name of the file that was requested.
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pExtListenInfo.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pExtListenInfo.aidl
new file mode 100644
index 0000000..1086c94
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pExtListenInfo.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (C) 2023 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.wifi.supplicant;
+
+import android.hardware.wifi.common.OuiKeyedData;
+
+/**
+ * Parameters used to configure the P2P Extended Listen Interval.
+ */
+@VintfStability
+parcelable P2pExtListenInfo {
+    /**
+     * Period in milliseconds.
+     */
+    int periodMs;
+    /**
+     * Interval in milliseconds.
+     */
+    int intervalMs;
+    /**
+     * Optional vendor-specific parameters. Null value indicates
+     * that no vendor data is provided.
+     */
+    @nullable OuiKeyedData[] vendorData;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pProvisionDiscoveryCompletedEventParams.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pProvisionDiscoveryCompletedEventParams.aidl
index b559216..05152a9 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pProvisionDiscoveryCompletedEventParams.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pProvisionDiscoveryCompletedEventParams.aidl
@@ -18,7 +18,6 @@
 
 import android.hardware.wifi.common.OuiKeyedData;
 import android.hardware.wifi.supplicant.P2pProvDiscStatusCode;
-import android.hardware.wifi.supplicant.WpsConfigMethods;
 
 /**
  * Parameters passed as a part of P2P provision discovery frame notification.
@@ -34,8 +33,8 @@
     boolean isRequest;
     /** Status of the provision discovery */
     P2pProvDiscStatusCode status;
-    /** Mask of WPS configuration methods supported */
-    WpsConfigMethods configMethods;
+    /** Mask of |WpsConfigMethods| indicating the supported methods */
+    int configMethods;
     /** 8-digit pin generated */
     String generatedPin;
     /**
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 7574141..e5e9735 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
@@ -110,6 +110,7 @@
         initializeService();
         supplicant_ = getSupplicant(GetParam().c_str());
         ASSERT_NE(supplicant_, nullptr);
+        ASSERT_TRUE(supplicant_->getInterfaceVersion(&interface_version_).isOk());
         ASSERT_TRUE(supplicant_
                         ->setDebugParams(DebugLevel::EXCESSIVE,
                                          true,  // show timestamps
@@ -131,6 +132,7 @@
     std::shared_ptr<ISupplicant> supplicant_;
     std::shared_ptr<ISupplicantStaIface> sta_iface_;
     std::shared_ptr<ISupplicantStaNetwork> sta_network_;
+    int interface_version_;
 
     void removeNetwork() {
         ASSERT_NE(sta_iface_, nullptr);
@@ -826,6 +828,9 @@
  * disableEht
  */
 TEST_P(SupplicantStaNetworkAidlTest, DisableEht) {
+    if (interface_version_ < 3) {
+        GTEST_SKIP() << "disableEht is available as of Supplicant V3";
+    }
     EXPECT_TRUE(sta_network_->disableEht().isOk());
 }