Merge "Do not blocklist BDS on CN builds" into main
diff --git a/Android.bp b/Android.bp
index 223a1a9..baf3291 100644
--- a/Android.bp
+++ b/Android.bp
@@ -51,7 +51,6 @@
     // Lists all dependencies that can *not* be expected on the device.
     static_libs: [
         "VtsHalHidlTestUtils",
-        "libhidlbase",
         "libhidl-gen-utils",
     ],
 
@@ -64,6 +63,7 @@
         "libbase",
         // All the following are dependencies of any HAL definition library.
         "libcutils",
+        "libhidlbase",
         "liblog",
         "libutils",
     ],
@@ -72,14 +72,6 @@
         "-g",
     ],
 
-    target: {
-        android: {
-            shared_libs: [
-                "libvndksupport",
-            ],
-        },
-    },
-
     require_root: true,
 }
 
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl
index 8addab7..aa1a86f 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl
@@ -55,6 +55,9 @@
   parcelable HapticScale {
     int id;
     android.hardware.audio.effect.HapticGenerator.VibratorScale scale = android.hardware.audio.effect.HapticGenerator.VibratorScale.MUTE;
+    float scaleFactor = (-1.0f) /* -1.000000f */;
+    float adaptiveScaleFactor = (-1.0f) /* -1.000000f */;
+    const float UNDEFINED_SCALE_FACTOR = (-1.0f) /* -1.000000f */;
   }
   @VintfStability
   parcelable VibratorInformation {
diff --git a/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl b/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
index 65ea9ef..cfe001e 100644
--- a/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
+++ b/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
@@ -386,14 +386,23 @@
          * For input streams: the moment when data at the specified stream position
          *   was acquired (i.e. capture position).
          *
-         * The observable position must never be reset by the HAL module.
-         * The data type of the frame counter is large enough to support
-         * continuous counting for years of operation.
+         * The observable position must never be reset by the HAL module,
+         * providing an abstraction of continuous audio data flow. The data
+         * type of the frame counter is large enough to support continuous
+         * counting for years of operation.
          */
         Position observable;
         /**
          * Used only for MMap streams to provide the hardware read / write
          * position for audio data in the shared memory buffer 'audio.mmap'.
+         * Similar to the observable position, the 'Position::UNKNOWN' value
+         * can be returned when the HAL module is unable to retrieve the current
+         * position.
+         *
+         * The hardware position must never be reset by the HAL module,
+         * providing an abstraction of continuous audio data flow. The data
+         * type of the frame counter is large enough to support continuous
+         * counting for years of operation.
          */
         Position hardware;
         /**
diff --git a/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl b/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl
index 3cc5acb..f882d63 100644
--- a/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl
+++ b/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl
@@ -56,13 +56,51 @@
     @VintfStability
     parcelable HapticScale {
         /**
+         * Representation of undefined scale factor, applied by default for backwards compatibility.
+         */
+        const float UNDEFINED_SCALE_FACTOR = -1.0f;
+
+        /**
          * Audio track ID.
          */
         int id;
+
         /**
          * Haptic intensity.
+         *
+         * This represents haptics scale as fixed levels defined by VibrationScale. If the field
+         * scaleFactor is defined then this will be ignored in favor of scaleFactor, otherwise this
+         * will be used to define the intensity for the haptics.
          */
         VibratorScale scale = VibratorScale.MUTE;
+
+        /**
+         * Haptic scale factor.
+         *
+         * This is a continuous scale representation of VibratorScale, allowing flexible number of
+         * scale levels. If this field is defined then it will be used to define the intensity of
+         * the haptics, instead of the old VibratorScale field. If this field is undefined then the
+         * old VibratorScale field will be used.
+         *
+         * The value zero represents the same as VibratorScale.MUTE and the value one represents
+         * VibratorScale.NONE. Values in (0,1) should scale down, and values > 1 should scale up
+         * within hardware bounds. Negative values will be ignored.
+         */
+        float scaleFactor = -1.0f; // UNDEFINED_SCALE_FACTOR
+
+        /**
+         * Haptic adaptive scale factor.
+         *
+         * This is an additional scale value that should be applied on top of the vibrator scale to
+         * adapt to the device current state. This should be applied to linearly scale the haptic
+         * data after scale/scaleFactor is applied.
+         *
+         * The value zero mutes the haptics, even if the scale/scaleFactor are not set to MUTE/zero.
+         * The value one will not scale the haptics, and can be used as a constant for no-op.
+         * Values in (0,1) should scale down. Values > 1 should scale up within hardware bounds.
+         * Negative values will be ignored.
+         */
+        float adaptiveScaleFactor = -1.0f; // UNDEFINED_SCALE_FACTOR
     }
 
     /**
diff --git a/audio/aidl/common/Android.bp b/audio/aidl/common/Android.bp
index 5c0c685..c14d19d 100644
--- a/audio/aidl/common/Android.bp
+++ b/audio/aidl/common/Android.bp
@@ -32,10 +32,12 @@
     header_libs: [
         "libbase_headers",
         "libsystem_headers",
+        "libutils_headers",
     ],
     export_header_lib_headers: [
         "libbase_headers",
         "libsystem_headers",
+        "libutils_headers",
     ],
     srcs: [
         "StreamWorker.cpp",
diff --git a/audio/aidl/common/include/Utils.h b/audio/aidl/common/include/Utils.h
index 6241f44..ce29635 100644
--- a/audio/aidl/common/include/Utils.h
+++ b/audio/aidl/common/include/Utils.h
@@ -29,8 +29,10 @@
 #include <aidl/android/media/audio/common/AudioIoFlags.h>
 #include <aidl/android/media/audio/common/AudioMode.h>
 #include <aidl/android/media/audio/common/AudioOutputFlags.h>
+#include <aidl/android/media/audio/common/AudioPolicyForcedConfig.h>
 #include <aidl/android/media/audio/common/PcmType.h>
 #include <android/binder_auto_utils.h>
+#include <utils/FastStrcmp.h>
 
 namespace ndk {
 
@@ -61,6 +63,36 @@
         ::aidl::android::media::audio::common::AudioMode::CALL_SCREEN,
 };
 
+constexpr std::array<::aidl::android::media::audio::common::AudioPolicyForcedConfig, 17>
+        kValidAudioPolicyForcedConfig = {
+                ::aidl::android::media::audio::common::AudioPolicyForcedConfig::NONE,
+                ::aidl::android::media::audio::common::AudioPolicyForcedConfig::SPEAKER,
+                ::aidl::android::media::audio::common::AudioPolicyForcedConfig::HEADPHONES,
+                ::aidl::android::media::audio::common::AudioPolicyForcedConfig::BT_SCO,
+                ::aidl::android::media::audio::common::AudioPolicyForcedConfig::BT_A2DP,
+                ::aidl::android::media::audio::common::AudioPolicyForcedConfig::WIRED_ACCESSORY,
+                ::aidl::android::media::audio::common::AudioPolicyForcedConfig::BT_CAR_DOCK,
+                ::aidl::android::media::audio::common::AudioPolicyForcedConfig::BT_DESK_DOCK,
+                ::aidl::android::media::audio::common::AudioPolicyForcedConfig::ANALOG_DOCK,
+                ::aidl::android::media::audio::common::AudioPolicyForcedConfig::DIGITAL_DOCK,
+                ::aidl::android::media::audio::common::AudioPolicyForcedConfig::NO_BT_A2DP,
+                ::aidl::android::media::audio::common::AudioPolicyForcedConfig::SYSTEM_ENFORCED,
+                ::aidl::android::media::audio::common::AudioPolicyForcedConfig::
+                        HDMI_SYSTEM_AUDIO_ENFORCED,
+                ::aidl::android::media::audio::common::AudioPolicyForcedConfig::
+                        ENCODED_SURROUND_NEVER,
+                ::aidl::android::media::audio::common::AudioPolicyForcedConfig::
+                        ENCODED_SURROUND_ALWAYS,
+                ::aidl::android::media::audio::common::AudioPolicyForcedConfig::
+                        ENCODED_SURROUND_MANUAL,
+                ::aidl::android::media::audio::common::AudioPolicyForcedConfig::BT_BLE,
+};
+
+constexpr bool iequals(const std::string& str1, const std::string& str2) {
+    return str1.length() == str2.length() &&
+           !fasticmp<strncmp>(str1.c_str(), str2.c_str(), str1.length());
+}
+
 constexpr size_t getPcmSampleSizeInBytes(::aidl::android::media::audio::common::PcmType pcm) {
     using ::aidl::android::media::audio::common::PcmType;
     switch (pcm) {
@@ -136,6 +168,12 @@
            kValidAudioModes.end();
 }
 
+constexpr bool isValidAudioPolicyForcedConfig(
+        ::aidl::android::media::audio::common::AudioPolicyForcedConfig config) {
+    return std::find(kValidAudioPolicyForcedConfig.begin(), kValidAudioPolicyForcedConfig.end(),
+                     config) != kValidAudioPolicyForcedConfig.end();
+}
+
 static inline bool maybeVendorExtension(const std::string& s) {
     // Only checks whether the string starts with the "vendor prefix".
     static const std::string vendorPrefix = "VX_";
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index f5b590b..f51f65e 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -54,6 +54,7 @@
         "AidlConversionXsdc.cpp",
         "AudioPolicyConfigXmlConverter.cpp",
         "Bluetooth.cpp",
+        "CapEngineConfigXmlConverter.cpp",
         "Config.cpp",
         "Configuration.cpp",
         "EngineConfigXmlConverter.cpp",
@@ -83,14 +84,17 @@
         "usb/UsbAlsaMixerControl.cpp",
     ],
     generated_sources: [
+        "audio_policy_capengine_configuration_aidl_default",
         "audio_policy_configuration_aidl_default",
         "audio_policy_engine_configuration_aidl_default",
     ],
     generated_headers: [
+        "audio_policy_capengine_configuration_aidl_default",
         "audio_policy_configuration_aidl_default",
         "audio_policy_engine_configuration_aidl_default",
     ],
     export_generated_headers: [
+        "audio_policy_capengine_configuration_aidl_default",
         "audio_policy_configuration_aidl_default",
         "audio_policy_engine_configuration_aidl_default",
     ],
diff --git a/audio/aidl/default/CapEngineConfigXmlConverter.cpp b/audio/aidl/default/CapEngineConfigXmlConverter.cpp
new file mode 100644
index 0000000..8210664
--- /dev/null
+++ b/audio/aidl/default/CapEngineConfigXmlConverter.cpp
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHAL_Config"
+
+#include <aidl/android/media/audio/common/AudioProductStrategyType.h>
+#include <android-base/logging.h>
+#include <media/AidlConversionCppNdk.h>
+#include <media/TypeConverter.h>
+#include <media/convert.h>
+#include <utils/FastStrcmp.h>
+
+#include "core-impl/CapEngineConfigXmlConverter.h"
+#include "core-impl/XsdcConversion.h"
+
+using aidl::android::hardware::audio::common::iequals;
+using aidl::android::media::audio::common::AudioDeviceAddress;
+using aidl::android::media::audio::common::AudioDeviceDescription;
+using aidl::android::media::audio::common::AudioHalCapConfiguration;
+using aidl::android::media::audio::common::AudioHalCapCriterionV2;
+using aidl::android::media::audio::common::AudioHalCapDomain;
+using aidl::android::media::audio::common::AudioHalCapParameter;
+using aidl::android::media::audio::common::AudioHalCapRule;
+using aidl::android::media::audio::common::AudioPolicyForceUse;
+using aidl::android::media::audio::common::AudioSource;
+using aidl::android::media::audio::common::AudioStreamType;
+
+using ::android::BAD_VALUE;
+using ::android::base::unexpected;
+using ::android::utilities::convertTo;
+
+namespace eng_xsd = android::audio::policy::capengine::configuration;
+
+namespace aidl::android::hardware::audio::core::internal {
+
+static constexpr const char* gStrategiesParameter = "product_strategies";
+static constexpr const char* gInputSourcesParameter = "input_sources";
+static constexpr const char* gStreamsParameter = "streams";
+static constexpr const char* gOutputDevicesParameter = "selected_output_devices";
+static constexpr const char* gOutputDeviceAddressParameter = "device_address";
+static constexpr const char* gStrategyPrefix = "vx_";
+static constexpr const char* gLegacyOutputDevicePrefix = "AUDIO_DEVICE_OUT_";
+static constexpr const char* gLegacyInputDevicePrefix = "AUDIO_DEVICE_IN_";
+static constexpr const char* gLegacyStreamPrefix = "AUDIO_STREAM_";
+static constexpr const char* gLegacySourcePrefix = "AUDIO_SOURCE_";
+
+std::optional<std::vector<std::optional<AudioHalCapDomain>>>&
+CapEngineConfigXmlConverter::getAidlCapEngineConfig() {
+    return mAidlCapDomains;
+}
+
+ConversionResult<AudioHalCapRule::CriterionRule> convertCriterionRuleToAidl(
+        const eng_xsd::SelectionCriterionRuleType& xsdcRule) {
+    using Tag = AudioHalCapCriterionV2::Tag;
+    AudioHalCapRule::CriterionRule rule{};
+    std::string criterionName = xsdcRule.getSelectionCriterion();
+    std::string criterionValue = xsdcRule.getValue();
+    if (iequals(criterionName, toString(Tag::availableInputDevices))) {
+        rule.criterion = AudioHalCapCriterionV2::make<Tag::availableInputDevices>();
+        rule.criterionTypeValue =
+                VALUE_OR_RETURN(convertDeviceTypeToAidl(gLegacyInputDevicePrefix + criterionValue));
+    } else if (iequals(criterionName, toString(Tag::availableOutputDevices))) {
+        rule.criterion = AudioHalCapCriterionV2::make<Tag::availableOutputDevices>();
+        rule.criterionTypeValue = VALUE_OR_RETURN(
+                convertDeviceTypeToAidl(gLegacyOutputDevicePrefix + criterionValue));
+    } else if (iequals(criterionName, toString(Tag::availableInputDevicesAddresses))) {
+        rule.criterion = AudioHalCapCriterionV2::make<Tag::availableInputDevicesAddresses>();
+        rule.criterionTypeValue =
+                AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(criterionValue);
+    } else if (iequals(criterionName, toString(Tag::availableOutputDevicesAddresses))) {
+        rule.criterion = AudioHalCapCriterionV2::make<Tag::availableOutputDevicesAddresses>();
+        rule.criterionTypeValue =
+                AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(criterionValue);
+    } else if (iequals(criterionName, toString(Tag::telephonyMode))) {
+        rule.criterion = AudioHalCapCriterionV2::make<Tag::telephonyMode>();
+        rule.criterionTypeValue = VALUE_OR_RETURN(convertTelephonyModeToAidl(criterionValue));
+    } else if (!fastcmp<strncmp>(criterionName.c_str(), kXsdcForceConfigForUse,
+            strlen(kXsdcForceConfigForUse))) {
+        rule.criterion = AudioHalCapCriterionV2::make<Tag::forceConfigForUse>(
+                VALUE_OR_RETURN(convertForceUseCriterionToAidl(criterionName)));
+        rule.criterionTypeValue = VALUE_OR_RETURN(convertForcedConfigToAidl(criterionValue));
+    } else {
+        LOG(ERROR) << __func__ << " unrecognized criterion " << criterionName;
+        return unexpected(BAD_VALUE);
+    }
+    if (xsdcRule.getMatchesWhen() == eng_xsd::MatchesWhenEnum::Excludes) {
+        rule.matchingRule = AudioHalCapRule::MatchingRule::EXCLUDES;
+    } else if (xsdcRule.getMatchesWhen() == eng_xsd::MatchesWhenEnum::Includes) {
+        rule.matchingRule = AudioHalCapRule::MatchingRule::INCLUDES;
+    } else if (xsdcRule.getMatchesWhen() == eng_xsd::MatchesWhenEnum::Is) {
+        rule.matchingRule = AudioHalCapRule::MatchingRule::IS;
+    } else if (xsdcRule.getMatchesWhen() == eng_xsd::MatchesWhenEnum::IsNot) {
+        rule.matchingRule = AudioHalCapRule::MatchingRule::IS_NOT;
+    } else {
+        LOG(ERROR) << "Unsupported match when rule.";
+        return unexpected(BAD_VALUE);
+    }
+    return rule;
+}
+
+ConversionResult<AudioHalCapRule> convertRule(const eng_xsd::CompoundRuleType& xsdcCompoundRule) {
+    AudioHalCapRule rule{};
+    bool isPreviousCompoundRule = true;
+    if (xsdcCompoundRule.getType() == eng_xsd::TypeEnum::Any) {
+        rule.compoundRule = AudioHalCapRule::CompoundRule::ANY;
+    } else if (xsdcCompoundRule.getType() == eng_xsd::TypeEnum::All) {
+        rule.compoundRule = AudioHalCapRule::CompoundRule::ALL;
+    } else {
+        LOG(ERROR) << "Unsupported compound rule type.";
+        return unexpected(BAD_VALUE);
+    }
+    for (const auto& childXsdcCoumpoundRule : xsdcCompoundRule.getCompoundRule_optional()) {
+        if (childXsdcCoumpoundRule.hasCompoundRule_optional()) {
+            rule.nestedRules.push_back(VALUE_OR_FATAL(convertRule(childXsdcCoumpoundRule)));
+        } else if (childXsdcCoumpoundRule.hasSelectionCriterionRule_optional()) {
+            rule.nestedRules.push_back(VALUE_OR_FATAL(convertRule(childXsdcCoumpoundRule)));
+        }
+    }
+    if (xsdcCompoundRule.hasSelectionCriterionRule_optional()) {
+        for (const auto& xsdcRule : xsdcCompoundRule.getSelectionCriterionRule_optional()) {
+            rule.criterionRules.push_back(VALUE_OR_FATAL(convertCriterionRuleToAidl(xsdcRule)));
+        }
+    }
+    return rule;
+}
+
+ConversionResult<int> getAudioProductStrategyId(const std::string& path) {
+    std::vector<std::string> strings;
+    std::istringstream pathStream(path);
+    std::string stringToken;
+    while (getline(pathStream, stringToken, '/')) {
+        std::size_t pos = stringToken.find(gStrategyPrefix);
+        if (pos != std::string::npos) {
+            std::string strategyIdLiteral = stringToken.substr(pos + std::strlen(gStrategyPrefix));
+            int strategyId;
+            if (!convertTo(strategyIdLiteral, strategyId)) {
+                LOG(ERROR) << "Invalid strategy " << stringToken << " from path " << path;
+                return unexpected(BAD_VALUE);
+            }
+            return strategyId;
+        }
+    }
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<AudioSource> getAudioSource(const std::string& path) {
+    std::vector<std::string> strings;
+    std::istringstream pathStream(path);
+    std::string stringToken;
+    while (getline(pathStream, stringToken, '/')) {
+        if (stringToken.find(gInputSourcesParameter) != std::string::npos) {
+            getline(pathStream, stringToken, '/');
+            std::transform(stringToken.begin(), stringToken.end(), stringToken.begin(),
+                           [](char c) { return std::toupper(c); });
+            std::string legacySourceLiteral = "AUDIO_SOURCE_" + stringToken;
+            audio_source_t legacySource;
+            if (!::android::SourceTypeConverter::fromString(legacySourceLiteral, legacySource)) {
+                LOG(ERROR) << "Invalid source " << stringToken << " from path " << path;
+                return unexpected(BAD_VALUE);
+            }
+            return legacy2aidl_audio_source_t_AudioSource(legacySource);
+        }
+    }
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<AudioStreamType> getAudioStreamType(const std::string& path) {
+    std::vector<std::string> strings;
+    std::istringstream pathStream(path);
+    std::string stringToken;
+
+    while (getline(pathStream, stringToken, '/')) {
+        if (stringToken.find(gStreamsParameter) != std::string::npos) {
+            getline(pathStream, stringToken, '/');
+            std::transform(stringToken.begin(), stringToken.end(), stringToken.begin(),
+                           [](char c) { return std::toupper(c); });
+            std::string legacyStreamLiteral = std::string(gLegacyStreamPrefix) + stringToken;
+            audio_stream_type_t legacyStream;
+            if (!::android::StreamTypeConverter::fromString(legacyStreamLiteral, legacyStream)) {
+                LOG(ERROR) << "Invalid stream " << stringToken << " from path " << path;
+                return unexpected(BAD_VALUE);
+            }
+            return legacy2aidl_audio_stream_type_t_AudioStreamType(legacyStream);
+        }
+    }
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<std::string> toUpperAndAppendPrefix(const std::string& capName,
+                                                     const std::string& legacyPrefix) {
+    std::string legacyName = capName;
+    std::transform(legacyName.begin(), legacyName.end(), legacyName.begin(),
+                   [](char c) { return std::toupper(c); });
+    return legacyPrefix + legacyName;
+}
+
+ConversionResult<AudioHalCapParameter> CapEngineConfigXmlConverter::convertParamToAidl(
+        const eng_xsd::ConfigurableElementSettingsType& element) {
+    const auto& path = element.getPath();
+
+    AudioHalCapParameter parameterSetting;
+    if (path.find(gStrategiesParameter) != std::string::npos) {
+        int strategyId = VALUE_OR_FATAL(getAudioProductStrategyId(path));
+        if (path.find(gOutputDevicesParameter) != std::string::npos) {
+            // Value is 1 or 0
+            if (!element.hasBitParameter_optional()) {
+                LOG(ERROR) << "Invalid strategy value type";
+                return unexpected(BAD_VALUE);
+            }
+            // Convert name to output device type
+            const auto* xsdcParam = element.getFirstBitParameter_optional();
+            std::string outputDevice = VALUE_OR_FATAL(toUpperAndAppendPrefix(
+                    eng_xsd::toString(xsdcParam->getName()), gLegacyOutputDevicePrefix));
+            audio_devices_t legacyType;
+            if (!::android::OutputDeviceConverter::fromString(outputDevice, legacyType)) {
+                LOG(ERROR) << "Invalid strategy device type " << outputDevice;
+                return unexpected(BAD_VALUE);
+            }
+            AudioDeviceDescription aidlDevice =
+                    VALUE_OR_FATAL(legacy2aidl_audio_devices_t_AudioDeviceDescription(legacyType));
+            bool isSelected;
+            if (!convertTo(xsdcParam->getValue(), isSelected)) {
+                LOG(ERROR) << "Invalid strategy device selection value " << xsdcParam->getValue();
+                return unexpected(BAD_VALUE);
+            }
+            parameterSetting =
+                    AudioHalCapParameter::StrategyDevice(aidlDevice, strategyId, isSelected);
+        } else if (path.find(gOutputDeviceAddressParameter) != std::string::npos) {
+            // Value is the address
+            if (!element.hasStringParameter_optional()) {
+                return unexpected(BAD_VALUE);
+            }
+            std::string address = element.getFirstStringParameter_optional()->getValue();
+            parameterSetting = AudioHalCapParameter::StrategyDeviceAddress(
+                    AudioDeviceAddress(address), strategyId);
+        }
+    } else if (path.find(gInputSourcesParameter) != std::string::npos) {
+        // Value is 1 or 0
+        if (!element.hasBitParameter_optional()) {
+            LOG(ERROR) << "Invalid source value type";
+            return unexpected(BAD_VALUE);
+        }
+        AudioSource audioSourceAidl = VALUE_OR_FATAL(getAudioSource(path));
+        const auto* xsdcParam = element.getFirstBitParameter_optional();
+        std::string inputDeviceLiteral = VALUE_OR_FATAL(toUpperAndAppendPrefix(
+                eng_xsd::toString(xsdcParam->getName()), gLegacyInputDevicePrefix));
+        audio_devices_t inputDeviceType;
+        if (!::android::InputDeviceConverter::fromString(inputDeviceLiteral, inputDeviceType)) {
+            LOG(ERROR) << "Invalid source device type " << inputDeviceLiteral;
+            return unexpected(BAD_VALUE);
+        }
+        AudioDeviceDescription aidlDevice =
+                VALUE_OR_FATAL(legacy2aidl_audio_devices_t_AudioDeviceDescription(inputDeviceType));
+
+        bool isSelected;
+        if (!convertTo(xsdcParam->getValue(), isSelected)) {
+            LOG(ERROR) << "Invalid source value type " << xsdcParam->getValue();
+            return unexpected(BAD_VALUE);
+        }
+        parameterSetting =
+                AudioHalCapParameter::InputSourceDevice(aidlDevice, audioSourceAidl, isSelected);
+    } else if (path.find(gStreamsParameter) != std::string::npos) {
+        AudioStreamType audioStreamAidl = VALUE_OR_FATAL(getAudioStreamType(path));
+        if (!element.hasEnumParameter_optional()) {
+            LOG(ERROR) << "Invalid stream value type";
+            return unexpected(BAD_VALUE);
+        }
+        const auto* xsdcParam = element.getFirstEnumParameter_optional();
+        std::string profileLiteral =
+                VALUE_OR_FATAL(toUpperAndAppendPrefix(xsdcParam->getValue(), gLegacyStreamPrefix));
+        audio_stream_type_t profileLegacyStream;
+        if (!::android::StreamTypeConverter::fromString(profileLiteral, profileLegacyStream)) {
+            LOG(ERROR) << "Invalid stream value " << profileLiteral;
+            return unexpected(BAD_VALUE);
+        }
+        AudioStreamType profileStreamAidl = VALUE_OR_FATAL(
+                legacy2aidl_audio_stream_type_t_AudioStreamType(profileLegacyStream));
+        parameterSetting =
+                AudioHalCapParameter::StreamVolumeProfile(audioStreamAidl, profileStreamAidl);
+    }
+    return parameterSetting;
+}
+
+ConversionResult<std::vector<AudioHalCapParameter>>
+CapEngineConfigXmlConverter::convertSettingToAidl(
+        const eng_xsd::SettingsType::Configuration& xsdcSetting) {
+    std::vector<AudioHalCapParameter> aidlCapParameterSettings;
+    for (const auto& element : xsdcSetting.getConfigurableElement()) {
+        aidlCapParameterSettings.push_back(VALUE_OR_FATAL(convertParamToAidl(element)));
+    }
+    return aidlCapParameterSettings;
+}
+
+ConversionResult<AudioHalCapConfiguration> CapEngineConfigXmlConverter::convertConfigurationToAidl(
+        const eng_xsd::ConfigurationsType::Configuration& xsdcConfiguration,
+        const eng_xsd::SettingsType::Configuration& xsdcSettingConfiguration) {
+    AudioHalCapConfiguration aidlCapConfiguration;
+    aidlCapConfiguration.name = xsdcConfiguration.getName();
+    if (xsdcConfiguration.hasCompoundRule()) {
+        if (xsdcConfiguration.getCompoundRule().size() != 1) {
+            return unexpected(BAD_VALUE);
+        }
+        aidlCapConfiguration.rule =
+                VALUE_OR_FATAL(convertRule(xsdcConfiguration.getCompoundRule()[0]));
+        aidlCapConfiguration.parameterSettings =
+                VALUE_OR_FATAL(convertSettingToAidl(xsdcSettingConfiguration));
+    }
+    return aidlCapConfiguration;
+}
+
+ConversionResult<eng_xsd::SettingsType::Configuration> getConfigurationByName(
+        const std::string& name, const std::vector<eng_xsd::SettingsType>& xsdcSettingsVec) {
+    for (const auto& xsdcSettings : xsdcSettingsVec) {
+        for (const auto& xsdcConfiguration : xsdcSettings.getConfiguration()) {
+            if (xsdcConfiguration.getName() == name) {
+                return xsdcConfiguration;
+            }
+        }
+    }
+    LOG(ERROR) << __func__ << " failed to find configuration " << name;
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<std::vector<AudioHalCapConfiguration>>
+CapEngineConfigXmlConverter::convertConfigurationsToAidl(
+        const std::vector<eng_xsd::ConfigurationsType>& xsdcConfigurationsVec,
+        const std::vector<eng_xsd::SettingsType>& xsdcSettingsVec) {
+    if (xsdcConfigurationsVec.empty() || xsdcSettingsVec.empty()) {
+        LOG(ERROR) << __func__ << " empty configurations/settings";
+        return unexpected(BAD_VALUE);
+    }
+    std::vector<AudioHalCapConfiguration> aidlConfigurations;
+    for (const auto& xsdcConfigurations : xsdcConfigurationsVec) {
+        for (const auto& xsdcConfiguration : xsdcConfigurations.getConfiguration()) {
+            auto xsdcSettingConfiguration = VALUE_OR_FATAL(
+                    getConfigurationByName(xsdcConfiguration.getName(), xsdcSettingsVec));
+            aidlConfigurations.push_back(VALUE_OR_FATAL(
+                    convertConfigurationToAidl(xsdcConfiguration, xsdcSettingConfiguration)));
+        }
+    }
+    return aidlConfigurations;
+}
+
+ConversionResult<AudioHalCapDomain> CapEngineConfigXmlConverter::convertConfigurableDomainToAidl(
+        const eng_xsd::ConfigurableDomainType& xsdcConfigurableDomain) {
+    AudioHalCapDomain aidlConfigurableDomain;
+
+    aidlConfigurableDomain.name = xsdcConfigurableDomain.getName();
+    if (xsdcConfigurableDomain.hasSequenceAware() && xsdcConfigurableDomain.getSequenceAware()) {
+        LOG(ERROR) << "sequence aware not supported.";
+        return unexpected(BAD_VALUE);
+    }
+    if (xsdcConfigurableDomain.hasConfigurations() && xsdcConfigurableDomain.hasSettings()) {
+        aidlConfigurableDomain.configurations = VALUE_OR_FATAL(convertConfigurationsToAidl(
+                xsdcConfigurableDomain.getConfigurations(), xsdcConfigurableDomain.getSettings()));
+    }
+    return aidlConfigurableDomain;
+}
+
+void CapEngineConfigXmlConverter::init() {
+    if (getXsdcConfig()->hasConfigurableDomain()) {
+        mAidlCapDomains = std::make_optional<>(VALUE_OR_FATAL(
+                (convertCollectionToAidlOptionalValues<eng_xsd::ConfigurableDomainType,
+                                                       AudioHalCapDomain>(
+                        getXsdcConfig()->getConfigurableDomain(),
+                        std::bind(&CapEngineConfigXmlConverter::convertConfigurableDomainToAidl,
+                                  this, std::placeholders::_1)))));
+    } else {
+        mAidlCapDomains = std::nullopt;
+    }
+}
+
+}  // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/EngineConfigXmlConverter.cpp b/audio/aidl/default/EngineConfigXmlConverter.cpp
index 631cdce..5a8b0a3 100644
--- a/audio/aidl/default/EngineConfigXmlConverter.cpp
+++ b/audio/aidl/default/EngineConfigXmlConverter.cpp
@@ -26,15 +26,19 @@
 #include <aidl/android/media/audio/common/AudioProductStrategyType.h>
 #include <android-base/logging.h>
 
+#include "core-impl/CapEngineConfigXmlConverter.h"
 #include "core-impl/EngineConfigXmlConverter.h"
 #include "core-impl/XsdcConversion.h"
 
+using aidl::android::hardware::audio::core::internal::CapEngineConfigXmlConverter;
+using aidl::android::hardware::audio::core::internal::convertAudioUsageToAidl;
 using aidl::android::media::audio::common::AudioAttributes;
 using aidl::android::media::audio::common::AudioContentType;
 using aidl::android::media::audio::common::AudioFlag;
 using aidl::android::media::audio::common::AudioHalAttributesGroup;
 using aidl::android::media::audio::common::AudioHalCapCriterion;
 using aidl::android::media::audio::common::AudioHalCapCriterionType;
+using aidl::android::media::audio::common::AudioHalCapCriterionV2;
 using aidl::android::media::audio::common::AudioHalEngineConfig;
 using aidl::android::media::audio::common::AudioHalProductStrategy;
 using aidl::android::media::audio::common::AudioHalVolumeCurve;
@@ -43,6 +47,7 @@
 using aidl::android::media::audio::common::AudioSource;
 using aidl::android::media::audio::common::AudioStreamType;
 using aidl::android::media::audio::common::AudioUsage;
+
 using ::android::BAD_VALUE;
 using ::android::base::unexpected;
 
@@ -50,6 +55,10 @@
 
 namespace aidl::android::hardware::audio::core::internal {
 
+/** Default path of audio policy cap engine configuration file. */
+static constexpr char kCapEngineConfigFileName[] =
+        "/parameter-framework/Settings/Policy/PolicyConfigurableDomains.xml";
+
 void EngineConfigXmlConverter::initProductStrategyMap() {
 #define STRATEGY_ENTRY(name) {"STRATEGY_" #name, static_cast<int>(AudioProductStrategyType::name)}
 
@@ -74,6 +83,13 @@
     return it->second;
 }
 
+ConversionResult<int> EngineConfigXmlConverter::convertProductStrategyIdToAidl(int xsdcId) {
+    if (xsdcId < AudioHalProductStrategy::VENDOR_STRATEGY_ID_START) {
+        return unexpected(BAD_VALUE);
+    }
+    return xsdcId;
+}
+
 bool isDefaultAudioAttributes(const AudioAttributes& attributes) {
     return ((attributes.contentType == AudioContentType::UNKNOWN) &&
             (attributes.usage == AudioUsage::UNKNOWN) &&
@@ -95,29 +111,26 @@
     }
     AudioAttributes aidlAudioAttributes;
     if (xsdcAudioAttributes.hasContentType()) {
-        aidlAudioAttributes.contentType = static_cast<AudioContentType>(
-                xsdcAudioAttributes.getFirstContentType()->getValue());
+        aidlAudioAttributes.contentType = VALUE_OR_FATAL(convertAudioContentTypeToAidl(
+                xsdcAudioAttributes.getFirstContentType()->getValue()));
     }
     if (xsdcAudioAttributes.hasUsage()) {
-        aidlAudioAttributes.usage =
-                static_cast<AudioUsage>(xsdcAudioAttributes.getFirstUsage()->getValue());
+        aidlAudioAttributes.usage = VALUE_OR_FATAL(
+                convertAudioUsageToAidl(xsdcAudioAttributes.getFirstUsage()->getValue()));
     }
     if (xsdcAudioAttributes.hasSource()) {
-        aidlAudioAttributes.source =
-                static_cast<AudioSource>(xsdcAudioAttributes.getFirstSource()->getValue());
+        aidlAudioAttributes.source = VALUE_OR_FATAL(
+                convertAudioSourceToAidl(xsdcAudioAttributes.getFirstSource()->getValue()));
     }
     if (xsdcAudioAttributes.hasFlags()) {
         std::vector<eng_xsd::FlagType> xsdcFlagTypeVec =
                 xsdcAudioAttributes.getFirstFlags()->getValue();
-        for (const eng_xsd::FlagType& xsdcFlagType : xsdcFlagTypeVec) {
-            if (xsdcFlagType != eng_xsd::FlagType::AUDIO_FLAG_NONE) {
-                aidlAudioAttributes.flags |= 1 << (static_cast<int>(xsdcFlagType) - 1);
-            }
-        }
+        aidlAudioAttributes.flags = VALUE_OR_FATAL(convertAudioFlagsToAidl(xsdcFlagTypeVec));
     }
     if (xsdcAudioAttributes.hasBundle()) {
         const eng_xsd::BundleType* xsdcBundle = xsdcAudioAttributes.getFirstBundle();
-        aidlAudioAttributes.tags[0] = xsdcBundle->getKey() + "=" + xsdcBundle->getValue();
+        aidlAudioAttributes.tags.reserve(1);
+        aidlAudioAttributes.tags.push_back(xsdcBundle->getKey() + "_" + xsdcBundle->getValue());
     }
     if (isDefaultAudioAttributes(aidlAudioAttributes)) {
         mDefaultProductStrategyId = std::optional<int>{-1};
@@ -131,8 +144,10 @@
     static const int kStreamTypeEnumOffset =
             static_cast<int>(eng_xsd::Stream::AUDIO_STREAM_VOICE_CALL) -
             static_cast<int>(AudioStreamType::VOICE_CALL);
-    aidlAttributesGroup.streamType = static_cast<AudioStreamType>(
-            static_cast<int>(xsdcAttributesGroup.getStreamType()) - kStreamTypeEnumOffset);
+    aidlAttributesGroup.streamType = xsdcAttributesGroup.hasStreamType()
+                                             ? VALUE_OR_FATAL(convertAudioStreamTypeToAidl(
+                                                       xsdcAttributesGroup.getStreamType()))
+                                             : AudioStreamType::INVALID;
     aidlAttributesGroup.volumeGroupName = xsdcAttributesGroup.getVolumeGroup();
     if (xsdcAttributesGroup.hasAttributes_optional()) {
         aidlAttributesGroup.attributes =
@@ -165,7 +180,8 @@
     AudioHalProductStrategy aidlProductStrategy;
 
     aidlProductStrategy.id =
-            VALUE_OR_FATAL(convertProductStrategyNameToAidl(xsdcProductStrategy.getName()));
+            VALUE_OR_FATAL(convertProductStrategyIdToAidl(xsdcProductStrategy.getId()));
+    aidlProductStrategy.name = xsdcProductStrategy.getName();
 
     if (xsdcProductStrategy.hasAttributesGroup()) {
         aidlProductStrategy.attributesGroups = VALUE_OR_FATAL(
@@ -247,18 +263,15 @@
     }
     if (getXsdcConfig()->hasCriteria() && getXsdcConfig()->hasCriterion_types()) {
         AudioHalEngineConfig::CapSpecificConfig capSpecificConfig;
-        capSpecificConfig.criteria = VALUE_OR_FATAL(
-                (convertWrappedCollectionToAidl<eng_xsd::CriteriaType, eng_xsd::CriterionType,
-                                                AudioHalCapCriterion>(
-                        getXsdcConfig()->getCriteria(), &eng_xsd::CriteriaType::getCriterion,
-                        &convertCapCriterionToAidl)));
-        capSpecificConfig.criterionTypes =
-                VALUE_OR_FATAL((convertWrappedCollectionToAidl<eng_xsd::CriterionTypesType,
-                                                               eng_xsd::CriterionTypeType,
-                                                               AudioHalCapCriterionType>(
-                        getXsdcConfig()->getCriterion_types(),
-                        &eng_xsd::CriterionTypesType::getCriterion_type,
-                        &convertCapCriterionTypeToAidl)));
+        capSpecificConfig.criteriaV2 =
+                std::make_optional<>(VALUE_OR_FATAL((convertCapCriteriaCollectionToAidl(
+                        getXsdcConfig()->getCriteria(), getXsdcConfig()->getCriterion_types()))));
+        internal::CapEngineConfigXmlConverter capEngConfigConverter{
+                ::android::audio_find_readable_configuration_file(kCapEngineConfigFileName)};
+        if (capEngConfigConverter.getStatus() == ::android::OK) {
+            capSpecificConfig.domains = std::move(capEngConfigConverter.getAidlCapEngineConfig());
+        }
+        mAidlEngineConfig.capSpecificConfig = capSpecificConfig;
     }
 }
 }  // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index 389860f..eecc972 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -663,10 +663,14 @@
 }
 
 StreamCommonImpl::~StreamCommonImpl() {
-    if (!isClosed()) {
-        LOG(ERROR) << __func__ << ": stream was not closed prior to destruction, resource leak";
-        stopWorker();
-        // The worker and the context should clean up by themselves via destructors.
+    // It is responsibility of the class that implements 'DriverInterface' to call 'cleanupWorker'
+    // in the destructor. Note that 'cleanupWorker' can not be properly called from this destructor
+    // because any subclasses have already been destroyed and thus the 'DriverInterface'
+    // implementation is not valid. Thus, here it can only be asserted whether the subclass has done
+    // its job.
+    if (!mWorkerStopIssued && !isClosed()) {
+        LOG(FATAL) << __func__ << ": the stream implementation must call 'cleanupWorker' "
+                   << "in order to clean up the worker thread.";
     }
 }
 
@@ -770,10 +774,7 @@
 ndk::ScopedAStatus StreamCommonImpl::close() {
     LOG(DEBUG) << __func__;
     if (!isClosed()) {
-        stopWorker();
-        LOG(DEBUG) << __func__ << ": joining the worker thread...";
-        mWorker->join();
-        LOG(DEBUG) << __func__ << ": worker thread joined";
+        stopAndJoinWorker();
         onClose(mWorker->setClosed());
         return ndk::ScopedAStatus::ok();
     } else {
@@ -791,6 +792,20 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
 }
 
+void StreamCommonImpl::cleanupWorker() {
+    if (!isClosed()) {
+        LOG(ERROR) << __func__ << ": stream was not closed prior to destruction, resource leak";
+        stopAndJoinWorker();
+    }
+}
+
+void StreamCommonImpl::stopAndJoinWorker() {
+    stopWorker();
+    LOG(DEBUG) << __func__ << ": joining the worker thread...";
+    mWorker->join();
+    LOG(DEBUG) << __func__ << ": worker thread joined";
+}
+
 void StreamCommonImpl::stopWorker() {
     if (auto commandMQ = mContext.getCommandMQ(); commandMQ != nullptr) {
         LOG(DEBUG) << __func__ << ": asking the worker to exit...";
@@ -805,6 +820,7 @@
         }
         LOG(DEBUG) << __func__ << ": done";
     }
+    mWorkerStopIssued = true;
 }
 
 ndk::ScopedAStatus StreamCommonImpl::updateMetadataCommon(const Metadata& metadata) {
diff --git a/audio/aidl/default/XsdcConversion.cpp b/audio/aidl/default/XsdcConversion.cpp
index 1720949..ba6110d 100644
--- a/audio/aidl/default/XsdcConversion.cpp
+++ b/audio/aidl/default/XsdcConversion.cpp
@@ -10,11 +10,21 @@
 #include <aidl/android/media/audio/common/AudioPortConfig.h>
 #include <media/AidlConversionCppNdk.h>
 #include <media/TypeConverter.h>
+#include <media/convert.h>
+#include <utils/FastStrcmp.h>
+
+#include <Utils.h>
 
 #include "core-impl/XmlConverter.h"
 #include "core-impl/XsdcConversion.h"
 
+using aidl::android::hardware::audio::common::iequals;
+using aidl::android::hardware::audio::common::isValidAudioMode;
+using aidl::android::hardware::audio::common::isValidAudioPolicyForcedConfig;
+using aidl::android::hardware::audio::common::kValidAudioModes;
+using aidl::android::hardware::audio::common::kValidAudioPolicyForcedConfig;
 using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioContentType;
 using aidl::android::media::audio::common::AudioDevice;
 using aidl::android::media::audio::common::AudioDeviceAddress;
 using aidl::android::media::audio::common::AudioDeviceDescription;
@@ -24,22 +34,39 @@
 using aidl::android::media::audio::common::AudioGain;
 using aidl::android::media::audio::common::AudioHalCapCriterion;
 using aidl::android::media::audio::common::AudioHalCapCriterionType;
+using aidl::android::media::audio::common::AudioHalCapCriterionV2;
 using aidl::android::media::audio::common::AudioHalVolumeCurve;
 using aidl::android::media::audio::common::AudioIoFlags;
+using aidl::android::media::audio::common::AudioMode;
+using aidl::android::media::audio::common::AudioPolicyForcedConfig;
+using aidl::android::media::audio::common::AudioPolicyForceUse;
 using aidl::android::media::audio::common::AudioPort;
 using aidl::android::media::audio::common::AudioPortConfig;
 using aidl::android::media::audio::common::AudioPortDeviceExt;
 using aidl::android::media::audio::common::AudioPortExt;
 using aidl::android::media::audio::common::AudioPortMixExt;
 using aidl::android::media::audio::common::AudioProfile;
+using aidl::android::media::audio::common::AudioSource;
+using aidl::android::media::audio::common::AudioStreamType;
+using aidl::android::media::audio::common::AudioUsage;
 using ::android::BAD_VALUE;
 using ::android::base::unexpected;
+using ::android::utilities::convertTo;
 
 namespace ap_xsd = android::audio::policy::configuration;
 namespace eng_xsd = android::audio::policy::engine::configuration;
 
 namespace aidl::android::hardware::audio::core::internal {
 
+static constexpr const char kXsdcForceConfigForCommunication[] = "ForceUseForCommunication";
+static constexpr const char kXsdcForceConfigForMedia[] = "ForceUseForMedia";
+static constexpr const char kXsdcForceConfigForRecord[] = "ForceUseForRecord";
+static constexpr const char kXsdcForceConfigForDock[] = "ForceUseForDock";
+static constexpr const char kXsdcForceConfigForSystem[] = "ForceUseForSystem";
+static constexpr const char kXsdcForceConfigForHdmiSystemAudio[] = "ForceUseForHdmiSystemAudio";
+static constexpr const char kXsdcForceConfigForEncodedSurround[] = "ForceUseForEncodedSurround";
+static constexpr const char kXsdcForceConfigForVibrateRinging[] = "ForceUseForVibrateRinging";
+
 inline ConversionResult<std::string> assertNonEmpty(const std::string& s) {
     if (s.empty()) {
         LOG(ERROR) << __func__ << " Review Audio Policy config: "
@@ -51,6 +78,100 @@
 
 #define NON_EMPTY_STRING_OR_FATAL(s) VALUE_OR_FATAL(assertNonEmpty(s))
 
+ConversionResult<int32_t> convertAudioFlagsToAidl(
+        const std::vector<eng_xsd::FlagType>& xsdcFlagTypeVec) {
+    int legacyFlagMask = 0;
+    for (const eng_xsd::FlagType& xsdcFlagType : xsdcFlagTypeVec) {
+        if (xsdcFlagType != eng_xsd::FlagType::AUDIO_FLAG_NONE) {
+            audio_flags_mask_t legacyFlag = AUDIO_FLAG_NONE;
+            if (!::android::AudioFlagConverter::fromString(eng_xsd::toString(xsdcFlagType),
+                                                           legacyFlag)) {
+                LOG(ERROR) << __func__ << " Review Audio Policy config, "
+                           << eng_xsd::toString(xsdcFlagType) << " is not a valid flag.";
+                return unexpected(BAD_VALUE);
+            }
+            legacyFlagMask |= static_cast<int>(legacyFlag);
+        }
+    }
+    ConversionResult<int32_t> result = legacy2aidl_audio_flags_mask_t_int32_t_mask(
+            static_cast<audio_flags_mask_t>(legacyFlagMask));
+    if (!result.ok()) {
+        LOG(ERROR) << __func__ << " Review Audio Policy config, " << legacyFlagMask
+                   << " has invalid flag(s).";
+        return unexpected(BAD_VALUE);
+    }
+    return result;
+}
+
+ConversionResult<AudioStreamType> convertAudioStreamTypeToAidl(const eng_xsd::Stream& xsdcStream) {
+    audio_stream_type_t legacyStreamType;
+    if (!::android::StreamTypeConverter::fromString(eng_xsd::toString(xsdcStream),
+                                                    legacyStreamType)) {
+        LOG(ERROR) << __func__ << " Review Audio Policy config, " << eng_xsd::toString(xsdcStream)
+                   << " is not a valid audio stream type.";
+        return unexpected(BAD_VALUE);
+    }
+    ConversionResult<AudioStreamType> result =
+            legacy2aidl_audio_stream_type_t_AudioStreamType(legacyStreamType);
+    if (!result.ok()) {
+        LOG(ERROR) << __func__ << " Review Audio Policy config, " << legacyStreamType
+                   << " is not a valid audio stream type.";
+        return unexpected(BAD_VALUE);
+    }
+    return result;
+}
+
+ConversionResult<AudioSource> convertAudioSourceToAidl(
+        const eng_xsd::SourceEnumType& xsdcSourceType) {
+    audio_source_t legacySourceType;
+    if (!::android::SourceTypeConverter::fromString(eng_xsd::toString(xsdcSourceType),
+                                                    legacySourceType)) {
+        LOG(ERROR) << __func__ << " Review Audio Policy config, "
+                   << eng_xsd::toString(xsdcSourceType) << " is not a valid audio source.";
+        return unexpected(BAD_VALUE);
+    }
+    ConversionResult<AudioSource> result = legacy2aidl_audio_source_t_AudioSource(legacySourceType);
+    if (!result.ok()) {
+        LOG(ERROR) << __func__ << " Review Audio Policy config, " << legacySourceType
+                   << " is not a valid audio source.";
+        return unexpected(BAD_VALUE);
+    }
+    return result;
+}
+
+ConversionResult<AudioContentType> convertAudioContentTypeToAidl(
+        const eng_xsd::ContentType& xsdcContentType) {
+    audio_content_type_t legacyContentType;
+    if (!::android::AudioContentTypeConverter::fromString(eng_xsd::toString(xsdcContentType),
+                                                          legacyContentType)) {
+        LOG(ERROR) << __func__ << " Review Audio Policy config, "
+                   << eng_xsd::toString(xsdcContentType) << " is not a valid audio content type.";
+        return unexpected(BAD_VALUE);
+    }
+    ConversionResult<AudioContentType> result =
+            legacy2aidl_audio_content_type_t_AudioContentType(legacyContentType);
+    if (!result.ok()) {
+        LOG(ERROR) << __func__ << " Review Audio Policy config, " << legacyContentType
+                   << " is not a valid audio content type.";
+        return unexpected(BAD_VALUE);
+    }
+    return result;
+}
+
+ConversionResult<AudioUsage> convertAudioUsageToAidl(const eng_xsd::UsageEnumType& xsdcUsage) {
+    audio_usage_t legacyUsage;
+    if (!::android::UsageTypeConverter::fromString(eng_xsd::toString(xsdcUsage), legacyUsage)) {
+        LOG(ERROR) << __func__ << " Review Audio Policy config, not a valid audio usage.";
+        return unexpected(BAD_VALUE);
+    }
+    ConversionResult<AudioUsage> result = legacy2aidl_audio_usage_t_AudioUsage(legacyUsage);
+    if (!result.ok()) {
+        LOG(ERROR) << __func__ << " Review Audio Policy config, not a valid audio usage.";
+        return unexpected(BAD_VALUE);
+    }
+    return result;
+}
+
 ConversionResult<AudioFormatDescription> convertAudioFormatToAidl(const std::string& xsdcFormat) {
     audio_format_t legacyFormat = ::android::formatFromString(xsdcFormat, AUDIO_FORMAT_DEFAULT);
     ConversionResult<AudioFormatDescription> result =
@@ -410,32 +531,240 @@
     return result;
 }
 
+ConversionResult<AudioPolicyForcedConfig> convertForcedConfigToAidl(
+        const std::string& xsdcForcedConfigCriterionType) {
+    const auto it = std::find_if(
+            kValidAudioPolicyForcedConfig.begin(), kValidAudioPolicyForcedConfig.end(),
+            [&](const auto& config) { return toString(config) == xsdcForcedConfigCriterionType; });
+    if (it == kValidAudioPolicyForcedConfig.end()) {
+        LOG(ERROR) << __func__ << " invalid forced config " << xsdcForcedConfigCriterionType;
+        return unexpected(BAD_VALUE);
+    }
+    return *it;
+}
+
+ConversionResult<AudioMode> convertTelephonyModeToAidl(const std::string& xsdcModeCriterionType) {
+    const auto it = std::find_if(kValidAudioModes.begin(), kValidAudioModes.end(),
+                                 [&xsdcModeCriterionType](const auto& mode) {
+                                     return toString(mode) == xsdcModeCriterionType;
+                                 });
+    if (it == kValidAudioModes.end()) {
+        LOG(ERROR) << __func__ << " invalid mode " << xsdcModeCriterionType;
+        return unexpected(BAD_VALUE);
+    }
+    return *it;
+}
+
+ConversionResult<AudioDeviceAddress> convertDeviceAddressToAidl(const std::string& xsdcAddress) {
+    return AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(xsdcAddress);
+}
+
+ConversionResult<eng_xsd::CriterionTypeType> getCriterionTypeByName(
+        const std::string& name,
+        const std::vector<eng_xsd::CriterionTypesType>& xsdcCriterionTypesVec) {
+    for (const auto& xsdCriterionTypes : xsdcCriterionTypesVec) {
+        for (const auto& xsdcCriterionType : xsdCriterionTypes.getCriterion_type()) {
+            if (xsdcCriterionType.getName() == name) {
+                return xsdcCriterionType;
+            }
+        }
+    }
+    LOG(ERROR) << __func__ << " failed to find criterion type " << name;
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<std::vector<std::optional<AudioHalCapCriterionV2>>>
+convertCapCriteriaCollectionToAidl(
+        const std::vector<eng_xsd::CriteriaType>& xsdcCriteriaVec,
+        const std::vector<eng_xsd::CriterionTypesType>& xsdcCriterionTypesVec) {
+    std::vector<std::optional<AudioHalCapCriterionV2>> resultAidlCriterionVec;
+    if (xsdcCriteriaVec.empty() || xsdcCriterionTypesVec.empty()) {
+        LOG(ERROR) << __func__ << " empty criteria/criterionTypes";
+        return unexpected(BAD_VALUE);
+    }
+    for (const auto& xsdCriteria : xsdcCriteriaVec) {
+        for (const auto& xsdcCriterion : xsdCriteria.getCriterion()) {
+            resultAidlCriterionVec.push_back(
+                    std::optional<AudioHalCapCriterionV2>(VALUE_OR_FATAL(
+                            convertCapCriterionV2ToAidl(xsdcCriterion, xsdcCriterionTypesVec))));
+        }
+    }
+    return resultAidlCriterionVec;
+}
+
+ConversionResult<std::vector<AudioDeviceDescription>> convertDevicesToAidl(
+        const eng_xsd::CriterionTypeType& xsdcDeviceCriterionType) {
+    if (xsdcDeviceCriterionType.getValues().empty()) {
+        LOG(ERROR) << __func__ << " no values provided";
+        return unexpected(BAD_VALUE);
+    }
+    std::vector<AudioDeviceDescription> aidlDevices;
+    for (eng_xsd::ValuesType xsdcValues : xsdcDeviceCriterionType.getValues()) {
+        aidlDevices.reserve(xsdcValues.getValue().size());
+        for (const eng_xsd::ValueType& xsdcValue : xsdcValues.getValue()) {
+            if (!xsdcValue.hasAndroid_type()) {
+                LOG(ERROR) << __func__ << " empty android type";
+                return unexpected(BAD_VALUE);
+            }
+            uint32_t integerValue;
+            if (!convertTo(xsdcValue.getAndroid_type(), integerValue)) {
+                LOG(ERROR) << __func__ << " failed to convert android type "
+                           << xsdcValue.getAndroid_type();
+                return unexpected(BAD_VALUE);
+            }
+            aidlDevices.push_back(
+                    VALUE_OR_RETURN(legacy2aidl_audio_devices_t_AudioDeviceDescription(
+                            static_cast<audio_devices_t>(integerValue))));
+        }
+    }
+    return aidlDevices;
+}
+
+ConversionResult<std::vector<AudioDeviceAddress>> convertDeviceAddressesToAidl(
+        const eng_xsd::CriterionTypeType& xsdcDeviceAddressesCriterionType) {
+    if (xsdcDeviceAddressesCriterionType.getValues().empty()) {
+        LOG(ERROR) << __func__ << " no values provided";
+        return unexpected(BAD_VALUE);
+    }
+    std::vector<AudioDeviceAddress> aidlDeviceAddresses;
+    for (eng_xsd::ValuesType xsdcValues : xsdcDeviceAddressesCriterionType.getValues()) {
+        aidlDeviceAddresses.reserve(xsdcValues.getValue().size());
+        for (const eng_xsd::ValueType& xsdcValue : xsdcValues.getValue()) {
+            aidlDeviceAddresses.push_back(
+                    AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(xsdcValue.getLiteral()));
+        }
+    }
+    return aidlDeviceAddresses;
+}
+
+ConversionResult<std::vector<AudioMode>> convertTelephonyModesToAidl(
+        const eng_xsd::CriterionTypeType& xsdcTelephonyModeCriterionType) {
+    if (xsdcTelephonyModeCriterionType.getValues().empty()) {
+        LOG(ERROR) << __func__ << " no values provided";
+        return unexpected(BAD_VALUE);
+    }
+    std::vector<AudioMode> aidlAudioModes;
+    for (eng_xsd::ValuesType xsdcValues : xsdcTelephonyModeCriterionType.getValues()) {
+        aidlAudioModes.reserve(xsdcValues.getValue().size());
+        for (const eng_xsd::ValueType& xsdcValue : xsdcValues.getValue()) {
+            int integerValue = xsdcValue.getNumerical();
+            if (!isValidAudioMode(AudioMode(integerValue))) {
+                LOG(ERROR) << __func__ << " invalid audio mode " << integerValue;
+                return unexpected(BAD_VALUE);
+            }
+            aidlAudioModes.push_back(AudioMode(integerValue));
+        }
+    }
+    return aidlAudioModes;
+}
+
+ConversionResult<std::vector<AudioPolicyForcedConfig>> convertForcedConfigsToAidl(
+        const eng_xsd::CriterionTypeType& xsdcForcedConfigCriterionType) {
+    if (xsdcForcedConfigCriterionType.getValues().empty()) {
+        LOG(ERROR) << __func__ << " no values provided";
+        return unexpected(BAD_VALUE);
+    }
+    std::vector<AudioPolicyForcedConfig> aidlForcedConfigs;
+    for (eng_xsd::ValuesType xsdcValues : xsdcForcedConfigCriterionType.getValues()) {
+        aidlForcedConfigs.reserve(xsdcValues.getValue().size());
+        for (const eng_xsd::ValueType& xsdcValue : xsdcValues.getValue()) {
+            int integerValue = xsdcValue.getNumerical();
+            if (!isValidAudioPolicyForcedConfig(AudioPolicyForcedConfig(integerValue))) {
+                LOG(ERROR) << __func__ << " invalid forced config mode " << integerValue;
+                return unexpected(BAD_VALUE);
+            }
+            aidlForcedConfigs.push_back(AudioPolicyForcedConfig(integerValue));
+        }
+    }
+    return aidlForcedConfigs;
+}
+
+ConversionResult<AudioPolicyForceUse> convertForceUseCriterionToAidl(
+        const std::string& xsdcCriterionName) {
+    if (!fastcmp<strncmp>(xsdcCriterionName.c_str(), kXsdcForceConfigForCommunication,
+            strlen(kXsdcForceConfigForCommunication))) {
+        return AudioPolicyForceUse::COMMUNICATION;
+    }
+    if (!fasticmp<strncmp>(xsdcCriterionName.c_str(), kXsdcForceConfigForMedia,
+            strlen(kXsdcForceConfigForMedia))) {
+        return AudioPolicyForceUse::MEDIA;
+    }
+    if (!fasticmp<strncmp>(xsdcCriterionName.c_str(), kXsdcForceConfigForRecord,
+            strlen(kXsdcForceConfigForRecord))) {
+        return AudioPolicyForceUse::RECORD;
+    }
+    if (!fasticmp<strncmp>(xsdcCriterionName.c_str(), kXsdcForceConfigForDock,
+            strlen(kXsdcForceConfigForDock))) {
+        return AudioPolicyForceUse::DOCK;
+    }
+    if (!fasticmp<strncmp>(xsdcCriterionName.c_str(), kXsdcForceConfigForSystem,
+            strlen(kXsdcForceConfigForSystem))) {
+        return AudioPolicyForceUse::SYSTEM;
+    }
+    if (!fasticmp<strncmp>(xsdcCriterionName.c_str(), kXsdcForceConfigForHdmiSystemAudio,
+            strlen(kXsdcForceConfigForHdmiSystemAudio))) {
+        return AudioPolicyForceUse::HDMI_SYSTEM_AUDIO;
+    }
+    if (!fasticmp<strncmp>(xsdcCriterionName.c_str(), kXsdcForceConfigForEncodedSurround,
+            strlen(kXsdcForceConfigForEncodedSurround))) {
+        return AudioPolicyForceUse::ENCODED_SURROUND;
+    }
+    if (!fasticmp<strncmp>(xsdcCriterionName.c_str(), kXsdcForceConfigForVibrateRinging,
+            strlen(kXsdcForceConfigForVibrateRinging))) {
+        return AudioPolicyForceUse::VIBRATE_RINGING;
+    }
+    LOG(ERROR) << __func__ << " unrecognized force use " << xsdcCriterionName;
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<AudioHalCapCriterionV2> convertCapCriterionV2ToAidl(
+        const eng_xsd::CriterionType& xsdcCriterion,
+        const std::vector<eng_xsd::CriterionTypesType>& xsdcCriterionTypesVec) {
+    eng_xsd::CriterionTypeType xsdcCriterionType =
+            VALUE_OR_RETURN(getCriterionTypeByName(xsdcCriterion.getType(), xsdcCriterionTypesVec));
+    std::string defaultLiteralValue =
+            xsdcCriterion.has_default() ? xsdcCriterion.get_default() : "";
+    using Tag = AudioHalCapCriterionV2::Tag;
+    if (iequals(xsdcCriterion.getName(), toString(Tag::availableInputDevices))) {
+        return AudioHalCapCriterionV2::make<Tag::availableInputDevices>(
+                VALUE_OR_RETURN(convertDevicesToAidl(xsdcCriterionType)));
+    }
+    if (iequals(xsdcCriterion.getName(), toString(Tag::availableOutputDevices))) {
+        return AudioHalCapCriterionV2::make<Tag::availableOutputDevices>(
+                VALUE_OR_RETURN(convertDevicesToAidl(xsdcCriterionType)));
+    }
+    if (iequals(xsdcCriterion.getName(), toString(Tag::availableInputDevicesAddresses))) {
+        return AudioHalCapCriterionV2::make<Tag::availableInputDevicesAddresses>(
+                VALUE_OR_RETURN(convertDeviceAddressesToAidl(xsdcCriterionType)));
+    }
+    if (iequals(xsdcCriterion.getName(), toString(Tag::availableOutputDevicesAddresses))) {
+        return AudioHalCapCriterionV2::make<Tag::availableOutputDevicesAddresses>(
+                VALUE_OR_RETURN(convertDeviceAddressesToAidl(xsdcCriterionType)));
+    }
+    if (iequals(xsdcCriterion.getName(), toString(Tag::telephonyMode))) {
+        return AudioHalCapCriterionV2::make<Tag::telephonyMode>(
+                VALUE_OR_RETURN(convertTelephonyModesToAidl(xsdcCriterionType)));
+    }
+    if (!fastcmp<strncmp>(xsdcCriterion.getName().c_str(), kXsdcForceConfigForUse,
+            strlen(kXsdcForceConfigForUse))) {
+        return AudioHalCapCriterionV2::make<Tag::forceConfigForUse>(
+                VALUE_OR_RETURN(convertForceUseCriterionToAidl(xsdcCriterion.getName())),
+                VALUE_OR_RETURN(convertForcedConfigsToAidl(xsdcCriterionType)));
+    }
+    LOG(ERROR) << __func__ << " unrecognized criterion " << xsdcCriterion.getName();
+    return unexpected(BAD_VALUE);
+}
+
 ConversionResult<AudioHalCapCriterion> convertCapCriterionToAidl(
         const eng_xsd::CriterionType& xsdcCriterion) {
     AudioHalCapCriterion aidlCapCriterion;
     aidlCapCriterion.name = xsdcCriterion.getName();
     aidlCapCriterion.criterionTypeName = xsdcCriterion.getType();
-    aidlCapCriterion.defaultLiteralValue = xsdcCriterion.get_default();
+    aidlCapCriterion.defaultLiteralValue =
+            xsdcCriterion.has_default() ? xsdcCriterion.get_default() : "";
     return aidlCapCriterion;
 }
 
-ConversionResult<std::string> convertCriterionTypeValueToAidl(
-        const eng_xsd::ValueType& xsdcCriterionTypeValue) {
-    return xsdcCriterionTypeValue.getLiteral();
-}
-
-ConversionResult<AudioHalCapCriterionType> convertCapCriterionTypeToAidl(
-        const eng_xsd::CriterionTypeType& xsdcCriterionType) {
-    AudioHalCapCriterionType aidlCapCriterionType;
-    aidlCapCriterionType.name = xsdcCriterionType.getName();
-    aidlCapCriterionType.isInclusive = !(static_cast<bool>(xsdcCriterionType.getType()));
-    aidlCapCriterionType.values = VALUE_OR_RETURN(
-            (convertWrappedCollectionToAidl<eng_xsd::ValuesType, eng_xsd::ValueType, std::string>(
-                    xsdcCriterionType.getValues(), &eng_xsd::ValuesType::getValue,
-                    &convertCriterionTypeValueToAidl)));
-    return aidlCapCriterionType;
-}
-
 ConversionResult<AudioHalVolumeCurve::CurvePoint> convertCurvePointToAidl(
         const std::string& xsdcCurvePoint) {
     AudioHalVolumeCurve::CurvePoint aidlCurvePoint{};
diff --git a/audio/aidl/default/alsa/StreamAlsa.cpp b/audio/aidl/default/alsa/StreamAlsa.cpp
index e57d538..f548903 100644
--- a/audio/aidl/default/alsa/StreamAlsa.cpp
+++ b/audio/aidl/default/alsa/StreamAlsa.cpp
@@ -37,6 +37,10 @@
       mConfig(alsa::getPcmConfig(getContext(), mIsInput)),
       mReadWriteRetries(readWriteRetries) {}
 
+StreamAlsa::~StreamAlsa() {
+    cleanupWorker();
+}
+
 ::android::status_t StreamAlsa::init() {
     return mConfig.has_value() ? ::android::OK : ::android::NO_INIT;
 }
diff --git a/audio/aidl/default/bluetooth/StreamBluetooth.cpp b/audio/aidl/default/bluetooth/StreamBluetooth.cpp
index efab470..6e1a811 100644
--- a/audio/aidl/default/bluetooth/StreamBluetooth.cpp
+++ b/audio/aidl/default/bluetooth/StreamBluetooth.cpp
@@ -66,6 +66,10 @@
                                                  1000),
       mBtDeviceProxy(btDeviceProxy) {}
 
+StreamBluetooth::~StreamBluetooth() {
+    cleanupWorker();
+}
+
 ::android::status_t StreamBluetooth::init() {
     std::lock_guard guard(mLock);
     if (mBtDeviceProxy == nullptr) {
diff --git a/audio/aidl/default/config/audioPolicy/capengine/Android.bp b/audio/aidl/default/config/audioPolicy/capengine/Android.bp
new file mode 100644
index 0000000..cb99923
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/capengine/Android.bp
@@ -0,0 +1,17 @@
+package {
+    default_team: "trendy_team_android_media_audio_framework",
+    // 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"],
+}
+
+xsd_config {
+    name: "audio_policy_capengine_configuration_aidl_default",
+    srcs: ["PolicyConfigurableDomains.xsd"],
+    package_name: "android.audio.policy.capengine.configuration",
+    nullability: true,
+    root_elements: ["ConfigurableDomains"],
+}
diff --git a/audio/aidl/default/config/audioPolicy/capengine/PolicyConfigurableDomains.xsd b/audio/aidl/default/config/audioPolicy/capengine/PolicyConfigurableDomains.xsd
new file mode 100644
index 0000000..4e7c0bb
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/capengine/PolicyConfigurableDomains.xsd
@@ -0,0 +1,467 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+    <!-- BEGIN W3cXmlAttributes.xsd -->
+    <xs:annotation>
+        <xs:documentation>
+            See http://www.w3.org/XML/1998/namespace.html and
+            http://www.w3.org/TR/REC-xml for information about this namespace.
+
+            This schema document describes the XML namespace, in a form
+            suitable for import by other schema documents.
+
+            Note that local names in this namespace are intended to be defined
+            only by the World Wide Web Consortium or its subgroups.  The
+            following names are currently defined in this namespace and should
+            not be used with conflicting semantics by any Working Group,
+            specification, or document instance:
+
+            base (as an attribute name): denotes an attribute whose value
+            provides a URI to be used as the base for interpreting any
+            relative URIs in the scope of the element on which it
+            appears; its value is inherited.  This name is reserved
+            by virtue of its definition in the XML Base specification.
+
+            id   (as an attribute name): denotes an attribute whose value
+            should be interpreted as if declared to be of type ID.
+            The xml:id specification is not yet a W3C Recommendation,
+            but this attribute is included here to facilitate experimentation
+            with the mechanisms it proposes.  Note that it is _not_ included
+            in the specialAttrs attribute group.
+
+            lang (as an attribute name): denotes an attribute whose value
+            is a language code for the natural language of the content of
+            any element; its value is inherited.  This name is reserved
+            by virtue of its definition in the XML specification.
+
+            space (as an attribute name): denotes an attribute whose
+            value is a keyword indicating what whitespace processing
+            discipline is intended for the content of the element; its
+            value is inherited.  This name is reserved by virtue of its
+            definition in the XML specification.
+
+            Father (in any context at all): denotes Jon Bosak, the chair of
+            the original XML Working Group.  This name is reserved by
+            the following decision of the W3C XML Plenary and
+            XML Coordination groups:
+
+            In appreciation for his vision, leadership and dedication
+            the W3C XML Plenary on this 10th day of February, 2000
+            reserves for Jon Bosak in perpetuity the XML name
+            xml:Father
+        </xs:documentation>
+    </xs:annotation>
+
+    <xs:annotation>
+        <xs:documentation>This schema defines attributes and an attribute group
+            suitable for use by
+            schemas wishing to allow xml:base, xml:lang, xml:space or xml:id
+            attributes on elements they define.
+
+            To enable this, such a schema must import this schema
+            for the XML namespace, e.g. as follows:
+            &lt;schema . . .>
+            . . .
+            &lt;import namespace="http://www.w3.org/XML/1998/namespace"
+            schemaLocation="http://www.w3.org/2005/08/xml.xsd"/>
+
+            Subsequently, qualified reference to any of the attributes
+            or the group defined below will have the desired effect, e.g.
+
+            &lt;type . . .>
+            . . .
+            &lt;attributeGroup ref="xml:specialAttrs"/>
+
+            will define a type which will schema-validate an instance
+            element with any of those attributes</xs:documentation>
+    </xs:annotation>
+
+    <xs:annotation>
+        <xs:documentation>In keeping with the XML Schema WG's standard versioning
+            policy, this schema document will persist at
+            http://www.w3.org/2005/08/xml.xsd.
+            At the date of issue it can also be found at
+            http://www.w3.org/2001/xml.xsd.
+            The schema document at that URI may however change in the future,
+            in order to remain compatible with the latest version of XML Schema
+            itself, or with the XML namespace itself.  In other words, if the XML
+            Schema or XML namespaces change, the version of this document at
+            http://www.w3.org/2001/xml.xsd will change
+            accordingly; the version at
+            http://www.w3.org/2005/08/xml.xsd will not change.
+        </xs:documentation>
+    </xs:annotation>
+
+    <xs:attribute name="lang">
+        <xs:annotation>
+            <xs:documentation>Attempting to install the relevant ISO 2- and 3-letter
+                codes as the enumerated possible values is probably never
+                going to be a realistic possibility.  See
+                RFC 3066 at http://www.ietf.org/rfc/rfc3066.txt and the IANA registry
+                at http://www.iana.org/assignments/lang-tag-apps.htm for
+                further information.
+
+                The union allows for the 'un-declaration' of xml:lang with
+                the empty string.</xs:documentation>
+        </xs:annotation>
+        <xs:simpleType>
+            <xs:union memberTypes="xs:language">
+                <xs:simpleType name="langEnum">
+                    <xs:restriction base="xs:string">
+                        <xs:enumeration value=""/>
+                    </xs:restriction>
+                </xs:simpleType>
+            </xs:union>
+        </xs:simpleType>
+    </xs:attribute>
+
+    <xs:attribute name="space">
+        <xs:simpleType name="spaceEnum">
+            <xs:restriction base="xs:NCName">
+                <xs:enumeration value="default"/>
+                <xs:enumeration value="preserve"/>
+            </xs:restriction>
+        </xs:simpleType>
+    </xs:attribute>
+
+    <xs:attribute name="base" type="xs:anyURI">
+        <xs:annotation>
+            <xs:documentation>See http://www.w3.org/TR/xmlbase/ for
+                information about this attribute.</xs:documentation>
+        </xs:annotation>
+    </xs:attribute>
+
+    <xs:attribute name="id" type="xs:ID">
+        <xs:annotation>
+            <xs:documentation>See http://www.w3.org/TR/xml-id/ for
+                information about this attribute.</xs:documentation>
+        </xs:annotation>
+    </xs:attribute>
+
+    <xs:attributeGroup name="specialAttrs">
+        <xs:attribute ref="xml:base"/>
+        <xs:attribute ref="xml:lang"/>
+        <xs:attribute ref="xml:space"/>
+    </xs:attributeGroup>
+    <!-- END W3cXmlAttributes.xsd -->
+
+    <!-- BEGIN ParameterSettings.xsd -->
+    <!-- BUG b/147297854 - removed "abstract" from type definition -->
+    <xs:complexType name="BooleanParameterType">
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute name="Name" type="ParameterNameEnumType" use="required"/>
+            </xs:extension>
+            <!--xs:restriction base="xs:string">
+                <xs:pattern value="([01][\s]*)+"/>
+                <xs:pattern value="((0x0|0x1)[\s]*)+"/>
+                <xs:attribute name="Name" type="xs:string" use="required"/>
+            </xs:restriction-->
+        </xs:simpleContent>
+    </xs:complexType>
+    <xs:complexType name="IntegerParameterType">
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute name="Name" type="ParameterNameEnumType" use="required"/>
+            </xs:extension>
+            <!--xs:restriction base="xs:string">
+                <xs:pattern value="(0|([+-]?[1-9][0-9]*))(\s+(0|([+-]?[1-9][0-9]*)))*"/>
+                <xs:pattern value="(0x[0-9a-fA-F]+)(\s+(0x[0-9a-fA-F]+))*"/>
+                <xs:attribute name="Name" type="xs:string" use="required"/>
+            </xs:restriction-->
+        </xs:simpleContent>
+    </xs:complexType>
+    <xs:complexType name="EnumParameterType">
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute name="Name" type="ParameterNameEnumType" use="required"/>
+            </xs:extension>
+            <!--xs:extension base="xs:string">
+                <xs:attribute name="Name" type="xs:string" use="required"/>
+            </xs:extension-->
+        </xs:simpleContent>
+    </xs:complexType>
+    <xs:complexType name="PointParameterType">
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute name="Name" type="ParameterNameEnumType" use="required"/>
+            </xs:extension>
+            <!--xs:restriction base="xs:string">
+                <xs:pattern value="((0|[+-]?0\.[0-9]+|(([+-]?[1-9][0-9]*)(\.[0-9]+)?))([Ee][+-]?[0-9]+)?)(\s+(0|[+-]?0\.[0-9]+|(([+-]?[1-9][0-9]*)(\.[0-9]+)?))([Ee][+-]?[0-9]+)?)*"/>
+                <xs:pattern value="(0x[0-9a-fA-F]+)(\s+(0x[0-9a-fA-F]+))*"/>
+                <xs:attribute name="Name" type="xs:NMTOKEN" use="required"/>
+            </xs:restriction-->
+        </xs:simpleContent>
+    </xs:complexType>
+    <xs:complexType name="BitParameterBlockType">
+        <xs:sequence>
+            <xs:element name="BitParameter" maxOccurs="unbounded" type="IntegerParameterType"/>
+        </xs:sequence>
+        <xs:attribute name="Name" type="ParameterNameEnumType" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="StringParameterType">
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute name="Name" type="ParameterNameEnumType" use="required"/>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+    <xs:group name="ParameterBlockGroup">
+        <xs:choice>
+            <xs:element name="BooleanParameter" type="BooleanParameterType"/>
+            <xs:element name="IntegerParameter" type="IntegerParameterType"/>
+            <xs:element name="EnumParameter" type="EnumParameterType"/>
+            <xs:element name="FixedPointParameter" type="PointParameterType"/>
+            <xs:element name="FloatingPointParameter" type="PointParameterType"/>
+            <xs:element name="BitParameterBlock" type="BitParameterBlockType">
+                <xs:unique name="BitParameterBlockSubElementsUniqueness">
+                    <xs:selector xpath="*"/>
+                    <xs:field xpath="@Name"/>
+                </xs:unique>
+            </xs:element>
+            <xs:element name="StringParameter" type="StringParameterType"/>
+            <!--xs:element name="Component" type="ParameterBlockType"/-->
+            <xs:element name="ParameterBlock" type="ParameterBlockType">
+                <xs:unique name="ParameterBlockSubElementsUniqueness">
+                    <xs:selector xpath="*"/>
+                    <xs:field xpath="@Name"/>
+                </xs:unique>
+            </xs:element>
+        </xs:choice>
+    </xs:group>
+    <xs:complexType name="ParameterBlockType">
+        <xs:sequence>
+            <xs:group ref="ParameterBlockGroup" maxOccurs="unbounded"/>
+        </xs:sequence>
+        <xs:attribute name="Name" type="xs:NMTOKEN" use="required"/>
+    </xs:complexType>
+    <!-- END ParameterSettings.xsd -->
+
+    <!-- BEGIN ConfigurableDomain.xsd -->
+    <xs:complexType name="SelectionCriterionRuleType">
+        <xs:attribute name="SelectionCriterion" type="xs:NMTOKEN" use="required"/>
+        <xs:attribute name="MatchesWhen" use="required">
+            <xs:simpleType name="MatchesWhenEnum">
+                <xs:restriction base="xs:NMTOKEN">
+                    <xs:enumeration value="Is"/>
+                    <xs:enumeration value="IsNot"/>
+                    <xs:enumeration value="Includes"/>
+                    <xs:enumeration value="Excludes"/>
+                </xs:restriction>
+            </xs:simpleType>
+        </xs:attribute>
+        <xs:attribute name="Value" use="required" type="xs:NMTOKEN"/>
+    </xs:complexType>
+    <xs:group name="RuleGroup">
+        <xs:choice>
+            <xs:element name="CompoundRule" type="CompoundRuleType"/>
+            <xs:element name="SelectionCriterionRule" type="SelectionCriterionRuleType"/>
+        </xs:choice>
+    </xs:group>
+    <xs:complexType name="CompoundRuleType">
+        <xs:sequence>
+            <xs:group ref="RuleGroup" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+        <xs:attribute name="Type">
+            <xs:simpleType name="TypeEnum">
+                <xs:restriction base="xs:NMTOKEN">
+                    <xs:enumeration value="Any"/>
+                    <xs:enumeration value="All"/>
+                </xs:restriction>
+            </xs:simpleType>
+        </xs:attribute>
+    </xs:complexType>
+    <xs:complexType name="ConfigurationsType">
+        <xs:sequence>
+            <xs:element maxOccurs="unbounded" name="Configuration">
+                <xs:complexType>
+                    <xs:sequence>
+                        <xs:element name="CompoundRule" type="CompoundRuleType" minOccurs="0" maxOccurs="1"/>
+                    </xs:sequence>
+                    <xs:attribute name="Name" use="required" type="xs:NCName"/>
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:group name="ComponentGroup">
+        <xs:sequence>
+            <xs:group ref="ParameterBlockGroup"/>
+        </xs:sequence>
+    </xs:group>
+    <xs:complexType name="ComponentType">
+        <xs:sequence>
+            <xs:choice>
+                <xs:group ref="ComponentGroup" maxOccurs="unbounded"/>
+                <xs:element name="Subsystem" type="ComponentType" maxOccurs="unbounded"/>
+            </xs:choice>
+        </xs:sequence>
+        <xs:attribute name="Name" use="required" type="xs:NCName"/>
+    </xs:complexType>
+    <xs:complexType name="ConfigurableElementsType">
+        <xs:sequence>
+            <xs:element maxOccurs="unbounded" minOccurs="0" name="ConfigurableElement">
+                <xs:complexType>
+                    <xs:attribute name="Path" use="required">
+                        <xs:simpleType>
+                            <xs:restriction base="xs:anyURI">
+                                <xs:pattern value="/.*[^/]"/>
+                            </xs:restriction>
+                        </xs:simpleType>
+                    </xs:attribute>
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="ConfigurableElementSettingsType">
+        <xs:choice>
+            <xs:element name="BooleanParameter" type="BooleanParameterType"/>
+            <xs:element name="IntegerParameter" type="IntegerParameterType"/>
+            <xs:element name="EnumParameter" type="EnumParameterType"/>
+            <xs:element name="FixedPointParameter" type="PointParameterType"/>
+            <xs:element name="FloatingPointParameter" type="PointParameterType"/>
+            <xs:element name="BitParameter" type="IntegerParameterType"/>
+            <xs:element name="BitParameterBlock" type="BitParameterBlockType">
+                <xs:unique name="BitParameterBlockSubElementsUniqueness">
+                    <xs:selector xpath="*"/>
+                    <xs:field xpath="@Name"/>
+                </xs:unique>
+            </xs:element>
+            <xs:element name="StringParameter" type="StringParameterType"/>
+            <!--xs:element name="Component" type="ParameterBlockType"/-->
+            <xs:element name="ParameterBlock" type="ParameterBlockType">
+                <xs:unique name="ParameterBlockSubElementsUniqueness">
+                    <xs:selector xpath="*"/>
+                    <xs:field xpath="@Name"/>
+                </xs:unique>
+            </xs:element>
+        </xs:choice>
+        <!--xs:choice>
+            <xs:element name="BitParameter" type="IntegerParameterType"/>
+            <xs:group ref="ComponentGroup"/>
+        </xs:choice-->
+        <xs:attribute name="Path" use="required">
+            <xs:simpleType>
+                <xs:restriction base="xs:anyURI">
+                    <xs:pattern value="/.*[^/]"/>
+                </xs:restriction>
+            </xs:simpleType>
+        </xs:attribute>
+    </xs:complexType>
+    <xs:complexType name="SettingsType">
+        <xs:sequence>
+            <xs:element maxOccurs="unbounded" minOccurs="0" name="Configuration">
+                <xs:complexType>
+                    <xs:sequence>
+                        <xs:element name="ConfigurableElement" minOccurs="0" maxOccurs="unbounded" type="ConfigurableElementSettingsType"/>
+                    </xs:sequence>
+                    <xs:attribute name="Name" use="required" type="xs:NCName"/>
+                </xs:complexType>
+                <xs:unique name="ConfigurableElementUniqueness">
+                    <xs:selector xpath="ConfigurableElement"/>
+                    <xs:field xpath="@Path"/>
+                </xs:unique>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="ConfigurableDomainType">
+        <xs:sequence>
+            <xs:element name="Configurations" type="ConfigurationsType"/>
+            <xs:element name="ConfigurableElements" type="ConfigurableElementsType"/>
+            <xs:element name="Settings" type="SettingsType" minOccurs="0"/>
+        </xs:sequence>
+        <xs:attribute name="Name" use="required" type="xs:NCName"/>
+        <xs:attribute name="SequenceAware" use="optional" type="xs:boolean" default="false"/>
+    </xs:complexType>
+    <xs:element name="ConfigurableDomain" type="ConfigurableDomainType"/>
+    <!-- END ConfigurableDomain.xsd -->
+
+    <!-- BEGIN ConfigurableDomains.xsd -->
+    <xs:element name="ConfigurableDomains">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element maxOccurs="unbounded" name="ConfigurableDomain" type="ConfigurableDomainType">
+                    <xs:key name="ConfigurableElementKey">
+                        <xs:selector xpath="ConfigurableElements/ConfigurableElement"/>
+                        <xs:field xpath="@Path"/>
+                    </xs:key>
+                    <xs:keyref refer="ConfigurableElementKey" name="ConfigurableDomainReference">
+                        <xs:selector xpath="Settings/Configuration/ConfigurableElement"/>
+                        <xs:field xpath="@Path"/>
+                    </xs:keyref>
+                    <xs:key name="ConfigurationKey">
+                        <xs:selector xpath="Configurations/Configuration"/>
+                        <xs:field xpath="@Name"/>
+                    </xs:key>
+                    <xs:keyref refer="ConfigurationKey" name="ConfigurationReference2">
+                        <xs:selector xpath="ConfigurableElements/ConfigurableElement/Configuration"/>
+                        <xs:field xpath="@Name"/>
+                    </xs:keyref>
+                    <xs:keyref refer="ConfigurationKey" name="ConfigurationReference">
+                        <xs:selector xpath="Settings/Configuration"/>
+                        <xs:field xpath="@Name"/>
+                    </xs:keyref>
+                </xs:element>
+            </xs:sequence>
+            <xs:attribute name="SystemClassName" use="required" type="xs:NCName"/>
+        </xs:complexType>
+        <xs:unique name="ConfigurableDomainUniqueness">
+            <xs:selector xpath="ConfigurableDomain"/>
+            <xs:field xpath="@Name"/>
+        </xs:unique>
+    </xs:element>
+    <!-- END ConfigurableDomains.xsd -->
+
+    <xs:simpleType name="ParameterNameEnumType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="volume_profile"/>
+
+            <xs:enumeration value="communication"/>
+            <xs:enumeration value="ambient"/>
+            <xs:enumeration value="builtin_mic"/>
+            <xs:enumeration value="bluetooth_sco_headset"/>
+            <xs:enumeration value="wired_headset"/>
+            <xs:enumeration value="hdmi"/>
+            <xs:enumeration value="telephony_rx"/>
+            <xs:enumeration value="back_mic"/>
+            <xs:enumeration value="remote_submix"/>
+            <xs:enumeration value="anlg_dock_headset"/>
+            <xs:enumeration value="dgtl_dock_headset"/>
+            <xs:enumeration value="usb_accessory"/>
+            <xs:enumeration value="usb_device"/>
+            <xs:enumeration value="fm_tuner"/>
+            <xs:enumeration value="tv_tuner"/>
+            <xs:enumeration value="line"/>
+            <xs:enumeration value="spdif"/>
+            <xs:enumeration value="bluetooth_a2dp" />
+            <xs:enumeration value="loopback" />
+            <xs:enumeration value="ip" />
+            <xs:enumeration value="bus" />
+            <xs:enumeration value="proxy"/>
+            <xs:enumeration value="usb_headset"/>
+            <xs:enumeration value="bluetooth_ble"/>
+            <xs:enumeration value="hdmi_arc"/>
+            <xs:enumeration value="echo_reference"/>
+            <xs:enumeration value="ble_headset"/>
+            <xs:enumeration value="stub"/>
+            <xs:enumeration value="hdmi_earc"/>
+
+            <xs:enumeration value="device_address"/>
+
+            <xs:enumeration value="earpiece" />
+            <xs:enumeration value="speaker" />
+            <xs:enumeration value="wired_headphone" />
+            <xs:enumeration value="bluetooth_sco" />
+            <xs:enumeration value="bluetooth_sco_carkit"/>
+            <xs:enumeration value="bluetooth_a2dp_headphones"/>
+            <xs:enumeration value="bluetooth_a2dp_speaker"/>
+            <xs:enumeration value="telephony_tx"/>
+            <xs:enumeration value="fm"/>
+            <xs:enumeration value="aux_line"/>
+            <xs:enumeration value="speaker_safe"/>
+            <xs:enumeration value="hearing_aid" />
+            <xs:enumeration value="echo_canceller" />
+            <xs:enumeration value="ble_speaker" />
+            <xs:enumeration value="ble_broadcast" />
+        </xs:restriction>
+    </xs:simpleType>
+</xs:schema>
diff --git a/audio/aidl/default/config/audioPolicy/capengine/api/current.txt b/audio/aidl/default/config/audioPolicy/capengine/api/current.txt
new file mode 100644
index 0000000..481abbf
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/capengine/api/current.txt
@@ -0,0 +1,264 @@
+// Signature format: 2.0
+package android.audio.policy.capengine.configuration {
+
+  public class BitParameterBlockType {
+    ctor public BitParameterBlockType();
+    method @Nullable public java.util.List<android.audio.policy.capengine.configuration.IntegerParameterType> getBitParameter();
+    method @Nullable public android.audio.policy.capengine.configuration.ParameterNameEnumType getName();
+    method public void setName(@Nullable android.audio.policy.capengine.configuration.ParameterNameEnumType);
+  }
+
+  public class BooleanParameterType {
+    ctor public BooleanParameterType();
+    method @Nullable public android.audio.policy.capengine.configuration.ParameterNameEnumType getName();
+    method @Nullable public String getValue();
+    method public void setName(@Nullable android.audio.policy.capengine.configuration.ParameterNameEnumType);
+    method public void setValue(@Nullable String);
+  }
+
+  public class ComponentType {
+    ctor public ComponentType();
+    method @Nullable public String getName();
+    method @Nullable public java.util.List<android.audio.policy.capengine.configuration.ComponentType> getSubsystem_optional();
+    method public void setName(@Nullable String);
+  }
+
+  public class CompoundRuleType {
+    ctor public CompoundRuleType();
+    method @Nullable public android.audio.policy.capengine.configuration.CompoundRuleType getCompoundRule_optional();
+    method @Nullable public android.audio.policy.capengine.configuration.SelectionCriterionRuleType getSelectionCriterionRule_optional();
+    method @Nullable public android.audio.policy.capengine.configuration.TypeEnum getType();
+    method public void setCompoundRule_optional(@Nullable android.audio.policy.capengine.configuration.CompoundRuleType);
+    method public void setSelectionCriterionRule_optional(@Nullable android.audio.policy.capengine.configuration.SelectionCriterionRuleType);
+    method public void setType(@Nullable android.audio.policy.capengine.configuration.TypeEnum);
+  }
+
+  public class ConfigurableDomainType {
+    ctor public ConfigurableDomainType();
+    method @Nullable public android.audio.policy.capengine.configuration.ConfigurableElementsType getConfigurableElements();
+    method @Nullable public android.audio.policy.capengine.configuration.ConfigurationsType getConfigurations();
+    method @Nullable public String getName();
+    method @Nullable public boolean getSequenceAware();
+    method @Nullable public android.audio.policy.capengine.configuration.SettingsType getSettings();
+    method public void setConfigurableElements(@Nullable android.audio.policy.capengine.configuration.ConfigurableElementsType);
+    method public void setConfigurations(@Nullable android.audio.policy.capengine.configuration.ConfigurationsType);
+    method public void setName(@Nullable String);
+    method public void setSequenceAware(@Nullable boolean);
+    method public void setSettings(@Nullable android.audio.policy.capengine.configuration.SettingsType);
+  }
+
+  public class ConfigurableDomains {
+    ctor public ConfigurableDomains();
+    method @Nullable public java.util.List<android.audio.policy.capengine.configuration.ConfigurableDomainType> getConfigurableDomain();
+    method @Nullable public String getSystemClassName();
+    method public void setSystemClassName(@Nullable String);
+  }
+
+  public class ConfigurableElementSettingsType {
+    ctor public ConfigurableElementSettingsType();
+    method @Nullable public android.audio.policy.capengine.configuration.BitParameterBlockType getBitParameterBlock_optional();
+    method @Nullable public android.audio.policy.capengine.configuration.IntegerParameterType getBitParameter_optional();
+    method @Nullable public android.audio.policy.capengine.configuration.BooleanParameterType getBooleanParameter_optional();
+    method @Nullable public android.audio.policy.capengine.configuration.EnumParameterType getEnumParameter_optional();
+    method @Nullable public android.audio.policy.capengine.configuration.PointParameterType getFixedPointParameter_optional();
+    method @Nullable public android.audio.policy.capengine.configuration.PointParameterType getFloatingPointParameter_optional();
+    method @Nullable public android.audio.policy.capengine.configuration.IntegerParameterType getIntegerParameter_optional();
+    method @Nullable public android.audio.policy.capengine.configuration.ParameterBlockType getParameterBlock_optional();
+    method @Nullable public String getPath();
+    method @Nullable public android.audio.policy.capengine.configuration.StringParameterType getStringParameter_optional();
+    method public void setBitParameterBlock_optional(@Nullable android.audio.policy.capengine.configuration.BitParameterBlockType);
+    method public void setBitParameter_optional(@Nullable android.audio.policy.capengine.configuration.IntegerParameterType);
+    method public void setBooleanParameter_optional(@Nullable android.audio.policy.capengine.configuration.BooleanParameterType);
+    method public void setEnumParameter_optional(@Nullable android.audio.policy.capengine.configuration.EnumParameterType);
+    method public void setFixedPointParameter_optional(@Nullable android.audio.policy.capengine.configuration.PointParameterType);
+    method public void setFloatingPointParameter_optional(@Nullable android.audio.policy.capengine.configuration.PointParameterType);
+    method public void setIntegerParameter_optional(@Nullable android.audio.policy.capengine.configuration.IntegerParameterType);
+    method public void setParameterBlock_optional(@Nullable android.audio.policy.capengine.configuration.ParameterBlockType);
+    method public void setPath(@Nullable String);
+    method public void setStringParameter_optional(@Nullable android.audio.policy.capengine.configuration.StringParameterType);
+  }
+
+  public class ConfigurableElementsType {
+    ctor public ConfigurableElementsType();
+    method @Nullable public java.util.List<android.audio.policy.capengine.configuration.ConfigurableElementsType.ConfigurableElement> getConfigurableElement();
+  }
+
+  public static class ConfigurableElementsType.ConfigurableElement {
+    ctor public ConfigurableElementsType.ConfigurableElement();
+    method @Nullable public String getPath();
+    method public void setPath(@Nullable String);
+  }
+
+  public class ConfigurationsType {
+    ctor public ConfigurationsType();
+    method @Nullable public java.util.List<android.audio.policy.capengine.configuration.ConfigurationsType.Configuration> getConfiguration();
+  }
+
+  public static class ConfigurationsType.Configuration {
+    ctor public ConfigurationsType.Configuration();
+    method @Nullable public android.audio.policy.capengine.configuration.CompoundRuleType getCompoundRule();
+    method @Nullable public String getName();
+    method public void setCompoundRule(@Nullable android.audio.policy.capengine.configuration.CompoundRuleType);
+    method public void setName(@Nullable String);
+  }
+
+  public class EnumParameterType {
+    ctor public EnumParameterType();
+    method @Nullable public android.audio.policy.capengine.configuration.ParameterNameEnumType getName();
+    method @Nullable public String getValue();
+    method public void setName(@Nullable android.audio.policy.capengine.configuration.ParameterNameEnumType);
+    method public void setValue(@Nullable String);
+  }
+
+  public class IntegerParameterType {
+    ctor public IntegerParameterType();
+    method @Nullable public android.audio.policy.capengine.configuration.ParameterNameEnumType getName();
+    method @Nullable public String getValue();
+    method public void setName(@Nullable android.audio.policy.capengine.configuration.ParameterNameEnumType);
+    method public void setValue(@Nullable String);
+  }
+
+  public enum LangEnum {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.capengine.configuration.LangEnum EMPTY;
+  }
+
+  public enum MatchesWhenEnum {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.capengine.configuration.MatchesWhenEnum Excludes;
+    enum_constant public static final android.audio.policy.capengine.configuration.MatchesWhenEnum Includes;
+    enum_constant public static final android.audio.policy.capengine.configuration.MatchesWhenEnum Is;
+    enum_constant public static final android.audio.policy.capengine.configuration.MatchesWhenEnum IsNot;
+  }
+
+  public class ParameterBlockType {
+    ctor public ParameterBlockType();
+    method @Nullable public android.audio.policy.capengine.configuration.BitParameterBlockType getBitParameterBlock_optional();
+    method @Nullable public android.audio.policy.capengine.configuration.BooleanParameterType getBooleanParameter_optional();
+    method @Nullable public android.audio.policy.capengine.configuration.EnumParameterType getEnumParameter_optional();
+    method @Nullable public android.audio.policy.capengine.configuration.PointParameterType getFixedPointParameter_optional();
+    method @Nullable public android.audio.policy.capengine.configuration.PointParameterType getFloatingPointParameter_optional();
+    method @Nullable public android.audio.policy.capengine.configuration.IntegerParameterType getIntegerParameter_optional();
+    method @Nullable public String getName();
+    method @Nullable public android.audio.policy.capengine.configuration.ParameterBlockType getParameterBlock_optional();
+    method @Nullable public android.audio.policy.capengine.configuration.StringParameterType getStringParameter_optional();
+    method public void setBitParameterBlock_optional(@Nullable android.audio.policy.capengine.configuration.BitParameterBlockType);
+    method public void setBooleanParameter_optional(@Nullable android.audio.policy.capengine.configuration.BooleanParameterType);
+    method public void setEnumParameter_optional(@Nullable android.audio.policy.capengine.configuration.EnumParameterType);
+    method public void setFixedPointParameter_optional(@Nullable android.audio.policy.capengine.configuration.PointParameterType);
+    method public void setFloatingPointParameter_optional(@Nullable android.audio.policy.capengine.configuration.PointParameterType);
+    method public void setIntegerParameter_optional(@Nullable android.audio.policy.capengine.configuration.IntegerParameterType);
+    method public void setName(@Nullable String);
+    method public void setParameterBlock_optional(@Nullable android.audio.policy.capengine.configuration.ParameterBlockType);
+    method public void setStringParameter_optional(@Nullable android.audio.policy.capengine.configuration.StringParameterType);
+  }
+
+  public enum ParameterNameEnumType {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType ambient;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType anlg_dock_headset;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType aux_line;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType back_mic;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType ble_broadcast;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType ble_headset;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType ble_speaker;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType bluetooth_a2dp;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType bluetooth_a2dp_headphones;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType bluetooth_a2dp_speaker;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType bluetooth_ble;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType bluetooth_sco;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType bluetooth_sco_carkit;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType bluetooth_sco_headset;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType builtin_mic;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType bus;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType communication;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType device_address;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType dgtl_dock_headset;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType earpiece;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType echo_canceller;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType echo_reference;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType fm;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType fm_tuner;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType hdmi;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType hdmi_arc;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType hdmi_earc;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType hearing_aid;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType ip;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType line;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType loopback;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType proxy;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType remote_submix;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType spdif;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType speaker;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType speaker_safe;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType stub;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType telephony_rx;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType telephony_tx;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType tv_tuner;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType usb_accessory;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType usb_device;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType usb_headset;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType volume_profile;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType wired_headphone;
+    enum_constant public static final android.audio.policy.capengine.configuration.ParameterNameEnumType wired_headset;
+  }
+
+  public class PointParameterType {
+    ctor public PointParameterType();
+    method @Nullable public android.audio.policy.capengine.configuration.ParameterNameEnumType getName();
+    method @Nullable public String getValue();
+    method public void setName(@Nullable android.audio.policy.capengine.configuration.ParameterNameEnumType);
+    method public void setValue(@Nullable String);
+  }
+
+  public class SelectionCriterionRuleType {
+    ctor public SelectionCriterionRuleType();
+    method @Nullable public android.audio.policy.capengine.configuration.MatchesWhenEnum getMatchesWhen();
+    method @Nullable public String getSelectionCriterion();
+    method @Nullable public String getValue();
+    method public void setMatchesWhen(@Nullable android.audio.policy.capengine.configuration.MatchesWhenEnum);
+    method public void setSelectionCriterion(@Nullable String);
+    method public void setValue(@Nullable String);
+  }
+
+  public class SettingsType {
+    ctor public SettingsType();
+    method @Nullable public java.util.List<android.audio.policy.capengine.configuration.SettingsType.Configuration> getConfiguration();
+  }
+
+  public static class SettingsType.Configuration {
+    ctor public SettingsType.Configuration();
+    method @Nullable public java.util.List<android.audio.policy.capengine.configuration.ConfigurableElementSettingsType> getConfigurableElement();
+    method @Nullable public String getName();
+    method public void setName(@Nullable String);
+  }
+
+  public enum SpaceEnum {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.capengine.configuration.SpaceEnum _default;
+    enum_constant public static final android.audio.policy.capengine.configuration.SpaceEnum preserve;
+  }
+
+  public class StringParameterType {
+    ctor public StringParameterType();
+    method @Nullable public android.audio.policy.capengine.configuration.ParameterNameEnumType getName();
+    method @Nullable public String getValue();
+    method public void setName(@Nullable android.audio.policy.capengine.configuration.ParameterNameEnumType);
+    method public void setValue(@Nullable String);
+  }
+
+  public enum TypeEnum {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.capengine.configuration.TypeEnum All;
+    enum_constant public static final android.audio.policy.capengine.configuration.TypeEnum Any;
+  }
+
+  public class XmlParser {
+    ctor public XmlParser();
+    method @Nullable public static android.audio.policy.capengine.configuration.ConfigurableDomains readConfigurableDomains(@NonNull java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method @Nullable public static String readText(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static void skip(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+  }
+
+}
+
diff --git a/audio/aidl/default/config/audioPolicy/capengine/api/last_current.txt b/audio/aidl/default/config/audioPolicy/capengine/api/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/capengine/api/last_current.txt
diff --git a/audio/aidl/default/config/audioPolicy/capengine/api/last_removed.txt b/audio/aidl/default/config/audioPolicy/capengine/api/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/capengine/api/last_removed.txt
diff --git a/audio/aidl/default/config/audioPolicy/capengine/api/removed.txt b/audio/aidl/default/config/audioPolicy/capengine/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/capengine/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/audio/aidl/default/config/audioPolicy/engine/api/current.txt b/audio/aidl/default/config/audioPolicy/engine/api/current.txt
index 063b05d..8e0e9a2 100644
--- a/audio/aidl/default/config/audioPolicy/engine/api/current.txt
+++ b/audio/aidl/default/config/audioPolicy/engine/api/current.txt
@@ -162,7 +162,9 @@
   public static class ProductStrategies.ProductStrategy {
     ctor public ProductStrategies.ProductStrategy();
     method @Nullable public java.util.List<android.audio.policy.engine.configuration.AttributesGroup> getAttributesGroup();
+    method @Nullable public int getId();
     method @Nullable public String getName();
+    method public void setId(@Nullable int);
     method public void setName(@Nullable String);
   }
 
diff --git a/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd b/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd
index 40396bb..e2508ea 100644
--- a/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd
+++ b/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd
@@ -105,6 +105,7 @@
                         <xs:element name="AttributesGroup" type="AttributesGroup" minOccurs="1" maxOccurs="unbounded"/>
                     </xs:sequence>
                     <xs:attribute name="name" type="xs:string" use="required"/>
+                    <xs:attribute name="id" type="xs:int" use="required"/>
                 </xs:complexType>
             </xs:element>
         </xs:sequence>
@@ -188,6 +189,19 @@
         </xs:sequence>
     </xs:complexType>
     <xs:complexType name="valueType">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Criterion type is provided as a tuple of 'human readable' string (referred as the
+                literal part, that will allow to express 'human readable' rules, numerical value
+                associated in order to improve performances of the parameter framework library used,
+                and an optional android type.
+                This android type is reserved for device type mapping with parameter framework
+                representation on a bitfield (Only one bit is expected to represent a device) and
+                android representation of a type that may use several bits.
+                The lookup table will allow wrap android device type to parameter framework device
+                types data model.
+            </xs:documentation>
+        </xs:annotation>
         <xs:attribute name="literal" type="xs:string" use="required"/>
         <xs:attribute name="numerical" type="xs:long" use="required"/>
         <xs:attribute name="android_type" type="longDecimalOrHexType" use="optional"/>
diff --git a/audio/aidl/default/include/core-impl/CapEngineConfigXmlConverter.h b/audio/aidl/default/include/core-impl/CapEngineConfigXmlConverter.h
new file mode 100644
index 0000000..e5da4f4
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/CapEngineConfigXmlConverter.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/core/BnConfig.h>
+#include <aidl/android/media/audio/common/AudioHalEngineConfig.h>
+#include <system/audio_config.h>
+
+#include <android_audio_policy_capengine_configuration.h>
+#include <android_audio_policy_capengine_configuration_enums.h>
+
+#include "EngineConfigXmlConverter.h"
+
+namespace aidl::android::hardware::audio::core::internal {
+
+namespace capconfiguration = ::android::audio::policy::capengine::configuration;
+namespace aidlcommon = ::aidl::android::media::audio::common;
+
+class CapEngineConfigXmlConverter {
+  public:
+    explicit CapEngineConfigXmlConverter(const std::string& configFilePath)
+        : mConverter(configFilePath, &capconfiguration::readConfigurableDomains) {
+        if (mConverter.getXsdcConfig()) {
+            init();
+        }
+    }
+    std::string getError() const { return mConverter.getError(); }
+    ::android::status_t getStatus() const { return mConverter.getStatus(); }
+
+    std::optional<
+            std::vector<std::optional<::aidl::android::media::audio::common::AudioHalCapDomain>>>&
+    getAidlCapEngineConfig();
+
+  private:
+    ConversionResult<std::vector<aidlcommon::AudioHalCapParameter>> convertSettingToAidl(
+            const capconfiguration::SettingsType::Configuration& xsdcSetting);
+
+    ConversionResult<std::vector<aidlcommon::AudioHalCapConfiguration>> convertConfigurationsToAidl(
+            const std::vector<capconfiguration::ConfigurationsType>& xsdcConfigurationsVec,
+            const std::vector<capconfiguration::SettingsType>& xsdcSettingsVec);
+
+    ConversionResult<aidlcommon::AudioHalCapConfiguration> convertConfigurationToAidl(
+            const capconfiguration::ConfigurationsType::Configuration& xsdcConfiguration,
+            const capconfiguration::SettingsType::Configuration& xsdcSettingConfiguration);
+
+    ConversionResult<aidlcommon::AudioHalCapParameter> convertParamToAidl(
+            const capconfiguration::ConfigurableElementSettingsType& element);
+
+    ConversionResult<aidlcommon::AudioHalCapConfiguration> convertConfigurationToAidl(
+            const capconfiguration::ConfigurationsType::Configuration& xsdcConfiguration);
+    ConversionResult<aidlcommon::AudioHalCapDomain> convertConfigurableDomainToAidl(
+            const capconfiguration::ConfigurableDomainType& xsdcConfigurableDomain);
+
+    const std::optional<capconfiguration::ConfigurableDomains>& getXsdcConfig() {
+        return mConverter.getXsdcConfig();
+    }
+    void init();
+
+    std::optional<std::vector<std::optional<aidlcommon::AudioHalCapDomain>>> mAidlCapDomains;
+    XmlConverter<capconfiguration::ConfigurableDomains> mConverter;
+};
+}  // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/include/core-impl/EngineConfigXmlConverter.h b/audio/aidl/default/include/core-impl/EngineConfigXmlConverter.h
index 22ac8cb..211c16f 100644
--- a/audio/aidl/default/include/core-impl/EngineConfigXmlConverter.h
+++ b/audio/aidl/default/include/core-impl/EngineConfigXmlConverter.h
@@ -59,6 +59,7 @@
     ConversionResult<::aidl::android::media::audio::common::AudioHalProductStrategy>
     convertProductStrategyToAidl(const ::android::audio::policy::engine::configuration::
                                          ProductStrategies::ProductStrategy& xsdcProductStrategy);
+    ConversionResult<int> convertProductStrategyIdToAidl(int xsdcId);
     ConversionResult<int> convertProductStrategyNameToAidl(
             const std::string& xsdcProductStrategyName);
     ConversionResult<::aidl::android::media::audio::common::AudioHalVolumeCurve>
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index 93ace96..100b4c8 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -457,6 +457,11 @@
     }
 
     virtual void onClose(StreamDescriptor::State statePriorToClosing) = 0;
+    // Any stream class implementing 'DriverInterface::shutdown' must call 'cleanupWorker' in
+    // the destructor in order to stop and join the worker thread in the case when the client
+    // has not called 'IStreamCommon::close' method.
+    void cleanupWorker();
+    void stopAndJoinWorker();
     void stopWorker();
 
     const StreamContext& mContext;
@@ -464,6 +469,9 @@
     std::unique_ptr<StreamWorkerInterface> mWorker;
     ChildInterface<StreamCommonDelegator> mCommon;
     ConnectedDevices mConnectedDevices;
+
+  private:
+    std::atomic<bool> mWorkerStopIssued = false;
 };
 
 // Note: 'StreamIn/Out' can not be used on their own. Instead, they must be used for defining
diff --git a/audio/aidl/default/include/core-impl/StreamAlsa.h b/audio/aidl/default/include/core-impl/StreamAlsa.h
index 2c3b284..0356946 100644
--- a/audio/aidl/default/include/core-impl/StreamAlsa.h
+++ b/audio/aidl/default/include/core-impl/StreamAlsa.h
@@ -32,6 +32,8 @@
 class StreamAlsa : public StreamCommonImpl {
   public:
     StreamAlsa(StreamContext* context, const Metadata& metadata, int readWriteRetries);
+    ~StreamAlsa();
+
     // Methods of 'DriverInterface'.
     ::android::status_t init() override;
     ::android::status_t drain(StreamDescriptor::DrainMode) override;
diff --git a/audio/aidl/default/include/core-impl/StreamBluetooth.h b/audio/aidl/default/include/core-impl/StreamBluetooth.h
index 7f4239c..357a546 100644
--- a/audio/aidl/default/include/core-impl/StreamBluetooth.h
+++ b/audio/aidl/default/include/core-impl/StreamBluetooth.h
@@ -41,6 +41,8 @@
             const std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl>&
                     btDeviceProxy,
             const ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& pcmConfig);
+    ~StreamBluetooth();
+
     // Methods of 'DriverInterface'.
     ::android::status_t init() override;
     ::android::status_t drain(StreamDescriptor::DrainMode) override;
diff --git a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
index 0d50c96..6ea7968 100644
--- a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
+++ b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
@@ -29,7 +29,9 @@
     StreamRemoteSubmix(
             StreamContext* context, const Metadata& metadata,
             const ::aidl::android::media::audio::common::AudioDeviceAddress& deviceAddress);
+    ~StreamRemoteSubmix();
 
+    // Methods of 'DriverInterface'.
     ::android::status_t init() override;
     ::android::status_t drain(StreamDescriptor::DrainMode) override;
     ::android::status_t flush() override;
diff --git a/audio/aidl/default/include/core-impl/StreamStub.h b/audio/aidl/default/include/core-impl/StreamStub.h
index 3857e0e..22b2020 100644
--- a/audio/aidl/default/include/core-impl/StreamStub.h
+++ b/audio/aidl/default/include/core-impl/StreamStub.h
@@ -23,6 +23,8 @@
 class StreamStub : public StreamCommonImpl {
   public:
     StreamStub(StreamContext* context, const Metadata& metadata);
+    ~StreamStub();
+
     // Methods of 'DriverInterface'.
     ::android::status_t init() override;
     ::android::status_t drain(StreamDescriptor::DrainMode) override;
@@ -42,6 +44,10 @@
     const bool mIsInput;
     bool mIsInitialized = false;  // Used for validating the state machine logic.
     bool mIsStandby = true;       // Used for validating the state machine logic.
+
+    // Used by the worker thread.
+    int64_t mStartTimeNs = 0;
+    long mFramesSinceStart = 0;
 };
 
 class StreamInStub final : public StreamIn, public StreamStub {
diff --git a/audio/aidl/default/include/core-impl/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h
index 608f27d..694fccf 100644
--- a/audio/aidl/default/include/core-impl/StreamUsb.h
+++ b/audio/aidl/default/include/core-impl/StreamUsb.h
@@ -29,6 +29,7 @@
 class StreamUsb : public StreamAlsa {
   public:
     StreamUsb(StreamContext* context, const Metadata& metadata);
+
     // Methods of 'DriverInterface'.
     ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
                                  int32_t* latencyMs) override;
diff --git a/audio/aidl/default/include/core-impl/XmlConverter.h b/audio/aidl/default/include/core-impl/XmlConverter.h
index 68e6b8e..4b99d72 100644
--- a/audio/aidl/default/include/core-impl/XmlConverter.h
+++ b/audio/aidl/default/include/core-impl/XmlConverter.h
@@ -106,6 +106,19 @@
 }
 
 template <typename X, typename A>
+static ConversionResult<std::vector<std::optional<A>>> convertCollectionToAidlOptionalValues(
+        const std::vector<X>& xsdcTypeVec,
+        std::function<ConversionResult<A>(const X&)> convertToAidl) {
+    std::vector<std::optional<A>> resultAidlTypeVec;
+    resultAidlTypeVec.reserve(xsdcTypeVec.size());
+    for (const X& xsdcType : xsdcTypeVec) {
+        resultAidlTypeVec.push_back(
+                std::optional<A>(std::move(VALUE_OR_FATAL(convertToAidl(xsdcType)))));
+    }
+    return resultAidlTypeVec;
+}
+
+template <typename X, typename A>
 static ConversionResult<std::vector<A>> convertCollectionToAidl(
         const std::vector<X>& xsdcTypeVec,
         std::function<ConversionResult<A>(const X&)> convertToAidl) {
diff --git a/audio/aidl/default/include/core-impl/XsdcConversion.h b/audio/aidl/default/include/core-impl/XsdcConversion.h
index 30dc8b6..e855a3e 100644
--- a/audio/aidl/default/include/core-impl/XsdcConversion.h
+++ b/audio/aidl/default/include/core-impl/XsdcConversion.h
@@ -4,6 +4,7 @@
 
 #include <aidl/android/media/audio/common/AudioHalCapCriterion.h>
 #include <aidl/android/media/audio/common/AudioHalCapCriterionType.h>
+#include <aidl/android/media/audio/common/AudioHalCapCriterionV2.h>
 #include <aidl/android/media/audio/common/AudioHalVolumeCurve.h>
 #include <aidl/android/media/audio/common/AudioPort.h>
 #include <android_audio_policy_configuration.h>
@@ -15,15 +16,40 @@
 
 namespace aidl::android::hardware::audio::core::internal {
 
-ConversionResult<::aidl::android::media::audio::common::AudioHalCapCriterion>
-convertCapCriterionToAidl(
-        const ::android::audio::policy::engine::configuration::CriterionType& xsdcCriterion);
-ConversionResult<::aidl::android::media::audio::common::AudioHalCapCriterionType>
-convertCapCriterionTypeToAidl(
-        const ::android::audio::policy::engine::configuration::CriterionTypeType&
-                xsdcCriterionType);
-ConversionResult<::aidl::android::media::audio::common::AudioHalVolumeCurve::CurvePoint>
-convertCurvePointToAidl(const std::string& xsdcCurvePoint);
+namespace engineconfiguration = ::android::audio::policy::engine::configuration;
+namespace aidlaudiocommon = ::aidl::android::media::audio::common;
+
+static constexpr const char kXsdcForceConfigForUse[] = "ForceUseFor";
+
+ConversionResult<aidlaudiocommon::AudioPolicyForceUse> convertForceUseCriterionToAidl(
+        const std::string& xsdcCriterionName);
+ConversionResult<aidlaudiocommon::AudioPolicyForcedConfig> convertForcedConfigToAidl(
+        const std::string& xsdcForcedConfigCriterionType);
+ConversionResult<aidlaudiocommon::AudioDeviceAddress> convertDeviceAddressToAidl(
+        const std::string& xsdcAddress);
+ConversionResult<aidlaudiocommon::AudioMode> convertTelephonyModeToAidl(
+        const std::string& xsdcModeCriterionType);
+ConversionResult<aidlaudiocommon::AudioDeviceDescription> convertDeviceTypeToAidl(
+        const std::string& xType);
+ConversionResult<std::vector<std::optional<aidlaudiocommon::AudioHalCapCriterionV2>>>
+convertCapCriteriaCollectionToAidl(
+        const std::vector<engineconfiguration::CriteriaType>& xsdcCriteriaVec,
+        const std::vector<engineconfiguration::CriterionTypesType>& xsdcCriterionTypesVec);
+ConversionResult<aidlaudiocommon::AudioHalCapCriterionV2> convertCapCriterionV2ToAidl(
+        const engineconfiguration::CriterionType& xsdcCriterion,
+        const std::vector<engineconfiguration::CriterionTypesType>& xsdcCriterionTypesVec);
+ConversionResult<aidlaudiocommon::AudioHalVolumeCurve::CurvePoint> convertCurvePointToAidl(
+        const std::string& xsdcCurvePoint);
 ConversionResult<std::unique_ptr<Module::Configuration>> convertModuleConfigToAidl(
         const ::android::audio::policy::configuration::Modules::Module& moduleConfig);
+ConversionResult<aidlaudiocommon::AudioUsage> convertAudioUsageToAidl(
+        const engineconfiguration::UsageEnumType& xsdcUsage);
+ConversionResult<aidlaudiocommon::AudioContentType> convertAudioContentTypeToAidl(
+        const engineconfiguration::ContentType& xsdcContentType);
+ConversionResult<aidlaudiocommon::AudioSource> convertAudioSourceToAidl(
+        const engineconfiguration::SourceEnumType& xsdcSourceType);
+ConversionResult<aidlaudiocommon::AudioStreamType> convertAudioStreamTypeToAidl(
+        const engineconfiguration::Stream& xsdStreamType);
+ConversionResult<int32_t> convertAudioFlagsToAidl(
+        const std::vector<engineconfiguration::FlagType>& xsdcFlagTypeVec);
 }  // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/main.cpp b/audio/aidl/default/main.cpp
index 6ab747d..0b3e3ba 100644
--- a/audio/aidl/default/main.cpp
+++ b/audio/aidl/default/main.cpp
@@ -71,6 +71,7 @@
     // For more logs, use VERBOSE, however this may hinder performance.
     // android::base::SetMinimumLogSeverity(::android::base::VERBOSE);
     ABinderProcess_setThreadPoolMaxThreadCount(16);
+    ABinderProcess_startThreadPool();
 
     // Guaranteed log for b/210919187 and logd_integration_test
     LOG(INFO) << "Init for Audio AIDL HAL";
diff --git a/audio/aidl/default/primary/StreamPrimary.cpp b/audio/aidl/default/primary/StreamPrimary.cpp
index 7325a91..498f029 100644
--- a/audio/aidl/default/primary/StreamPrimary.cpp
+++ b/audio/aidl/default/primary/StreamPrimary.cpp
@@ -116,8 +116,7 @@
             GetBoolProperty("ro.boot.audio.tinyalsa.simulate_input", false);
     return kSimulateInput || device.type.type == AudioDeviceType::IN_TELEPHONY_RX ||
            device.type.type == AudioDeviceType::IN_FM_TUNER ||
-           device.type.connection == AudioDeviceDescription::CONNECTION_BUS /*deprecated */ ||
-           (device.type.type == AudioDeviceType::IN_BUS && device.type.connection.empty());
+           device.type.connection == AudioDeviceDescription::CONNECTION_BUS /*deprecated */;
 }
 
 StreamSwitcher::DeviceSwitchBehavior StreamInPrimary::switchCurrentStream(
@@ -188,8 +187,7 @@
     static const bool kSimulateOutput =
             GetBoolProperty("ro.boot.audio.tinyalsa.ignore_output", false);
     return kSimulateOutput || device.type.type == AudioDeviceType::OUT_TELEPHONY_TX ||
-           device.type.connection == AudioDeviceDescription::CONNECTION_BUS /*deprecated*/ ||
-           (device.type.type == AudioDeviceType::OUT_BUS && device.type.connection.empty());
+           device.type.connection == AudioDeviceDescription::CONNECTION_BUS /*deprecated*/;
 }
 
 StreamSwitcher::DeviceSwitchBehavior StreamOutPrimary::switchCurrentStream(
diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
index a266b54..db105b6 100644
--- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
+++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
@@ -43,6 +43,10 @@
     mStreamConfig.sampleRate = context->getSampleRate();
 }
 
+StreamRemoteSubmix::~StreamRemoteSubmix() {
+    cleanupWorker();
+}
+
 ::android::status_t StreamRemoteSubmix::init() {
     mCurrentRoute = SubmixRoute::findOrCreateRoute(mDeviceAddress, mStreamConfig);
     if (mCurrentRoute == nullptr) {
diff --git a/audio/aidl/default/stub/StreamStub.cpp b/audio/aidl/default/stub/StreamStub.cpp
index 2422fe4..a3d99a8 100644
--- a/audio/aidl/default/stub/StreamStub.cpp
+++ b/audio/aidl/default/stub/StreamStub.cpp
@@ -39,6 +39,10 @@
       mIsAsynchronous(!!getContext().getAsyncCallback()),
       mIsInput(isInput(metadata)) {}
 
+StreamStub::~StreamStub() {
+    cleanupWorker();
+}
+
 ::android::status_t StreamStub::init() {
     mIsInitialized = true;
     return ::android::OK;
@@ -79,7 +83,6 @@
     if (!mIsInitialized) {
         LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
     }
-    usleep(500);
     mIsStandby = true;
     return ::android::OK;
 }
@@ -88,8 +91,9 @@
     if (!mIsInitialized) {
         LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
     }
-    usleep(500);
     mIsStandby = false;
+    mStartTimeNs = ::android::uptimeNanos();
+    mFramesSinceStart = 0;
     return ::android::OK;
 }
 
@@ -101,14 +105,23 @@
     if (mIsStandby) {
         LOG(FATAL) << __func__ << ": must not happen while in standby";
     }
-    static constexpr float kMicrosPerSecond = MICROS_PER_SECOND;
-    static constexpr float kScaleFactor = .8f;
+    *actualFrameCount = frameCount;
     if (mIsAsynchronous) {
         usleep(500);
     } else {
-        const size_t delayUs = static_cast<size_t>(
-                std::roundf(kScaleFactor * frameCount * kMicrosPerSecond / mSampleRate));
-        usleep(delayUs);
+        mFramesSinceStart += *actualFrameCount;
+        const long bufferDurationUs =
+                (*actualFrameCount) * MICROS_PER_SECOND / mContext.getSampleRate();
+        const auto totalDurationUs =
+                (::android::uptimeNanos() - mStartTimeNs) / NANOS_PER_MICROSECOND;
+        const long totalOffsetUs =
+                mFramesSinceStart * MICROS_PER_SECOND / mContext.getSampleRate() - totalDurationUs;
+        LOG(VERBOSE) << __func__ << ": totalOffsetUs " << totalOffsetUs;
+        if (totalOffsetUs > 0) {
+            const long sleepTimeUs = std::min(totalOffsetUs, bufferDurationUs);
+            LOG(VERBOSE) << __func__ << ": sleeping for " << sleepTimeUs << " us";
+            usleep(sleepTimeUs);
+        }
     }
     if (mIsInput) {
         uint8_t* byteBuffer = static_cast<uint8_t*>(buffer);
@@ -116,7 +129,6 @@
             byteBuffer[i] = std::rand() % 255;
         }
     }
-    *actualFrameCount = frameCount;
     return ::android::OK;
 }
 
diff --git a/audio/aidl/vts/VtsHalAudioCoreConfigTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreConfigTargetTest.cpp
index f82e8e5..25fcd46 100644
--- a/audio/aidl/vts/VtsHalAudioCoreConfigTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreConfigTargetTest.cpp
@@ -38,16 +38,24 @@
 using aidl::android::hardware::audio::core::IConfig;
 using aidl::android::hardware::audio::core::SurroundSoundConfig;
 using aidl::android::media::audio::common::AudioAttributes;
+using aidl::android::media::audio::common::AudioDeviceAddress;
+using aidl::android::media::audio::common::AudioDeviceDescription;
 using aidl::android::media::audio::common::AudioFlag;
 using aidl::android::media::audio::common::AudioFormatDescription;
 using aidl::android::media::audio::common::AudioFormatType;
 using aidl::android::media::audio::common::AudioHalAttributesGroup;
-using aidl::android::media::audio::common::AudioHalCapCriterion;
-using aidl::android::media::audio::common::AudioHalCapCriterionType;
+using aidl::android::media::audio::common::AudioHalCapConfiguration;
+using aidl::android::media::audio::common::AudioHalCapCriterionV2;
+using aidl::android::media::audio::common::AudioHalCapDomain;
+using aidl::android::media::audio::common::AudioHalCapParameter;
+using aidl::android::media::audio::common::AudioHalCapRule;
 using aidl::android::media::audio::common::AudioHalEngineConfig;
 using aidl::android::media::audio::common::AudioHalProductStrategy;
 using aidl::android::media::audio::common::AudioHalVolumeCurve;
 using aidl::android::media::audio::common::AudioHalVolumeGroup;
+using aidl::android::media::audio::common::AudioMode;
+using aidl::android::media::audio::common::AudioPolicyForceUse;
+using aidl::android::media::audio::common::AudioPolicyForcedConfig;
 using aidl::android::media::audio::common::AudioProductStrategyType;
 using aidl::android::media::audio::common::AudioSource;
 using aidl::android::media::audio::common::AudioStreamType;
@@ -256,48 +264,318 @@
     }
 
     /**
-     * Verify defaultLiteralValue is empty for inclusive criterion.
+     * Verify criterion provides a non empty value list.
+     * Verify logic rule provided is the expected one.
      */
-    void ValidateAudioHalCapCriterion(const AudioHalCapCriterion& criterion,
-                                      const AudioHalCapCriterionType& criterionType) {
-        if (criterionType.isInclusive) {
-            EXPECT_TRUE(criterion.defaultLiteralValue.empty());
+    void ValidateAudioHalCapCriterion(const AudioHalCapCriterionV2& criterionV2) {
+        switch (criterionV2.getTag()) {
+            case AudioHalCapCriterionV2::availableInputDevices: {
+                auto criterion = criterionV2.get<AudioHalCapCriterionV2::availableInputDevices>();
+                EXPECT_FALSE(criterion.values.empty());
+                EXPECT_EQ(criterion.logic, AudioHalCapCriterionV2::LogicalDisjunction::INCLUSIVE);
+                break;
+            }
+            case AudioHalCapCriterionV2::availableOutputDevices: {
+                auto criterion = criterionV2.get<AudioHalCapCriterionV2::availableOutputDevices>();
+                EXPECT_FALSE(criterion.values.empty());
+                EXPECT_EQ(criterion.logic, AudioHalCapCriterionV2::LogicalDisjunction::INCLUSIVE);
+                break;
+            }
+            case AudioHalCapCriterionV2::availableInputDevicesAddresses: {
+                auto criterion =
+                        criterionV2.get<AudioHalCapCriterionV2::availableInputDevicesAddresses>();
+                EXPECT_FALSE(criterion.values.empty());
+                EXPECT_EQ(criterion.logic, AudioHalCapCriterionV2::LogicalDisjunction::INCLUSIVE);
+                break;
+            }
+            case AudioHalCapCriterionV2::availableOutputDevicesAddresses: {
+                auto criterion =
+                        criterionV2.get<AudioHalCapCriterionV2::availableOutputDevicesAddresses>();
+                EXPECT_FALSE(criterion.values.empty());
+                EXPECT_EQ(criterion.logic, AudioHalCapCriterionV2::LogicalDisjunction::INCLUSIVE);
+                break;
+            }
+            case AudioHalCapCriterionV2::telephonyMode: {
+                auto criterion = criterionV2.get<AudioHalCapCriterionV2::telephonyMode>();
+                EXPECT_FALSE(criterion.values.empty());
+                EXPECT_EQ(criterion.logic, AudioHalCapCriterionV2::LogicalDisjunction::EXCLUSIVE);
+                break;
+            }
+            case AudioHalCapCriterionV2::forceConfigForUse: {
+                auto criterion = criterionV2.get<AudioHalCapCriterionV2::forceConfigForUse>();
+                EXPECT_FALSE(criterion.values.empty());
+                EXPECT_EQ(criterion.logic, AudioHalCapCriterionV2::LogicalDisjunction::EXCLUSIVE);
+                break;
+            }
+            default:
+                ADD_FAILURE() << "Invalid criterion tag " << toString(criterionV2.getTag());
         }
     }
 
     /**
-     * Verify values only contain alphanumeric characters.
+     * Verify the rule involve the right matching logic according to the criterion logic.
+     * @param matchingRule logic followed by the rule
+     * @param logicalDisjunction logic exposed by the criterion
      */
-    void ValidateAudioHalCapCriterionType(const AudioHalCapCriterionType& criterionType) {
-        auto isNotAlnum = [](const char& c) { return !isalnum(c); };
-        for (const std::string& value : criterionType.values) {
-            EXPECT_EQ(find_if(value.begin(), value.end(), isNotAlnum), value.end());
+    void ValidateAudioHalCapRuleMatchingRule(
+            const AudioHalCapRule::MatchingRule matchingRule,
+            const AudioHalCapCriterionV2::LogicalDisjunction logicalDisjunction) {
+        if (logicalDisjunction == AudioHalCapCriterionV2::LogicalDisjunction::INCLUSIVE) {
+            EXPECT_TRUE(matchingRule == AudioHalCapRule::MatchingRule::EXCLUDES ||
+                        matchingRule == AudioHalCapRule::MatchingRule::INCLUDES);
+        } else if (logicalDisjunction == AudioHalCapCriterionV2::LogicalDisjunction::EXCLUSIVE) {
+            EXPECT_TRUE(matchingRule == AudioHalCapRule::MatchingRule::IS ||
+                        matchingRule == AudioHalCapRule::MatchingRule::IS_NOT);
+        } else {
+            ADD_FAILURE() << "Invalid criterion Logical rule";
         }
     }
 
     /**
-     * Verify each criterionType has a unique name.
-     * Verify each criterion has a unique name.
-     * Verify each criterion maps to a criterionType.
-     * Verify each criterionType is used in a criterion.
-     * Validate contained types.
+     * Verify that the value and the matching rule are supported by the given criterion
+     */
+    template <typename CriterionV2, typename Value>
+    void validateAudioHalCapRule(CriterionV2 criterionV2, Value value,
+                                 const AudioHalCapRule::MatchingRule matchingRule) {
+        ValidateAudioHalCapRuleMatchingRule(matchingRule, criterionV2.logic);
+        EXPECT_FALSE(criterionV2.values.empty());
+        auto values = criterionV2.values;
+        auto valueIt = find_if(values.begin(), values.end(),
+                               [&](const auto& typedValue) { return typedValue == value; });
+        EXPECT_NE(valueIt, values.end());
+    }
+
+    /**
+     * Verify rule involves a supported criterion.
+     * Verify rule involves supported logic keyword according to logic rule exposed by the
+     * criterion.
+     * Verify rule involves a value supported by the associated criterion.
+     */
+    void ValidateAudioHalConfigurationRule(
+            const AudioHalCapRule& rule,
+            const std::vector<std::optional<AudioHalCapCriterionV2>>& criteria) {
+        const auto& compoundRule = rule.compoundRule;
+        using TypeTag = AudioHalCapCriterionV2::Type::Tag;
+        if (rule.nestedRules.empty() && rule.criterionRules.empty()) {
+            EXPECT_EQ(compoundRule, AudioHalCapRule::CompoundRule::ALL);
+        }
+        EXPECT_TRUE(compoundRule == AudioHalCapRule::CompoundRule::ANY ||
+                    compoundRule == AudioHalCapRule::CompoundRule::ALL);
+        for (const auto& nestedRule : rule.nestedRules) {
+            ValidateAudioHalConfigurationRule(nestedRule, criteria);
+        }
+        for (const auto& criterionRule : rule.criterionRules) {
+            auto selectionCriterion = criterionRule.criterion;
+            auto criterionValue = criterionRule.criterionTypeValue;
+            auto matchesWhen = criterionRule.matchingRule;
+            auto criteriaIt = find_if(criteria.begin(), criteria.end(), [&](const auto& criterion) {
+                return criterion.has_value() &&
+                       criterion.value().getTag() == selectionCriterion.getTag();
+            });
+            EXPECT_NE(criteriaIt, criteria.end())
+                    << " Invalid rule criterion " << toString(selectionCriterion.getTag());
+            AudioHalCapCriterionV2 matchingCriterion = (*criteriaIt).value();
+            switch (selectionCriterion.getTag()) {
+                case AudioHalCapCriterionV2::availableInputDevices: {
+                    EXPECT_EQ(criterionValue.getTag(), TypeTag::availableDevicesType);
+                    validateAudioHalCapRule(
+                            matchingCriterion.get<AudioHalCapCriterionV2::availableInputDevices>(),
+                            criterionValue.get<TypeTag::availableDevicesType>(), matchesWhen);
+                    break;
+                }
+                case AudioHalCapCriterionV2::availableOutputDevices: {
+                    EXPECT_EQ(criterionValue.getTag(), TypeTag::availableDevicesType);
+                    validateAudioHalCapRule(
+                            matchingCriterion.get<AudioHalCapCriterionV2::availableOutputDevices>(),
+                            criterionValue.get<TypeTag::availableDevicesType>(), matchesWhen);
+                    break;
+                }
+                case AudioHalCapCriterionV2::availableInputDevicesAddresses: {
+                    EXPECT_EQ(criterionValue.getTag(), TypeTag::availableDevicesAddressesType);
+                    validateAudioHalCapRule(
+                            matchingCriterion
+                                    .get<AudioHalCapCriterionV2::availableInputDevicesAddresses>(),
+                            criterionValue.get<TypeTag::availableDevicesAddressesType>(),
+                            matchesWhen);
+                    break;
+                }
+                case AudioHalCapCriterionV2::availableOutputDevicesAddresses: {
+                    EXPECT_EQ(criterionValue.getTag(), TypeTag::availableDevicesAddressesType);
+                    validateAudioHalCapRule(
+                            matchingCriterion
+                                    .get<AudioHalCapCriterionV2::availableOutputDevicesAddresses>(),
+                            criterionValue.get<TypeTag::availableDevicesAddressesType>(),
+                            matchesWhen);
+                    break;
+                }
+                case AudioHalCapCriterionV2::telephonyMode: {
+                    EXPECT_EQ(criterionValue.getTag(), TypeTag::telephonyModeType);
+                    validateAudioHalCapRule(
+                            matchingCriterion.get<AudioHalCapCriterionV2::telephonyMode>(),
+                            criterionValue.get<TypeTag::telephonyModeType>(), matchesWhen);
+                    break;
+                }
+                case AudioHalCapCriterionV2::forceConfigForUse: {
+                    EXPECT_EQ(criterionValue.getTag(), TypeTag::forcedConfigType);
+                    validateAudioHalCapRule(
+                            matchingCriterion
+                                    .get<AudioHalCapCriterionV2::forceConfigForUse>(),
+                            criterionValue.get<TypeTag::forcedConfigType>(), matchesWhen);
+                    break;
+                }
+                default:
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Get the number of occurrence of a given parameter within a given vector of parameter.
+     * It just take into account the parameter, not its associated value.
+     * @param parameter to consider
+     * @param domainParameters to check against
+     * @return matching occurrence of the parameter within the provided vector.
+     */
+    size_t countsParameter(const AudioHalCapParameter& parameter,
+                           const std::vector<AudioHalCapParameter>& domainParameters) {
+        size_t count = 0;
+        for (const auto& domainParameter : domainParameters) {
+            if (domainParameter.getTag() != parameter.getTag()) {
+                continue;
+            }
+            switch (domainParameter.getTag()) {
+                case AudioHalCapParameter::selectedStrategyDevice: {
+                    auto typedDomainParam =
+                            domainParameter.get<AudioHalCapParameter::selectedStrategyDevice>();
+                    auto typedParam = parameter.get<AudioHalCapParameter::selectedStrategyDevice>();
+                    if (typedDomainParam.id == typedParam.id &&
+                        typedDomainParam.device == typedParam.device) {
+                        count += 1;
+                    }
+                    break;
+                }
+                case AudioHalCapParameter::strategyDeviceAddress: {
+                    auto typedDomainParam =
+                            domainParameter.get<AudioHalCapParameter::strategyDeviceAddress>();
+                    auto typedParam = parameter.get<AudioHalCapParameter::strategyDeviceAddress>();
+                    if (typedDomainParam.id == typedParam.id) {
+                        count += 1;
+                    }
+                    break;
+                }
+                case AudioHalCapParameter::selectedInputSourceDevice: {
+                    auto typedDomainParam =
+                            domainParameter.get<AudioHalCapParameter::selectedInputSourceDevice>();
+                    auto typedParam =
+                            parameter.get<AudioHalCapParameter::selectedInputSourceDevice>();
+                    if (typedDomainParam.inputSource == typedParam.inputSource &&
+                        typedDomainParam.device == typedParam.device) {
+                        count += 1;
+                    }
+                    break;
+                }
+                case AudioHalCapParameter::streamVolumeProfile: {
+                    auto typedDomainParam =
+                            domainParameter.get<AudioHalCapParameter::streamVolumeProfile>();
+                    auto typedParam = parameter.get<AudioHalCapParameter::streamVolumeProfile>();
+                    if (typedDomainParam.stream == typedParam.stream) {
+                        count += 1;
+                    }
+                    break;
+                }
+                default:
+                    break;
+            }
+        }
+        return count;
+    }
+
+    /**
+     * Verify each configuration has unique name within a domain
+     * Verify no duplicate parameter within a domain.
+     * Verify that each configuration has no duplicated parameter.
+     * Verify that each configuration has an associated value for all parameter within a domain.
+     */
+    void ValidateAudioHalCapDomain(
+            const AudioHalCapDomain& domain,
+            const std::vector<std::optional<AudioHalCapCriterionV2>>& criteria) {
+        std::unordered_set<std::string> configurationNames;
+        for (const AudioHalCapConfiguration& configuration : domain.configurations) {
+            EXPECT_TRUE(configurationNames.insert(configuration.name).second);
+            ValidateAudioHalConfigurationRule(configuration.rule, criteria);
+        }
+        auto domainParameters = domain.configurations[0].parameterSettings;
+        for (const auto& settingParameter : domainParameters) {
+            EXPECT_EQ(1ul, countsParameter(settingParameter, domainParameters))
+                    << "Duplicated parameter within domain " << domain.name << " configuration "
+                    << domain.configurations[0].name << " for parameter "
+                    << settingParameter.toString();
+        }
+        for (const auto& configuration : domain.configurations) {
+            auto configurationParameters = configuration.parameterSettings;
+            for (const auto& configurationParameter : configurationParameters) {
+                EXPECT_EQ(1ul, countsParameter(configurationParameter, configurationParameters))
+                        << "Duplicated parameter within domain " << domain.name << " configuration "
+                        << configuration.name << " for parameter "
+                        << configurationParameter.toString();
+            }
+            EXPECT_EQ(domainParameters.size(), configurationParameters.size());
+            for (const auto& settingParameter : configuration.parameterSettings) {
+                EXPECT_EQ(1ul, countsParameter(settingParameter, domainParameters))
+                        << "Confiugration " << configuration.name << " within domain "
+                        << domain.name << " exposes invalid parameter "
+                        << settingParameter.toString();
+                ;
+            }
+        }
+    }
+
+    /**
+     * Verify each domain has a unique name.
+     * Verify that a given parameter does not appear in more than one domain.
+     */
+    void ValidateAudioHalCapDomains(
+            const std::vector<std::optional<AudioHalCapDomain>>& domains,
+            const std::vector<std::optional<AudioHalCapCriterionV2>>& criteria) {
+        std::unordered_map<std::string, AudioHalCapDomain> domainMap;
+        std::vector<AudioHalCapParameter> allDomainParameters;
+        for (const auto& domain : domains) {
+            EXPECT_TRUE(domain.has_value());
+            EXPECT_FALSE(domain.value().configurations.empty());
+            auto domainParameters = domain.value().configurations[0].parameterSettings;
+            for (const auto& domainParameter : domainParameters) {
+                EXPECT_EQ(0ul, countsParameter(domainParameter, allDomainParameters))
+                        << "Duplicated parameter in domain " << domain.value().name
+                        << " for parameter " << domainParameter.toString();
+                allDomainParameters.push_back(domainParameter);
+            }
+            EXPECT_NO_FATAL_FAILURE(ValidateAudioHalCapDomain(domain.value(), criteria));
+            EXPECT_TRUE(domainMap.insert({domain.value().name, domain.value()}).second);
+        }
+    }
+
+    /**
+     * Verify unique criterion is provided for a given Tag, except for ForceUse
+     * Verify unique forceUse criterion are provided for usage
+     * Verify each criterion is validating.
+     * Verify domains.
      */
     void ValidateCapSpecificConfig(const AudioHalEngineConfig::CapSpecificConfig& capCfg) {
-        EXPECT_FALSE(capCfg.criteria.empty());
-        EXPECT_FALSE(capCfg.criterionTypes.empty());
-        std::unordered_map<std::string, AudioHalCapCriterionType> criterionTypeMap;
-        for (const AudioHalCapCriterionType& criterionType : capCfg.criterionTypes) {
-            EXPECT_NO_FATAL_FAILURE(ValidateAudioHalCapCriterionType(criterionType));
-            EXPECT_TRUE(criterionTypeMap.insert({criterionType.name, criterionType}).second);
+        EXPECT_TRUE(capCfg.criteriaV2.has_value());
+        std::unordered_set<AudioHalCapCriterionV2::Tag> criterionTagSet;
+        std::unordered_set<AudioPolicyForceUse> forceUseCriterionUseSet;
+        for (const auto& criterion : capCfg.criteriaV2.value()) {
+            EXPECT_TRUE(criterion.has_value());
+            if (criterion.value().getTag() != AudioHalCapCriterionV2::forceConfigForUse) {
+                EXPECT_TRUE(criterionTagSet.insert(criterion.value().getTag()).second);
+            } else {
+                auto forceUseCriterion =
+                        criterion.value().get<AudioHalCapCriterionV2::forceConfigForUse>();
+                EXPECT_TRUE(forceUseCriterionUseSet.insert(forceUseCriterion.forceUse).second);
+            }
+            EXPECT_NO_FATAL_FAILURE(ValidateAudioHalCapCriterion(criterion.value()));
         }
-        std::unordered_set<std::string> criterionNameSet;
-        for (const AudioHalCapCriterion& criterion : capCfg.criteria) {
-            EXPECT_TRUE(criterionNameSet.insert(criterion.name).second);
-            EXPECT_EQ(criterionTypeMap.count(criterion.criterionTypeName), 1UL);
-            EXPECT_NO_FATAL_FAILURE(ValidateAudioHalCapCriterion(
-                    criterion, criterionTypeMap.at(criterion.criterionTypeName)));
-        }
-        EXPECT_EQ(criterionTypeMap.size(), criterionNameSet.size());
+        ValidateAudioHalCapDomains(capCfg.domains.value(), capCfg.criteriaV2.value());
     }
 
     /**
diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
index bbc4caf..8d430de 100644
--- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -2975,15 +2975,15 @@
 
     // The five methods below is intended to be called after the worker
     // thread has joined, thus no extra synchronization is needed.
-    bool hasObservablePositionIncrease() const { return mObservablePositionIncrease; }
-    bool hasObservableRetrogradePosition() const { return mRetrogradeObservablePosition; }
+    bool hasObservablePositionIncrease() const { return mObservable.hasPositionIncrease; }
+    bool hasObservableRetrogradePosition() const { return mObservable.hasRetrogradePosition; }
     bool hasHardwarePositionIncrease() const {
         // For non-MMap, always return true to pass the validation.
-        return mIsMmap ? mHardwarePositionIncrease : true;
+        return mIsMmap ? mHardware.hasPositionIncrease : true;
     }
     bool hasHardwareRetrogradePosition() const {
         // For non-MMap, always return false to pass the validation.
-        return mIsMmap ? mRetrogradeHardwarePosition : false;
+        return mIsMmap ? mHardware.hasRetrogradePosition : false;
     }
     std::string getUnexpectedStateTransition() const { return mUnexpectedTransition; }
 
@@ -3011,25 +3011,9 @@
     }
     bool interceptRawReply(const StreamDescriptor::Reply&) override { return false; }
     bool processValidReply(const StreamDescriptor::Reply& reply) override {
-        if (reply.observable.frames != StreamDescriptor::Position::UNKNOWN) {
-            if (mPreviousObservableFrames.has_value()) {
-                if (reply.observable.frames > mPreviousObservableFrames.value()) {
-                    mObservablePositionIncrease = true;
-                } else if (reply.observable.frames < mPreviousObservableFrames.value()) {
-                    mRetrogradeObservablePosition = true;
-                }
-            }
-            mPreviousObservableFrames = reply.observable.frames;
-        }
+        mObservable.update(reply.observable.frames);
         if (mIsMmap) {
-            if (mPreviousHardwareFrames.has_value()) {
-                if (reply.hardware.frames > mPreviousHardwareFrames.value()) {
-                    mHardwarePositionIncrease = true;
-                } else if (reply.hardware.frames < mPreviousHardwareFrames.value()) {
-                    mRetrogradeHardwarePosition = true;
-                }
-            }
-            mPreviousHardwareFrames = reply.hardware.frames;
+            mHardware.update(reply.hardware.frames);
         }
 
         auto expected = mCommands->getExpectedStates();
@@ -3054,16 +3038,30 @@
     }
 
   protected:
+    struct FramesCounter {
+        std::optional<int64_t> previous;
+        bool hasPositionIncrease = false;
+        bool hasRetrogradePosition = false;
+
+        void update(int64_t position) {
+            if (position == StreamDescriptor::Position::UNKNOWN) return;
+            if (previous.has_value()) {
+                if (position > previous.value()) {
+                    hasPositionIncrease = true;
+                } else if (position < previous.value()) {
+                    hasRetrogradePosition = true;
+                }
+            }
+            previous = position;
+        }
+    };
+
     std::shared_ptr<StateSequence> mCommands;
     const size_t mFrameSizeBytes;
     const bool mIsMmap;
     std::optional<StreamDescriptor::State> mPreviousState;
-    std::optional<int64_t> mPreviousObservableFrames;
-    bool mObservablePositionIncrease = false;
-    bool mRetrogradeObservablePosition = false;
-    std::optional<int64_t> mPreviousHardwareFrames;
-    bool mHardwarePositionIncrease = false;
-    bool mRetrogradeHardwarePosition = false;
+    FramesCounter mObservable;
+    FramesCounter mHardware;
     std::string mUnexpectedTransition;
 };
 
diff --git a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
index 6af326d..154a5af 100644
--- a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
@@ -42,13 +42,15 @@
     PARAM_INSTANCE_NAME,
     PARAM_HAPTIC_SCALE_ID,
     PARAM_HAPTIC_SCALE_VIBRATOR_SCALE,
+    PARAM_HAPTIC_SCALE_SCALE_FACTOR,
+    PARAM_HAPTIC_SCALE_ADAPTIVE_SCALE_FACTOR,
     PARAM_VIBRATION_INFORMATION_RESONANT_FREQUENCY,
     PARAM_VIBRATION_INFORMATION_Q_FACTOR,
     PARAM_VIBRATION_INFORMATION_MAX_AMPLITUDE,
 };
 using HapticGeneratorParamTestParam =
         std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int,
-                   HapticGenerator::VibratorScale, float, float, float>;
+                   HapticGenerator::VibratorScale, float, float, float, float, float>;
 
 /*
  * Testing parameter range, assuming the parameter supported by effect is in this range.
@@ -67,17 +69,25 @@
 const std::vector<HapticGenerator::VibratorScale> kVibratorScaleValues = {
         ndk::enum_range<HapticGenerator::VibratorScale>().begin(),
         ndk::enum_range<HapticGenerator::VibratorScale>().end()};
+const std::vector<float> kScaleFactorValues = {HapticGenerator::HapticScale::UNDEFINED_SCALE_FACTOR,
+                                               0.0f, 0.5f, 1.0f, MAX_FLOAT};
+const std::vector<float> kAdaptiveScaleFactorValues = {
+        HapticGenerator::HapticScale::UNDEFINED_SCALE_FACTOR, 0.0f, 0.5f, 1.0f, MAX_FLOAT};
 
 const std::vector<float> kResonantFrequencyValues = {MIN_FLOAT, 100, MAX_FLOAT};
 const std::vector<float> kQFactorValues = {MIN_FLOAT, 100, MAX_FLOAT};
 const std::vector<float> kMaxAmplitude = {MIN_FLOAT, 100, MAX_FLOAT};
 
+constexpr int HAPTIC_SCALE_FACTORS_EFFECT_MIN_VERSION = 3;
+
 class HapticGeneratorParamTest : public ::testing::TestWithParam<HapticGeneratorParamTestParam>,
                                  public EffectHelper {
   public:
     HapticGeneratorParamTest()
         : mParamHapticScaleId(std::get<PARAM_HAPTIC_SCALE_ID>(GetParam())),
           mParamVibratorScale(std::get<PARAM_HAPTIC_SCALE_VIBRATOR_SCALE>(GetParam())),
+          mParamScaleFactor(std::get<PARAM_HAPTIC_SCALE_SCALE_FACTOR>(GetParam())),
+          mParamAdaptiveScaleFactor(std::get<PARAM_HAPTIC_SCALE_ADAPTIVE_SCALE_FACTOR>(GetParam())),
           mParamResonantFrequency(
                   std::get<PARAM_VIBRATION_INFORMATION_RESONANT_FREQUENCY>(GetParam())),
           mParamQFactor(std::get<PARAM_VIBRATION_INFORMATION_Q_FACTOR>(GetParam())),
@@ -87,6 +97,7 @@
     void SetUp() override {
         ASSERT_NE(nullptr, mFactory);
         ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+        EXPECT_STATUS(EX_NONE, mEffect->getInterfaceVersion(&mEffectInterfaceVersion));
 
         Parameter::Common common = createParamCommon(
                 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
@@ -105,8 +116,11 @@
     std::shared_ptr<IFactory> mFactory;
     std::shared_ptr<IEffect> mEffect;
     Descriptor mDescriptor;
+    int mEffectInterfaceVersion;
     int mParamHapticScaleId = 0;
     HapticGenerator::VibratorScale mParamVibratorScale = HapticGenerator::VibratorScale::MUTE;
+    float mParamScaleFactor = HapticGenerator::HapticScale::UNDEFINED_SCALE_FACTOR;
+    float mParamAdaptiveScaleFactor = HapticGenerator::HapticScale::UNDEFINED_SCALE_FACTOR;
     float mParamResonantFrequency = 0;
     float mParamQFactor = 0;
     float mParamMaxAmplitude = 0;
@@ -135,9 +149,18 @@
         }
     }
 
-    void addHapticScaleParam(int id, HapticGenerator::VibratorScale scale) {
+    void addHapticScaleParam(int id, HapticGenerator::VibratorScale scale, float scaleFactor,
+                             float adaptiveScaleFactor) {
         HapticGenerator setHg;
-        std::vector<HapticGenerator::HapticScale> hapticScales = {{.id = id, .scale = scale}};
+        std::vector<HapticGenerator::HapticScale> hapticScales;
+        if (mEffectInterfaceVersion >= HAPTIC_SCALE_FACTORS_EFFECT_MIN_VERSION) {
+            hapticScales = {{.id = id,
+                             .scale = scale,
+                             .scaleFactor = scaleFactor,
+                             .adaptiveScaleFactor = adaptiveScaleFactor}};
+        } else {
+            hapticScales = {{.id = id, .scale = scale}};
+        }
         setHg.set<HapticGenerator::hapticScales>(hapticScales);
         mTags.push_back({HapticGenerator::hapticScales, setHg});
     }
@@ -160,13 +183,16 @@
 };
 
 TEST_P(HapticGeneratorParamTest, SetAndGetHapticScale) {
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(mParamHapticScaleId, mParamVibratorScale));
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(mParamHapticScaleId, mParamVibratorScale,
+                                                mParamScaleFactor, mParamAdaptiveScaleFactor));
     SetAndGetHapticGeneratorParameters();
 }
 
 TEST_P(HapticGeneratorParamTest, SetAndGetMultipleHapticScales) {
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(mParamHapticScaleId, mParamVibratorScale));
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(mParamHapticScaleId, mParamVibratorScale));
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(mParamHapticScaleId, mParamVibratorScale,
+                                                mParamScaleFactor, mParamAdaptiveScaleFactor));
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(mParamHapticScaleId, mParamVibratorScale,
+                                                mParamScaleFactor, mParamAdaptiveScaleFactor));
     SetAndGetHapticGeneratorParameters();
 }
 
@@ -182,6 +208,8 @@
                                    IFactory::descriptor, getEffectTypeUuidHapticGenerator())),
                            testing::ValuesIn(kHapticScaleIdValues),
                            testing::ValuesIn(kVibratorScaleValues),
+                           testing::ValuesIn(kScaleFactorValues),
+                           testing::ValuesIn(kAdaptiveScaleFactorValues),
                            testing::ValuesIn(kResonantFrequencyValues),
                            testing::ValuesIn(kQFactorValues), testing::ValuesIn(kMaxAmplitude)),
         [](const testing::TestParamInfo<HapticGeneratorParamTest::ParamType>& info) {
@@ -189,6 +217,10 @@
             std::string hapticScaleID = std::to_string(std::get<PARAM_HAPTIC_SCALE_ID>(info.param));
             std::string hapticScaleVibScale = std::to_string(
                     static_cast<int>(std::get<PARAM_HAPTIC_SCALE_VIBRATOR_SCALE>(info.param)));
+            std::string hapticScaleFactor =
+                    std::to_string(std::get<PARAM_HAPTIC_SCALE_SCALE_FACTOR>(info.param));
+            std::string hapticAdaptiveScaleFactor =
+                    std::to_string(std::get<PARAM_HAPTIC_SCALE_ADAPTIVE_SCALE_FACTOR>(info.param));
             std::string resonantFrequency = std::to_string(
                     std::get<PARAM_VIBRATION_INFORMATION_RESONANT_FREQUENCY>(info.param));
             std::string qFactor =
@@ -196,7 +228,9 @@
             std::string maxAmplitude =
                     std::to_string(std::get<PARAM_VIBRATION_INFORMATION_MAX_AMPLITUDE>(info.param));
             std::string name = getPrefix(descriptor) + "_hapticScaleId" + hapticScaleID +
-                               "_hapticScaleVibScale" + hapticScaleVibScale + "_resonantFrequency" +
+                               "_hapticScaleVibScale" + hapticScaleVibScale + "_hapticScaleFactor" +
+                               hapticScaleFactor + "_hapticAdaptiveScaleFactor" +
+                               hapticAdaptiveScaleFactor + "_resonantFrequency" +
                                resonantFrequency + "_qFactor" + qFactor + "_maxAmplitude" +
                                maxAmplitude;
             std::replace_if(
@@ -210,6 +244,8 @@
                                    IFactory::descriptor, getEffectTypeUuidHapticGenerator())),
                            testing::Values(MIN_ID),
                            testing::Values(HapticGenerator::VibratorScale::NONE),
+                           testing::Values(HapticGenerator::HapticScale::UNDEFINED_SCALE_FACTOR),
+                           testing::Values(HapticGenerator::HapticScale::UNDEFINED_SCALE_FACTOR),
                            testing::Values(MIN_FLOAT), testing::Values(MIN_FLOAT),
                            testing::Values(MIN_FLOAT)),
         [](const testing::TestParamInfo<HapticGeneratorParamTest::ParamType>& info) {
@@ -217,6 +253,10 @@
             std::string hapticScaleID = std::to_string(std::get<PARAM_HAPTIC_SCALE_ID>(info.param));
             std::string hapticScaleVibScale = std::to_string(
                     static_cast<int>(std::get<PARAM_HAPTIC_SCALE_VIBRATOR_SCALE>(info.param)));
+            std::string hapticScaleFactor =
+                    std::to_string(std::get<PARAM_HAPTIC_SCALE_SCALE_FACTOR>(info.param));
+            std::string hapticAdaptiveScaleFactor =
+                    std::to_string(std::get<PARAM_HAPTIC_SCALE_ADAPTIVE_SCALE_FACTOR>(info.param));
             std::string resonantFrequency = std::to_string(
                     std::get<PARAM_VIBRATION_INFORMATION_RESONANT_FREQUENCY>(info.param));
             std::string qFactor =
@@ -227,6 +267,8 @@
                                descriptor.common.name + "_UUID_" +
                                toString(descriptor.common.id.uuid) + "_hapticScaleId" +
                                hapticScaleID + "_hapticScaleVibScale" + hapticScaleVibScale +
+                               "_hapticScaleFactor" + hapticScaleFactor +
+                               "_hapticAdaptiveScaleFactor" + hapticAdaptiveScaleFactor +
                                "_resonantFrequency" + resonantFrequency + "_qFactor" + qFactor +
                                "_maxAmplitude" + maxAmplitude;
             std::replace_if(
diff --git a/audio/policy/1.0/vts/functional/Android.bp b/audio/policy/1.0/vts/functional/Android.bp
index b32c223..c2335e4 100644
--- a/audio/policy/1.0/vts/functional/Android.bp
+++ b/audio/policy/1.0/vts/functional/Android.bp
@@ -17,8 +17,9 @@
         "libxml2",
         "liblog",
         "libmedia_helper",
-        "libaudiopolicyengine_config",
+        "libaudiopolicycapengine_config",
         "libaudiopolicycomponents",
+        "libaudiopolicyengine_config",
         "libaudiopolicyengineconfigurable_pfwwrapper",
         "android.hardware.audio.common.test.utility",
         "libparameter",
diff --git a/audio/policy/1.0/xml/api/current.txt b/audio/policy/1.0/xml/api/current.txt
index 01d77d7..19a8123 100644
--- a/audio/policy/1.0/xml/api/current.txt
+++ b/audio/policy/1.0/xml/api/current.txt
@@ -162,7 +162,9 @@
   public static class ProductStrategies.ProductStrategy {
     ctor public ProductStrategies.ProductStrategy();
     method public java.util.List<audio.policy.V1_0.AttributesGroup> getAttributesGroup();
+    method public int getId();
     method public String getName();
+    method public void setId(int);
     method public void setName(String);
   }
 
diff --git a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
index 40396bb..02e593a 100644
--- a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
+++ b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
@@ -105,6 +105,7 @@
                         <xs:element name="AttributesGroup" type="AttributesGroup" minOccurs="1" maxOccurs="unbounded"/>
                     </xs:sequence>
                     <xs:attribute name="name" type="xs:string" use="required"/>
+                    <xs:attribute name="id" type="xs:int" use="required"/>
                 </xs:complexType>
             </xs:element>
         </xs:sequence>
diff --git a/automotive/remoteaccess/hal/default/Android.bp b/automotive/remoteaccess/hal/default/Android.bp
index cc8f2b0..b6c0525 100644
--- a/automotive/remoteaccess/hal/default/Android.bp
+++ b/automotive/remoteaccess/hal/default/Android.bp
@@ -51,15 +51,22 @@
 cc_binary {
     name: "android.hardware.automotive.remoteaccess@V2-default-service",
     defaults: ["remote-access-hal-defaults"],
-    vintf_fragments: ["remoteaccess-default-service.xml"],
     init_rc: ["remoteaccess-default-service.rc"],
+    vintf_fragment_modules: ["remoteaccess-default-service.xml"],
+
 }
 
 cc_binary {
     name: "android.hardware.automotive.remoteaccess@V2-tcu-test-service",
     defaults: ["remote-access-hal-defaults"],
-    vintf_fragments: ["remoteaccess-default-service.xml"],
     init_rc: ["remoteaccess-tcu-test-service.rc"],
+    vintf_fragment_modules: ["remoteaccess-default-service.xml"],
+}
+
+vintf_fragment {
+    name: "remoteaccess-default-service.xml",
+    src: "remoteaccess-default-service.xml",
+    vendor: true,
 }
 
 cc_library {
diff --git a/automotive/vehicle/Android.bp b/automotive/vehicle/Android.bp
index e614937..606e108 100644
--- a/automotive/vehicle/Android.bp
+++ b/automotive/vehicle/Android.bp
@@ -22,7 +22,7 @@
     name: "VehicleHalInterfaceDefaults",
     static_libs: [
         "android.hardware.automotive.vehicle-V3-ndk",
-        "android.hardware.automotive.vehicle.property-V3-ndk",
+        "android.hardware.automotive.vehicle.property-V4-ndk",
     ],
 }
 
@@ -30,6 +30,14 @@
     name: "VehicleHalInterfaceRustDefaults",
     rustlibs: [
         "android.hardware.automotive.vehicle-V3-rust",
-        "android.hardware.automotive.vehicle.property-V3-rust",
+        "android.hardware.automotive.vehicle.property-V4-rust",
+    ],
+}
+
+aidl_interface_defaults {
+    name: "android.hardware.automotive.vehicle-latest-defaults",
+    imports: [
+        "android.hardware.automotive.vehicle-V3",
+        "android.hardware.automotive.vehicle.property-V4",
     ],
 }
diff --git a/automotive/vehicle/aidl/aidl_test/Android.bp b/automotive/vehicle/aidl/aidl_test/Android.bp
index f517df8..1e43070 100644
--- a/automotive/vehicle/aidl/aidl_test/Android.bp
+++ b/automotive/vehicle/aidl/aidl_test/Android.bp
@@ -40,7 +40,7 @@
 cc_test {
     name: "VehiclePropertyAnnotationCppTest",
     srcs: ["VehiclePropertyAnnotationCppTest.cpp"],
-    header_libs: ["IVehicleGeneratedHeaders-V3"],
+    header_libs: ["IVehicleGeneratedHeaders-V4"],
     defaults: ["VehicleHalInterfaceDefaults"],
     test_suites: ["general-tests"],
 }
@@ -49,11 +49,11 @@
     name: "VehiclePropertyAnnotationJavaTest",
     srcs: [
         "VehiclePropertyAnnotationJavaTest.java",
-        ":IVehicleGeneratedJavaFiles-V3",
+        ":IVehicleGeneratedJavaFiles-V4",
     ],
     static_libs: [
         "android.hardware.automotive.vehicle-V3-java",
-        "android.hardware.automotive.vehicle.property-V3-java",
+        "android.hardware.automotive.vehicle.property-V4-java",
         "androidx.test.runner",
         "truth",
     ],
diff --git a/automotive/vehicle/aidl/generated_lib/3/cpp/AccessForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/3/cpp/AccessForVehicleProperty.h
index 51a3025..6f6c91c 100644
--- a/automotive/vehicle/aidl/generated_lib/3/cpp/AccessForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/3/cpp/AccessForVehicleProperty.h
@@ -27,6 +27,10 @@
 #include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
 #include <aidl/android/hardware/automotive/vehicle/VehiclePropertyAccess.h>
 
+// Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+#include <PerDisplayMaxBrightness.h>
+// End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+
 #include <unordered_map>
 
 namespace aidl {
@@ -302,6 +306,9 @@
         {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},
+        // Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+        {PER_DISPLAY_MAX_BRIGHTNESS, VehiclePropertyAccess::READ},
+        // End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/generated_lib/3/cpp/ChangeModeForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/3/cpp/ChangeModeForVehicleProperty.h
index 60e9a72..88f2f88 100644
--- a/automotive/vehicle/aidl/generated_lib/3/cpp/ChangeModeForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/3/cpp/ChangeModeForVehicleProperty.h
@@ -27,6 +27,10 @@
 #include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
 #include <aidl/android/hardware/automotive/vehicle/VehiclePropertyChangeMode.h>
 
+// Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+#include <PerDisplayMaxBrightness.h>
+// End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+
 #include <unordered_map>
 
 namespace aidl {
@@ -302,6 +306,9 @@
         {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},
+        // Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+        {PER_DISPLAY_MAX_BRIGHTNESS, VehiclePropertyChangeMode::STATIC},
+        // End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
 };
 
 }  // namespace vehicle
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/automotive/vehicle/aidl/generated_lib/3/cpp/PerDisplayMaxBrightness.h
similarity index 62%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
copy to automotive/vehicle/aidl/generated_lib/3/cpp/PerDisplayMaxBrightness.h
index c7be950..2b50db3 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ b/automotive/vehicle/aidl/generated_lib/3/cpp/PerDisplayMaxBrightness.h
@@ -14,22 +14,13 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+#pragma once
 
-import android.hardware.biometrics.fingerprint.AcquiredInfo;
+#include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
 
-/**
- * @hide
- */
-@VintfStability
-union AcquiredInfoAndVendorCode {
-    /**
-     * Acquired info as specified in AcqauiredInfo.aidl
-     */
-    AcquiredInfo acquiredInfo = AcquiredInfo.UNKNOWN;
+namespace aidl::android::hardware::automotive::vehicle {
 
-    /**
-     * Vendor specific code
-     */
-    int vendorCode;
-}
+// Same as VehicleProperty::PER_DISPLAY_MAX_BRIGHTNESS as defined in v4.
+static constexpr VehicleProperty PER_DISPLAY_MAX_BRIGHTNESS = (VehicleProperty)0x11410F4E;
+
+}  // namespace aidl::android::hardware::automotive::vehicle
diff --git a/automotive/vehicle/aidl/generated_lib/3/cpp/VersionForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/3/cpp/VersionForVehicleProperty.h
index 0e80bd8..0d24273 100644
--- a/automotive/vehicle/aidl/generated_lib/3/cpp/VersionForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/3/cpp/VersionForVehicleProperty.h
@@ -26,6 +26,10 @@
 
 #include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
 
+// Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+#include <PerDisplayMaxBrightness.h>
+// End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+
 #include <unordered_map>
 
 namespace aidl {
@@ -301,6 +305,9 @@
         {VehicleProperty::CROSS_TRAFFIC_MONITORING_WARNING_STATE, 3},
         {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED, 3},
         {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, 3},
+        // Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+        {PER_DISPLAY_MAX_BRIGHTNESS, 2},
+        // End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/generated_lib/3/java/AccessForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/3/java/AccessForVehicleProperty.java
index afb6cab..f899df8 100644
--- a/automotive/vehicle/aidl/generated_lib/3/java/AccessForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/3/java/AccessForVehicleProperty.java
@@ -28,6 +28,10 @@
 
 public final class AccessForVehicleProperty {
 
+    // Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+    private static final int PER_DISPLAY_MAX_BRIGHTNESS = 0x11410F4E;
+    // End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+
     public static final Map<Integer, Integer> values = Map.ofEntries(
         Map.entry(VehicleProperty.INFO_VIN, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.INFO_MAKE, VehiclePropertyAccess.READ),
@@ -294,7 +298,10 @@
         Map.entry(VehicleProperty.CROSS_TRAFFIC_MONITORING_ENABLED, VehiclePropertyAccess.READ_WRITE),
         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)
+        Map.entry(VehicleProperty.LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyAccess.READ),
+        // Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+        Map.entry(PER_DISPLAY_MAX_BRIGHTNESS, VehiclePropertyAccess.READ)
+        // End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
     );
 
 }
diff --git a/automotive/vehicle/aidl/generated_lib/3/java/ChangeModeForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/3/java/ChangeModeForVehicleProperty.java
index 12aff40..09989bf 100644
--- a/automotive/vehicle/aidl/generated_lib/3/java/ChangeModeForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/3/java/ChangeModeForVehicleProperty.java
@@ -28,6 +28,10 @@
 
 public final class ChangeModeForVehicleProperty {
 
+    // Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+    private static final int PER_DISPLAY_MAX_BRIGHTNESS = 0x11410F4E;
+    // End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+
     public static final Map<Integer, Integer> values = Map.ofEntries(
         Map.entry(VehicleProperty.INFO_VIN, VehiclePropertyChangeMode.STATIC),
         Map.entry(VehicleProperty.INFO_MAKE, VehiclePropertyChangeMode.STATIC),
@@ -294,7 +298,10 @@
         Map.entry(VehicleProperty.CROSS_TRAFFIC_MONITORING_ENABLED, 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)
+        Map.entry(VehicleProperty.LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyChangeMode.ON_CHANGE),
+        // Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+        Map.entry(PER_DISPLAY_MAX_BRIGHTNESS, VehiclePropertyChangeMode.STATIC)
+        // End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
     );
 
 }
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp
index 28c95ce..aef2909 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp
@@ -27,7 +27,7 @@
     defaults: ["VehicleHalDefaults"],
     static_libs: ["VehicleHalUtils"],
     header_libs: [
-        "IVehicleGeneratedHeaders-V3",
+        "IVehicleGeneratedHeaders-V4",
     ],
     shared_libs: ["libjsoncpp"],
 }
@@ -44,7 +44,7 @@
     defaults: ["VehicleHalDefaults"],
     static_libs: ["VehicleHalUtils"],
     header_libs: [
-        "IVehicleGeneratedHeaders-V3",
+        "IVehicleGeneratedHeaders-V4",
         "libbinder_headers",
     ],
     cflags: ["-DENABLE_VEHICLE_HAL_TEST_PROPERTIES"],
@@ -60,7 +60,7 @@
     defaults: ["VehicleHalDefaults"],
     static_libs: ["VehicleHalUtils"],
     header_libs: [
-        "IVehicleGeneratedHeaders-V3",
+        "IVehicleGeneratedHeaders-V4",
     ],
     shared_libs: ["libjsoncpp"],
 }
diff --git a/automotive/vehicle/aidl/impl/default_config/test/Android.bp b/automotive/vehicle/aidl/impl/default_config/test/Android.bp
index 70933be..52014fb 100644
--- a/automotive/vehicle/aidl/impl/default_config/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/default_config/test/Android.bp
@@ -31,7 +31,7 @@
         "libgtest",
     ],
     header_libs: [
-        "IVehicleGeneratedHeaders-V3",
+        "IVehicleGeneratedHeaders-V4",
     ],
     shared_libs: [
         "libjsoncpp",
@@ -57,7 +57,7 @@
         "-DENABLE_VEHICLE_HAL_TEST_PROPERTIES",
     ],
     header_libs: [
-        "IVehicleGeneratedHeaders-V3",
+        "IVehicleGeneratedHeaders-V4",
     ],
     shared_libs: [
         "libjsoncpp",
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
index 201ddb0..8750375 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
@@ -276,6 +276,7 @@
     return {
             .callerShouldDumpState = protoDumpResult.caller_should_dump_state(),
             .buffer = protoDumpResult.buffer(),
+            .refreshPropertyConfigs = protoDumpResult.refresh_property_configs(),
     };
 }
 
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
index d7cbe1b..7697c03 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
@@ -226,6 +226,7 @@
     auto dumpResult = mHardware->dump(dumpOptionStrings);
     result->set_caller_should_dump_state(dumpResult.callerShouldDumpState);
     result->set_buffer(dumpResult.buffer);
+    result->set_refresh_property_configs(dumpResult.refreshPropertyConfigs);
     return ::grpc::Status::OK;
 }
 
diff --git a/automotive/vehicle/aidl/impl/proto/Android.bp b/automotive/vehicle/aidl/impl/proto/Android.bp
index b2edf75..1d35e0c 100644
--- a/automotive/vehicle/aidl/impl/proto/Android.bp
+++ b/automotive/vehicle/aidl/impl/proto/Android.bp
@@ -106,3 +106,17 @@
         "-Wno-unused-parameter",
     ],
 }
+
+rust_protobuf {
+    name: "libvehicle_hal_property_protos",
+    crate_name: "vehicle_hal_property_protos",
+    protos: [":VehicleHalProtoFiles"],
+    source_stem: "vehicle_hal_property_protos",
+    host_supported: true,
+    vendor_available: true,
+    product_available: true,
+    exported_include_dirs: ["."],
+    proto_flags: [
+        "-I external/protobuf/src",
+    ],
+}
diff --git a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/DumpResult.proto b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/DumpResult.proto
index 25bb7d4..fbfb505 100644
--- a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/DumpResult.proto
+++ b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/DumpResult.proto
@@ -25,4 +25,6 @@
     bool caller_should_dump_state = 1;
     /* The dumped information for the caller to print. */
     string buffer = 2;
+    /* To pass if DefaultVehicleHal should refresh the property configs. */
+    bool refresh_property_configs = 3;
 }
diff --git a/automotive/vehicle/aidl/impl/vhal/Android.bp b/automotive/vehicle/aidl/impl/vhal/Android.bp
index 5cc071d..54d148e 100644
--- a/automotive/vehicle/aidl/impl/vhal/Android.bp
+++ b/automotive/vehicle/aidl/impl/vhal/Android.bp
@@ -66,7 +66,7 @@
     ],
     header_libs: [
         "IVehicleHardware",
-        "IVehicleGeneratedHeaders-V3",
+        "IVehicleGeneratedHeaders-V4",
     ],
     shared_libs: [
         "libbinder_ndk",
diff --git a/automotive/vehicle/tools/generate_emu_metadata/src/com/android/car/tool/EmuMetadataGenerator.java b/automotive/vehicle/tools/generate_emu_metadata/src/com/android/car/tool/EmuMetadataGenerator.java
index bea5951..7f4ceb8 100644
--- a/automotive/vehicle/tools/generate_emu_metadata/src/com/android/car/tool/EmuMetadataGenerator.java
+++ b/automotive/vehicle/tools/generate_emu_metadata/src/com/android/car/tool/EmuMetadataGenerator.java
@@ -79,17 +79,18 @@
             + "either this or input_files must be specified\n" + INPUT_FILES_OPTION
             + ": one or more Java files, this is used to decide the input "
             + "directory\n" + PACKAGE_NAME_OPTION
-            + ": the optional package name for the interface, by default is " + DEFAULT_PACKAGE_NAME
-            + "\n" + OUTPUT_JSON_OPTION + ": The output JSON file\n" + OUTPUT_EMPTY_FILE_OPTION
-            + ": Only used for check_mode, this file will be created if "
+            + ": the optional package name for the interface, by default is "
+            + DEFAULT_PACKAGE_NAME + "\n" + OUTPUT_JSON_OPTION + ": The output JSON file\n"
+            + OUTPUT_EMPTY_FILE_OPTION + ": Only used for check_mode, this file will be created if "
             + "check  passed\n" + CHECK_AGAINST_OPTION
             + ": An optional JSON file to check against. If specified, the "
-            + "generated output file will be checked against this file, if they are not the same, "
+            + ("generated output file will be checked against this file, if they are not the "
+                    + "same, ")
             + "the script will fail, otherwise, the output_empty_file will be created\n"
             + "For example: \n"
             + "EnumMetadataGenerator --input_dir out/soong/.intermediates/hardware/"
             + "interfaces/automotive/vehicle/aidl_property/android.hardware.automotive.vehicle."
-            + "property-V3-java-source/gen/ --package_name android.hardware.automotive.vehicle "
+            + "property-V4-java-source/gen/ --package_name android.hardware.automotive.vehicle "
             + "--output_json /tmp/android.hardware.automotive.vehicle-types-meta.json";
     private static final String VEHICLE_PROPERTY_FILE = "VehicleProperty.java";
     private static final String CHECK_FILE_PATH =
diff --git a/automotive/vehicle/vhal_static_cpp_lib.mk b/automotive/vehicle/vhal_static_cpp_lib.mk
index 6b3d486..9371453 100644
--- a/automotive/vehicle/vhal_static_cpp_lib.mk
+++ b/automotive/vehicle/vhal_static_cpp_lib.mk
@@ -17,4 +17,4 @@
 
 LOCAL_STATIC_LIBRARIES += \
     android.hardware.automotive.vehicle-V3-ndk \
-    android.hardware.automotive.vehicle.property-V3-ndk
+    android.hardware.automotive.vehicle.property-V4-ndk
diff --git a/automotive/vehicle/vts/Android.bp b/automotive/vehicle/vts/Android.bp
index 40aec59..433ac41 100644
--- a/automotive/vehicle/vts/Android.bp
+++ b/automotive/vehicle/vts/Android.bp
@@ -43,7 +43,7 @@
         "vhalclient_defaults",
     ],
     header_libs: [
-        "IVehicleGeneratedHeaders-V3",
+        "IVehicleGeneratedHeaders-V4",
     ],
     test_suites: [
         "general-tests",
diff --git a/biometrics/common/aidl/Android.bp b/biometrics/common/aidl/Android.bp
index 246bcf2..854bd4a 100644
--- a/biometrics/common/aidl/Android.bp
+++ b/biometrics/common/aidl/Android.bp
@@ -22,6 +22,12 @@
         cpp: {
             enabled: false,
         },
+        ndk: {
+            apex_available: [
+                "//apex_available:anyapex",
+                "//apex_available:platform",
+            ],
+        },
     },
     versions_with_info: [
         {
diff --git a/biometrics/common/config/Android.bp b/biometrics/common/config/Android.bp
index d38ffe8..b86aafa 100644
--- a/biometrics/common/config/Android.bp
+++ b/biometrics/common/config/Android.bp
@@ -22,7 +22,7 @@
     //   SPDX-license-identifier-Apache-2.0
     name: "android.hardware.biometrics.common.config",
     export_include_dirs: ["include"],
-    vendor: true,
+    vendor_available: true,
     srcs: [
         "Config.cpp",
     ],
@@ -30,6 +30,10 @@
         "libbase",
         "libbinder_ndk",
     ],
+    apex_available: [
+        "//apex_available:anyapex",
+        "//apex_available:platform",
+    ],
 }
 
 cc_test_host {
diff --git a/biometrics/common/thread/Android.bp b/biometrics/common/thread/Android.bp
index e7a7e4c..c1ebe3b 100644
--- a/biometrics/common/thread/Android.bp
+++ b/biometrics/common/thread/Android.bp
@@ -10,10 +10,14 @@
     //   SPDX-license-identifier-Apache-2.0
     name: "android.hardware.biometrics.common.thread",
     export_include_dirs: ["include"],
-    vendor: true,
+    vendor_available: true,
     srcs: [
         "WorkerThread.cpp",
     ],
+    apex_available: [
+        "//apex_available:anyapex",
+        "//apex_available:platform",
+    ],
 }
 
 cc_test_host {
diff --git a/biometrics/common/util/Android.bp b/biometrics/common/util/Android.bp
index 599c491..a0bd211 100644
--- a/biometrics/common/util/Android.bp
+++ b/biometrics/common/util/Android.bp
@@ -6,7 +6,7 @@
     //   SPDX-license-identifier-Apache-2.0
     name: "android.hardware.biometrics.common.util",
     export_include_dirs: ["include"],
-    vendor: true,
+    vendor_available: true,
     srcs: [
         "CancellationSignal.cpp",
     ],
@@ -15,4 +15,8 @@
         "libbinder_ndk",
         "android.hardware.biometrics.common-V4-ndk",
     ],
+    apex_available: [
+        "//apex_available:anyapex",
+        "//apex_available:platform",
+    ],
 }
diff --git a/biometrics/fingerprint/aidl/Android.bp b/biometrics/fingerprint/aidl/Android.bp
index a395c01..c5b9937 100644
--- a/biometrics/fingerprint/aidl/Android.bp
+++ b/biometrics/fingerprint/aidl/Android.bp
@@ -11,7 +11,7 @@
     name: "android.hardware.biometrics.fingerprint",
     vendor_available: true,
     srcs: [
-        "android/hardware/biometrics/fingerprint/**/*.aidl",
+        "android/hardware/biometrics/fingerprint/*.aidl",
     ],
     imports: [
         "android.hardware.biometrics.common-V4",
@@ -25,6 +25,12 @@
         cpp: {
             enabled: false,
         },
+        ndk: {
+            apex_available: [
+                "//apex_available:platform",
+                "//apex_available:anyapex",
+            ],
+        },
     },
     versions_with_info: [
         {
@@ -57,5 +63,34 @@
         },
 
     ],
+    frozen: true,
+}
+
+aidl_interface {
+    name: "android.hardware.biometrics.fingerprint.virtualhal",
+    srcs: [
+        "android/hardware/biometrics/fingerprint/virtualhal/*.aidl",
+    ],
+    imports: [
+        "android.hardware.biometrics.common-V4",
+        "android.hardware.keymaster-V4",
+        "android.hardware.biometrics.fingerprint-V4",
+    ],
+    vendor_available: true,
+    unstable: true,
+    backend: {
+        java: {
+            platform_apis: true,
+        },
+        cpp: {
+            enabled: false,
+        },
+        ndk: {
+            apex_available: [
+                "com.android.hardware.biometrics.fingerprint.virtual",
+                "//apex_available:platform",
+            ],
+        },
+    },
     frozen: false,
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
deleted file mode 100644
index c1dc51c..0000000
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file built
-// with the aidl_interface module type with versions property set. The module
-// type is used to build AIDL files in a way that they can be used across
-// independently updatable components of the system. If a device is shipped
-// with such a backward incompatible change, it has a high risk of breaking
-// later when a module using the interface is updated, e.g., Mainline modules.
-
-package android.hardware.biometrics.fingerprint;
-/* @hide */
-@VintfStability
-union AcquiredInfoAndVendorCode {
-  android.hardware.biometrics.fingerprint.AcquiredInfo acquiredInfo = android.hardware.biometrics.fingerprint.AcquiredInfo.UNKNOWN;
-  int vendorCode;
-}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IVirtualHal.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IVirtualHal.aidl
deleted file mode 100644
index 33ae83c..0000000
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IVirtualHal.aidl
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file built
-// with the aidl_interface module type with versions property set. The module
-// type is used to build AIDL files in a way that they can be used across
-// independently updatable components of the system. If a device is shipped
-// with such a backward incompatible change, it has a high risk of breaking
-// later when a module using the interface is updated, e.g., Mainline modules.
-
-package android.hardware.biometrics.fingerprint;
-/* @hide */
-@VintfStability
-interface IVirtualHal {
-  oneway void setEnrollments(in int[] id);
-  oneway void setEnrollmentHit(in int hit_id);
-  oneway void setNextEnrollment(in android.hardware.biometrics.fingerprint.NextEnrollment next_enrollment);
-  oneway void setAuthenticatorId(in long id);
-  oneway void setChallenge(in long challenge);
-  oneway void setOperationAuthenticateFails(in boolean fail);
-  oneway void setOperationAuthenticateLatency(in int[] latencyMs);
-  oneway void setOperationAuthenticateDuration(in int durationMs);
-  oneway void setOperationAuthenticateError(in int error);
-  oneway void setOperationAuthenticateAcquired(in android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquired);
-  oneway void setOperationEnrollError(in int error);
-  oneway void setOperationEnrollLatency(in int[] latencyMs);
-  oneway void setOperationDetectInteractionLatency(in int[] latencyMs);
-  oneway void setOperationDetectInteractionError(in int error);
-  oneway void setOperationDetectInteractionDuration(in int durationMs);
-  oneway void setOperationDetectInteractionAcquired(in android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquired);
-  oneway void setLockout(in boolean lockout);
-  oneway void setLockoutEnable(in boolean enable);
-  oneway void setLockoutTimedThreshold(in int threshold);
-  oneway void setLockoutTimedDuration(in int durationMs);
-  oneway void setLockoutPermanentThreshold(in int threshold);
-  oneway void resetConfigurations();
-  oneway void setType(in android.hardware.biometrics.fingerprint.FingerprintSensorType type);
-  oneway void setSensorId(in int id);
-  oneway void setSensorStrength(in android.hardware.biometrics.common.SensorStrength strength);
-  oneway void setMaxEnrollmentPerUser(in int max);
-  oneway void setSensorLocation(in android.hardware.biometrics.fingerprint.SensorLocation loc);
-  oneway void setNavigationGuesture(in boolean v);
-  oneway void setDetectInteraction(in boolean v);
-  oneway void setDisplayTouch(in boolean v);
-  oneway void setControlIllumination(in boolean v);
-  const int STATUS_INVALID_PARAMETER = 1;
-}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/NextEnrollment.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/NextEnrollment.aidl
deleted file mode 100644
index 75ed070..0000000
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/NextEnrollment.aidl
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file built
-// with the aidl_interface module type with versions property set. The module
-// type is used to build AIDL files in a way that they can be used across
-// independently updatable components of the system. If a device is shipped
-// with such a backward incompatible change, it has a high risk of breaking
-// later when a module using the interface is updated, e.g., Mainline modules.
-
-package android.hardware.biometrics.fingerprint;
-/* @hide */
-@VintfStability
-parcelable NextEnrollment {
-  int id;
-  android.hardware.biometrics.fingerprint.EnrollmentProgressStep[] progressSteps;
-  boolean result = true;
-}
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/AcquiredInfoAndVendorCode.aidl
similarity index 93%
rename from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
rename to biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/AcquiredInfoAndVendorCode.aidl
index c7be950..1fc7221 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/AcquiredInfoAndVendorCode.aidl
@@ -14,14 +14,13 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+package android.hardware.biometrics.fingerprint.virtualhal;
 
 import android.hardware.biometrics.fingerprint.AcquiredInfo;
 
 /**
  * @hide
  */
-@VintfStability
 union AcquiredInfoAndVendorCode {
     /**
      * Acquired info as specified in AcqauiredInfo.aidl
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/EnrollmentProgressStep.aidl
similarity index 87%
rename from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
rename to biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/EnrollmentProgressStep.aidl
index bf038f6..b0b2926 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/EnrollmentProgressStep.aidl
@@ -14,14 +14,13 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+package android.hardware.biometrics.fingerprint.virtualhal;
 
-import android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode;
+import android.hardware.biometrics.fingerprint.virtualhal.AcquiredInfoAndVendorCode;
 
 /**
  * @hide
  */
-@VintfStability
 parcelable EnrollmentProgressStep {
     /**
      * The duration of the enrollment step in milli-seconds
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IVirtualHal.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/IVirtualHal.aidl
similarity index 96%
rename from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IVirtualHal.aidl
rename to biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/IVirtualHal.aidl
index cb9135e..5af84ed 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IVirtualHal.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/IVirtualHal.aidl
@@ -14,19 +14,19 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+package android.hardware.biometrics.fingerprint.virtualhal;
 
 import android.hardware.biometrics.common.SensorStrength;
-import android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode;
 import android.hardware.biometrics.fingerprint.FingerprintSensorType;
-import android.hardware.biometrics.fingerprint.NextEnrollment;
+import android.hardware.biometrics.fingerprint.IFingerprint;
 import android.hardware.biometrics.fingerprint.SensorLocation;
+import android.hardware.biometrics.fingerprint.virtualhal.AcquiredInfoAndVendorCode;
+import android.hardware.biometrics.fingerprint.virtualhal.NextEnrollment;
 
 /**
  * @hide
  */
-@VintfStability
-oneway interface IVirtualHal {
+interface IVirtualHal {
     /**
      * The operation failed due to invalid input parameters, the error messages should
      * gives more details
@@ -315,4 +315,5 @@
     void setDetectInteraction(in boolean v);
     void setDisplayTouch(in boolean v);
     void setControlIllumination(in boolean v);
+    IFingerprint getFingerprintHal();
 }
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/NextEnrollment.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/NextEnrollment.aidl
similarity index 85%
rename from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/NextEnrollment.aidl
rename to biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/NextEnrollment.aidl
index 4b50850..2d704f1 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/NextEnrollment.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/NextEnrollment.aidl
@@ -14,12 +14,13 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+package android.hardware.biometrics.fingerprint.virtualhal;
+
+import android.hardware.biometrics.fingerprint.virtualhal.EnrollmentProgressStep;
 
 /**
  * @hide
  */
-@VintfStability
 parcelable NextEnrollment {
     /**
      *  Identifier of the next enrollment if successful
@@ -31,7 +32,7 @@
      *  and sequence of acquired info codes to be generated by HAL.
      *  See EnrollmentProgressStep.aidl for more details
      */
-    android.hardware.biometrics.fingerprint.EnrollmentProgressStep[] progressSteps;
+    EnrollmentProgressStep[] progressSteps;
 
     /**
      * Success or failure of the next enrollment
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/README.md b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/README.md
new file mode 100644
index 0000000..eaf2336
--- /dev/null
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/README.md
@@ -0,0 +1,2 @@
+The aidl files in this directory are used only by fingerprint virtual hal
+which is controlled/configured via IVirtualHal interface
diff --git a/biometrics/fingerprint/aidl/default/Android.bp b/biometrics/fingerprint/aidl/default/Android.bp
index 9b72c87..faaa9c6 100644
--- a/biometrics/fingerprint/aidl/default/Android.bp
+++ b/biometrics/fingerprint/aidl/default/Android.bp
@@ -8,10 +8,9 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
-cc_binary {
-    name: "android.hardware.biometrics.fingerprint-service.example",
-    vendor: true,
-    relative_install_path: "hw",
+cc_library_static {
+    name: "android.hardware.biometrics.fingerprint-service.lib",
+    vendor_available: true,
     local_include_dirs: ["include"],
     srcs: [
         "FakeLockoutTracker.cpp",
@@ -30,22 +29,80 @@
         "libbinder_ndk",
         "liblog",
     ],
-    static_libs: [
+    whole_static_libs: [
         "libandroid.hardware.biometrics.fingerprint.VirtualProps",
         "libbase",
-        "android.hardware.biometrics.fingerprint-V5-ndk",
+        "android.hardware.biometrics.fingerprint.virtualhal-ndk",
+        "android.hardware.biometrics.fingerprint-V4-ndk",
         "android.hardware.biometrics.common-V4-ndk",
         "android.hardware.biometrics.common.thread",
         "android.hardware.biometrics.common.util",
         "android.hardware.biometrics.common.config",
         "android.hardware.keymaster-V4-ndk",
     ],
+    product_variables: {
+        debuggable: {
+            cflags: ["-DFPS_DEBUGGABLE"],
+        },
+    },
+    apex_available: [
+        "com.android.hardware.biometrics.fingerprint.virtual",
+        "//apex_available:platform",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.biometrics.fingerprint-service.example",
+    system_ext_specific: true,
+    relative_install_path: "hw",
+    local_include_dirs: ["include"],
+    srcs: [
+    ],
+    stl: "c++_static",
+    shared_libs: [
+        "libbinder_ndk",
+        "liblog",
+    ],
+    whole_static_libs: [
+        "android.hardware.biometrics.fingerprint-service.lib",
+    ],
     installable: false, // install APEX instead
     product_variables: {
         debuggable: {
             cflags: ["-DFPS_DEBUGGABLE"],
         },
     },
+    apex_available: [
+        "com.android.hardware.biometrics.fingerprint.virtual",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.biometrics.fingerprint-service.default",
+    //system_ext_specific: true,
+    vendor: true,
+    relative_install_path: "hw",
+    init_rc: ["fingerprint-default.rc"],
+    vintf_fragments: ["fingerprint-default.xml"],
+    local_include_dirs: ["include"],
+    srcs: [
+    ],
+    stl: "c++_static",
+    shared_libs: [
+        "libbinder_ndk",
+        "liblog",
+    ],
+    whole_static_libs: [
+        "android.hardware.biometrics.fingerprint-service.lib",
+    ],
+    product_variables: {
+        debuggable: {
+            cflags: ["-DFPS_DEBUGGABLE"],
+        },
+    },
+    apex_available: [
+        "//apex_available:platform",
+    ],
 }
 
 cc_test {
@@ -63,14 +120,13 @@
     ],
     static_libs: [
         "libandroid.hardware.biometrics.fingerprint.VirtualProps",
-        "android.hardware.biometrics.fingerprint-V5-ndk",
+        "android.hardware.biometrics.fingerprint-V4-ndk",
         "android.hardware.biometrics.common-V4-ndk",
         "android.hardware.keymaster-V4-ndk",
         "android.hardware.biometrics.common.util",
         "android.hardware.biometrics.common.config",
         "android.hardware.biometrics.common.thread",
     ],
-    vendor: true,
     test_suites: ["general-tests"],
     require_root: true,
 }
@@ -91,14 +147,13 @@
     ],
     static_libs: [
         "libandroid.hardware.biometrics.fingerprint.VirtualProps",
-        "android.hardware.biometrics.fingerprint-V5-ndk",
+        "android.hardware.biometrics.fingerprint-V4-ndk",
         "android.hardware.biometrics.common-V4-ndk",
         "android.hardware.keymaster-V4-ndk",
         "android.hardware.biometrics.common.util",
         "android.hardware.biometrics.common.config",
         "android.hardware.biometrics.common.thread",
     ],
-    vendor: true,
     test_suites: ["general-tests"],
     require_root: true,
 }
@@ -117,14 +172,13 @@
     ],
     static_libs: [
         "libandroid.hardware.biometrics.fingerprint.VirtualProps",
-        "android.hardware.biometrics.fingerprint-V5-ndk",
+        "android.hardware.biometrics.fingerprint-V4-ndk",
         "android.hardware.biometrics.common-V4-ndk",
         "android.hardware.keymaster-V4-ndk",
         "android.hardware.biometrics.common.util",
         "android.hardware.biometrics.common.thread",
         "android.hardware.biometrics.common.config",
     ],
-    vendor: true,
     test_suites: ["general-tests"],
     require_root: true,
 }
@@ -145,14 +199,13 @@
     ],
     static_libs: [
         "libandroid.hardware.biometrics.fingerprint.VirtualProps",
-        "android.hardware.biometrics.fingerprint-V5-ndk",
+        "android.hardware.biometrics.fingerprint-V4-ndk",
         "android.hardware.biometrics.common-V4-ndk",
         "android.hardware.keymaster-V4-ndk",
         "android.hardware.biometrics.common.util",
         "android.hardware.biometrics.common.thread",
         "android.hardware.biometrics.common.config",
     ],
-    vendor: true,
     test_suites: ["general-tests"],
     require_root: true,
 }
@@ -178,7 +231,8 @@
     ],
     static_libs: [
         "libandroid.hardware.biometrics.fingerprint.VirtualProps",
-        "android.hardware.biometrics.fingerprint-V5-ndk",
+        "android.hardware.biometrics.fingerprint-V4-ndk",
+        "android.hardware.biometrics.fingerprint.virtualhal-ndk",
         "android.hardware.biometrics.common-V4-ndk",
         "android.hardware.keymaster-V4-ndk",
         "android.hardware.biometrics.common.util",
@@ -190,7 +244,6 @@
             cflags: ["-DFPS_DEBUGGABLE"],
         },
     },
-    vendor: true,
     test_suites: ["general-tests"],
     require_root: true,
 }
@@ -198,39 +251,34 @@
 sysprop_library {
     name: "android.hardware.biometrics.fingerprint.VirtualProps",
     srcs: ["fingerprint.sysprop"],
-    property_owner: "Vendor",
-    vendor: true,
+    property_owner: "Platform",
+    vendor_available: true,
+    apex_available: [
+        "com.android.hardware.biometrics.fingerprint.virtual",
+        "//apex_available:platform",
+    ],
 }
 
 prebuilt_etc {
-    name: "fingerprint-example.rc",
-    src: "fingerprint-example.rc",
-    installable: false,
-}
-
-prebuilt_etc {
-    name: "fingerprint-example.xml",
-    src: "fingerprint-example.xml",
-    sub_dir: "vintf",
+    name: "fingerprint-virtual.rc",
+    src: "fingerprint-virtual.rc",
     installable: false,
 }
 
 apex {
     name: "com.android.hardware.biometrics.fingerprint.virtual",
     manifest: "apex_manifest.json",
-    file_contexts: "apex_file_contexts",
+    file_contexts: ":com.android.biometrics.virtual.fingerprint-file_contexts",
     key: "com.android.hardware.key",
     certificate: ":com.android.hardware.certificate",
     updatable: false,
-    vendor: true,
+    system_ext_specific: true,
 
     binaries: [
         "android.hardware.biometrics.fingerprint-service.example",
     ],
     prebuilts: [
         // init_rc
-        "fingerprint-example.rc",
-        // vintf_fragment
-        "fingerprint-example.xml",
+        "fingerprint-virtual.rc",
     ],
 }
diff --git a/biometrics/fingerprint/aidl/default/VirtualHal.cpp b/biometrics/fingerprint/aidl/default/VirtualHal.cpp
index e107d2f..d161765 100644
--- a/biometrics/fingerprint/aidl/default/VirtualHal.cpp
+++ b/biometrics/fingerprint/aidl/default/VirtualHal.cpp
@@ -26,7 +26,7 @@
 #define LOG_TAG "FingerprintVirtualHalAidl"
 
 namespace aidl::android::hardware::biometrics::fingerprint {
-
+using AcquiredInfoAndVendorCode = virtualhal::AcquiredInfoAndVendorCode;
 using Tag = AcquiredInfoAndVendorCode::Tag;
 
 ::ndk::ScopedAStatus VirtualHal::setEnrollments(const std::vector<int32_t>& enrollments) {
@@ -41,8 +41,7 @@
     return ndk::ScopedAStatus::ok();
 }
 
-::ndk::ScopedAStatus VirtualHal::setNextEnrollment(
-        const ::aidl::android::hardware::biometrics::fingerprint::NextEnrollment& next_enrollment) {
+::ndk::ScopedAStatus VirtualHal::setNextEnrollment(const NextEnrollment& next_enrollment) {
     Fingerprint::cfg().sourcedFromAidl();
     std::ostringstream os;
     os << next_enrollment.id << ":";
@@ -333,4 +332,10 @@
     return ndk::ScopedAStatus::ok();
 }
 
+::ndk::ScopedAStatus VirtualHal::getFingerprintHal(
+        std::shared_ptr<::aidl::android::hardware::biometrics::fingerprint::IFingerprint>* pFp) {
+    LOG(INFO) << " calling getFingerprintHal in VirtualHal.cpp";
+    *pFp = mFp;
+    return ndk::ScopedAStatus::ok();
+}
 }  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/api/android.hardware.biometrics.fingerprint.VirtualProps-current.txt b/biometrics/fingerprint/aidl/default/api/android.hardware.biometrics.fingerprint.VirtualProps-current.txt
index e69de29..8c02a68 100644
--- a/biometrics/fingerprint/aidl/default/api/android.hardware.biometrics.fingerprint.VirtualProps-current.txt
+++ b/biometrics/fingerprint/aidl/default/api/android.hardware.biometrics.fingerprint.VirtualProps-current.txt
@@ -0,0 +1,178 @@
+props {
+  owner: Vendor
+  module: "android.fingerprint.virt.FingerprintHalProperties"
+  prop {
+    api_name: "authenticator_id"
+    type: Long
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.authenticator_id"
+  }
+  prop {
+    api_name: "challenge"
+    type: Long
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.challenge"
+  }
+  prop {
+    api_name: "control_illumination"
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.udfps.control_illumination"
+  }
+  prop {
+    api_name: "detect_interaction"
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.detect_interaction"
+  }
+  prop {
+    api_name: "display_touch"
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.udfps.display_touch"
+  }
+  prop {
+    api_name: "enrollment_hit"
+    type: Integer
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.enrollment_hit"
+  }
+  prop {
+    api_name: "enrollments"
+    type: IntegerList
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.enrollments"
+  }
+  prop {
+    api_name: "lockout"
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.lockout"
+  }
+  prop {
+    api_name: "lockout_enable"
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.lockout_enable"
+  }
+  prop {
+    api_name: "lockout_permanent_threshold"
+    type: Integer
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.lockout_permanent_threshold"
+  }
+  prop {
+    api_name: "lockout_timed_duration"
+    type: Integer
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.lockout_timed_duration"
+  }
+  prop {
+    api_name: "lockout_timed_threshold"
+    type: Integer
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.lockout_timed_threshold"
+  }
+  prop {
+    api_name: "max_enrollments"
+    type: Integer
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.max_enrollments"
+  }
+  prop {
+    api_name: "navigation_guesture"
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.navigation_guesture"
+  }
+  prop {
+    api_name: "next_enrollment"
+    type: String
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.next_enrollment"
+  }
+  prop {
+    api_name: "operation_authenticate_acquired"
+    type: String
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_authenticate_acquired"
+  }
+  prop {
+    api_name: "operation_authenticate_duration"
+    type: Integer
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_authenticate_duration"
+  }
+  prop {
+    api_name: "operation_authenticate_error"
+    type: Integer
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_authenticate_error"
+  }
+  prop {
+    api_name: "operation_authenticate_fails"
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_authenticate_fails"
+  }
+  prop {
+    api_name: "operation_authenticate_latency"
+    type: IntegerList
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_authenticate_latency"
+  }
+  prop {
+    api_name: "operation_detect_interaction_acquired"
+    type: String
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_acquired"
+  }
+  prop {
+    api_name: "operation_detect_interaction_duration"
+    type: Integer
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_duration"
+  }
+  prop {
+    api_name: "operation_detect_interaction_error"
+    type: Integer
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_error"
+  }
+  prop {
+    api_name: "operation_detect_interaction_latency"
+    type: IntegerList
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_latency"
+  }
+  prop {
+    api_name: "operation_enroll_error"
+    type: Integer
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_enroll_error"
+  }
+  prop {
+    api_name: "operation_enroll_latency"
+    type: IntegerList
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_enroll_latency"
+  }
+  prop {
+    api_name: "sensor_id"
+    type: Integer
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.sensor_id"
+  }
+  prop {
+    api_name: "sensor_location"
+    type: String
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.sensor_location"
+  }
+  prop {
+    api_name: "sensor_strength"
+    type: Integer
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.sensor_strength"
+  }
+  prop {
+    api_name: "type"
+    type: String
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.type"
+    enum_values: "default|rear|udfps|side"
+  }
+}
diff --git a/biometrics/fingerprint/aidl/default/fingerprint-default.rc b/biometrics/fingerprint/aidl/default/fingerprint-default.rc
new file mode 100644
index 0000000..7e46bc1
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/fingerprint-default.rc
@@ -0,0 +1,7 @@
+service vendor.fingerprint-default /vendor/bin/hw/android.hardware.biometrics.fingerprint-service.default default
+    class hal
+    user nobody
+    group nobody
+    interface aidl android.hardware.biometrics.fingerprint.IFingerprint/default
+    oneshot
+    disabled
diff --git a/biometrics/fingerprint/aidl/default/fingerprint-default.xml b/biometrics/fingerprint/aidl/default/fingerprint-default.xml
new file mode 100644
index 0000000..d140459
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/fingerprint-default.xml
@@ -0,0 +1,10 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.biometrics.fingerprint</name>
+        <version>4</version>
+        <interface>
+          <name>IFingerprint</name>
+          <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/biometrics/fingerprint/aidl/default/fingerprint-example.rc b/biometrics/fingerprint/aidl/default/fingerprint-example.rc
deleted file mode 100644
index da4ea45..0000000
--- a/biometrics/fingerprint/aidl/default/fingerprint-example.rc
+++ /dev/null
@@ -1,7 +0,0 @@
-service vendor.fingerprint-example /apex/com.android.hardware.biometrics.fingerprint.virtual/bin/hw/android.hardware.biometrics.fingerprint-service.example
-    class hal
-    user nobody
-    group nobody
-    interface aidl android.hardware.biometrics.fingerprint.IFingerprint/virtual
-    oneshot
-    disabled
diff --git a/biometrics/fingerprint/aidl/default/fingerprint-example.xml b/biometrics/fingerprint/aidl/default/fingerprint-example.xml
deleted file mode 100644
index ee529e9..0000000
--- a/biometrics/fingerprint/aidl/default/fingerprint-example.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<manifest version="1.0" type="device">
-    <hal format="aidl">
-        <name>android.hardware.biometrics.fingerprint</name>
-        <version>5</version>
-        <fqname>IFingerprint/virtual</fqname>
-    </hal>
-</manifest>
diff --git a/biometrics/fingerprint/aidl/default/fingerprint-virtual.rc b/biometrics/fingerprint/aidl/default/fingerprint-virtual.rc
new file mode 100644
index 0000000..5d1506c
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/fingerprint-virtual.rc
@@ -0,0 +1,7 @@
+service fingerprint-virtual /apex/com.android.hardware.biometrics.fingerprint.virtual/bin/hw/android.hardware.biometrics.fingerprint-service.example virtual
+    class hal
+    user nobody
+    group nobody
+    interface aidl android.hardware.biometrics.fingerprint.virtualhal.IVirtualHal/virtual
+    oneshot
+    disabled
diff --git a/biometrics/fingerprint/aidl/default/fingerprint.sysprop b/biometrics/fingerprint/aidl/default/fingerprint.sysprop
index 6a6c297..eb33432 100644
--- a/biometrics/fingerprint/aidl/default/fingerprint.sysprop
+++ b/biometrics/fingerprint/aidl/default/fingerprint.sysprop
@@ -7,7 +7,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.type"
     type: String
-    scope: Internal
+    scope: Public
     access: ReadWrite
     enum_values: "default|rear|udfps|side"
     api_name: "type"
@@ -17,7 +17,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.enrollments"
     type: IntegerList
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "enrollments"
 }
@@ -27,7 +27,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.enrollment_hit"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "enrollment_hit"
 }
@@ -42,7 +42,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.next_enrollment"
     type: String
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "next_enrollment"
 }
@@ -51,7 +51,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.authenticator_id"
     type: Long
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "authenticator_id"
 }
@@ -60,7 +60,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.challenge"
     type: Long
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "challenge"
 }
@@ -69,7 +69,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_authenticate_fails"
     type: Boolean
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_authenticate_fails"
 }
@@ -82,7 +82,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_error"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_detect_interaction_error"
 }
@@ -91,7 +91,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_enroll_error"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_enroll_error"
 }
@@ -104,7 +104,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_authenticate_latency"
     type: IntegerList
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_authenticate_latency"
 }
@@ -114,7 +114,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_latency"
     type: IntegerList
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_detect_interaction_latency"
 }
@@ -124,7 +124,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_enroll_latency"
     type: IntegerList
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_enroll_latency"
 }
@@ -134,7 +134,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_authenticate_duration"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_authenticate_duration"
 }
@@ -143,7 +143,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_authenticate_error"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_authenticate_error"
 }
@@ -153,7 +153,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.sensor_location"
     type: String
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "sensor_location"
 }
@@ -162,7 +162,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_authenticate_acquired"
     type: String
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_authenticate_acquired"
 }
@@ -172,7 +172,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_duration"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_detect_interaction_duration"
 }
@@ -184,7 +184,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_acquired"
     type: String
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_detect_interaction_acquired"
 }
@@ -193,7 +193,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.sensor_id"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "sensor_id"
 }
@@ -203,7 +203,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.sensor_strength"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "sensor_strength"
 }
@@ -213,7 +213,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.max_enrollments"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "max_enrollments"
 }
@@ -222,7 +222,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.navigation_guesture"
     type: Boolean
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "navigation_guesture"
 }
@@ -231,7 +231,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.detect_interaction"
     type: Boolean
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "detect_interaction"
 }
@@ -240,7 +240,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.udfps.display_touch"
     type: Boolean
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "display_touch"
 }
@@ -249,7 +249,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.udfps.control_illumination"
     type: Boolean
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "control_illumination"
 }
@@ -258,7 +258,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.lockout"
     type: Boolean
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "lockout"
 }
@@ -267,7 +267,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.lockout_enable"
     type: Boolean
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "lockout_enable"
 }
@@ -276,7 +276,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.lockout_timed_threshold"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "lockout_timed_threshold"
 }
@@ -285,7 +285,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.lockout_timed_duration"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "lockout_timed_duration"
 }
@@ -294,7 +294,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.lockout_permanent_threshold"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "lockout_permanent_threshold"
 }
diff --git a/biometrics/fingerprint/aidl/default/include/VirtualHal.h b/biometrics/fingerprint/aidl/default/include/VirtualHal.h
index e5f62fc..5488383 100644
--- a/biometrics/fingerprint/aidl/default/include/VirtualHal.h
+++ b/biometrics/fingerprint/aidl/default/include/VirtualHal.h
@@ -16,21 +16,21 @@
 
 #pragma once
 
-#include <aidl/android/hardware/biometrics/fingerprint/BnVirtualHal.h>
+#include <aidl/android/hardware/biometrics/fingerprint/virtualhal/BnVirtualHal.h>
 
 #include "Fingerprint.h"
 
 namespace aidl::android::hardware::biometrics::fingerprint {
 
+using namespace virtualhal;
+
 class VirtualHal : public BnVirtualHal {
   public:
-    VirtualHal(Fingerprint* fp) : mFp(fp) {}
+    VirtualHal(std::shared_ptr<Fingerprint> fp) : mFp(fp) {}
 
     ::ndk::ScopedAStatus setEnrollments(const std::vector<int32_t>& in_id) override;
     ::ndk::ScopedAStatus setEnrollmentHit(int32_t in_hit_id) override;
-    ::ndk::ScopedAStatus setNextEnrollment(
-            const ::aidl::android::hardware::biometrics::fingerprint::NextEnrollment&
-                    in_next_enrollment) override;
+    ::ndk::ScopedAStatus setNextEnrollment(const NextEnrollment& in_next_enrollment) override;
     ::ndk::ScopedAStatus setAuthenticatorId(int64_t in_id) override;
     ::ndk::ScopedAStatus setChallenge(int64_t in_challenge) override;
     ::ndk::ScopedAStatus setOperationAuthenticateFails(bool in_fail) override;
@@ -67,12 +67,15 @@
     ::ndk::ScopedAStatus setDetectInteraction(bool in_v) override;
     ::ndk::ScopedAStatus setDisplayTouch(bool in_v) override;
     ::ndk::ScopedAStatus setControlIllumination(bool in_v) override;
+    ::ndk::ScopedAStatus getFingerprintHal(
+            std::shared_ptr<::aidl::android::hardware::biometrics::fingerprint::IFingerprint>*
+                    _aidl_return);
 
   private:
     OptIntVec intVec2OptIntVec(const std::vector<int32_t>& intVec);
     OptIntVec acquiredInfoVec2OptIntVec(const std::vector<AcquiredInfoAndVendorCode>& intVec);
     ::ndk::ScopedAStatus sanityCheckLatency(const std::vector<int32_t>& in_latency);
-    Fingerprint* mFp;
+    std::shared_ptr<Fingerprint> mFp;
 };
 
 }  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/main.cpp b/biometrics/fingerprint/aidl/default/main.cpp
index ba0c8ec..8ca44d6 100644
--- a/biometrics/fingerprint/aidl/default/main.cpp
+++ b/biometrics/fingerprint/aidl/default/main.cpp
@@ -24,21 +24,38 @@
 using aidl::android::hardware::biometrics::fingerprint::Fingerprint;
 using aidl::android::hardware::biometrics::fingerprint::VirtualHal;
 
-int main() {
-    LOG(INFO) << "Fingerprint HAL started";
+int main(int argc, char** argv) {
+    if (argc < 2) {
+        LOG(ERROR) << "Missing argument -> exiting";
+        return EXIT_FAILURE;
+    }
+
+    LOG(INFO) << "Fingerprint HAL started: " << argv[1];
     ABinderProcess_setThreadPoolMaxThreadCount(0);
     std::shared_ptr<Fingerprint> hal = ndk::SharedRefBase::make<Fingerprint>();
-    auto binder = hal->asBinder();
-
-    std::shared_ptr<VirtualHal> hal_ext = ndk::SharedRefBase::make<VirtualHal>(hal.get());
-    auto binder_ext = hal_ext->asBinder();
+    std::shared_ptr<VirtualHal> hal_vhal = ndk::SharedRefBase::make<VirtualHal>(hal);
 
     if (hal->connected()) {
-        CHECK(STATUS_OK == AIBinder_setExtension(binder.get(), binder_ext.get()));
-        const std::string instance = std::string(Fingerprint::descriptor) + "/virtual";
-        binder_status_t status =
-                AServiceManager_registerLazyService(binder.get(), instance.c_str());
-        CHECK_EQ(status, STATUS_OK);
+        if (strcmp(argv[1], "default") == 0) {
+            const std::string instance = std::string(Fingerprint::descriptor) + "/default";
+            auto binder = hal->asBinder();
+            auto binder_ext = hal_vhal->asBinder();
+            CHECK(STATUS_OK == AIBinder_setExtension(binder.get(), binder_ext.get()));
+            binder_status_t status =
+                    AServiceManager_registerLazyService(binder.get(), instance.c_str());
+            CHECK_EQ(status, STATUS_OK);
+            LOG(INFO) << "started IFingerprint/default";
+        } else if (strcmp(argv[1], "virtual") == 0) {
+            const std::string instance = std::string(VirtualHal::descriptor) + "/virtual";
+            auto binder = hal_vhal->asBinder();
+            binder_status_t status =
+                    AServiceManager_registerLazyService(binder.get(), instance.c_str());
+            CHECK_EQ(status, STATUS_OK);
+            LOG(INFO) << "started IVirtualHal/virtual";
+        } else {
+            LOG(ERROR) << "Unexpected argument: " << argv[1];
+            return EXIT_FAILURE;
+        }
         AServiceManager_forceLazyServicesPersist(true);
     } else {
         LOG(ERROR) << "Fingerprint HAL is not connected";
diff --git a/biometrics/fingerprint/aidl/default/tests/VirtualHalTest.cpp b/biometrics/fingerprint/aidl/default/tests/VirtualHalTest.cpp
index 3fe0b2a..8ffc96b 100644
--- a/biometrics/fingerprint/aidl/default/tests/VirtualHalTest.cpp
+++ b/biometrics/fingerprint/aidl/default/tests/VirtualHalTest.cpp
@@ -35,7 +35,7 @@
   protected:
     void SetUp() override {
         mHal = ndk::SharedRefBase::make<Fingerprint>();
-        mVhal = ndk::SharedRefBase::make<VirtualHal>(mHal.get());
+        mVhal = ndk::SharedRefBase::make<VirtualHal>(mHal);
         ASSERT_TRUE(mVhal != nullptr);
         mHal->resetConfigToDefault();
     }
diff --git a/biometrics/fingerprint/aidl/vts/Android.bp b/biometrics/fingerprint/aidl/vts/Android.bp
index fc32fe6..628f03f 100644
--- a/biometrics/fingerprint/aidl/vts/Android.bp
+++ b/biometrics/fingerprint/aidl/vts/Android.bp
@@ -16,8 +16,8 @@
     ],
     srcs: ["VtsHalBiometricsFingerprintTargetTest.cpp"],
     static_libs: [
-        "android.hardware.biometrics.common-V3-ndk",
-        "android.hardware.biometrics.fingerprint-V3-ndk",
+        "android.hardware.biometrics.common-V4-ndk",
+        "android.hardware.biometrics.fingerprint-V4-ndk",
         "android.hardware.keymaster-V4-ndk",
     ],
     shared_libs: [
diff --git a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
index ad8d4c8..e0e3a0e 100644
--- a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
+++ b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
@@ -288,77 +288,70 @@
 }
 
 TEST_P(CameraAidlTest, getSessionCharacteristics) {
-    if (flags::feature_combination_query()) {
-        std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    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);
+    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);
 
-            int32_t interfaceVersion = -1;
-            ret = device->getInterfaceVersion(&interfaceVersion);
-            ASSERT_TRUE(ret.isOk());
-            bool supportSessionCharacteristics =
-                    (interfaceVersion >= CAMERA_DEVICE_API_MINOR_VERSION_3);
-            if (!supportSessionCharacteristics) {
-                continue;
-            }
-
-            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 camera_chars;
-            ret = device->getCameraCharacteristics(&camera_chars);
-            ASSERT_TRUE(ret.isOk());
-
-            CameraMetadata session_chars;
-            ret = device->getSessionCharacteristics(config, &session_chars);
-            ASSERT_TRUE(ret.isOk());
-            verifySessionCharacteristics(session_chars, camera_chars);
-
-            ret = mSession->close();
-            mSession = nullptr;
-            ASSERT_TRUE(ret.isOk());
+        int32_t interfaceVersion = -1;
+        ret = device->getInterfaceVersion(&interfaceVersion);
+        ASSERT_TRUE(ret.isOk());
+        bool supportSessionCharacteristics =
+                (interfaceVersion >= CAMERA_DEVICE_API_MINOR_VERSION_3);
+        if (!supportSessionCharacteristics) {
+            continue;
         }
-    } else {
-        ALOGI("getSessionCharacteristics: Test skipped.\n");
-        GTEST_SKIP();
+
+        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 camera_chars;
+        ret = device->getCameraCharacteristics(&camera_chars);
+        ASSERT_TRUE(ret.isOk());
+
+        CameraMetadata session_chars;
+        ret = device->getSessionCharacteristics(config, &session_chars);
+        ASSERT_TRUE(ret.isOk());
+        verifySessionCharacteristics(session_chars, camera_chars);
+
+        ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
     }
 }
 
@@ -615,19 +608,17 @@
                 ASSERT_EQ(0u, rawMetadata.metadata.size());
             }
 
-            if (flags::feature_combination_query()) {
-                if (supportFeatureCombinationQuery) {
-                    CameraMetadata rawMetadata2;
-                    ndk::ScopedAStatus ret2 =
-                            device->constructDefaultRequestSettings(reqTemplate, &rawMetadata2);
+            if (supportFeatureCombinationQuery) {
+                CameraMetadata rawMetadata2;
+                ndk::ScopedAStatus ret2 =
+                        device->constructDefaultRequestSettings(reqTemplate, &rawMetadata2);
 
-                    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()) {
-                        validateDefaultRequestMetadata(reqTemplate, rawMetadata2);
-                    }
+                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 f905011..6ecd451 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.cpp
+++ b/camera/provider/aidl/vts/camera_aidl_test.cpp
@@ -1920,28 +1920,22 @@
         ASSERT_TRUE(ret.isOk());
         ASSERT_EQ(expectedStatus, streamCombinationSupported);
 
-        if (flags::feature_combination_query()) {
-            int32_t interfaceVersion;
-            ret = device->getInterfaceVersion(&interfaceVersion);
+        int32_t interfaceVersion;
+        ret = device->getInterfaceVersion(&interfaceVersion);
+        ASSERT_TRUE(ret.isOk());
+        bool supportFeatureCombinationQuery =
+                (interfaceVersion >= CAMERA_DEVICE_API_MINOR_VERSION_3);
+        if (supportFeatureCombinationQuery) {
+            ret = device->isStreamCombinationWithSettingsSupported(config,
+                                                                   &streamCombinationSupported);
             ASSERT_TRUE(ret.isOk());
-            bool supportFeatureCombinationQuery =
-                    (interfaceVersion >= CAMERA_DEVICE_API_MINOR_VERSION_3);
-            if (supportFeatureCombinationQuery) {
-                ret = device->isStreamCombinationWithSettingsSupported(config,
-                                                                       &streamCombinationSupported);
-                ASSERT_TRUE(ret.isOk());
-                ASSERT_EQ(expectedStatus, streamCombinationSupported);
-            }
+            ASSERT_EQ(expectedStatus, streamCombinationSupported);
         }
     }
 }
 
 void CameraAidlTest::verifySessionCharacteristics(const CameraMetadata& session_chars,
                                                   const CameraMetadata& camera_chars) {
-    if (!flags::feature_combination_query()) {
-        return;
-    }
-
     const camera_metadata_t* session_metadata =
             reinterpret_cast<const camera_metadata_t*>(session_chars.metadata.data());
 
diff --git a/compatibility_matrices/compatibility_matrix.202404.xml b/compatibility_matrices/compatibility_matrix.202404.xml
index 9ea476a..aa6b8f0 100644
--- a/compatibility_matrices/compatibility_matrix.202404.xml
+++ b/compatibility_matrices/compatibility_matrix.202404.xml
@@ -28,7 +28,7 @@
     </hal>
     <hal format="aidl">
         <name>android.hardware.audio.sounddose</name>
-        <version>1-2</version>
+        <version>1-3</version>
         <interface>
             <name>ISoundDoseFactory</name>
             <instance>default</instance>
diff --git a/compatibility_matrices/compatibility_matrix.202504.xml b/compatibility_matrices/compatibility_matrix.202504.xml
index 30ddec4..ed45c1b 100644
--- a/compatibility_matrices/compatibility_matrix.202504.xml
+++ b/compatibility_matrices/compatibility_matrix.202504.xml
@@ -26,14 +26,6 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl">
-        <name>android.hardware.audio.sounddose</name>
-        <version>1-3</version>
-        <interface>
-            <name>ISoundDoseFactory</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
     <hal format="aidl" updatable-via-apex="true">
          <name>android.hardware.authsecret</name>
          <version>1</version>
@@ -670,7 +662,7 @@
     </hal>
     <hal format="aidl">
         <name>android.hardware.wifi.hostapd</name>
-        <version>1-2</version>
+        <version>2-3</version>
         <interface>
             <name>IHostapd</name>
             <instance>default</instance>
diff --git a/compatibility_matrices/exclude/fcm_exclude.cpp b/compatibility_matrices/exclude/fcm_exclude.cpp
index fca9e1c..e7a31e6 100644
--- a/compatibility_matrices/exclude/fcm_exclude.cpp
+++ b/compatibility_matrices/exclude/fcm_exclude.cpp
@@ -149,6 +149,7 @@
             "android.hardware.radio@",
             "android.hardware.uwb.fira_android@",
             "android.hardware.wifi.common@",
+            "android.hardware.biometrics.fingerprint.virtualhal@",
 
             // Test packages are exempted.
             "android.hardware.tests.",
@@ -167,6 +168,7 @@
             "android.hardware.audio.core.sounddose@3",
 
             // Deprecated HALs.
+            "android.hardware.audio.sounddose@3",
             "android.hardware.bluetooth.audio@1",
     };
 
diff --git a/drm/aidl/Android.bp b/drm/aidl/Android.bp
index afcb603..99780dc 100644
--- a/drm/aidl/Android.bp
+++ b/drm/aidl/Android.bp
@@ -14,6 +14,7 @@
     stability: "vintf",
     imports: [
         "android.hardware.common-V2",
+        "android.hardware.drm.common-V1",
     ],
     backend: {
         cpp: {
@@ -30,7 +31,10 @@
     versions_with_info: [
         {
             version: "1",
-            imports: ["android.hardware.common-V2"],
+            imports: [
+                "android.hardware.common-V2",
+                "android.hardware.drm.common-V1",
+            ],
         },
     ],
 
diff --git a/drm/aidl/aidl_api/android.hardware.drm/1/.hash b/drm/aidl/aidl_api/android.hardware.drm/1/.hash
index 886e28c..9a735e9 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/1/.hash
+++ b/drm/aidl/aidl_api/android.hardware.drm/1/.hash
@@ -1 +1,2 @@
 7b4b0a0f36a7a6bb22d2016375e4a9d4a033592f
+3a0197fb44863256da9034c26e721b1eee12d1be
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/EventType.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/EventType.aidl
index 80ebb28..f09eadd 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/EventType.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/EventType.aidl
@@ -34,9 +34,9 @@
 package android.hardware.drm;
 @Backing(type="int") @VintfStability
 enum EventType {
-  PROVISION_REQUIRED = 0,
-  KEY_NEEDED = 1,
-  KEY_EXPIRED = 2,
-  VENDOR_DEFINED = 3,
-  SESSION_RECLAIMED = 4,
+  PROVISION_REQUIRED,
+  KEY_NEEDED,
+  KEY_EXPIRED,
+  VENDOR_DEFINED,
+  SESSION_RECLAIMED,
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/HdcpLevel.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/HdcpLevel.aidl
deleted file mode 100644
index 5704fb0..0000000
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/HdcpLevel.aidl
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file built
-// with the aidl_interface module type with versions property set. The module
-// type is used to build AIDL files in a way that they can be used across
-// independently updatable components of the system. If a device is shipped
-// with such a backward incompatible change, it has a high risk of breaking
-// later when a module using the interface is updated, e.g., Mainline modules.
-
-package android.hardware.drm;
-@Backing(type="int") @VintfStability
-enum HdcpLevel {
-  HDCP_UNKNOWN = 0,
-  HDCP_NONE = 1,
-  HDCP_V1 = 2,
-  HDCP_V2 = 3,
-  HDCP_V2_1 = 4,
-  HDCP_V2_2 = 5,
-  HDCP_NO_OUTPUT = 6,
-  HDCP_V2_3 = 7,
-}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyRequestType.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyRequestType.aidl
index 34b9615..556ee38 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyRequestType.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyRequestType.aidl
@@ -34,10 +34,10 @@
 package android.hardware.drm;
 @Backing(type="int") @VintfStability
 enum KeyRequestType {
-  INITIAL = 0,
-  RENEWAL = 1,
-  RELEASE = 2,
-  UNKNOWN = 3,
-  NONE = 4,
-  UPDATE = 5,
+  INITIAL,
+  RENEWAL,
+  RELEASE,
+  UNKNOWN,
+  NONE,
+  UPDATE,
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyStatusType.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyStatusType.aidl
index 261516f..5a46552 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyStatusType.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyStatusType.aidl
@@ -34,10 +34,10 @@
 package android.hardware.drm;
 @Backing(type="int") @VintfStability
 enum KeyStatusType {
-  USABLE = 0,
-  EXPIRED = 1,
-  OUTPUT_NOT_ALLOWED = 2,
-  STATUS_PENDING = 3,
-  INTERNAL_ERROR = 4,
-  USABLE_IN_FUTURE = 5,
+  USABLE,
+  EXPIRED,
+  OUTPUT_NOT_ALLOWED,
+  STATUS_PENDING,
+  INTERNAL_ERROR,
+  USABLE_IN_FUTURE,
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyType.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyType.aidl
index 7a9d633..e677c86 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyType.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyType.aidl
@@ -34,7 +34,7 @@
 package android.hardware.drm;
 @Backing(type="int") @VintfStability
 enum KeyType {
-  OFFLINE = 0,
-  STREAMING = 1,
-  RELEASE = 2,
+  OFFLINE,
+  STREAMING,
+  RELEASE,
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/LogPriority.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/LogPriority.aidl
index 83362c3..b77ddf6 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/LogPriority.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/LogPriority.aidl
@@ -34,12 +34,12 @@
 package android.hardware.drm;
 @Backing(type="int") @VintfStability
 enum LogPriority {
-  UNKNOWN = 0,
-  DEFAULT = 1,
-  VERBOSE = 2,
-  DEBUG = 3,
-  INFO = 4,
-  WARN = 5,
-  ERROR = 6,
-  FATAL = 7,
+  UNKNOWN,
+  DEFAULT,
+  VERBOSE,
+  DEBUG,
+  INFO,
+  WARN,
+  ERROR,
+  FATAL,
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/OfflineLicenseState.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/OfflineLicenseState.aidl
index 629564d..be0e822 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/OfflineLicenseState.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/OfflineLicenseState.aidl
@@ -34,7 +34,7 @@
 package android.hardware.drm;
 @Backing(type="int") @VintfStability
 enum OfflineLicenseState {
-  UNKNOWN = 0,
-  USABLE = 1,
-  INACTIVE = 2,
+  UNKNOWN,
+  USABLE,
+  INACTIVE,
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SecurityLevel.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SecurityLevel.aidl
index 65b2b9d..87b3641 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SecurityLevel.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SecurityLevel.aidl
@@ -34,11 +34,11 @@
 package android.hardware.drm;
 @Backing(type="int") @VintfStability
 enum SecurityLevel {
-  UNKNOWN = 0,
-  SW_SECURE_CRYPTO = 1,
-  SW_SECURE_DECODE = 2,
-  HW_SECURE_CRYPTO = 3,
-  HW_SECURE_DECODE = 4,
-  HW_SECURE_ALL = 5,
-  DEFAULT = 6,
+  UNKNOWN,
+  SW_SECURE_CRYPTO,
+  SW_SECURE_DECODE,
+  HW_SECURE_CRYPTO,
+  HW_SECURE_DECODE,
+  HW_SECURE_ALL,
+  DEFAULT,
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Status.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Status.aidl
index c640689..a3ba6c3 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Status.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Status.aidl
@@ -34,44 +34,44 @@
 package android.hardware.drm;
 @Backing(type="int") @VintfStability
 enum Status {
-  OK = 0,
-  ERROR_DRM_NO_LICENSE = 1,
-  ERROR_DRM_LICENSE_EXPIRED = 2,
-  ERROR_DRM_SESSION_NOT_OPENED = 3,
-  ERROR_DRM_CANNOT_HANDLE = 4,
-  ERROR_DRM_INVALID_STATE = 5,
-  BAD_VALUE = 6,
-  ERROR_DRM_NOT_PROVISIONED = 7,
-  ERROR_DRM_RESOURCE_BUSY = 8,
-  ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION = 9,
-  ERROR_DRM_DEVICE_REVOKED = 10,
-  ERROR_DRM_DECRYPT = 11,
-  ERROR_DRM_UNKNOWN = 12,
-  ERROR_DRM_INSUFFICIENT_SECURITY = 13,
-  ERROR_DRM_FRAME_TOO_LARGE = 14,
-  ERROR_DRM_SESSION_LOST_STATE = 15,
-  ERROR_DRM_RESOURCE_CONTENTION = 16,
-  CANNOT_DECRYPT_ZERO_SUBSAMPLES = 17,
-  CRYPTO_LIBRARY_ERROR = 18,
-  GENERAL_OEM_ERROR = 19,
-  GENERAL_PLUGIN_ERROR = 20,
-  INIT_DATA_INVALID = 21,
-  KEY_NOT_LOADED = 22,
-  LICENSE_PARSE_ERROR = 23,
-  LICENSE_POLICY_ERROR = 24,
-  LICENSE_RELEASE_ERROR = 25,
-  LICENSE_REQUEST_REJECTED = 26,
-  LICENSE_RESTORE_ERROR = 27,
-  LICENSE_STATE_ERROR = 28,
-  MALFORMED_CERTIFICATE = 29,
-  MEDIA_FRAMEWORK_ERROR = 30,
-  MISSING_CERTIFICATE = 31,
-  PROVISIONING_CERTIFICATE_ERROR = 32,
-  PROVISIONING_CONFIGURATION_ERROR = 33,
-  PROVISIONING_PARSE_ERROR = 34,
-  PROVISIONING_REQUEST_REJECTED = 35,
-  RETRYABLE_PROVISIONING_ERROR = 36,
-  SECURE_STOP_RELEASE_ERROR = 37,
-  STORAGE_READ_FAILURE = 38,
-  STORAGE_WRITE_FAILURE = 39,
+  OK,
+  ERROR_DRM_NO_LICENSE,
+  ERROR_DRM_LICENSE_EXPIRED,
+  ERROR_DRM_SESSION_NOT_OPENED,
+  ERROR_DRM_CANNOT_HANDLE,
+  ERROR_DRM_INVALID_STATE,
+  BAD_VALUE,
+  ERROR_DRM_NOT_PROVISIONED,
+  ERROR_DRM_RESOURCE_BUSY,
+  ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION,
+  ERROR_DRM_DEVICE_REVOKED,
+  ERROR_DRM_DECRYPT,
+  ERROR_DRM_UNKNOWN,
+  ERROR_DRM_INSUFFICIENT_SECURITY,
+  ERROR_DRM_FRAME_TOO_LARGE,
+  ERROR_DRM_SESSION_LOST_STATE,
+  ERROR_DRM_RESOURCE_CONTENTION,
+  CANNOT_DECRYPT_ZERO_SUBSAMPLES,
+  CRYPTO_LIBRARY_ERROR,
+  GENERAL_OEM_ERROR,
+  GENERAL_PLUGIN_ERROR,
+  INIT_DATA_INVALID,
+  KEY_NOT_LOADED,
+  LICENSE_PARSE_ERROR,
+  LICENSE_POLICY_ERROR,
+  LICENSE_RELEASE_ERROR,
+  LICENSE_REQUEST_REJECTED,
+  LICENSE_RESTORE_ERROR,
+  LICENSE_STATE_ERROR,
+  MALFORMED_CERTIFICATE,
+  MEDIA_FRAMEWORK_ERROR,
+  MISSING_CERTIFICATE,
+  PROVISIONING_CERTIFICATE_ERROR,
+  PROVISIONING_CONFIGURATION_ERROR,
+  PROVISIONING_PARSE_ERROR,
+  PROVISIONING_REQUEST_REJECTED,
+  RETRYABLE_PROVISIONING_ERROR,
+  SECURE_STOP_RELEASE_ERROR,
+  STORAGE_READ_FAILURE,
+  STORAGE_WRITE_FAILURE,
 }
diff --git a/drm/aidl/vts/Android.bp b/drm/aidl/vts/Android.bp
index 5139036..27ce0d7 100644
--- a/drm/aidl/vts/Android.bp
+++ b/drm/aidl/vts/Android.bp
@@ -47,6 +47,7 @@
     ],
     static_libs: [
         "android.hardware.drm@1.0-helper",
+        "android.hardware.drm.common-V1-ndk",
         "android.hardware.drm-V1-ndk",
         "android.hardware.common-V2-ndk",
         "libaidlcommonsupport",
@@ -59,13 +60,19 @@
             data: [":libvtswidevine-arm-prebuilts"],
         },
         arm64: {
-            data: [":libvtswidevine-arm64-prebuilts", ":libvtswidevine-arm-prebuilts"],
+            data: [
+                ":libvtswidevine-arm64-prebuilts",
+                ":libvtswidevine-arm-prebuilts",
+            ],
         },
         x86: {
             data: [":libvtswidevine-x86-prebuilts"],
         },
         x86_64: {
-            data: [":libvtswidevine-x86_64-prebuilts", ":libvtswidevine-x86-prebuilts"],
+            data: [
+                ":libvtswidevine-x86_64-prebuilts",
+                ":libvtswidevine-x86-prebuilts",
+            ],
         },
     },
     test_suites: [
diff --git a/drm/common/aidl/Android.bp b/drm/common/aidl/Android.bp
new file mode 100644
index 0000000..c5cb441
--- /dev/null
+++ b/drm/common/aidl/Android.bp
@@ -0,0 +1,39 @@
+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.drm.common",
+    host_supported: true,
+    vendor_available: true,
+    srcs: ["android/hardware/drm/*.aidl"],
+    stability: "vintf",
+    backend: {
+        cpp: {
+            enabled: false,
+        },
+        java: {
+            sdk_version: "module_current",
+        },
+        ndk: {
+            min_sdk_version: "34",
+        },
+        rust: {
+            enabled: true,
+        },
+    },
+    double_loadable: true,
+    versions_with_info: [
+        {
+            version: "1",
+            imports: [],
+        },
+    ],
+    frozen: true,
+
+}
diff --git a/drm/common/aidl/aidl_api/android.hardware.drm.common/1/.hash b/drm/common/aidl/aidl_api/android.hardware.drm.common/1/.hash
new file mode 100644
index 0000000..66690e1
--- /dev/null
+++ b/drm/common/aidl/aidl_api/android.hardware.drm.common/1/.hash
@@ -0,0 +1 @@
+1b5e9159609b3aa05e2c7158f3a1488fda2250d1
diff --git a/drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevel.aidl b/drm/common/aidl/aidl_api/android.hardware.drm.common/1/android/hardware/drm/HdcpLevel.aidl
similarity index 92%
rename from drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevel.aidl
rename to drm/common/aidl/aidl_api/android.hardware.drm.common/1/android/hardware/drm/HdcpLevel.aidl
index 5704fb0..118bef6 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevel.aidl
+++ b/drm/common/aidl/aidl_api/android.hardware.drm.common/1/android/hardware/drm/HdcpLevel.aidl
@@ -34,12 +34,12 @@
 package android.hardware.drm;
 @Backing(type="int") @VintfStability
 enum HdcpLevel {
-  HDCP_UNKNOWN = 0,
-  HDCP_NONE = 1,
-  HDCP_V1 = 2,
-  HDCP_V2 = 3,
-  HDCP_V2_1 = 4,
-  HDCP_V2_2 = 5,
-  HDCP_NO_OUTPUT = 6,
-  HDCP_V2_3 = 7,
+  HDCP_UNKNOWN,
+  HDCP_NONE,
+  HDCP_V1,
+  HDCP_V2,
+  HDCP_V2_1,
+  HDCP_V2_2,
+  HDCP_NO_OUTPUT,
+  HDCP_V2_3,
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevels.aidl b/drm/common/aidl/aidl_api/android.hardware.drm.common/1/android/hardware/drm/HdcpLevels.aidl
similarity index 100%
rename from drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevels.aidl
rename to drm/common/aidl/aidl_api/android.hardware.drm.common/1/android/hardware/drm/HdcpLevels.aidl
diff --git a/drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevel.aidl b/drm/common/aidl/aidl_api/android.hardware.drm.common/current/android/hardware/drm/HdcpLevel.aidl
similarity index 92%
copy from drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevel.aidl
copy to drm/common/aidl/aidl_api/android.hardware.drm.common/current/android/hardware/drm/HdcpLevel.aidl
index 5704fb0..118bef6 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevel.aidl
+++ b/drm/common/aidl/aidl_api/android.hardware.drm.common/current/android/hardware/drm/HdcpLevel.aidl
@@ -34,12 +34,12 @@
 package android.hardware.drm;
 @Backing(type="int") @VintfStability
 enum HdcpLevel {
-  HDCP_UNKNOWN = 0,
-  HDCP_NONE = 1,
-  HDCP_V1 = 2,
-  HDCP_V2 = 3,
-  HDCP_V2_1 = 4,
-  HDCP_V2_2 = 5,
-  HDCP_NO_OUTPUT = 6,
-  HDCP_V2_3 = 7,
+  HDCP_UNKNOWN,
+  HDCP_NONE,
+  HDCP_V1,
+  HDCP_V2,
+  HDCP_V2_1,
+  HDCP_V2_2,
+  HDCP_NO_OUTPUT,
+  HDCP_V2_3,
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/HdcpLevels.aidl b/drm/common/aidl/aidl_api/android.hardware.drm.common/current/android/hardware/drm/HdcpLevels.aidl
similarity index 100%
rename from drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/HdcpLevels.aidl
rename to drm/common/aidl/aidl_api/android.hardware.drm.common/current/android/hardware/drm/HdcpLevels.aidl
diff --git a/drm/aidl/android/hardware/drm/HdcpLevel.aidl b/drm/common/aidl/android/hardware/drm/HdcpLevel.aidl
similarity index 100%
rename from drm/aidl/android/hardware/drm/HdcpLevel.aidl
rename to drm/common/aidl/android/hardware/drm/HdcpLevel.aidl
diff --git a/drm/aidl/android/hardware/drm/HdcpLevels.aidl b/drm/common/aidl/android/hardware/drm/HdcpLevels.aidl
similarity index 100%
rename from drm/aidl/android/hardware/drm/HdcpLevels.aidl
rename to drm/common/aidl/android/hardware/drm/HdcpLevels.aidl
diff --git a/graphics/Android.bp b/graphics/Android.bp
index 352f3bd..c33f7ff 100644
--- a/graphics/Android.bp
+++ b/graphics/Android.bp
@@ -53,6 +53,7 @@
 cc_defaults {
     name: "android.hardware.graphics.composer3-ndk_static",
     static_libs: [
+        "android.hardware.drm.common-V1-ndk",
         "android.hardware.graphics.composer3-V4-ndk",
     ],
 }
@@ -60,6 +61,7 @@
 cc_defaults {
     name: "android.hardware.graphics.composer3-ndk_shared",
     shared_libs: [
+        "android.hardware.drm.common-V1-ndk",
         "android.hardware.graphics.composer3-V4-ndk",
     ],
 }
diff --git a/graphics/composer/aidl/Android.bp b/graphics/composer/aidl/Android.bp
index 3b60f68..1728f78 100644
--- a/graphics/composer/aidl/Android.bp
+++ b/graphics/composer/aidl/Android.bp
@@ -37,6 +37,7 @@
     imports: [
         "android.hardware.graphics.common-V5",
         "android.hardware.common-V2",
+        "android.hardware.drm.common-V1",
     ],
     backend: {
         cpp: {
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayLuts.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayLuts.aidl
index 869db5b..327e84c 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayLuts.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayLuts.aidl
@@ -35,5 +35,9 @@
 @VintfStability
 parcelable DisplayLuts {
   long display;
-  android.hardware.graphics.composer3.Lut[] luts;
+  android.hardware.graphics.composer3.DisplayLuts.LayerLut[] layerLuts;
+  parcelable LayerLut {
+    long layer;
+    android.hardware.graphics.composer3.Lut lut;
+  }
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerCallback.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerCallback.aidl
index e64bd52..cd27360 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerCallback.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerCallback.aidl
@@ -45,4 +45,5 @@
   oneway void onVsyncIdle(long display);
   oneway void onRefreshRateChangedDebug(in android.hardware.graphics.composer3.RefreshRateChangedDebugData data);
   void onHotplugEvent(long display, android.hardware.graphics.common.DisplayHotplugEvent event);
+  oneway void onHdcpLevelsChanged(long display, in android.hardware.drm.HdcpLevels levels);
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Lut.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Lut.aidl
index 39245b5..5fae35b 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Lut.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Lut.aidl
@@ -34,7 +34,6 @@
 package android.hardware.graphics.composer3;
 @VintfStability
 parcelable Lut {
-  long layer;
   @nullable ParcelFileDescriptor pfd;
   android.hardware.graphics.composer3.LutProperties lutProperties;
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayLuts.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayLuts.aidl
index 56381e0..ac0a606 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayLuts.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayLuts.aidl
@@ -27,12 +27,20 @@
 @VintfStability
 parcelable DisplayLuts {
     /**
-     * The display which this commands refers to.
+     * The display which the layerLuts list is for.
      */
     long display;
 
-    /**
-     * A Lut list specified by the HWC for given HDR layers that don't have Luts provided.
-     */
-    Lut[] luts;
+    parcelable LayerLut {
+        /**
+         * The layer that the HWC is requesting a LUT to be applied during GPU composition.
+         */
+        long layer;
+        /**
+         * A Lut specified by the HWC for given HDR layers that don't have Luts provided.
+         */
+        Lut lut;
+    }
+
+    LayerLut[] layerLuts;
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerCallback.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerCallback.aidl
index 96eccd7..a1d61fd 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerCallback.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerCallback.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.graphics.composer3;
 
+import android.hardware.drm.HdcpLevels;
 import android.hardware.graphics.common.DisplayHotplugEvent;
 import android.hardware.graphics.composer3.RefreshRateChangedDebugData;
 import android.hardware.graphics.composer3.VsyncPeriodChangeTimeline;
@@ -139,4 +140,12 @@
      * @param event is the type of event that occurred.
      */
     void onHotplugEvent(long display, DisplayHotplugEvent event);
+
+    /**
+     * Notify the client the HDCP levels of the display changed.
+     *
+     * @param display is the display whose HDCP levels have changed.
+     * @param levels is the new HDCP levels.
+     */
+    oneway void onHdcpLevelsChanged(long display, in HdcpLevels levels);
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/Lut.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/Lut.aidl
index e4320f5..abfeb14 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/Lut.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/Lut.aidl
@@ -28,11 +28,6 @@
 @VintfStability
 parcelable Lut {
     /**
-     * The layer which this commands refer to.
-     */
-    long layer;
-
-    /**
      * A handle to a memory region.
      * If the file descriptor is not set, this means that the HWC doesn't specify a Lut.
      *
diff --git a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h
index fc96882..331d717 100644
--- a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h
+++ b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h
@@ -186,7 +186,7 @@
     }
 
     // Get the lut(s) requested by hardware composer.
-    std::vector<Lut> takeDisplayLuts(int64_t display) {
+    std::vector<DisplayLuts::LayerLut> takeDisplayLuts(int64_t display) {
         LOG_ALWAYS_FATAL_IF(mDisplay && display != *mDisplay);
         auto found = mReturnData.find(display);
 
@@ -196,7 +196,7 @@
         }
 
         ReturnData& data = found->second;
-        return std::move(data.luts);
+        return std::move(data.layerLuts);
     }
 
   private:
@@ -247,10 +247,11 @@
     void parseSetDisplayLuts(DisplayLuts&& displayLuts) {
         LOG_ALWAYS_FATAL_IF(mDisplay && displayLuts.display != *mDisplay);
         auto& data = mReturnData[displayLuts.display];
-        for (auto& lut : displayLuts.luts) {
-            if (lut.pfd.get() >= 0) {
-                data.luts.push_back({lut.layer, ndk::ScopedFileDescriptor(lut.pfd.release()),
-                                     lut.lutProperties});
+        for (auto& layerLut : displayLuts.layerLuts) {
+            if (layerLut.lut.pfd.get() >= 0) {
+                data.layerLuts.push_back(
+                        {layerLut.layer, Lut{ndk::ScopedFileDescriptor(layerLut.lut.pfd.release()),
+                                             layerLut.lut.lutProperties}});
             }
         }
     }
@@ -266,7 +267,7 @@
                 .clientTargetProperty = {common::PixelFormat::RGBA_8888, Dataspace::UNKNOWN},
                 .brightness = 1.f,
         };
-        std::vector<Lut> luts;
+        std::vector<DisplayLuts::LayerLut> layerLuts;
     };
 
     std::vector<CommandError> mErrors;
diff --git a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
index a1ccbfe..02fb3aa 100644
--- a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
+++ b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
@@ -30,6 +30,7 @@
 #include <aidl/android/hardware/graphics/composer3/DisplayBrightness.h>
 #include <aidl/android/hardware/graphics/composer3/LayerBrightness.h>
 #include <aidl/android/hardware/graphics/composer3/LayerLifecycleBatchCommandType.h>
+#include <aidl/android/hardware/graphics/composer3/Lut.h>
 #include <aidl/android/hardware/graphics/composer3/PerFrameMetadata.h>
 #include <aidl/android/hardware/graphics/composer3/PerFrameMetadataBlob.h>
 
@@ -245,6 +246,15 @@
         getLayerCommand(display, layer).blockingRegion.emplace(blocking.begin(), blocking.end());
     }
 
+    void setLayerLuts(int64_t display, int64_t layer, std::vector<Lut>& luts) {
+        std::vector<std::optional<Lut>> currentLuts;
+        for (auto& lut : luts) {
+            currentLuts.push_back(std::make_optional<Lut>(
+                    {ndk::ScopedFileDescriptor(lut.pfd.release()), lut.lutProperties}));
+        }
+        getLayerCommand(display, layer).luts.emplace(std::move(currentLuts));
+    }
+
     std::vector<DisplayCommand> takePendingCommands() {
         flushLayerCommand();
         flushDisplayCommand();
diff --git a/graphics/composer/aidl/vts/Android.bp b/graphics/composer/aidl/vts/Android.bp
index a2ab3d6..894ca52 100644
--- a/graphics/composer/aidl/vts/Android.bp
+++ b/graphics/composer/aidl/vts/Android.bp
@@ -66,6 +66,7 @@
         "android.hardware.graphics.common@1.2",
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
+        "android.hardware.drm.common-V1-ndk",
         "libaidlcommonsupport",
         "libarect",
         "libbase",
diff --git a/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp b/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp
index 544f692..1f7972c 100644
--- a/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp
+++ b/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp
@@ -208,4 +208,15 @@
     }
 }
 
+::ndk::ScopedAStatus GraphicsComposerCallback::onHdcpLevelsChanged(
+        int64_t in_display, const ::aidl::android::hardware::drm::HdcpLevels&) {
+    std::scoped_lock lock(mMutex);
+
+    const auto it = std::find(mDisplays.begin(), mDisplays.end(), in_display);
+    if (it != mDisplays.end()) {
+        mHdcpLevelChangedCount++;
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
 }  // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/vts/GraphicsComposerCallback.h b/graphics/composer/aidl/vts/GraphicsComposerCallback.h
index 7a8d4a3..97f8e2b 100644
--- a/graphics/composer/aidl/vts/GraphicsComposerCallback.h
+++ b/graphics/composer/aidl/vts/GraphicsComposerCallback.h
@@ -65,6 +65,8 @@
             const RefreshRateChangedDebugData&) override;
     virtual ::ndk::ScopedAStatus onHotplugEvent(int64_t in_display,
                                                 common::DisplayHotplugEvent) override;
+    virtual ::ndk::ScopedAStatus onHdcpLevelsChanged(
+            int64_t in_display, const ::aidl::android::hardware::drm::HdcpLevels&) override;
 
     mutable std::mutex mMutex;
     // the set of all currently connected displays
@@ -88,6 +90,7 @@
     int32_t mInvalidVsyncPeriodChangeCount GUARDED_BY(mMutex) = 0;
     int32_t mInvalidSeamlessPossibleCount GUARDED_BY(mMutex) = 0;
     int32_t mInvalidRefreshRateDebugEnabledCallbackCount GUARDED_BY(mMutex) = 0;
+    int32_t mHdcpLevelChangedCount GUARDED_BY(mMutex) = 0;
 };
 
 }  // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/vts/ReadbackVts.cpp b/graphics/composer/aidl/vts/ReadbackVts.cpp
index 283b8ce..9d5928d 100644
--- a/graphics/composer/aidl/vts/ReadbackVts.cpp
+++ b/graphics/composer/aidl/vts/ReadbackVts.cpp
@@ -16,6 +16,7 @@
 
 #include "ReadbackVts.h"
 #include <aidl/android/hardware/graphics/common/BufferUsage.h>
+#include <cmath>
 #include "RenderEngineVts.h"
 #include "renderengine/ExternalTexture.h"
 #include "renderengine/impl/ExternalTexture.h"
@@ -106,37 +107,72 @@
     return layerSettings;
 }
 
-int32_t ReadbackHelper::GetBytesPerPixel(common::PixelFormat pixelFormat) {
+int32_t ReadbackHelper::GetBitsPerChannel(common::PixelFormat pixelFormat) {
     switch (pixelFormat) {
+        case common::PixelFormat::RGBA_1010102:
+            return 10;
         case common::PixelFormat::RGBA_8888:
-            return 4;
         case common::PixelFormat::RGB_888:
-            return 3;
+            return 8;
         default:
             return -1;
     }
 }
 
-void ReadbackHelper::fillBuffer(uint32_t width, uint32_t height, uint32_t stride, void* bufferData,
+int32_t ReadbackHelper::GetAlphaBits(common::PixelFormat pixelFormat) {
+    switch (pixelFormat) {
+        case common::PixelFormat::RGBA_8888:
+            return 8;
+        case common::PixelFormat::RGBA_1010102:
+            return 2;
+        case common::PixelFormat::RGB_888:
+            return 0;
+        default:
+            return -1;
+    }
+}
+
+void ReadbackHelper::fillBuffer(uint32_t width, uint32_t height, uint32_t stride,
+                                int32_t bytesPerPixel, void* bufferData,
                                 common::PixelFormat pixelFormat,
                                 std::vector<Color> desiredPixelColors) {
     ASSERT_TRUE(pixelFormat == common::PixelFormat::RGB_888 ||
-                pixelFormat == common::PixelFormat::RGBA_8888);
-    int32_t bytesPerPixel = GetBytesPerPixel(pixelFormat);
+                pixelFormat == common::PixelFormat::RGBA_8888 ||
+                pixelFormat == common::PixelFormat::RGBA_1010102);
+    int32_t bitsPerChannel = GetBitsPerChannel(pixelFormat);
+    int32_t alphaBits = GetAlphaBits(pixelFormat);
+    ASSERT_NE(-1, alphaBits);
+    ASSERT_NE(-1, bitsPerChannel);
     ASSERT_NE(-1, bytesPerPixel);
-    for (int row = 0; row < height; row++) {
-        for (int col = 0; col < width; col++) {
-            auto pixel = row * static_cast<int32_t>(width) + col;
+
+    uint32_t maxValue = (1 << bitsPerChannel) - 1;
+    uint32_t maxAlphaValue = (1 << alphaBits) - 1;
+    for (uint32_t row = 0; row < height; row++) {
+        for (uint32_t col = 0; col < width; col++) {
+            auto pixel = row * width + col;
             Color srcColor = desiredPixelColors[static_cast<size_t>(pixel)];
 
-            int offset = (row * static_cast<int32_t>(stride) + col) * bytesPerPixel;
-            uint8_t* pixelColor = (uint8_t*)bufferData + offset;
-            pixelColor[0] = static_cast<uint8_t>(std::round(255.0f * srcColor.r));
-            pixelColor[1] = static_cast<uint8_t>(std::round(255.0f * srcColor.g));
-            pixelColor[2] = static_cast<uint8_t>(std::round(255.0f * srcColor.b));
+            uint32_t offset = (row * stride + col) * static_cast<uint32_t>(bytesPerPixel);
 
-            if (bytesPerPixel == 4) {
-                pixelColor[3] = static_cast<uint8_t>(std::round(255.0f * srcColor.a));
+            uint32_t* pixelStart = (uint32_t*)((uint8_t*)bufferData + offset);
+
+            uint32_t red = static_cast<uint32_t>(std::round(maxValue * srcColor.r));
+            uint32_t green = static_cast<uint32_t>(std::round(maxValue * srcColor.g));
+            uint32_t blue = static_cast<uint32_t>(std::round(maxValue * srcColor.b));
+
+            // Boo we're not word aligned so special case this.
+            if (pixelFormat == common::PixelFormat::RGB_888) {
+                uint8_t* pixelColor = (uint8_t*)pixelStart;
+                pixelColor[0] = static_cast<uint8_t>(red);
+                pixelColor[1] = static_cast<uint8_t>(green);
+                pixelColor[2] = static_cast<uint8_t>(blue);
+            } else {
+                uint32_t alpha = static_cast<uint32_t>(std::round(maxAlphaValue * srcColor.a));
+                uint32_t color = (alpha << (32 - alphaBits)) |
+                                 (blue << (32 - alphaBits - bitsPerChannel)) |
+                                 (green << (32 - alphaBits - bitsPerChannel * 2)) |
+                                 (red << (32 - alphaBits - bitsPerChannel * 3));
+                *pixelStart = color;
             }
         }
     }
@@ -165,7 +201,8 @@
 bool ReadbackHelper::readbackSupported(const common::PixelFormat& pixelFormat,
                                        const common::Dataspace& dataspace) {
     if (pixelFormat != common::PixelFormat::RGB_888 &&
-        pixelFormat != common::PixelFormat::RGBA_8888) {
+        pixelFormat != common::PixelFormat::RGBA_8888 &&
+        pixelFormat != common::PixelFormat::RGBA_1010102) {
         return false;
     }
     if (std::find(dataspaces.begin(), dataspaces.end(), dataspace) == dataspaces.end()) {
@@ -175,36 +212,110 @@
 }
 
 void ReadbackHelper::compareColorBuffers(const std::vector<Color>& expectedColors, void* bufferData,
-                                         const uint32_t stride, const uint32_t width,
-                                         const uint32_t height, common::PixelFormat pixelFormat) {
-    const int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(pixelFormat);
-    ASSERT_NE(-1, bytesPerPixel);
-    for (int row = 0; row < height; row++) {
-        for (int col = 0; col < width; col++) {
-            auto pixel = row * static_cast<int32_t>(width) + col;
-            int offset = (row * static_cast<int32_t>(stride) + col) * bytesPerPixel;
-            uint8_t* pixelColor = (uint8_t*)bufferData + offset;
+                                         const uint32_t stride, int32_t bytesPerPixel,
+                                         const uint32_t width, const uint32_t height,
+                                         common::PixelFormat pixelFormat) {
+    int32_t bitsPerChannel = GetBitsPerChannel(pixelFormat);
+    int32_t alphaBits = GetAlphaBits(pixelFormat);
+    ASSERT_GT(bytesPerPixel, 0);
+    ASSERT_NE(-1, alphaBits);
+    ASSERT_NE(-1, bitsPerChannel);
+    uint32_t maxValue = (1 << bitsPerChannel) - 1;
+    uint32_t maxAlphaValue = (1 << alphaBits) - 1;
+    for (uint32_t row = 0; row < height; row++) {
+        for (uint32_t col = 0; col < width; col++) {
+            auto pixel = row * width + col;
             const Color expectedColor = expectedColors[static_cast<size_t>(pixel)];
-            ASSERT_EQ(std::round(255.0f * expectedColor.r), pixelColor[0]);
-            ASSERT_EQ(std::round(255.0f * expectedColor.g), pixelColor[1]);
-            ASSERT_EQ(std::round(255.0f * expectedColor.b), pixelColor[2]);
+
+            uint32_t offset = (row * stride + col) * static_cast<uint32_t>(bytesPerPixel);
+            uint32_t* pixelStart = (uint32_t*)((uint8_t*)bufferData + offset);
+
+            uint32_t expectedRed = static_cast<uint32_t>(std::round(maxValue * expectedColor.r));
+            uint32_t expectedGreen = static_cast<uint32_t>(std::round(maxValue * expectedColor.g));
+            uint32_t expectedBlue = static_cast<uint32_t>(std::round(maxValue * expectedColor.b));
+
+            // Boo we're not word aligned so special case this.
+            if (pixelFormat == common::PixelFormat::RGB_888) {
+                uint8_t* pixelColor = (uint8_t*)pixelStart;
+                ASSERT_EQ(pixelColor[0], static_cast<uint8_t>(expectedRed))
+                        << "Red channel mismatch at (" << row << ", " << col << ")";
+                ASSERT_EQ(pixelColor[1], static_cast<uint8_t>(expectedGreen))
+                        << "Green channel mismatch at (" << row << ", " << col << ")";
+                ASSERT_EQ(pixelColor[2], static_cast<uint8_t>(expectedBlue))
+                        << "Blue channel mismatch at (" << row << ", " << col << ")";
+            } else {
+                uint32_t expectedAlpha =
+                        static_cast<uint32_t>(std::round(maxAlphaValue * expectedColor.a));
+
+                uint32_t actualRed =
+                        (*pixelStart >> (32 - alphaBits - bitsPerChannel * 3)) & maxValue;
+                uint32_t actualGreen =
+                        (*pixelStart >> (32 - alphaBits - bitsPerChannel * 2)) & maxValue;
+                uint32_t actualBlue = (*pixelStart >> (32 - alphaBits - bitsPerChannel)) & maxValue;
+                uint32_t actualAlpha = (*pixelStart >> (32 - alphaBits)) & maxAlphaValue;
+
+                ASSERT_EQ(expectedRed, actualRed)
+                        << "Red channel mismatch at (" << row << ", " << col << ")";
+                ASSERT_EQ(expectedGreen, actualGreen)
+                        << "Green channel mismatch at (" << row << ", " << col << ")";
+                ASSERT_EQ(expectedBlue, actualBlue)
+                        << "Blue channel mismatch at (" << row << ", " << col << ")";
+            }
         }
     }
 }
 
 void ReadbackHelper::compareColorBuffers(void* expectedBuffer, void* actualBuffer,
-                                         const uint32_t stride, const uint32_t width,
-                                         const uint32_t height, common::PixelFormat pixelFormat) {
-    const int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(pixelFormat);
-    ASSERT_NE(-1, bytesPerPixel);
-    for (int row = 0; row < height; row++) {
-        for (int col = 0; col < width; col++) {
-            int offset = (row * static_cast<int32_t>(stride) + col) * bytesPerPixel;
-            uint8_t* expectedColor = (uint8_t*)expectedBuffer + offset;
-            uint8_t* actualColor = (uint8_t*)actualBuffer + offset;
-            ASSERT_EQ(expectedColor[0], actualColor[0]);
-            ASSERT_EQ(expectedColor[1], actualColor[1]);
-            ASSERT_EQ(expectedColor[2], actualColor[2]);
+                                         const uint32_t stride, int32_t bytesPerPixel,
+                                         const uint32_t width, const uint32_t height,
+                                         common::PixelFormat pixelFormat) {
+    int32_t bitsPerChannel = GetBitsPerChannel(pixelFormat);
+    int32_t alphaBits = GetAlphaBits(pixelFormat);
+    ASSERT_GT(bytesPerPixel, 0);
+    ASSERT_NE(-1, alphaBits);
+    ASSERT_NE(-1, bitsPerChannel);
+    uint32_t maxValue = (1 << bitsPerChannel) - 1;
+    uint32_t maxAlphaValue = (1 << alphaBits) - 1;
+    for (uint32_t row = 0; row < height; row++) {
+        for (uint32_t col = 0; col < width; col++) {
+            uint32_t offset = (row * stride + col) * static_cast<uint32_t>(bytesPerPixel);
+            uint32_t* expectedStart = (uint32_t*)((uint8_t*)expectedBuffer + offset);
+            uint32_t* actualStart = (uint32_t*)((uint8_t*)actualBuffer + offset);
+
+            // Boo we're not word aligned so special case this.
+            if (pixelFormat == common::PixelFormat::RGB_888) {
+                uint8_t* expectedPixel = (uint8_t*)expectedStart;
+                uint8_t* actualPixel = (uint8_t*)actualStart;
+                ASSERT_EQ(actualPixel[0], expectedPixel[0])
+                        << "Red channel mismatch at (" << row << ", " << col << ")";
+                ASSERT_EQ(actualPixel[1], expectedPixel[1])
+                        << "Green channel mismatch at (" << row << ", " << col << ")";
+                ASSERT_EQ(actualPixel[2], expectedPixel[2])
+                        << "Blue channel mismatch at (" << row << ", " << col << ")";
+            } else {
+                uint32_t expectedRed =
+                        (*expectedStart >> (32 - alphaBits - bitsPerChannel * 3)) & maxValue;
+                uint32_t expectedGreen =
+                        (*expectedStart >> (32 - alphaBits - bitsPerChannel * 2)) & maxValue;
+                uint32_t expectedBlue =
+                        (*expectedStart >> (32 - alphaBits - bitsPerChannel)) & maxValue;
+                uint32_t expectedAlpha = (*expectedStart >> (32 - alphaBits)) & maxAlphaValue;
+
+                uint32_t actualRed =
+                        (*actualStart >> (32 - alphaBits - bitsPerChannel * 3)) & maxValue;
+                uint32_t actualGreen =
+                        (*actualStart >> (32 - alphaBits - bitsPerChannel * 2)) & maxValue;
+                uint32_t actualBlue =
+                        (*actualStart >> (32 - alphaBits - bitsPerChannel)) & maxValue;
+                uint32_t actualAlpha = (*actualStart >> (32 - alphaBits)) & maxAlphaValue;
+
+                ASSERT_EQ(expectedRed, actualRed)
+                        << "Red channel mismatch at (" << row << ", " << col << ")";
+                ASSERT_EQ(expectedGreen, actualGreen)
+                        << "Green channel mismatch at (" << row << ", " << col << ")";
+                ASSERT_EQ(expectedBlue, actualBlue)
+                        << "Blue channel mismatch at (" << row << ", " << col << ")";
+            }
         }
     }
 }
@@ -258,12 +369,13 @@
     auto status = mGraphicBuffer->lockAsync(mUsage, mAccessRegion, &bufData, dup(bufferFence.get()),
                                             &bytesPerPixel, &bytesPerStride);
     EXPECT_EQ(::android::OK, status);
-    ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888);
+    ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888 ||
+                mPixelFormat == PixelFormat::RGBA_1010102);
     const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
                                     ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
                                     : mGraphicBuffer->getStride();
-    ReadbackHelper::compareColorBuffers(expectedColors, bufData, stride, mWidth, mHeight,
-                                        mPixelFormat);
+    ReadbackHelper::compareColorBuffers(expectedColors, bufData, stride, bytesPerPixel, mWidth,
+                                        mHeight, mPixelFormat);
     status = mGraphicBuffer->unlock();
     EXPECT_EQ(::android::OK, status);
 }
@@ -353,8 +465,8 @@
                                     ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
                                     : mGraphicBuffer->getStride();
     EXPECT_EQ(::android::OK, status);
-    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mWidth, mHeight, stride, bufData,
-                                                       mPixelFormat, expectedColors));
+    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mWidth, mHeight, stride, bytesPerPixel,
+                                                       bufData, mPixelFormat, expectedColors));
 
     const auto unlockStatus = mGraphicBuffer->unlockAsync(&mFillFence);
     ASSERT_EQ(::android::OK, unlockStatus);
diff --git a/graphics/composer/aidl/vts/ReadbackVts.h b/graphics/composer/aidl/vts/ReadbackVts.h
index 8ac0f4b..e3b2384 100644
--- a/graphics/composer/aidl/vts/ReadbackVts.h
+++ b/graphics/composer/aidl/vts/ReadbackVts.h
@@ -172,10 +172,12 @@
 
     static Dataspace getDataspaceForColorMode(ColorMode mode);
 
-    static int32_t GetBytesPerPixel(PixelFormat pixelFormat);
+    static int32_t GetBitsPerChannel(PixelFormat pixelFormat);
+    static int32_t GetAlphaBits(PixelFormat pixelFormat);
 
-    static void fillBuffer(uint32_t width, uint32_t height, uint32_t stride, void* bufferData,
-                           PixelFormat pixelFormat, std::vector<Color> desiredPixelColors);
+    static void fillBuffer(uint32_t width, uint32_t height, uint32_t stride, int32_t bytesPerPixel,
+                           void* bufferData, PixelFormat pixelFormat,
+                           std::vector<Color> desiredPixelColors);
 
     static void clearColors(std::vector<Color>& expectedColors, int32_t width, int32_t height,
                             int32_t displayWidth);
@@ -189,11 +191,12 @@
     static const std::vector<Dataspace> dataspaces;
 
     static void compareColorBuffers(const std::vector<Color>& expectedColors, void* bufferData,
-                                    const uint32_t stride, const uint32_t width,
-                                    const uint32_t height, PixelFormat pixelFormat);
-    static void compareColorBuffers(void* expectedBuffer, void* actualBuffer, const uint32_t stride,
+                                    const uint32_t stride, int32_t bytesPerPixel,
                                     const uint32_t width, const uint32_t height,
                                     PixelFormat pixelFormat);
+    static void compareColorBuffers(void* expectedBuffer, void* actualBuffer, const uint32_t stride,
+                                    int32_t bytesPerPixel, const uint32_t width,
+                                    const uint32_t height, PixelFormat pixelFormat);
 };
 
 class ReadbackBuffer {
diff --git a/graphics/composer/aidl/vts/RenderEngineVts.cpp b/graphics/composer/aidl/vts/RenderEngineVts.cpp
index 4e7f773..48cb8ae 100644
--- a/graphics/composer/aidl/vts/RenderEngineVts.cpp
+++ b/graphics/composer/aidl/vts/RenderEngineVts.cpp
@@ -83,7 +83,7 @@
     const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
                                     ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
                                     : mGraphicBuffer->getStride();
-    ReadbackHelper::compareColorBuffers(expectedColors, bufferData, stride,
+    ReadbackHelper::compareColorBuffers(expectedColors, bufferData, stride, bytesPerPixel,
                                         mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight(),
                                         mFormat);
     ASSERT_EQ(::android::OK, mGraphicBuffer->unlock());
@@ -110,7 +110,7 @@
 
     ASSERT_EQ(renderedStride, bufferStride);
 
-    ReadbackHelper::compareColorBuffers(renderedBufferData, bufferData, bufferStride,
+    ReadbackHelper::compareColorBuffers(renderedBufferData, bufferData, bufferStride, bytesPerPixel,
                                         mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight(),
                                         mFormat);
     ASSERT_EQ(::android::OK, buffer->unlock());
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
index 3d9253f..9db8794 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
@@ -496,11 +496,14 @@
             const auto& buffer = graphicBuffer->handle;
             void* clientBufData;
             const auto stride = static_cast<uint32_t>(graphicBuffer->stride);
-            graphicBuffer->lock(clientUsage, layer->getAccessRegion(), &clientBufData);
+            int bytesPerPixel = -1;
+            int bytesPerStride = -1;
+            graphicBuffer->lock(clientUsage, layer->getAccessRegion(), &clientBufData,
+                                &bytesPerPixel, &bytesPerStride);
 
-            ASSERT_NO_FATAL_FAILURE(
-                    ReadbackHelper::fillBuffer(layer->getWidth(), layer->getHeight(), stride,
-                                               clientBufData, clientFormat, expectedColors));
+            ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(
+                    layer->getWidth(), layer->getHeight(), stride, bytesPerPixel, clientBufData,
+                    clientFormat, expectedColors));
             int32_t clientFence;
             const auto unlockStatus = graphicBuffer->unlockAsync(&clientFence);
             ASSERT_EQ(::android::OK, unlockStatus);
@@ -677,15 +680,18 @@
         const auto& buffer = graphicBuffer->handle;
 
         void* clientBufData;
+        int bytesPerPixel = -1;
+        int bytesPerStride = -1;
         graphicBuffer->lock(clientUsage, {0, 0, getDisplayWidth(), getDisplayHeight()},
-                            &clientBufData);
+                            &clientBufData, &bytesPerPixel, &bytesPerStride);
 
         std::vector<Color> clientColors(
                 static_cast<size_t>(getDisplayWidth() * getDisplayHeight()));
         ReadbackHelper::fillColorsArea(clientColors, getDisplayWidth(), clientFrame, RED);
         ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(
                 static_cast<uint32_t>(getDisplayWidth()), static_cast<uint32_t>(getDisplayHeight()),
-                graphicBuffer->getStride(), clientBufData, clientFormat, clientColors));
+                graphicBuffer->getStride(), bytesPerPixel, clientBufData, clientFormat,
+                clientColors));
         int32_t clientFence;
         const auto unlockStatus = graphicBuffer->unlockAsync(&clientFence);
         ASSERT_EQ(::android::OK, unlockStatus);
diff --git a/health/aidl/default/corpus/seed-2024-08-29-0 b/health/aidl/default/corpus/seed-2024-08-29-0
new file mode 100644
index 0000000..07fd0e9
--- /dev/null
+++ b/health/aidl/default/corpus/seed-2024-08-29-0
Binary files differ
diff --git a/health/aidl/default/corpus/seed-2024-08-29-1 b/health/aidl/default/corpus/seed-2024-08-29-1
new file mode 100644
index 0000000..ef19735
--- /dev/null
+++ b/health/aidl/default/corpus/seed-2024-08-29-1
Binary files differ
diff --git a/health/aidl/default/corpus/seed-2024-08-29-2 b/health/aidl/default/corpus/seed-2024-08-29-2
new file mode 100644
index 0000000..76addb7
--- /dev/null
+++ b/health/aidl/default/corpus/seed-2024-08-29-2
Binary files differ
diff --git a/health/utils/libhealthloop/HealthLoop.cpp b/health/utils/libhealthloop/HealthLoop.cpp
index 70b7745..c5ad5a8 100644
--- a/health/utils/libhealthloop/HealthLoop.cpp
+++ b/health/utils/libhealthloop/HealthLoop.cpp
@@ -43,6 +43,8 @@
 namespace hardware {
 namespace health {
 
+static constexpr uint32_t kUeventMsgLen = 2048;
+
 HealthLoop::HealthLoop() {
     InitHealthdConfig(&healthd_config_);
     awake_poll_interval_ = -1;
@@ -62,8 +64,8 @@
                                   .get();
 
     struct epoll_event ev = {
-            .events = EPOLLIN | EPOLLERR,
-            .data.ptr = reinterpret_cast<void*>(event_handler),
+        .events = EPOLLIN | EPOLLERR,
+        .data.ptr = reinterpret_cast<void*>(event_handler),
     };
 
     if (wakeup == EVENT_WAKEUP_FD) ev.events |= EPOLLWAKEUP;
@@ -120,38 +122,42 @@
     ScheduleBatteryUpdate();
 }
 
-#define UEVENT_MSG_LEN 2048
-void HealthLoop::UeventEvent(uint32_t epevents) {
-    // No need to lock because uevent_fd_ is guaranteed to be initialized.
-
-    if (epevents & EPOLLERR) {
-        // The netlink receive buffer overflowed.
-        ScheduleBatteryUpdate();
-        return;
-    }
-
-    char msg[UEVENT_MSG_LEN + 2];
-    char* cp;
-    int n;
-
-    n = uevent_kernel_multicast_recv(uevent_fd_, msg, UEVENT_MSG_LEN);
-    if (n <= 0) return;
-    if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
-        return;
-
-    msg[n] = '\0';
-    msg[n + 1] = '\0';
-    cp = msg;
-
-    while (*cp) {
-        if (!strcmp(cp, "SUBSYSTEM=power_supply")) {
-            ScheduleBatteryUpdate();
-            break;
+// Returns true if and only if the battery statistics should be updated.
+bool HealthLoop::RecvUevents() {
+    bool update_stats = false;
+    for (;;) {
+        char msg[kUeventMsgLen + 2];
+        int n = uevent_kernel_multicast_recv(uevent_fd_, msg, kUeventMsgLen);
+        if (n < 0 && errno == ENOBUFS) {
+            update_stats = true;
+        }
+        if (n <= 0) return update_stats;
+        if (n >= kUeventMsgLen) {
+            // too long -- discard
+            continue;
+        }
+        if (update_stats) {
+            continue;
         }
 
-        /* advance to after the next \0 */
-        while (*cp++)
-            ;
+        msg[n] = '\0';
+        msg[n + 1] = '\0';
+        for (char* cp = msg; *cp;) {
+            if (strcmp(cp, "SUBSYSTEM=power_supply") == 0) {
+                update_stats = true;
+                break;
+            }
+
+            /* advance to after the next \0 */
+            while (*cp++) {
+            }
+        }
+    }
+}
+
+void HealthLoop::UeventEvent(uint32_t /*epevents*/) {
+    if (RecvUevents()) {
+        ScheduleBatteryUpdate();
     }
 }
 
@@ -174,7 +180,7 @@
 }
 
 void HealthLoop::UeventInit(void) {
-    uevent_fd_.reset(uevent_create_socket(64 * 1024, true));
+    uevent_fd_.reset(uevent_create_socket(kUeventMsgLen, true));
 
     if (uevent_fd_ < 0) {
         KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
@@ -188,9 +194,9 @@
         std::string error_msg = attach_result.error().message();
         error_msg +=
                 ". This is expected in recovery mode and also for kernel versions before 5.10.";
-        KLOG_WARNING(LOG_TAG, "%s", error_msg.c_str());
+        KLOG_WARNING(LOG_TAG, "%s\n", error_msg.c_str());
     } else {
-        KLOG_INFO(LOG_TAG, "Successfully attached the BPF filter to the uevent socket");
+        KLOG_INFO(LOG_TAG, "Successfully attached the BPF filter to the uevent socket\n");
     }
 
     if (RegisterEvent(uevent_fd_, &HealthLoop::UeventEvent, EVENT_WAKEUP_FD))
diff --git a/health/utils/libhealthloop/filterPowerSupplyEventsTest.cpp b/health/utils/libhealthloop/filterPowerSupplyEventsTest.cpp
index e885f0b..04b8bcd 100644
--- a/health/utils/libhealthloop/filterPowerSupplyEventsTest.cpp
+++ b/health/utils/libhealthloop/filterPowerSupplyEventsTest.cpp
@@ -192,16 +192,21 @@
     bpf_object__close(obj);
 }
 
+static constexpr char input0[] = "a";
+static constexpr char input1[] = "abc\0SUBSYSTEM=block\0";
+static constexpr char input2[] = "\0SUBSYSTEM=block";
+static constexpr char input3[] = "\0SUBSYSTEM=power_supply";
+static constexpr char input4[] = "\0SUBSYSTEM=power_supply\0";
+static constexpr char input5[] =
+        "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
+        "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
+        "012345678901234567890123456789012345678901234567890123456789\0SUBSYSTEM=block\0";
+
 INSTANTIATE_TEST_SUITE_P(
         filterPse, filterPseTest,
-        testing::Values(test_data{false, "a"},
-                        test_data{true, std::string_view("abc\0SUBSYSTEM=block\0", 20)},
-                        test_data{true, std::string_view("\0SUBSYSTEM=block", 16)},
-                        test_data{true, std::string_view("\0SUBSYSTEM=power_supply", 23)},
-                        test_data{false, std::string_view("\0SUBSYSTEM=power_supply\0", 24)},
-                        test_data{
-                                false,
-                                "012345678901234567890123456789012345678901234567890123456789012345"
-                                "678901234567890123456789012345678901234567890123456789012345678901"
-                                "234567890123456789012345678901234567890123456789012345678901234567"
-                                "890123456789012345678901234567890123456789\0SUBSYSTEM=block\0"}));
+        testing::Values(test_data{false, std::string_view(input0, sizeof(input0) - 1)},
+                        test_data{true, std::string_view(input1, sizeof(input1) - 1)},
+                        test_data{true, std::string_view(input2, sizeof(input2) - 1)},
+                        test_data{true, std::string_view(input3, sizeof(input3) - 1)},
+                        test_data{false, std::string_view(input4, sizeof(input4) - 1)},
+                        test_data{false, std::string_view(input5, sizeof(input5) - 1)}));
diff --git a/health/utils/libhealthloop/include/health/HealthLoop.h b/health/utils/libhealthloop/include/health/HealthLoop.h
index 1af7274..43c38dc 100644
--- a/health/utils/libhealthloop/include/health/HealthLoop.h
+++ b/health/utils/libhealthloop/include/health/HealthLoop.h
@@ -93,6 +93,7 @@
     void WakeAlarmInit();
     void WakeAlarmEvent(uint32_t);
     void UeventInit();
+    bool RecvUevents();
     void UeventEvent(uint32_t);
     void WakeAlarmSetInterval(int interval);
     void PeriodicChores();
diff --git a/keymaster/aidl/Android.bp b/keymaster/aidl/Android.bp
index 0f2debd..9f4e5cb 100644
--- a/keymaster/aidl/Android.bp
+++ b/keymaster/aidl/Android.bp
@@ -18,6 +18,12 @@
         java: {
             platform_apis: true,
         },
+        ndk: {
+            apex_available: [
+                "com.android.hardware.biometrics.fingerprint.virtual",
+                "//apex_available:platform",
+            ],
+        },
     },
     versions_with_info: [
         {
diff --git a/media/bufferpool/aidl/default/BufferPoolClient.cpp b/media/bufferpool/aidl/default/BufferPoolClient.cpp
index ce4ad8e..b61893f 100644
--- a/media/bufferpool/aidl/default/BufferPoolClient.cpp
+++ b/media/bufferpool/aidl/default/BufferPoolClient.cpp
@@ -748,6 +748,10 @@
     } else {
         connection = mRemoteConnection;
     }
+    if (!connection) {
+        ALOGE("connection null: fetchBufferHandle()");
+        return ResultStatus::CRITICAL_ERROR;
+    }
     std::vector<FetchInfo> infos;
     std::vector<FetchResult> results;
     infos.emplace_back(FetchInfo{ToAidl(transactionId), ToAidl(bufferId)});
diff --git a/radio/aidl/android/hardware/radio/config/IRadioConfig.aidl b/radio/aidl/android/hardware/radio/config/IRadioConfig.aidl
index 8f4dff4..936315c 100644
--- a/radio/aidl/android/hardware/radio/config/IRadioConfig.aidl
+++ b/radio/aidl/android/hardware/radio/config/IRadioConfig.aidl
@@ -17,9 +17,10 @@
  * This interface is used by telephony and telecom to talk to cellular radio for the purpose of
  * radio configuration, and it is not associated with any specific modem or slot.
  * All the functions have minimum one parameter:
- * serial: which corresponds to serial no. of request. Serial numbers must only be memorized for the
- * duration of a method call. If clients provide colliding serials (including passing the same
- * serial to different methods), multiple responses (one for each method call) must still be served.
+ * serial: which corresponds to the serial number of the request. Serial numbers must only be
+ * memorized for the duration of a method call. If clients provide colliding serials (including
+ * passing the same serial to different methods), multiple responses (one for each method call) must
+ * still be served.
  */
 
 package android.hardware.radio.config;
@@ -108,12 +109,12 @@
 
     /**
      * Set preferred data modem Id.
-     * In a multi-SIM device, notify modem layer which logical modem will be used primarily
-     * for data. It helps modem with resource optimization and decisions of what data connections
-     * should be satisfied.
+     * In a multi-SIM device, notify the modem layer which logical modem will be used primarily
+     * for data. It helps the modem with resource optimization and decisions of what data
+     * connections should be satisfied.
      *
      * @param serial Serial number of request.
-     * @param modem Id the logical modem ID, which should match one of modem IDs returned
+     * @param modemId the logical modem ID which should match one of the modem IDs returned
      * from getPhoneCapability().
      *
      * Response callback is IRadioConfigResponse.setPreferredDataModemResponse()
@@ -136,30 +137,30 @@
     /**
      * Set SIM Slot mapping.
      *
-     * Maps the logical slots to the SlotPortMapping which consist of both physical slot id and port
-     * id. Logical slot is the slot that is seen by modem. Physical slot is the actual physical
-     * slot. PortId is the id (enumerated value) for the associated port available on the SIM. Each
-     * physical slot can have multiple ports which enables multi-enabled profile(MEP). If eUICC
-     * physical slot supports 2 ports, then the portId is numbered 0,1 and if eUICC2 supports 4
-     * ports then the portID is numbered 0,1,2,3. Each portId is unique within a UICC physical slot
-     * but not necessarily unique across UICC’s. SEP(Single enabled profile) eUICC and non-eUICC
-     * will only have portId 0.
+     * Maps the logical slots to the SlotPortMapping, which consists of both physical slot id and
+     * port id. Logical slot is the slot that is seen by the modem. Physical slot is the actual
+     * physical slot. PortId is the id (enumerated value) for the associated port available on the
+     * SIM. Each physical slot can have multiple ports, which enables multi-enabled profile(MEP). If
+     * eUICC physical slot supports 2 ports, then the portId is numbered 0,1 and if eUICC2 supports
+     * 4 ports then the portID is numbered 0,1,2,3. Each portId is unique within a UICC physical
+     * slot but not necessarily unique across UICC’s. SEP(Single enabled profile) eUICC and
+     * non-eUICC will only have portId 0.
      *
      * Logical slots that are already mapped to the requested SlotPortMapping are not impacted.
      *
-     * Example no. of logical slots 1 and physical slots 2 do not support MEP, each physical slot
-     * has one port:
-     * The only logical slot (index 0) can be mapped to first physical slot (value 0), port(index
-     * 0). or second
-     * physical slot(value 1), port (index 0), while the other physical slot remains unmapped and
-     * inactive.
+     * Example: There is 1 logical slot, 2 physical slots, MEP is not supported and each physical
+     * slot has one port:
+     * The only logical slot (index 0) can be mapped to the first physical slot (value 0),
+     * port(index 0), or second physical slot(value 1), port (index 0), while the other physical
+     * slot remains unmapped and inactive.
      * slotMap[0] = SlotPortMapping{0 //physical slot//, 0 //port//}
      * slotMap[0] = SlotPortMapping{1 //physical slot//, 0 //port//}
      *
-     * Example no. of logical slots 2 and physical slots 2 supports MEP with 2 ports available:
-     * Each logical slot must be mapped to a port (physical slot and port combination).
-     * First logical slot (index 0) can be mapped to physical slot 1 and the second logical slot
-     * can be mapped to either port from physical slot 2.
+     * Example: There are 2 logical slots, 2 physical slots, MEP is supported and there are 2 ports
+     * available:
+     * Each logical slot must be mapped to a port (physical slot and port combination). The first
+     * logical slot (index 0) can be mapped to the physical slot 1 and the second logical slot can
+     * be mapped to either port from physical slot 2.
      *
      * slotMap[0] = SlotPortMapping{0, 0} and slotMap[1] = SlotPortMapping{1, 0} or
      * slotMap[0] = SlotPortMapping{0, 0} and slotMap[1] = SlotPortMapping{1, 1}
@@ -178,10 +179,10 @@
      *
      * @param serial Serial number of request
      * @param slotMap Logical to physical slot and port mapping.
-     *        Index is mapping to logical slot and value to physical slot and port id, need to
-     *        provide all the slots mapping when sending request in case of multi slot device.
+     *        The index maps to the logical slot, and the value to the physical slot and port id. In
+     *        the case of a multi-slot device, provide all the slot mappings when sending a request.
      *
-     *        EX: SlotPortMapping(physical slot, port id)
+     *        Example: SlotPortMapping(physical slot, port id)
      *        index 0 is the first logical_slot number of logical slots is equal to number of Radio
      *        instances and number of physical slots is equal to size of slotStatus in
      *        getSimSlotsStatusResponse
diff --git a/radio/aidl/android/hardware/radio/config/IRadioConfigIndication.aidl b/radio/aidl/android/hardware/radio/config/IRadioConfigIndication.aidl
index 9eacb8e..0b60dbb 100644
--- a/radio/aidl/android/hardware/radio/config/IRadioConfigIndication.aidl
+++ b/radio/aidl/android/hardware/radio/config/IRadioConfigIndication.aidl
@@ -27,9 +27,9 @@
     /**
      * Indicates SIM slot status change.
      *
-     * This indication must be sent by the modem whenever there is any slot status change, even the
-     * slot is inactive. For example, this indication must be triggered if a SIM card is inserted
-     * into an inactive slot.
+     * This indication must be sent by the modem whenever there is any slot status change, even if
+     * the slot is inactive. For example, this indication must be triggered if a SIM card is
+     * inserted into an inactive slot.
      *
      * @param type Type of radio indication
      * @param slotStatus new slot status info with size equals to the number of physical slots on
@@ -39,7 +39,7 @@
             in android.hardware.radio.RadioIndicationType type, in SimSlotStatus[] slotStatus);
 
     /**
-     * The logical slots supporting simultaneous cellular calling has changed.
+     * The logical slots supporting simultaneous cellular calling have 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
diff --git a/radio/aidl/android/hardware/radio/config/IRadioConfigResponse.aidl b/radio/aidl/android/hardware/radio/config/IRadioConfigResponse.aidl
index 33b0ff0..8182cd1 100644
--- a/radio/aidl/android/hardware/radio/config/IRadioConfigResponse.aidl
+++ b/radio/aidl/android/hardware/radio/config/IRadioConfigResponse.aidl
@@ -26,18 +26,18 @@
 @VintfStability
 oneway interface IRadioConfigResponse {
     /**
-     * @param info Response info struct containing response type, serial no. and error
+     * @param info Response info struct containing response type, serial number and error
      * @param modemReducedFeatureSet1 True indicates that the modem does NOT support the following
-     *        features.
-     *        - Providing either LinkCapacityEstimate:secondaryDownlinkCapacityKbps
-     *          or LinkCapacityEstimate:secondaryUplinkCapacityKbps when given from
-     *          RadioIndication:currentLinkCapacityEstimate
-     *        - Calling IRadio.setNrDualConnectivityState or querying
-     *          IRadio.isNrDualConnectivityEnabled
-     *        - Requesting IRadio.setDataThrottling()
-     *        - Providing SlicingConfig through getSlicingConfig()
+     *        features:
+     *        - Providing either LinkCapacityEstimate#secondaryDownlinkCapacityKbps
+     *          or LinkCapacityEstimate#secondaryUplinkCapacityKbps when given from
+     *          IRadioNetworkIndication#currentLinkCapacityEstimate
+     *        - Calling IRadioNetwork#setNrDualConnectivityState or querying
+     *          IRadioNetwork#isNrDualConnectivityEnabled
+     *        - Requesting IRadioData#setDataThrottling
+     *        - Providing SlicingConfig through IRadioData#getSlicingConfig
      *        - Providing PhysicalChannelConfig through
-     *          IRadioIndication.currentPhysicalChannelConfigs_1_6()
+     *          IRadioNetworkIndication#currentPhysicalChannelConfigs
      *
      * Valid errors returned:
      *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony is not defined
@@ -49,7 +49,7 @@
             in android.hardware.radio.RadioResponseInfo info, in boolean modemReducedFeatureSet1);
 
     /**
-     * @param info Response info struct containing response type, serial no. and error
+     * @param info Response info struct containing response type, serial number and error
      * @param numOfLiveModems <byte> indicate the number of live modems i.e. modems that
      *        are enabled and actively working as part of a working connectivity stack
      *
@@ -62,8 +62,8 @@
             in android.hardware.radio.RadioResponseInfo info, in byte numOfLiveModems);
 
     /**
-     * @param info Response info struct containing response type, serial no. and error
-     * @param phoneCapability <PhoneCapability> it defines modem's capability for example
+     * @param info Response info struct containing response type, serial number and error
+     * @param phoneCapability <PhoneCapability> it defines the modem's capability. For example,
      *        how many logical modems it has, how many data connections it supports.
      *
      * Valid errors returned:
@@ -76,7 +76,7 @@
             in android.hardware.radio.RadioResponseInfo info, in PhoneCapability phoneCapability);
 
     /**
-     * @param info Response info struct containing response type, serial no. and error
+     * @param info Response info struct containing response type, serial number and error
      * @param slotStatus Sim slot struct containing all the physical SIM slots info with size
      *        equal to the number of physical slots on the device
      *
@@ -93,7 +93,7 @@
             in android.hardware.radio.RadioResponseInfo info, in SimSlotStatus[] slotStatus);
 
     /**
-     * @param info Response info struct containing response type, serial no. and error
+     * @param info Response info struct containing response type, serial number and error
      *
      * Valid errors returned:
      *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony is not defined
@@ -104,7 +104,7 @@
     void setNumOfLiveModemsResponse(in android.hardware.radio.RadioResponseInfo info);
 
     /**
-     * @param info Response info struct containing response type, serial no. and error
+     * @param info Response info struct containing response type, serial number and error
      *
      * Valid errors returned:
      *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.data is not defined
@@ -116,7 +116,7 @@
     void setPreferredDataModemResponse(in android.hardware.radio.RadioResponseInfo info);
 
     /**
-     * @param info Response info struct containing response type, serial no. and error
+     * @param info Response info struct containing response type, serial number and error
      *
      * Valid errors returned:
      *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
@@ -134,7 +134,7 @@
      * Response to the asynchronous
      * {@link IRadioConfig#getSimultaneousCallingSupport} request.
      *
-     * @param info Response info struct containing response type, serial no. and error
+     * @param info Response info struct containing response type, serial number 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
diff --git a/radio/aidl/android/hardware/radio/config/PhoneCapability.aidl b/radio/aidl/android/hardware/radio/config/PhoneCapability.aidl
index 7936eb6..265ab96 100644
--- a/radio/aidl/android/hardware/radio/config/PhoneCapability.aidl
+++ b/radio/aidl/android/hardware/radio/config/PhoneCapability.aidl
@@ -17,8 +17,8 @@
 package android.hardware.radio.config;
 
 /**
- * Phone capability which describes the data connection capability of modem.
- * It's used to evaluate possible phone config change, for example from single
+ * Phone capability which describes the data connection capability of the modem.
+ * It's used to evaluate a possible phone config change, for example, from single
  * SIM device to multi-SIM device.
  * @hide
  */
@@ -27,21 +27,18 @@
 parcelable PhoneCapability {
     const byte UNKNOWN = -1;
     /**
-     * maxActiveData defines how many logical modems can have
-     * PS attached simultaneously. For example, for L+L modem it
-     * should be 2.
+     * maxActiveData defines how many logical modems can have PS attached simultaneously. For
+     * example, for a L+L modem, it should be 2.
      */
     byte maxActiveData;
     /**
-     * maxActiveData defines how many logical modems can have
-     * internet PDN connections simultaneously. For example, for L+L
-     * DSDS modem it’s 1, and for DSDA modem it’s 2.
+     * maxActiveInternetData defines how many logical modems can have internet PDN connections
+     * simultaneously. For example, for a L+L DSDS modem, it’s 1, and for a DSDA modem, it’s 2.
      */
     byte maxActiveInternetData;
     /**
-     * Whether modem supports both internet PDN up so
-     * that we can do ping test before tearing down the
-     * other one.
+     * Whether the modem supports both internet PDNs up, so that we can do a ping test on one PDN
+     * before tearing down the other PDN.
      */
     boolean isInternetLingeringSupported;
     /**
@@ -49,9 +46,8 @@
      */
     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.
+     * 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/config/SimPortInfo.aidl b/radio/aidl/android/hardware/radio/config/SimPortInfo.aidl
index f579639..380932e 100644
--- a/radio/aidl/android/hardware/radio/config/SimPortInfo.aidl
+++ b/radio/aidl/android/hardware/radio/config/SimPortInfo.aidl
@@ -21,8 +21,8 @@
 @JavaDerive(toString=true)
 parcelable SimPortInfo {
     /**
-     * Integrated Circuit Card IDentifier (ICCID) is unique identifier of the SIM card. File is
-     * located in the SIM card at EFiccid (0x2FE2) as per ETSI 102.221. The ICCID is defined by
+     * Integrated Circuit Card IDentifier (ICCID) is the unique identifier of the SIM card. The file
+     * is located in the SIM card at EFiccid (0x2FE2) as per ETSI 102.221. The ICCID is defined by
      * the ITU-T recommendation E.118 ISO/IEC 7816.
      *
      * This data is applicable only when cardState is CardStatus.STATE_PRESENT.
@@ -33,13 +33,13 @@
      */
     String iccId;
     /**
-     * Logical slot id is identifier of the active slot
+     * The identifier of the active slot.
      */
     int logicalSlotId;
     /**
      * Port active status in the slot.
-     * Inactive means logical modem is no longer associated to the port.
-     * Active means logical modem is associated to the port.
+     * Inactive means that the logical modem is no longer associated to the port.
+     * Active means that the logical modem is associated to the port.
      */
     boolean portActive;
 }
diff --git a/radio/aidl/android/hardware/radio/config/SimSlotStatus.aidl b/radio/aidl/android/hardware/radio/config/SimSlotStatus.aidl
index 34f98c5..171d97a 100644
--- a/radio/aidl/android/hardware/radio/config/SimSlotStatus.aidl
+++ b/radio/aidl/android/hardware/radio/config/SimSlotStatus.aidl
@@ -46,12 +46,12 @@
     String eid;
     /**
      * PortInfo contains the ICCID, logical slot ID, and port state.
-     * Cardstate has no relationship with whether the slot is active or inactive. Should always
-     * report up at least 1 port otherwise the logicalSlotIndex and portActive info will be lost.
+     * Cardstate has no relationship with whether the slot is active or inactive. At least one port
+     * shall always be reported, otherwise the logicalSlotIndex and portActive info will be lost.
      * For example, the pSIM can be removed, but the slot can still be active. In that case, the
      * SIM_STATUS reported for the corresponding logical stack will show CARDSTATE_ABSENT.
-     * Similarly, even if there is no profile enabled on the eSIM, that port can still be the
-     * active port in the slot mapping.
+     * Similarly, even if there is no profile enabled on the eSIM, that port can still be the active
+     * port in the slot mapping.
      */
     SimPortInfo[] portInfo;
     /**
diff --git a/radio/aidl/vts/radio_sim_test.cpp b/radio/aidl/vts/radio_sim_test.cpp
index 9d1c356..6ffe2c5 100644
--- a/radio/aidl/vts/radio_sim_test.cpp
+++ b/radio/aidl/vts/radio_sim_test.cpp
@@ -531,7 +531,7 @@
         EXPECT_EQ(RadioError::NONE, radioRsp_sim->rspInfo.error);
 
         if (aidl_version <= 2) {
-            EXPECT_EQ(1, radioRsp_sim->carrierRestrictionsResp.allowedCarriers.size());
+            ASSERT_EQ(1, radioRsp_sim->carrierRestrictionsResp.allowedCarriers.size());
             EXPECT_EQ(0, radioRsp_sim->carrierRestrictionsResp.excludedCarriers.size());
 
             ASSERT_TRUE(std::string("123") ==
@@ -543,7 +543,7 @@
             ASSERT_TRUE(radioRsp_sim->carrierRestrictionsResp.allowedCarriersPrioritized);
             EXPECT_EQ(SimLockMultiSimPolicy::NO_MULTISIM_POLICY, radioRsp_sim->multiSimPolicyResp);
         } else {
-            EXPECT_EQ(1, radioRsp_sim->carrierRestrictionsResp.allowedCarrierInfoList.size());
+            ASSERT_EQ(1, radioRsp_sim->carrierRestrictionsResp.allowedCarrierInfoList.size());
             EXPECT_EQ(0, radioRsp_sim->carrierRestrictionsResp.excludedCarrierInfoList.size());
             ASSERT_TRUE(std::string("321") ==
                         radioRsp_sim->carrierRestrictionsResp.allowedCarrierInfoList[0].mcc);
diff --git a/security/keymint/aidl/default/Android.bp b/security/keymint/aidl/default/Android.bp
index fbb6140..22a46ed 100644
--- a/security/keymint/aidl/default/Android.bp
+++ b/security/keymint/aidl/default/Android.bp
@@ -7,6 +7,24 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
+vintf_fragment {
+    name: "android.hardware.security.keymint-service.xml",
+    src: "android.hardware.security.keymint-service.xml",
+    vendor: true,
+}
+
+vintf_fragment {
+    name: "android.hardware.security.sharedsecret-service.xml",
+    src: "android.hardware.security.sharedsecret-service.xml",
+    vendor: true,
+}
+
+vintf_fragment {
+    name: "android.hardware.security.secureclock-service.xml",
+    src: "android.hardware.security.secureclock-service.xml",
+    vendor: true,
+}
+
 // The following target has an insecure implementation of KeyMint where the
 // trusted application (TA) code runs in-process alongside the HAL service
 // code.
@@ -18,11 +36,6 @@
     name: "android.hardware.security.keymint-service",
     relative_install_path: "hw",
     init_rc: ["android.hardware.security.keymint-service.rc"],
-    vintf_fragments: [
-        "android.hardware.security.keymint-service.xml",
-        "android.hardware.security.sharedsecret-service.xml",
-        "android.hardware.security.secureclock-service.xml",
-    ],
     vendor: true,
     cflags: [
         "-Wall",
@@ -51,6 +64,11 @@
     required: [
         "android.hardware.hardware_keystore.xml",
     ],
+    vintf_fragment_modules: [
+        "android.hardware.security.keymint-service.xml",
+        "android.hardware.security.sharedsecret-service.xml",
+        "android.hardware.security.secureclock-service.xml",
+    ],
 }
 
 // The following target has an insecure implementation of KeyMint where the
@@ -65,11 +83,6 @@
     relative_install_path: "hw",
     vendor: true,
     init_rc: ["android.hardware.security.keymint-service.nonsecure.rc"],
-    vintf_fragments: [
-        "android.hardware.security.keymint-service.xml",
-        "android.hardware.security.sharedsecret-service.xml",
-        "android.hardware.security.secureclock-service.xml",
-    ],
     defaults: [
         "keymint_use_latest_hal_aidl_rust",
     ],
@@ -87,6 +100,11 @@
     required: [
         "android.hardware.hardware_keystore.xml",
     ],
+    vintf_fragment_modules: [
+        "android.hardware.security.keymint-service.xml",
+        "android.hardware.security.sharedsecret-service.xml",
+        "android.hardware.security.secureclock-service.xml",
+    ],
 }
 
 prebuilt_etc {
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 2ba75a3..c19ab11 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -236,10 +236,10 @@
 
 /**
  * An API to determine device IDs attestation is required or not,
- * which is mandatory for KeyMint version 2 or first_api_level 33 or greater.
+ * which is mandatory for KeyMint version 2 and first_api_level 33 or greater.
  */
 bool KeyMintAidlTestBase::isDeviceIdAttestationRequired() {
-    return AidlVersion() >= 2 || property_get_int32("ro.vendor.api_level", 0) >= __ANDROID_API_T__;
+    return AidlVersion() >= 2 && property_get_int32("ro.vendor.api_level", 0) >= __ANDROID_API_T__;
 }
 
 /**
diff --git a/security/keymint/support/include/remote_prov/remote_prov_utils.h b/security/keymint/support/include/remote_prov/remote_prov_utils.h
index 1d7db6a..b7c32ca 100644
--- a/security/keymint/support/include/remote_prov/remote_prov_utils.h
+++ b/security/keymint/support/include/remote_prov/remote_prov_utils.h
@@ -167,7 +167,8 @@
         const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
         const std::vector<uint8_t>& keysToSignMac, const ProtectedData& protectedData,
         const EekChain& eekChain, const std::vector<uint8_t>& eekId, int32_t supportedEekCurve,
-        IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge);
+        IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge,
+        bool allowAnyMode = false);
 
 /**
  * Verify the CSR as if the device is still early in the factory process and may not
@@ -181,7 +182,8 @@
  */
 ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyProductionCsr(
         const cppbor::Array& keysToSign, const std::vector<uint8_t>& csr,
-        IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge);
+        IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge,
+        bool allowAnyMode = false);
 
 /** Checks whether the CSR has a proper DICE chain. */
 ErrMsgOr<bool> isCsrWithProperDiceChain(const std::vector<uint8_t>& csr);
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
index 6638775..646037c 100644
--- a/security/keymint/support/remote_prov_utils.cpp
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -325,9 +325,16 @@
 }
 
 ErrMsgOr<std::vector<BccEntryData>> validateBcc(const cppbor::Array* bcc,
-                                                hwtrust::DiceChain::Kind kind) {
+                                                hwtrust::DiceChain::Kind kind, bool allowAnyMode) {
     auto encodedBcc = bcc->encode();
-    auto chain = hwtrust::DiceChain::Verify(encodedBcc, kind);
+
+    // Use ro.build.type instead of ro.debuggable because ro.debuggable=1 for VTS testing
+    std::string build_type = ::android::base::GetProperty("ro.build.type", "");
+    if (!build_type.empty() && build_type != "user") {
+        allowAnyMode = true;
+    }
+
+    auto chain = hwtrust::DiceChain::Verify(encodedBcc, kind, allowAnyMode);
     if (!chain.ok()) return chain.error().message();
     auto keys = chain->CosePublicKeys();
     if (!keys.ok()) return keys.error().message();
@@ -638,7 +645,7 @@
         const std::vector<uint8_t>& keysToSignMac, const ProtectedData& protectedData,
         const EekChain& eekChain, const std::vector<uint8_t>& eekId, int32_t supportedEekCurve,
         IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge,
-        bool isFactory) {
+        bool isFactory, bool allowAnyMode = false) {
     auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
     if (!parsedProtectedData) {
         return protDataErrMsg;
@@ -694,7 +701,7 @@
     }
 
     // BCC is [ pubkey, + BccEntry]
-    auto bccContents = validateBcc(bcc->asArray(), hwtrust::DiceChain::Kind::kVsr13);
+    auto bccContents = validateBcc(bcc->asArray(), hwtrust::DiceChain::Kind::kVsr13, allowAnyMode);
     if (!bccContents) {
         return bccContents.message() + "\n" + prettyPrint(bcc.get());
     }
@@ -747,10 +754,11 @@
         const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
         const std::vector<uint8_t>& keysToSignMac, const ProtectedData& protectedData,
         const EekChain& eekChain, const std::vector<uint8_t>& eekId, int32_t supportedEekCurve,
-        IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge) {
+        IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge,
+        bool allowAnyMode) {
     return verifyProtectedData(deviceInfo, keysToSign, keysToSignMac, protectedData, eekChain,
                                eekId, supportedEekCurve, provisionable, challenge,
-                               /*isFactory=*/false);
+                               /*isFactory=*/false, allowAnyMode);
 }
 
 ErrMsgOr<X509_Ptr> parseX509Cert(const std::vector<uint8_t>& cert) {
@@ -974,20 +982,22 @@
 
 ErrMsgOr<hwtrust::DiceChain::Kind> getDiceChainKind() {
     int vendor_api_level = ::android::base::GetIntProperty("ro.vendor.api_level", -1);
-    switch (vendor_api_level) {
-        case __ANDROID_API_T__:
-            return hwtrust::DiceChain::Kind::kVsr13;
-        case __ANDROID_API_U__:
-            return hwtrust::DiceChain::Kind::kVsr14;
-        case 202404: /* TODO(b/315056516) Use a version macro for vendor API 24Q2 */
-            return hwtrust::DiceChain::Kind::kVsr15;
-        default:
-            return "Unsupported vendor API level: " + std::to_string(vendor_api_level);
+    if (vendor_api_level == __ANDROID_API_T__) {
+        return hwtrust::DiceChain::Kind::kVsr13;
+    } else if (vendor_api_level == __ANDROID_API_U__) {
+        return hwtrust::DiceChain::Kind::kVsr14;
+    } else if (vendor_api_level == 202404) {
+        return hwtrust::DiceChain::Kind::kVsr15;
+    } else if (vendor_api_level > 202404) {
+        return hwtrust::DiceChain::Kind::kVsr16;
+    } else {
+        return "Unsupported vendor API level: " + std::to_string(vendor_api_level);
     }
 }
 
 ErrMsgOr<bytevec> parseAndValidateAuthenticatedRequest(const std::vector<uint8_t>& request,
-                                                       const std::vector<uint8_t>& challenge) {
+                                                       const std::vector<uint8_t>& challenge,
+                                                       bool allowAnyMode = false) {
     auto [parsedRequest, _, csrErrMsg] = cppbor::parse(request);
     if (!parsedRequest) {
         return csrErrMsg;
@@ -1025,7 +1035,7 @@
         return diceChainKind.message();
     }
 
-    auto diceContents = validateBcc(diceCertChain, *diceChainKind);
+    auto diceContents = validateBcc(diceCertChain, *diceChainKind, allowAnyMode);
     if (!diceContents) {
         return diceContents.message() + "\n" + prettyPrint(diceCertChain);
     }
@@ -1054,7 +1064,7 @@
                                                    const std::vector<uint8_t>& csr,
                                                    IRemotelyProvisionedComponent* provisionable,
                                                    const std::vector<uint8_t>& challenge,
-                                                   bool isFactory) {
+                                                   bool isFactory, bool allowAnyMode = false) {
     RpcHardwareInfo info;
     provisionable->getHardwareInfo(&info);
     if (info.versionNumber != 3) {
@@ -1062,7 +1072,7 @@
                ") does not match expected version (3).";
     }
 
-    auto csrPayload = parseAndValidateAuthenticatedRequest(csr, challenge);
+    auto csrPayload = parseAndValidateAuthenticatedRequest(csr, challenge, allowAnyMode);
     if (!csrPayload) {
         return csrPayload.message();
     }
@@ -1078,8 +1088,9 @@
 
 ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyProductionCsr(
         const cppbor::Array& keysToSign, const std::vector<uint8_t>& csr,
-        IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge) {
-    return verifyCsr(keysToSign, csr, provisionable, challenge, /*isFactory=*/false);
+        IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge,
+        bool allowAnyMode) {
+    return verifyCsr(keysToSign, csr, provisionable, challenge, /*isFactory=*/false, allowAnyMode);
 }
 
 ErrMsgOr<bool> isCsrWithProperDiceChain(const std::vector<uint8_t>& csr) {
@@ -1113,7 +1124,8 @@
     }
 
     auto encodedDiceChain = diceCertChain->encode();
-    auto chain = hwtrust::DiceChain::Verify(encodedDiceChain, *diceChainKind);
+    auto chain =
+            hwtrust::DiceChain::Verify(encodedDiceChain, *diceChainKind, /*allowAnyMode=*/false);
     if (!chain.ok()) return chain.error().message();
     return chain->IsProper();
 }
diff --git a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index 2dbc73f..f68ff91 100644
--- a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -188,7 +188,8 @@
         }
         ASSERT_NE(provisionable_, nullptr);
         auto status = provisionable_->getHardwareInfo(&rpcHardwareInfo);
-        if (GetParam() == RKP_VM_INSTANCE_NAME) {
+        isRkpVmInstance_ = GetParam() == RKP_VM_INSTANCE_NAME;
+        if (isRkpVmInstance_) {
             if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
                 GTEST_SKIP() << "The RKP VM is not supported on this system.";
             }
@@ -209,6 +210,7 @@
   protected:
     std::shared_ptr<IRemotelyProvisionedComponent> provisionable_;
     RpcHardwareInfo rpcHardwareInfo;
+    bool isRkpVmInstance_;
 };
 
 /**
@@ -765,7 +767,8 @@
                 provisionable_->generateCertificateRequestV2({} /* keysToSign */, challenge, &csr);
         ASSERT_TRUE(status.isOk()) << status.getDescription();
 
-        auto result = verifyProductionCsr(cppbor::Array(), csr, provisionable_.get(), challenge);
+        auto result = verifyProductionCsr(cppbor::Array(), csr, provisionable_.get(), challenge,
+                                          isRkpVmInstance_);
         ASSERT_TRUE(result) << result.message();
     }
 }
@@ -786,7 +789,8 @@
         auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge, &csr);
         ASSERT_TRUE(status.isOk()) << status.getDescription();
 
-        auto result = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge);
+        auto result = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge,
+                                          isRkpVmInstance_);
         ASSERT_TRUE(result) << result.message();
     }
 }
@@ -816,13 +820,15 @@
     auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
     ASSERT_TRUE(status.isOk()) << status.getDescription();
 
-    auto firstCsr = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
+    auto firstCsr = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_,
+                                        isRkpVmInstance_);
     ASSERT_TRUE(firstCsr) << firstCsr.message();
 
     status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
     ASSERT_TRUE(status.isOk()) << status.getDescription();
 
-    auto secondCsr = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
+    auto secondCsr = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_,
+                                         isRkpVmInstance_);
     ASSERT_TRUE(secondCsr) << secondCsr.message();
 
     ASSERT_EQ(**firstCsr, **secondCsr);
@@ -840,7 +846,8 @@
     auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
     ASSERT_TRUE(status.isOk()) << status.getDescription();
 
-    auto result = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
+    auto result = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_,
+                                      isRkpVmInstance_);
     ASSERT_TRUE(result) << result.message();
 }
 
diff --git a/threadnetwork/aidl/default/Android.bp b/threadnetwork/aidl/default/Android.bp
index 51e5c25..a840fa3 100644
--- a/threadnetwork/aidl/default/Android.bp
+++ b/threadnetwork/aidl/default/Android.bp
@@ -14,6 +14,8 @@
     vendor: true,
     relative_install_path: "hw",
 
+    defaults: ["android.hardware.threadnetwork-service.defaults"],
+
     shared_libs: [
         "libbinder_ndk",
         "liblog",
@@ -43,6 +45,17 @@
     ],
 }
 
+cc_defaults {
+    name: "android.hardware.threadnetwork-service.defaults",
+    product_variables: {
+        debuggable: {
+            cppflags: [
+                "-DDEV_BUILD",
+            ],
+        },
+    },
+}
+
 cc_fuzz {
     name: "android.hardware.threadnetwork-service.fuzzer",
 
diff --git a/threadnetwork/aidl/default/socket_interface.cpp b/threadnetwork/aidl/default/socket_interface.cpp
index 339fd6b..a5aa2b4 100644
--- a/threadnetwork/aidl/default/socket_interface.cpp
+++ b/threadnetwork/aidl/default/socket_interface.cpp
@@ -94,8 +94,8 @@
 otError SocketInterface::WaitForFrame(uint64_t aTimeoutUs) {
     otError error = OT_ERROR_NONE;
     struct timeval timeout;
-    timeout.tv_sec = static_cast<time_t>(aTimeoutUs / US_PER_S);
-    timeout.tv_usec = static_cast<suseconds_t>(aTimeoutUs % US_PER_S);
+    timeout.tv_sec = static_cast<time_t>(aTimeoutUs / OT_US_PER_S);
+    timeout.tv_usec = static_cast<suseconds_t>(aTimeoutUs % OT_US_PER_S);
 
     fd_set readFds;
     fd_set errorFds;
@@ -133,8 +133,8 @@
 
     while (mIsHardwareResetting && retries++ < kMaxRetriesForSocketCloseCheck) {
         struct timeval timeout;
-        timeout.tv_sec = static_cast<time_t>(aTimeoutMs / MS_PER_S);
-        timeout.tv_usec = static_cast<suseconds_t>((aTimeoutMs % MS_PER_S) * MS_PER_S);
+        timeout.tv_sec = static_cast<time_t>(aTimeoutMs / OT_MS_PER_S);
+        timeout.tv_usec = static_cast<suseconds_t>((aTimeoutMs % OT_MS_PER_S) * OT_MS_PER_S);
 
         fd_set readFds;
 
@@ -314,8 +314,8 @@
         fd_set fds;
         FD_ZERO(&fds);
         FD_SET(inotifyFd, &fds);
-        struct timeval timeout = {kMaxSelectTimeMs / MS_PER_S,
-                                  (kMaxSelectTimeMs % MS_PER_S) * MS_PER_S};
+        struct timeval timeout = {kMaxSelectTimeMs / OT_MS_PER_S,
+                                  (kMaxSelectTimeMs % OT_MS_PER_S) * OT_MS_PER_S};
 
         int rval = select(inotifyFd + 1, &fds, nullptr, nullptr, &timeout);
         VerifyOrDie(rval >= 0, OT_EXIT_ERROR_ERRNO);
diff --git a/threadnetwork/aidl/default/utils.cpp b/threadnetwork/aidl/default/utils.cpp
index 3552b3a..740f331 100644
--- a/threadnetwork/aidl/default/utils.cpp
+++ b/threadnetwork/aidl/default/utils.cpp
@@ -43,6 +43,7 @@
 }
 
 void otDumpDebgPlat(const char* aText, const void* aData, uint16_t aDataLength) {
+#ifdef DEV_BUILD
     constexpr uint16_t kBufSize = 512;
     char buf[kBufSize];
 
@@ -55,6 +56,11 @@
 
         __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "%s: %s", aText, buf);
     }
+#else
+    OT_UNUSED_VARIABLE(aText);
+    OT_UNUSED_VARIABLE(aData);
+    OT_UNUSED_VARIABLE(aDataLength);
+#endif
 }
 
 OT_TOOL_WEAK void otPlatAlarmMilliFired(otInstance* aInstance) {
diff --git a/tv/tuner/aidl/Android.bp b/tv/tuner/aidl/Android.bp
index 6cbf362..efcc327 100644
--- a/tv/tuner/aidl/Android.bp
+++ b/tv/tuner/aidl/Android.bp
@@ -41,6 +41,5 @@
         },
 
     ],
-    frozen: true,
 
 }
diff --git a/tv/tuner/aidl/default/Android.bp b/tv/tuner/aidl/default/Android.bp
index ed97d9c..a76a653 100644
--- a/tv/tuner/aidl/default/Android.bp
+++ b/tv/tuner/aidl/default/Android.bp
@@ -10,7 +10,6 @@
 cc_defaults {
     name: "tuner_hal_example_defaults",
     relative_install_path: "hw",
-    vintf_fragments: ["tuner-default.xml"],
     vendor: true,
     compile_multilib: "first",
     srcs: [
@@ -30,7 +29,7 @@
     ],
     shared_libs: [
         "android.hardware.common.fmq-V1-ndk",
-        "android.hardware.tv.tuner-V2-ndk",
+        "android.hardware.tv.tuner-V3-ndk",
         "libbase",
         "libbinder_ndk",
         "libcutils",
@@ -43,6 +42,15 @@
     header_libs: [
         "media_plugin_headers",
     ],
+    vintf_fragment_modules: [
+        "tuner-default.xml",
+    ],
+}
+
+vintf_fragment {
+    name: "tuner-default.xml",
+    src: "tuner-default.xml",
+    vendor: true,
 }
 
 cc_binary {
diff --git a/tv/tuner/aidl/vts/functional/Android.bp b/tv/tuner/aidl/vts/functional/Android.bp
index 09e63fc..0057b6f 100644
--- a/tv/tuner/aidl/vts/functional/Android.bp
+++ b/tv/tuner/aidl/vts/functional/Android.bp
@@ -55,7 +55,7 @@
         "android.hardware.cas-V1-ndk",
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
-        "android.hardware.tv.tuner-V2-ndk",
+        "android.hardware.tv.tuner-V3-ndk",
         "libaidlcommonsupport",
         "libfmq",
         "libcutils",
diff --git a/uwb/aidl/vts/VtsHalUwbTargetTest.cpp b/uwb/aidl/vts/VtsHalUwbTargetTest.cpp
index 548cae0..2b09f7e 100644
--- a/uwb/aidl/vts/VtsHalUwbTargetTest.cpp
+++ b/uwb/aidl/vts/VtsHalUwbTargetTest.cpp
@@ -201,14 +201,15 @@
     EXPECT_EQ(retrieved_chip_name, chip_name);
 }
 
-/**
 TEST_P(UwbAidl, ChipSendUciMessage_GetDeviceInfo) {
-const auto iuwb_chip = getAnyChipAndOpen(callback);
-EXPECT_TRUE(iuwb_chip->coreInit(callback).isOk());
+    const auto iuwb_chip = getAnyChipAndOpen();
+    EXPECT_TRUE(iuwb_chip->coreInit().isOk());
 
-const std::vector<uint8_t>
-EXPECT_TRUE(iuwb_chip->sendUciMessage().isOk());
-} */
+    std::vector<uint8_t> uciMessage = {0x20, 0x02, 0x00, 0x00}; /** CoreGetDeviceInfo */
+    int32_t* return_status = new int32_t;
+    EXPECT_TRUE(iuwb_chip->sendUciMessage(uciMessage, return_status).isOk());
+    EXPECT_EQ(*return_status, 4 /* Status Ok */);
+}
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UwbAidl);
 INSTANTIATE_TEST_SUITE_P(Uwb, UwbAidl,
diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrator.aidl
index af619c6..0dcc657 100644
--- a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrator.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrator.aidl
@@ -59,6 +59,11 @@
   android.hardware.vibrator.Braking[] getSupportedBraking();
   void composePwle(in android.hardware.vibrator.PrimitivePwle[] composite, in android.hardware.vibrator.IVibratorCallback callback);
   void performVendorEffect(in android.hardware.vibrator.VendorEffect vendorEffect, in android.hardware.vibrator.IVibratorCallback callback);
+  List<android.hardware.vibrator.PwleV2OutputMapEntry> getPwleV2FrequencyToOutputAccelerationMap();
+  int getPwleV2PrimitiveDurationMaxMillis();
+  int getPwleV2CompositionSizeMax();
+  int getPwleV2PrimitiveDurationMinMillis();
+  void composePwleV2(in android.hardware.vibrator.PwleV2Primitive[] composite, in android.hardware.vibrator.IVibratorCallback callback);
   const int CAP_ON_CALLBACK = (1 << 0) /* 1 */;
   const int CAP_PERFORM_CALLBACK = (1 << 1) /* 2 */;
   const int CAP_AMPLITUDE_CONTROL = (1 << 2) /* 4 */;
@@ -71,4 +76,5 @@
   const int CAP_FREQUENCY_CONTROL = (1 << 9) /* 512 */;
   const int CAP_COMPOSE_PWLE_EFFECTS = (1 << 10) /* 1024 */;
   const int CAP_PERFORM_VENDOR_EFFECTS = (1 << 11) /* 2048 */;
+  const int CAP_COMPOSE_PWLE_EFFECTS_V2 = (1 << 12) /* 4096 */;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PwleV2OutputMapEntry.aidl
similarity index 88%
rename from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
rename to vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PwleV2OutputMapEntry.aidl
index 173ac17..a5eda52 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PwleV2OutputMapEntry.aidl
@@ -31,10 +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.biometrics.fingerprint;
-/* @hide */
+package android.hardware.vibrator;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable PwleV2OutputMapEntry {
+  float frequencyHz;
+  float maxOutputAccelerationGs;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PwleV2Primitive.aidl
similarity index 88%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PwleV2Primitive.aidl
index 173ac17..c4f3ea9 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PwleV2Primitive.aidl
@@ -31,10 +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.biometrics.fingerprint;
-/* @hide */
+package android.hardware.vibrator;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable PwleV2Primitive {
+  float amplitude;
+  float frequencyHz;
+  int timeMillis;
 }
diff --git a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
index 768ec4f..11f36ba 100644
--- a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
@@ -23,6 +23,8 @@
 import android.hardware.vibrator.EffectStrength;
 import android.hardware.vibrator.IVibratorCallback;
 import android.hardware.vibrator.PrimitivePwle;
+import android.hardware.vibrator.PwleV2OutputMapEntry;
+import android.hardware.vibrator.PwleV2Primitive;
 import android.hardware.vibrator.VendorEffect;
 
 @VintfStability
@@ -75,6 +77,10 @@
      * Whether perform w/ vendor effect is supported.
      */
     const int CAP_PERFORM_VENDOR_EFFECTS = 1 << 11;
+    /**
+     * Whether composePwleV2 for PwlePrimitives is supported.
+     */
+    const int CAP_COMPOSE_PWLE_EFFECTS_V2 = 1 << 12;
 
     /**
      * Determine capabilities of the vibrator HAL (CAP_* mask)
@@ -385,4 +391,82 @@
      *         - EX_SERVICE_SPECIFIC for bad vendor data, vibration is not triggered.
      */
     void performVendorEffect(in VendorEffect vendorEffect, in IVibratorCallback callback);
+
+    /**
+     * Retrieves a mapping of vibration frequency (Hz) to the maximum achievable output
+     * acceleration (Gs) the device can reach at that frequency.
+     *
+     * The map, represented as a list of `PwleV2OutputMapEntry` (frequency, output acceleration)
+     * pairs, defines the device's frequency response. The platform uses the minimum and maximum
+     * frequency values to determine the supported input range for `IVibrator.composePwleV2`.
+     * Output acceleration values are used to identify a frequency range suitable to safely play
+     * perceivable vibrations with a simple API. The map is also exposed for developers using an
+     * advanced API.
+     *
+     * The platform does not impose specific requirements on map resolution which can vary
+     * depending on the shape of device output curve. The values will be linearly interpolated
+     * during lookups. The platform will provide a simple API, defined by the first frequency range
+     * where output acceleration consistently exceeds a minimum threshold of 10 db SL.
+     *
+     *
+     * This may not be supported and this support is reflected in getCapabilities
+     * (CAP_COMPOSE_PWLE_EFFECTS_V2). If this is supported, it's expected to be non-empty and
+     * describe a valid non-empty frequency range where the simple API can be defined
+     * (i.e. a range where the output acceleration is always above 10 db SL).
+     *
+     * @return A list of map entries representing the frequency to max acceleration
+     *         mapping.
+     * @throws EX_UNSUPPORTED_OPERATION if unsupported, as reflected by getCapabilities.
+     */
+    List<PwleV2OutputMapEntry> getPwleV2FrequencyToOutputAccelerationMap();
+
+    /**
+     * Retrieve the maximum duration allowed for any primitive PWLE in units of
+     * milliseconds.
+     *
+     * This may not be supported and this support is reflected in
+     * getCapabilities (CAP_COMPOSE_PWLE_EFFECTS_V2).
+     *
+     * @return The maximum duration allowed for a single PrimitivePwle. Non-zero value if supported.
+     * @throws EX_UNSUPPORTED_OPERATION if unsupported, as reflected by getCapabilities.
+     */
+    int getPwleV2PrimitiveDurationMaxMillis();
+
+    /**
+     * Retrieve the maximum number of PWLE primitives input supported by IVibrator.composePwleV2.
+     *
+     * This may not be supported and this support is reflected in
+     * getCapabilities (CAP_COMPOSE_PWLE_EFFECTS_V2). Devices supporting PWLE effects must
+     * support effects with at least 16 PwleV2Primitive.
+     *
+     * @return The maximum count allowed. Non-zero value if supported.
+     * @throws EX_UNSUPPORTED_OPERATION if unsupported, as reflected by getCapabilities.
+     */
+    int getPwleV2CompositionSizeMax();
+
+    /**
+     * Retrieves the minimum duration (in milliseconds) of any segment within a
+     * PWLE effect. Devices supporting PWLE effects must support a minimum ramp
+     * time of 20 milliseconds.
+     *
+     * This may not be supported and this support is reflected in
+     * getCapabilities (CAP_COMPOSE_PWLE_EFFECTS_V2).
+     *
+     * @return The minimum duration allowed for a single PrimitivePwle. Non-zero value if supported.
+     * @throws EX_UNSUPPORTED_OPERATION if unsupported, as reflected by getCapabilities.
+     */
+    int getPwleV2PrimitiveDurationMinMillis();
+
+    /**
+     * Play composed sequence of chirps with optional callback upon completion.
+     *
+     * This may not be supported and this support is reflected in
+     * getCapabilities (CAP_COMPOSE_PWLE_EFFECTS_V2).
+     *
+     * Doing this operation while the vibrator is already on is undefined behavior. Clients should
+     * explicitly call off. IVibratorCallback.onComplete() support is required for this API.
+     *
+     * @param composite An array of primitives that represents a PWLE (Piecewise-Linear Envelope).
+     */
+    void composePwleV2(in PwleV2Primitive[] composite, in IVibratorCallback callback);
 }
diff --git a/vibrator/aidl/android/hardware/vibrator/PwleV2OutputMapEntry.aidl b/vibrator/aidl/android/hardware/vibrator/PwleV2OutputMapEntry.aidl
new file mode 100644
index 0000000..a8db87c
--- /dev/null
+++ b/vibrator/aidl/android/hardware/vibrator/PwleV2OutputMapEntry.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.vibrator;
+
+@VintfStability
+parcelable PwleV2OutputMapEntry {
+    /**
+     * Absolute frequency point in the units of hertz
+     *
+     */
+    float frequencyHz;
+
+    /**
+     * Max output acceleration for the specified frequency in units of Gs.
+     *
+     * This value represents the maximum safe output acceleration (in Gs) achievable at the
+     * specified frequency, typically determined during calibration. The actual output acceleration
+     * is assumed to scale linearly with the input amplitude within the range of [0, 1].
+     */
+    float maxOutputAccelerationGs;
+}
diff --git a/vibrator/aidl/android/hardware/vibrator/PwleV2Primitive.aidl b/vibrator/aidl/android/hardware/vibrator/PwleV2Primitive.aidl
new file mode 100644
index 0000000..bd7bec6
--- /dev/null
+++ b/vibrator/aidl/android/hardware/vibrator/PwleV2Primitive.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.vibrator;
+
+@VintfStability
+parcelable PwleV2Primitive {
+    /**
+     * Input amplitude ranges from 0.0 (inclusive) to 1.0 (inclusive), representing the relative
+     * input value. Actual output acceleration depends on frequency and device response curve
+     * (see IVibrator.getPwleV2FrequencyToOutputAccelerationMap for max values).
+     *
+     * Input amplitude linearly maps to output acceleration (e.g., 0.5 amplitude yields half the
+     * max acceleration for that frequency).
+     *
+     * 0.0 represents no output acceleration amplitude
+     * 1.0 represents the maximum achievable strength for each frequency, as determined by the
+     *     actuator response curve
+     */
+    float amplitude;
+
+    /**
+     * Absolute frequency point in the units of hertz
+     *
+     * Values are within the continuous inclusive frequency range defined by
+     * IVibrator#getPwleV2FrequencyToOutputAccelerationMap.
+     */
+    float frequencyHz;
+
+    /* Total time from the previous PWLE point to the current one in units of milliseconds. */
+    int timeMillis;
+}
diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp
index 29e7d18..4f8c2b8 100644
--- a/vibrator/aidl/default/Vibrator.cpp
+++ b/vibrator/aidl/default/Vibrator.cpp
@@ -27,9 +27,12 @@
 static constexpr int32_t COMPOSE_DELAY_MAX_MS = 1000;
 static constexpr int32_t COMPOSE_SIZE_MAX = 256;
 static constexpr int32_t COMPOSE_PWLE_SIZE_MAX = 127;
+static constexpr int32_t COMPOSE_PWLE_V2_SIZE_MAX = 16;
 
 static constexpr float Q_FACTOR = 11.0;
 static constexpr int32_t COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS = 16383;
+static constexpr int32_t COMPOSE_PWLE_V2_PRIMITIVE_DURATION_MAX_MS = 1000;
+static constexpr int32_t COMPOSE_PWLE_V2_PRIMITIVE_DURATION_MIN_MS = 20;
 static constexpr float PWLE_LEVEL_MIN = 0.0;
 static constexpr float PWLE_LEVEL_MAX = 1.0;
 static constexpr float PWLE_FREQUENCY_RESOLUTION_HZ = 1.0;
@@ -44,12 +47,25 @@
 
 ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) {
     LOG(VERBOSE) << "Vibrator reporting capabilities";
-    *_aidl_return = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK |
-                    IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_EXTERNAL_CONTROL |
-                    IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL | IVibrator::CAP_COMPOSE_EFFECTS |
-                    IVibrator::CAP_ALWAYS_ON_CONTROL | IVibrator::CAP_GET_RESONANT_FREQUENCY |
-                    IVibrator::CAP_GET_Q_FACTOR | IVibrator::CAP_FREQUENCY_CONTROL |
-                    IVibrator::CAP_COMPOSE_PWLE_EFFECTS | IVibrator::CAP_PERFORM_VENDOR_EFFECTS;
+    std::lock_guard lock(mMutex);
+    if (mCapabilities == 0) {
+        if (!getInterfaceVersion(&mVersion).isOk()) {
+            return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_STATE));
+        }
+        mCapabilities = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK |
+                        IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_EXTERNAL_CONTROL |
+                        IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL | IVibrator::CAP_COMPOSE_EFFECTS |
+                        IVibrator::CAP_ALWAYS_ON_CONTROL | IVibrator::CAP_GET_RESONANT_FREQUENCY |
+                        IVibrator::CAP_GET_Q_FACTOR | IVibrator::CAP_FREQUENCY_CONTROL |
+                        IVibrator::CAP_COMPOSE_PWLE_EFFECTS;
+
+        if (mVersion >= 3) {
+            mCapabilities |= (IVibrator::CAP_PERFORM_VENDOR_EFFECTS |
+                              IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2);
+        }
+    }
+
+    *_aidl_return = mCapabilities;
     return ndk::ScopedAStatus::ok();
 }
 
@@ -108,6 +124,13 @@
 ndk::ScopedAStatus Vibrator::performVendorEffect(
         const VendorEffect& effect, const std::shared_ptr<IVibratorCallback>& callback) {
     LOG(VERBOSE) << "Vibrator perform vendor effect";
+    int32_t capabilities = 0;
+    if (!getCapabilities(&capabilities).isOk()) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if ((capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) == 0) {
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+    }
     EffectStrength strength = effect.strength;
     if (strength != EffectStrength::LIGHT && strength != EffectStrength::MEDIUM &&
         strength != EffectStrength::STRONG) {
@@ -449,6 +472,122 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Vibrator::getPwleV2FrequencyToOutputAccelerationMap(
+        std::vector<PwleV2OutputMapEntry>* _aidl_return) {
+    std::vector<PwleV2OutputMapEntry> frequencyToOutputAccelerationMap;
+
+    std::vector<std::pair<float, float>> frequencyToOutputAccelerationData = {
+            {30.0f, 0.01f},  {46.0f, 0.09f},  {50.0f, 0.1f},   {55.0f, 0.12f},  {62.0f, 0.66f},
+            {83.0f, 0.82f},  {85.0f, 0.85f},  {92.0f, 1.05f},  {107.0f, 1.63f}, {115.0f, 1.72f},
+            {123.0f, 1.81f}, {135.0f, 2.23f}, {144.0f, 2.47f}, {145.0f, 2.5f},  {150.0f, 3.0f},
+            {175.0f, 2.51f}, {181.0f, 2.41f}, {190.0f, 2.28f}, {200.0f, 2.08f}, {204.0f, 1.96f},
+            {205.0f, 1.9f},  {224.0f, 1.7f},  {235.0f, 1.5f},  {242.0f, 1.46f}, {253.0f, 1.41f},
+            {263.0f, 1.39f}, {65.0f, 1.38f},  {278.0f, 1.37f}, {294.0f, 1.35f}, {300.0f, 1.34f}};
+    for (const auto& entry : frequencyToOutputAccelerationData) {
+        frequencyToOutputAccelerationMap.push_back(
+                PwleV2OutputMapEntry(/*frequency=*/entry.first,
+                                     /*maxOutputAcceleration=*/entry.second));
+    }
+
+    *_aidl_return = frequencyToOutputAccelerationMap;
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::getPwleV2PrimitiveDurationMaxMillis(int32_t* maxDurationMs) {
+    *maxDurationMs = COMPOSE_PWLE_V2_PRIMITIVE_DURATION_MAX_MS;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::getPwleV2CompositionSizeMax(int32_t* maxSize) {
+    *maxSize = COMPOSE_PWLE_V2_SIZE_MAX;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::getPwleV2PrimitiveDurationMinMillis(int32_t* minDurationMs) {
+    *minDurationMs = COMPOSE_PWLE_V2_PRIMITIVE_DURATION_MIN_MS;
+    return ndk::ScopedAStatus::ok();
+}
+
+float getPwleV2FrequencyMinHz(std::vector<PwleV2OutputMapEntry> frequencyToOutputAccelerationMap) {
+    if (frequencyToOutputAccelerationMap.empty()) {
+        return 0.0f;
+    }
+
+    float minFrequency = frequencyToOutputAccelerationMap[0].frequencyHz;
+
+    for (const auto& entry : frequencyToOutputAccelerationMap) {
+        if (entry.frequencyHz < minFrequency) {
+            minFrequency = entry.frequencyHz;
+        }
+    }
+
+    return minFrequency;
+}
+
+float getPwleV2FrequencyMaxHz(std::vector<PwleV2OutputMapEntry> frequencyToOutputAccelerationMap) {
+    if (frequencyToOutputAccelerationMap.empty()) {
+        return 0.0f;
+    }
+
+    float maxFrequency = frequencyToOutputAccelerationMap[0].frequencyHz;
+
+    for (const auto& entry : frequencyToOutputAccelerationMap) {
+        if (entry.frequencyHz > maxFrequency) {
+            maxFrequency = entry.frequencyHz;
+        }
+    }
+
+    return maxFrequency;
+}
+
+ndk::ScopedAStatus Vibrator::composePwleV2(const std::vector<PwleV2Primitive>& composite,
+                                           const std::shared_ptr<IVibratorCallback>& callback) {
+    int32_t capabilities = 0;
+    if (!getCapabilities(&capabilities).isOk()) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if ((capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2) == 0) {
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+    }
+
+    int compositionSizeMax;
+    getPwleV2CompositionSizeMax(&compositionSizeMax);
+    if (composite.size() <= 0 || composite.size() > compositionSizeMax) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+
+    int32_t totalEffectDuration = 0;
+    std::vector<PwleV2OutputMapEntry> frequencyToOutputAccelerationMap;
+    getPwleV2FrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap);
+    float minFrequency = getPwleV2FrequencyMinHz(frequencyToOutputAccelerationMap);
+    float maxFrequency = getPwleV2FrequencyMaxHz(frequencyToOutputAccelerationMap);
+
+    for (auto& e : composite) {
+        if (e.timeMillis < 0.0f || e.timeMillis > COMPOSE_PWLE_V2_PRIMITIVE_DURATION_MAX_MS) {
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        }
+        if (e.amplitude < 0.0f || e.amplitude > 1.0f) {
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        }
+        if (e.frequencyHz < minFrequency || e.frequencyHz > maxFrequency) {
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        }
+        totalEffectDuration += e.timeMillis;
+    }
+
+    std::thread([totalEffectDuration, callback] {
+        LOG(VERBOSE) << "Starting composePwleV2 on another thread";
+        usleep(totalEffectDuration * 1000);
+        if (callback != nullptr) {
+            LOG(VERBOSE) << "Notifying compose PWLE V2 complete";
+            callback->onComplete();
+        }
+    }).detach();
+
+    return ndk::ScopedAStatus::ok();
+}
+
 }  // namespace vibrator
 }  // namespace hardware
 }  // namespace android
diff --git a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
index e8f64ca..28bc763 100644
--- a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
+++ b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <aidl/android/hardware/vibrator/BnVibrator.h>
+#include <android-base/thread_annotations.h>
 
 namespace aidl {
 namespace android {
@@ -57,7 +58,18 @@
     ndk::ScopedAStatus getSupportedBraking(std::vector<Braking>* supported) override;
     ndk::ScopedAStatus composePwle(const std::vector<PrimitivePwle> &composite,
                                    const std::shared_ptr<IVibratorCallback> &callback) override;
+    ndk::ScopedAStatus getPwleV2FrequencyToOutputAccelerationMap(
+            std::vector<PwleV2OutputMapEntry>* _aidl_return) override;
+    ndk::ScopedAStatus getPwleV2PrimitiveDurationMaxMillis(int32_t* maxDurationMs) override;
+    ndk::ScopedAStatus getPwleV2PrimitiveDurationMinMillis(int32_t* minDurationMs) override;
+    ndk::ScopedAStatus getPwleV2CompositionSizeMax(int32_t* maxSize) override;
+    ndk::ScopedAStatus composePwleV2(const std::vector<PwleV2Primitive>& composite,
+                                     const std::shared_ptr<IVibratorCallback>& callback) override;
 
+  private:
+    mutable std::mutex mMutex;
+    int32_t mVersion GUARDED_BY(mMutex) = 0;  // current Hal version
+    int32_t mCapabilities GUARDED_BY(mMutex) = 0;
 };
 
 }  // namespace vibrator
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index 2502589..bc017ae 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -27,8 +27,12 @@
 #include <cstdlib>
 #include <ctime>
 #include <future>
+#include <iomanip>
+#include <iostream>
+#include <random>
 
 #include "persistable_bundle_utils.h"
+#include "pwle_v2_utils.h"
 #include "test_utils.h"
 
 using aidl::android::hardware::vibrator::ActivePwle;
@@ -42,12 +46,16 @@
 using aidl::android::hardware::vibrator::IVibrator;
 using aidl::android::hardware::vibrator::IVibratorManager;
 using aidl::android::hardware::vibrator::PrimitivePwle;
+using aidl::android::hardware::vibrator::PwleV2OutputMapEntry;
+using aidl::android::hardware::vibrator::PwleV2Primitive;
 using aidl::android::hardware::vibrator::VendorEffect;
 using aidl::android::os::PersistableBundle;
 using std::chrono::high_resolution_clock;
 
 using namespace ::std::chrono_literals;
 
+namespace pwle_v2_utils = aidl::android::hardware::vibrator::testing::pwlev2;
+
 const std::vector<Effect> kEffects{ndk::enum_range<Effect>().begin(),
                                    ndk::enum_range<Effect>().end()};
 const std::vector<EffectStrength> kEffectStrengths{ndk::enum_range<EffectStrength>().begin(),
@@ -80,6 +88,9 @@
 // Timeout to wait for vibration callback completion.
 static constexpr std::chrono::milliseconds VIBRATION_CALLBACK_TIMEOUT = 100ms;
 
+static constexpr int32_t VENDOR_EFFECTS_MIN_VERSION = 3;
+static constexpr int32_t PWLE_V2_MIN_VERSION = 3;
+
 static std::vector<std::string> findVibratorManagerNames() {
     std::vector<std::string> names;
     constexpr auto callback = [](const char* instance, void* context) {
@@ -137,6 +148,7 @@
         }
 
         ASSERT_NE(vibrator, nullptr);
+        EXPECT_OK(vibrator->getInterfaceVersion(&version));
         EXPECT_OK(vibrator->getCapabilities(&capabilities));
     }
 
@@ -146,6 +158,7 @@
     }
 
     std::shared_ptr<IVibrator> vibrator;
+    int32_t version;
     int32_t capabilities;
 };
 
@@ -476,6 +489,10 @@
 }
 
 TEST_P(VibratorAidl, PerformVendorEffectUnsupported) {
+    if (version < VENDOR_EFFECTS_MIN_VERSION) {
+        EXPECT_EQ(capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS, 0)
+                << "Vibrator version " << version << " should not report vendor effects capability";
+    }
     if (capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) return;
 
     for (EffectStrength strength : kEffectStrengths) {
@@ -1035,6 +1052,172 @@
     }
 }
 
+TEST_P(VibratorAidl, PwleV2FrequencyToOutputAccelerationMapHasValidFrequencyRange) {
+    if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) {
+        GTEST_SKIP() << "PWLE V2 not supported, skipping test";
+        return;
+    }
+
+    std::vector<PwleV2OutputMapEntry> frequencyToOutputAccelerationMap;
+    ndk::ScopedAStatus status =
+            vibrator->getPwleV2FrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap);
+    EXPECT_OK(std::move(status));
+    ASSERT_FALSE(frequencyToOutputAccelerationMap.empty());
+    auto sharpnessRange =
+            pwle_v2_utils::getPwleV2SharpnessRange(vibrator, frequencyToOutputAccelerationMap);
+    // Validate the curve provides a usable sharpness range, which is a range of frequencies
+    // that are supported by the device.
+    ASSERT_TRUE(sharpnessRange.first >= 0);
+    // Validate that the sharpness range is a valid interval, not a single point.
+    ASSERT_TRUE(sharpnessRange.first < sharpnessRange.second);
+}
+
+TEST_P(VibratorAidl, GetPwleV2PrimitiveDurationMaxMillis) {
+    if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) {
+        GTEST_SKIP() << "PWLE V2 not supported, skipping test";
+        return;
+    }
+
+    int32_t durationMs;
+    ndk::ScopedAStatus status = vibrator->getPwleV2PrimitiveDurationMaxMillis(&durationMs);
+    EXPECT_OK(std::move(status));
+    ASSERT_GT(durationMs, 0);  // Ensure greater than zero
+    ASSERT_GE(durationMs, pwle_v2_utils::COMPOSE_PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS);
+}
+
+TEST_P(VibratorAidl, GetPwleV2CompositionSizeMax) {
+    if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) {
+        GTEST_SKIP() << "PWLE V2 not supported, skipping test";
+        return;
+    }
+
+    int32_t maxSize;
+    ndk::ScopedAStatus status = vibrator->getPwleV2CompositionSizeMax(&maxSize);
+    EXPECT_OK(std::move(status));
+    ASSERT_GT(maxSize, 0);  // Ensure greater than zero
+    ASSERT_GE(maxSize, pwle_v2_utils::COMPOSE_PWLE_V2_MIN_REQUIRED_SIZE);
+}
+
+TEST_P(VibratorAidl, GetPwleV2PrimitiveDurationMinMillis) {
+    if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) {
+        GTEST_SKIP() << "PWLE V2 not supported, skipping test";
+        return;
+    }
+
+    int32_t durationMs;
+    ndk::ScopedAStatus status = vibrator->getPwleV2PrimitiveDurationMinMillis(&durationMs);
+    EXPECT_OK(std::move(status));
+    ASSERT_GT(durationMs, 0);  // Ensure greater than zero
+    ASSERT_LE(durationMs, pwle_v2_utils::COMPOSE_PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS);
+}
+
+TEST_P(VibratorAidl, ComposeValidPwleV2Effect) {
+    if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) {
+        GTEST_SKIP() << "PWLE V2 not supported, skipping test";
+        return;
+    }
+
+    EXPECT_OK(vibrator->composePwleV2(pwle_v2_utils::composeValidPwleV2Effect(vibrator), nullptr));
+    EXPECT_OK(vibrator->off());
+}
+
+TEST_P(VibratorAidl, ComposePwleV2Unsupported) {
+    if (version < PWLE_V2_MIN_VERSION) {
+        EXPECT_EQ(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2, 0)
+                << "Vibrator version " << version << " should not report PWLE V2 capability.";
+    }
+    if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2) return;
+
+    std::vector<PwleV2Primitive> pwleEffect{
+            PwleV2Primitive(/*amplitude=*/1.0f, /*frequencyHz=*/100.0f, /*timeMillis=*/50)};
+
+    EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->composePwleV2(pwleEffect, nullptr));
+}
+
+TEST_P(VibratorAidl, ComposeValidPwleV2EffectWithCallback) {
+    if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) {
+        GTEST_SKIP() << "PWLE V2 not supported, skipping test";
+        return;
+    }
+
+    std::promise<void> completionPromise;
+    std::future<void> completionFuture{completionPromise.get_future()};
+    auto callback = ndk::SharedRefBase::make<CompletionCallback>(
+            [&completionPromise] { completionPromise.set_value(); });
+
+    int32_t minDuration;
+    EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMinMillis(&minDuration));
+    auto timeout = std::chrono::milliseconds(minDuration) + VIBRATION_CALLBACK_TIMEOUT;
+    float minFrequency = pwle_v2_utils::getPwleV2FrequencyMinHz(vibrator);
+
+    EXPECT_OK(vibrator->composePwleV2(
+            {PwleV2Primitive(/*amplitude=*/0.5, minFrequency, minDuration)}, callback));
+    EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
+    EXPECT_OK(vibrator->off());
+}
+
+TEST_P(VibratorAidl, composePwleV2EffectWithTooManyPoints) {
+    if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) {
+        GTEST_SKIP() << "PWLE V2 not supported, skipping test";
+        return;
+    }
+
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(
+            pwle_v2_utils::composePwleV2EffectWithTooManyPoints(vibrator), nullptr));
+}
+
+TEST_P(VibratorAidl, composeInvalidPwleV2Effect) {
+    if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) {
+        GTEST_SKIP() << "PWLE V2 not supported, skipping test";
+        return;
+    }
+
+    // Retrieve min and max durations
+    int32_t minDurationMs, maxDurationMs;
+    EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMinMillis(&minDurationMs));
+    EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMaxMillis(&maxDurationMs));
+
+    std::vector<PwleV2Primitive> composePwle;
+
+    // Negative amplitude
+    composePwle.push_back(PwleV2Primitive(/*amplitude=*/-0.8f, /*frequency=*/100, minDurationMs));
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr))
+            << "Composing PWLE V2 effect with negative amplitude should fail";
+    composePwle.clear();
+
+    // Amplitude exceeding 1.0
+    composePwle.push_back(PwleV2Primitive(/*amplitude=*/1.2f, /*frequency=*/100, minDurationMs));
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr))
+            << "Composing PWLE V2 effect with amplitude greater than 1.0 should fail";
+    composePwle.clear();
+
+    // Duration exceeding maximum
+    composePwle.push_back(
+            PwleV2Primitive(/*amplitude=*/0.2f, /*frequency=*/100, maxDurationMs + 10));
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr))
+            << "Composing PWLE V2 effect with duration exceeding maximum should fail";
+    composePwle.clear();
+
+    // Negative duration
+    composePwle.push_back(PwleV2Primitive(/*amplitude=*/0.2f, /*frequency=*/100, /*time=*/-1));
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr))
+            << "Composing PWLE V2 effect with negative duration should fail";
+    composePwle.clear();
+
+    // Frequency below minimum
+    float minFrequency = pwle_v2_utils::getPwleV2FrequencyMinHz(vibrator);
+    composePwle.push_back(PwleV2Primitive(/*amplitude=*/0.2f, minFrequency - 1, minDurationMs));
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr))
+            << "Composing PWLE V2 effect with frequency below minimum should fail";
+    composePwle.clear();
+
+    // Frequency above maximum
+    float maxFrequency = pwle_v2_utils::getPwleV2FrequencyMaxHz(vibrator);
+    composePwle.push_back(PwleV2Primitive(/*amplitude=*/0.2f, maxFrequency + 1, minDurationMs));
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr))
+            << "Composing PWLE V2 effect with frequency above maximum should fail";
+}
+
 std::vector<std::tuple<int32_t, int32_t>> GenerateVibratorMapping() {
     std::vector<std::tuple<int32_t, int32_t>> tuples;
 
diff --git a/vibrator/aidl/vts/pwle_v2_utils.h b/vibrator/aidl/vts/pwle_v2_utils.h
new file mode 100644
index 0000000..2163908
--- /dev/null
+++ b/vibrator/aidl/vts/pwle_v2_utils.h
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VIBRATOR_HAL_PWLE_V2_UTILS_H
+#define VIBRATOR_HAL_PWLE_V2_UTILS_H
+
+#include <aidl/android/hardware/vibrator/IVibrator.h>
+#include "test_utils.h"
+
+using aidl::android::hardware::vibrator::IVibrator;
+using aidl::android::hardware::vibrator::PwleV2OutputMapEntry;
+using aidl::android::hardware::vibrator::PwleV2Primitive;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace testing {
+namespace pwlev2 {
+
+static constexpr int32_t COMPOSE_PWLE_V2_MIN_REQUIRED_SIZE = 16;
+static constexpr int32_t COMPOSE_PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS = 1000;
+static constexpr int32_t COMPOSE_PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS = 20;
+static constexpr int32_t COMPOSE_PWLE_V2_MIN_REQUIRED_SENSITIVITY_DB_SL = 10;
+
+namespace {
+/**
+ * Returns a vector of (frequency in Hz, acceleration in dB) pairs, where the acceleration
+ * value denotes the minimum output required at the corresponding frequency to be perceptible
+ * by a human.
+ */
+static std::vector<std::pair<float, float>> getMinPerceptibleLevel() {
+    return {{0.4f, -97.81f},   {2.0f, -69.86f},   {3.0f, -62.81f},    {4.0f, -58.81f},
+            {5.0f, -56.69f},   {6.0f, -54.77f},   {7.2f, -52.85f},    {8.0f, -51.77f},
+            {8.64f, -50.84f},  {10.0f, -48.90f},  {10.37f, -48.52f},  {12.44f, -46.50f},
+            {14.93f, -44.43f}, {15.0f, -44.35f},  {17.92f, -41.96f},  {20.0f, -40.36f},
+            {21.5f, -39.60f},  {25.0f, -37.48f},  {25.8f, -36.93f},   {30.0f, -34.31f},
+            {35.0f, -33.13f},  {40.0f, -32.81f},  {50.0f, -31.94f},   {60.0f, -31.77f},
+            {70.0f, -31.59f},  {72.0f, -31.55f},  {80.0f, -31.77f},   {86.4f, -31.94f},
+            {90.0f, -31.73f},  {100.0f, -31.90f}, {103.68f, -31.77f}, {124.42f, -31.70f},
+            {149.3f, -31.38f}, {150.0f, -31.35f}, {179.16f, -31.02f}, {200.0f, -30.86f},
+            {215.0f, -30.35f}, {250.0f, -28.98f}, {258.0f, -28.68f},  {300.0f, -26.81f},
+            {400.0f, -19.81f}};
+}
+
+static float interpolateLinearly(const std::vector<float>& xAxis, const std::vector<float>& yAxis,
+                                 float x) {
+    EXPECT_TRUE(!xAxis.empty());
+    EXPECT_TRUE(xAxis.size() == yAxis.size());
+
+    if (x <= xAxis.front()) return yAxis.front();
+    if (x >= xAxis.back()) return yAxis.back();
+
+    auto it = std::upper_bound(xAxis.begin(), xAxis.end(), x);
+    int i = std::distance(xAxis.begin(), it) - 1;  // Index of the lower bound
+
+    const float& x0 = xAxis[i];
+    const float& y0 = yAxis[i];
+    const float& x1 = xAxis[i + 1];
+    const float& y1 = yAxis[i + 1];
+
+    return y0 + (x - x0) * (y1 - y0) / (x1 - x0);
+}
+
+static float minPerceptibleDbCurve(float frequency) {
+    // Initialize minPerceptibleMap only once
+    static auto minPerceptibleMap = []() -> std::function<float(float)> {
+        static std::vector<float> minPerceptibleFrequencies;
+        static std::vector<float> minPerceptibleAccelerations;
+
+        auto minPerceptibleLevel = getMinPerceptibleLevel();
+        // Sort the 'minPerceptibleLevel' data in ascending order based on the
+        // frequency values (first element of each pair).
+        std::sort(minPerceptibleLevel.begin(), minPerceptibleLevel.end(),
+                  [](const auto& a, const auto& b) { return a.first < b.first; });
+
+        for (const auto& entry : minPerceptibleLevel) {
+            minPerceptibleFrequencies.push_back(entry.first);
+            minPerceptibleAccelerations.push_back(entry.second);
+        }
+
+        return [&](float freq) {
+            return interpolateLinearly(minPerceptibleFrequencies, minPerceptibleAccelerations,
+                                       freq);
+        };
+    }();
+
+    return minPerceptibleMap(frequency);
+}
+
+static float convertSensitivityLevelToDecibel(int sl, float frequency) {
+    return sl + minPerceptibleDbCurve(frequency);
+}
+
+static float convertDecibelToAcceleration(float db) {
+    return std::pow(10.0f, db / 20.0f);
+}
+}  // namespace
+
+static float convertSensitivityLevelToAcceleration(int sl, float frequency) {
+    return pwlev2::convertDecibelToAcceleration(
+            pwlev2::convertSensitivityLevelToDecibel(sl, frequency));
+}
+
+static float getPwleV2FrequencyMinHz(const std::shared_ptr<IVibrator>& vibrator) {
+    std::vector<PwleV2OutputMapEntry> frequencyToOutputAccelerationMap;
+    EXPECT_OK(
+            vibrator->getPwleV2FrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap));
+    EXPECT_TRUE(!frequencyToOutputAccelerationMap.empty());
+    // We can't use ASSERT_TRUE() above because this is a non-void function,
+    // but we need to return to assure we don't crash from a null dereference.
+    if (frequencyToOutputAccelerationMap.empty()) {
+        return std::numeric_limits<float>::quiet_NaN();
+    }
+
+    auto entry = std::min_element(
+            frequencyToOutputAccelerationMap.begin(), frequencyToOutputAccelerationMap.end(),
+            [](const auto& a, const auto& b) { return a.frequencyHz < b.frequencyHz; });
+
+    return entry->frequencyHz;
+}
+
+static float getPwleV2FrequencyMaxHz(const std::shared_ptr<IVibrator>& vibrator) {
+    std::vector<PwleV2OutputMapEntry> frequencyToOutputAccelerationMap;
+    EXPECT_OK(
+            vibrator->getPwleV2FrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap));
+    EXPECT_TRUE(!frequencyToOutputAccelerationMap.empty());
+    // We can't use ASSERT_TRUE() above because this is a non-void function,
+    // but we need to return to assure we don't crash from a null dereference.
+    if (frequencyToOutputAccelerationMap.empty()) {
+        return std::numeric_limits<float>::quiet_NaN();
+    }
+
+    auto entry = std::max_element(
+            frequencyToOutputAccelerationMap.begin(), frequencyToOutputAccelerationMap.end(),
+            [](const auto& a, const auto& b) { return a.frequencyHz < b.frequencyHz; });
+
+    return entry->frequencyHz;
+}
+
+static std::vector<PwleV2Primitive> composeValidPwleV2Effect(
+        const std::shared_ptr<IVibrator>& vibrator) {
+    int32_t minDurationMs;
+    EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMinMillis(&minDurationMs));
+    int32_t maxDurationMs;
+    EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMaxMillis(&maxDurationMs));
+    float minFrequency = getPwleV2FrequencyMinHz(vibrator);
+    float maxFrequency = getPwleV2FrequencyMaxHz(vibrator);
+    int32_t maxCompositionSize;
+    EXPECT_OK(vibrator->getPwleV2CompositionSizeMax(&maxCompositionSize));
+
+    std::vector<PwleV2Primitive> pwleEffect;
+
+    pwleEffect.emplace_back(0.1f, minFrequency, minDurationMs);
+    pwleEffect.emplace_back(0.5f, maxFrequency, maxDurationMs);
+
+    float variedFrequency = (minFrequency + maxFrequency) / 2.0f;
+    for (int i = 0; i < maxCompositionSize - 2; i++) {
+        pwleEffect.emplace_back(0.7f, variedFrequency, minDurationMs);
+    }
+
+    return pwleEffect;
+}
+
+static std::vector<PwleV2Primitive> composePwleV2EffectWithTooManyPoints(
+        const std::shared_ptr<IVibrator>& vibrator) {
+    int32_t minDurationMs, maxCompositionSize;
+    EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMinMillis(&minDurationMs));
+    EXPECT_OK(vibrator->getPwleV2CompositionSizeMax(&maxCompositionSize));
+    float maxFrequency = getPwleV2FrequencyMaxHz(vibrator);
+
+    std::vector<PwleV2Primitive> pwleEffect(maxCompositionSize + 1);  // +1 to exceed the limit
+
+    std::fill(pwleEffect.begin(), pwleEffect.end(),
+              PwleV2Primitive(/*amplitude=*/0.2f, maxFrequency, minDurationMs));
+
+    return pwleEffect;
+}
+
+static std::pair<float, float> getPwleV2SharpnessRange(
+        const std::shared_ptr<IVibrator>& vibrator,
+        std::vector<PwleV2OutputMapEntry> freqToOutputAccelerationMap) {
+    std::pair<float, float> sharpnessRange = {-1, -1};
+
+    // Sort the entries by frequency in ascending order
+    std::sort(freqToOutputAccelerationMap.begin(), freqToOutputAccelerationMap.end(),
+              [](const auto& a, const auto& b) { return a.frequencyHz < b.frequencyHz; });
+
+    for (const auto& entry : freqToOutputAccelerationMap) {
+        float minAcceptableOutputAcceleration = convertSensitivityLevelToAcceleration(
+                pwlev2::COMPOSE_PWLE_V2_MIN_REQUIRED_SENSITIVITY_DB_SL, entry.frequencyHz);
+
+        if (sharpnessRange.first < 0 &&
+            minAcceptableOutputAcceleration <= entry.maxOutputAccelerationGs) {
+            sharpnessRange.first = entry.frequencyHz;  // Found the lower bound
+        } else if (sharpnessRange.first >= 0 &&
+                   minAcceptableOutputAcceleration >= entry.maxOutputAccelerationGs) {
+            sharpnessRange.second = entry.frequencyHz;  // Found the upper bound
+            return sharpnessRange;
+        }
+    }
+
+    if (sharpnessRange.first >= 0) {
+        // If only the lower bound was found, set the upper bound to the max frequency.
+        sharpnessRange.second = getPwleV2FrequencyMaxHz(vibrator);
+    }
+
+    return sharpnessRange;
+}
+}  // namespace pwlev2
+}  // namespace testing
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+#endif  // VIBRATOR_HAL_PWLE_V2_UTILS_H
diff --git a/weaver/vts/VtsHalWeaverTargetTest.cpp b/weaver/vts/VtsHalWeaverTargetTest.cpp
index 40e9558..8952dfc 100644
--- a/weaver/vts/VtsHalWeaverTargetTest.cpp
+++ b/weaver/vts/VtsHalWeaverTargetTest.cpp
@@ -221,7 +221,10 @@
         }
     }
     // Starting in Android 14, the system will always use at least one Weaver slot if Weaver is
-    // supported at all.  Make sure we saw at least one.
+    // supported at all.  This is true even if an LSKF hasn't been set yet, since Weaver is used to
+    // protect the initial binding of each user's synthetic password to ensure that binding can be
+    // securely deleted if an LSKF is set later.  Make sure we saw at least one slot, as otherwise
+    // the Weaver implementation must have a bug that makes it not fully usable by Android.
     ASSERT_FALSE(used_slots.empty())
             << "Could not determine which Weaver slots are in use by the system";
 
diff --git a/wifi/aidl/default/Android.bp b/wifi/aidl/default/Android.bp
index 2047807..3fcb77f 100644
--- a/wifi/aidl/default/Android.bp
+++ b/wifi/aidl/default/Android.bp
@@ -112,9 +112,14 @@
     export_include_dirs: ["."],
 }
 
+vintf_fragment {
+    name: "android.hardware.wifi-service.xml",
+    src: "android.hardware.wifi-service.xml",
+    vendor: true,
+}
+
 cc_binary {
     name: "android.hardware.wifi-service",
-    vintf_fragments: ["android.hardware.wifi-service.xml"],
     relative_install_path: "hw",
     proprietary: true,
     cppflags: [
@@ -137,11 +142,11 @@
     ],
     static_libs: ["android.hardware.wifi-service-lib"],
     init_rc: ["android.hardware.wifi-service.rc"],
+    vintf_fragment_modules: ["android.hardware.wifi-service.xml"],
 }
 
 cc_binary {
     name: "android.hardware.wifi-service-lazy",
-    vintf_fragments: ["android.hardware.wifi-service.xml"],
     overrides: ["android.hardware.wifi-service"],
     cflags: ["-DLAZY_SERVICE"],
     relative_install_path: "hw",
@@ -166,6 +171,7 @@
     ],
     static_libs: ["android.hardware.wifi-service-lib"],
     init_rc: ["android.hardware.wifi-service-lazy.rc"],
+    vintf_fragment_modules: ["android.hardware.wifi-service.xml"],
 }
 
 cc_test {
diff --git a/wifi/aidl/default/aidl_struct_util.cpp b/wifi/aidl/default/aidl_struct_util.cpp
index d82450e..d99edaa 100644
--- a/wifi/aidl/default/aidl_struct_util.cpp
+++ b/wifi/aidl/default/aidl_struct_util.cpp
@@ -3394,6 +3394,7 @@
     *legacy_request = {};
 
     legacy_request->service_instance_id = aidl_request.bootstrappingInstanceId;
+    legacy_request->bootstrapping_instance_id = aidl_request.bootstrappingInstanceId;
     legacy_request->rsp_code = aidl_request.acceptRequest ? NAN_BOOTSTRAPPING_REQUEST_ACCEPT
                                                           : NAN_BOOTSTRAPPING_REQUEST_REJECT;
     legacy_request->publish_subscribe_id = static_cast<uint8_t>(aidl_request.discoverySessionId);
diff --git a/wifi/hostapd/aidl/Android.bp b/wifi/hostapd/aidl/Android.bp
index 2e4d4d1..88f4ef2 100644
--- a/wifi/hostapd/aidl/Android.bp
+++ b/wifi/hostapd/aidl/Android.bp
@@ -65,5 +65,5 @@
         },
 
     ],
-    frozen: true,
+    frozen: false,
 }
diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/BandMask.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/BandMask.aidl
index b1e7f66..fa9f198 100644
--- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/BandMask.aidl
+++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/BandMask.aidl
@@ -34,8 +34,8 @@
 package android.hardware.wifi.hostapd;
 @Backing(type="int") @VintfStability
 enum BandMask {
-  BAND_2_GHZ = 1,
-  BAND_5_GHZ = 2,
-  BAND_6_GHZ = 4,
-  BAND_60_GHZ = 8,
+  BAND_2_GHZ = (1 << 0) /* 1 */,
+  BAND_5_GHZ = (1 << 1) /* 2 */,
+  BAND_6_GHZ = (1 << 2) /* 4 */,
+  BAND_60_GHZ = (1 << 3) /* 8 */,
 }
diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/EncryptionType.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/EncryptionType.aidl
index a7b20fa..840b875 100644
--- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/EncryptionType.aidl
+++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/EncryptionType.aidl
@@ -34,11 +34,11 @@
 package android.hardware.wifi.hostapd;
 @Backing(type="int") @VintfStability
 enum EncryptionType {
-  NONE = 0,
-  WPA = 1,
-  WPA2 = 2,
-  WPA3_SAE_TRANSITION = 3,
-  WPA3_SAE = 4,
-  WPA3_OWE_TRANSITION = 5,
-  WPA3_OWE = 6,
+  NONE,
+  WPA,
+  WPA2,
+  WPA3_SAE_TRANSITION,
+  WPA3_SAE,
+  WPA3_OWE_TRANSITION,
+  WPA3_OWE,
 }
diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Generation.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Generation.aidl
index 5bb0d32..a0c1886 100644
--- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Generation.aidl
+++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Generation.aidl
@@ -34,7 +34,7 @@
 package android.hardware.wifi.hostapd;
 @Backing(type="int") @VintfStability
 enum Generation {
-  WIFI_STANDARD_UNKNOWN = -1,
+  WIFI_STANDARD_UNKNOWN = (-1) /* -1 */,
   WIFI_STANDARD_LEGACY = 0,
   WIFI_STANDARD_11N = 1,
   WIFI_STANDARD_11AC = 2,
diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/HostapdStatusCode.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/HostapdStatusCode.aidl
index 548e497..7edff15 100644
--- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/HostapdStatusCode.aidl
+++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/HostapdStatusCode.aidl
@@ -34,10 +34,10 @@
 package android.hardware.wifi.hostapd;
 @Backing(type="int") @VintfStability
 enum HostapdStatusCode {
-  SUCCESS = 0,
-  FAILURE_UNKNOWN = 1,
-  FAILURE_ARGS_INVALID = 2,
-  FAILURE_IFACE_UNKNOWN = 3,
-  FAILURE_IFACE_EXISTS = 4,
-  FAILURE_CLIENT_UNKNOWN = 5,
+  SUCCESS,
+  FAILURE_UNKNOWN,
+  FAILURE_ARGS_INVALID,
+  FAILURE_IFACE_UNKNOWN,
+  FAILURE_IFACE_EXISTS,
+  FAILURE_CLIENT_UNKNOWN,
 }
diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IfaceParams.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IfaceParams.aidl
index 64367bb..8da3441 100644
--- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IfaceParams.aidl
+++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IfaceParams.aidl
@@ -38,4 +38,6 @@
   android.hardware.wifi.hostapd.HwModeParams hwModeParams;
   android.hardware.wifi.hostapd.ChannelParams[] channelParams;
   @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
+  @nullable String[] instanceIdentities;
+  boolean isMlo;
 }
diff --git a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl
index 3f8ee39..bb646e3 100644
--- a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl
+++ b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl
@@ -41,4 +41,12 @@
      * Optional vendor-specific configuration parameters.
      */
     @nullable OuiKeyedData[] vendorData;
+    /**
+     * The list of the instance identities.
+     */
+    @nullable String[] instanceIdentities;
+    /**
+     * Whether the current iface is MLO.
+     */
+    boolean isMlo;
 }
diff --git a/wifi/hostapd/aidl/vts/functional/Android.bp b/wifi/hostapd/aidl/vts/functional/Android.bp
index f614679..bf1b0d0 100644
--- a/wifi/hostapd/aidl/vts/functional/Android.bp
+++ b/wifi/hostapd/aidl/vts/functional/Android.bp
@@ -21,7 +21,7 @@
         "libvndksupport",
     ],
     static_libs: [
-        "android.hardware.wifi.hostapd-V2-ndk",
+        "android.hardware.wifi.hostapd-V3-ndk",
         "VtsHalWifiV1_0TargetTestUtil",
         "VtsHalWifiV1_5TargetTestUtil",
         "VtsHalWifiV1_6TargetTestUtil",
diff --git a/wifi/legacy_headers/include/hardware_legacy/wifi_nan.h b/wifi/legacy_headers/include/hardware_legacy/wifi_nan.h
index 55034d1..4e490d9 100644
--- a/wifi/legacy_headers/include/hardware_legacy/wifi_nan.h
+++ b/wifi/legacy_headers/include/hardware_legacy/wifi_nan.h
@@ -2972,11 +2972,17 @@
     u16 publish_subscribe_id;
 
     /*
-       This Id is the Peer Instance that is passed as
-       part of earlier MatchInd/FollowupInd message.
+      Same as the bootstrapping_instance_id
     */
     u32 service_instance_id;
 
+    /*
+      Unique Instance Id corresponding to a service/session.
+      This is similar to the publish_id generated on the
+      publisher side
+    */
+    u32 bootstrapping_instance_id;
+
     /* Discovery MAC addr of the peer/initiator */
     u8 peer_disc_mac_addr[NAN_MAC_ADDR_LEN];