Merge tag 'android-15.0.0_r6' of https://android.googlesource.com/platform/hardware/interfaces into HEAD

Android 15.0.0 Release 6 (AP4A.241205.013)

Change-Id: I7f4ddd96dd35aaa5d0c3979994bf018c548ddc41

# -----BEGIN PGP SIGNATURE-----
#
# iF0EABECAB0WIQRDQNE1cO+UXoOBCWTorT+BmrEOeAUCZ1IssgAKCRDorT+BmrEO
# eAQDAJ0Y9tLkI/9E6JFvvf9DIGZxnCabgQCghIthWz3dPjsuoGGuJCLjmZMbBXs=
# =kzIy
# -----END PGP SIGNATURE-----
# gpg: Signature faite le jeu 05 déc 2024 17:44:02 EST
# gpg:                avec la clef DSA 4340D13570EF945E83810964E8AD3F819AB10E78
# gpg: Impossible de vérifier la signature : Pas de clef publique
diff --git a/Android.bp b/Android.bp
index e437231..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,8 +63,8 @@
         "libbase",
         // All the following are dependencies of any HAL definition library.
         "libcutils",
-        "liblog",
         "libhidlbase",
+        "liblog",
         "libutils",
     ],
     cflags: [
@@ -73,14 +72,6 @@
         "-g",
     ],
 
-    target: {
-        android: {
-            shared_libs: [
-                "libvndksupport",
-            ],
-        },
-    },
-
     require_root: true,
 }
 
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index de7aa35..8c53006 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -5,6 +5,7 @@
 bpfmt = true
 clang_format = true
 aidl_format = true
+gofmt = true
 
 [Hook Scripts]
 aosp_hook_confirmationui = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} confirmationui
diff --git a/audio/OWNERS b/audio/OWNERS
index 3671685..80e2765 100644
--- a/audio/OWNERS
+++ b/audio/OWNERS
@@ -2,3 +2,4 @@
 
 elaurent@google.com
 mnaganov@google.com
+yaoshunkai@google.com
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index b67b9d2..4902497 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -44,7 +44,7 @@
         "android/hardware/audio/common/SinkMetadata.aidl",
         "android/hardware/audio/common/SourceMetadata.aidl",
     ],
-    frozen: true,
+    frozen: false,
     backend: {
         cpp: {
             enabled: true,
@@ -89,7 +89,7 @@
 }
 
 // Note: This should always be one version ahead of the last frozen version
-latest_android_hardware_audio_common = "android.hardware.audio.common-V3"
+latest_android_hardware_audio_common = "android.hardware.audio.common-V4"
 
 // Modules that depend on android.hardware.audio.common directly can include
 // the following cc_defaults to avoid explicitly managing dependency versions
@@ -198,11 +198,11 @@
         // IMPORTANT: Update latest_android_hardware_audio_core every time you
         // add the latest frozen version to versions_with_info
     ],
-    frozen: true,
+    frozen: false,
 }
 
 // Note: This should always be one version ahead of the last frozen version
-latest_android_hardware_audio_core = "android.hardware.audio.core-V2"
+latest_android_hardware_audio_core = "android.hardware.audio.core-V3"
 
 // Modules that depend on android.hardware.audio.core directly can include
 // the following cc_defaults to avoid explicitly managing dependency versions
@@ -260,11 +260,11 @@
         // IMPORTANT: Update latest_android_hardware_audio_core_sounddose every time you
         // add the latest frozen version to versions_with_info
     ],
-    frozen: true,
+    frozen: false,
 }
 
 // Note: This should always be one version ahead of the last frozen version
-latest_android_hardware_audio_core_sounddose = "android.hardware.audio.core.sounddose-V2"
+latest_android_hardware_audio_core_sounddose = "android.hardware.audio.core.sounddose-V3"
 
 // Modules that depend on android.hardware.audio.core.sounddose directly can include
 // the following cc_defaults to avoid explicitly managing dependency versions
@@ -368,11 +368,11 @@
         },
 
     ],
-    frozen: true,
+    frozen: false,
 
 }
 
-latest_android_hardware_audio_effect = "android.hardware.audio.effect-V2"
+latest_android_hardware_audio_effect = "android.hardware.audio.effect-V3"
 
 cc_defaults {
     name: "latest_android_hardware_audio_effect_ndk_shared",
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/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Processing.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Processing.aidl
index f6d6ee2..96d57d8 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Processing.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Processing.aidl
@@ -40,5 +40,6 @@
   union Type {
     android.media.audio.common.AudioStreamType streamType = android.media.audio.common.AudioStreamType.INVALID;
     android.media.audio.common.AudioSource source;
+    android.media.audio.common.AudioDevice device;
   }
 }
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/android/hardware/audio/effect/Processing.aidl b/audio/aidl/android/hardware/audio/effect/Processing.aidl
index cb77350..928ce16 100644
--- a/audio/aidl/android/hardware/audio/effect/Processing.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Processing.aidl
@@ -17,6 +17,7 @@
 package android.hardware.audio.effect;
 
 import android.hardware.audio.effect.Descriptor;
+import android.media.audio.common.AudioDevice;
 import android.media.audio.common.AudioSource;
 import android.media.audio.common.AudioStreamType;
 import android.media.audio.common.AudioUuid;
@@ -30,6 +31,7 @@
     union Type {
         AudioStreamType streamType = AudioStreamType.INVALID;
         AudioSource source;
+        AudioDevice device;
     }
 
     /**
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 b431340..ce29635 100644
--- a/audio/aidl/common/include/Utils.h
+++ b/audio/aidl/common/include/Utils.h
@@ -26,10 +26,13 @@
 #include <aidl/android/media/audio/common/AudioDeviceType.h>
 #include <aidl/android/media/audio/common/AudioFormatDescription.h>
 #include <aidl/android/media/audio/common/AudioInputFlags.h>
+#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 {
 
@@ -60,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) {
@@ -135,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_";
@@ -191,4 +230,15 @@
     return frameCountFromDurationUs(durationMs * 1000, sampleRateHz);
 }
 
+constexpr bool hasMmapFlag(const ::aidl::android::media::audio::common::AudioIoFlags& flags) {
+    return (flags.getTag() == ::aidl::android::media::audio::common::AudioIoFlags::Tag::input &&
+            isBitPositionFlagSet(
+                    flags.get<::aidl::android::media::audio::common::AudioIoFlags::Tag::input>(),
+                    ::aidl::android::media::audio::common::AudioInputFlags::MMAP_NOIRQ)) ||
+           (flags.getTag() == ::aidl::android::media::audio::common::AudioIoFlags::Tag::output &&
+            isBitPositionFlagSet(
+                    flags.get<::aidl::android::media::audio::common::AudioIoFlags::Tag::output>(),
+                    ::aidl::android::media::audio::common::AudioOutputFlags::MMAP_NOIRQ));
+}
+
 }  // namespace aidl::android::hardware::audio::common
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 844f1e9..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",
     ],
@@ -203,6 +207,7 @@
     ],
     vendor: true,
     shared_libs: [
+        "libaudio_aidl_conversion_common_ndk",
         "libaudioaidlcommon",
         "libaudioutils",
         "libbase",
@@ -224,6 +229,7 @@
         "-Wextra",
         "-Werror",
         "-Wthread-safety",
+        "-DBACKEND_NDK",
     ],
 }
 
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/EffectConfig.cpp b/audio/aidl/default/EffectConfig.cpp
index eb0c015..9c335ba 100644
--- a/audio/aidl/default/EffectConfig.cpp
+++ b/audio/aidl/default/EffectConfig.cpp
@@ -18,6 +18,8 @@
 #include <string>
 #define LOG_TAG "AHAL_EffectConfig"
 #include <android-base/logging.h>
+#include <media/AidlConversionCppNdk.h>
+#include <system/audio.h>
 #include <system/audio_aidl_utils.h>
 #include <system/audio_effects/audio_effects_conf.h>
 #include <system/audio_effects/effect_uuid.h>
@@ -28,6 +30,10 @@
 #include <android/apexsupport.h>
 #endif
 
+using aidl::android::media::audio::common::AudioDevice;
+using aidl::android::media::audio::common::AudioDeviceAddress;
+using aidl::android::media::audio::common::AudioDeviceDescription;
+using aidl::android::media::audio::common::AudioDeviceType;
 using aidl::android::media::audio::common::AudioSource;
 using aidl::android::media::audio::common::AudioStreamType;
 using aidl::android::media::audio::common::AudioUuid;
@@ -76,6 +82,14 @@
                 registerFailure(parseProcessing(Processing::Type::streamType, xmlStream));
             }
         }
+
+        // Parse device effect chains
+        for (auto& xmlDeviceEffects : getChildren(xmlConfig, "deviceEffects")) {
+            for (auto& xmlDevice : getChildren(xmlDeviceEffects, "device")) {
+                // AudioDevice
+                registerFailure(parseProcessing(Processing::Type::device, xmlDevice));
+            }
+        }
     }
     LOG(DEBUG) << __func__ << " successfully parsed " << file << ", skipping " << mSkippedElements
                << " element(s)";
@@ -195,7 +209,8 @@
 }
 
 std::optional<Processing::Type> EffectConfig::stringToProcessingType(Processing::Type::Tag typeTag,
-                                                                     const std::string& type) {
+                                                                     const std::string& type,
+                                                                     const std::string& address) {
     // see list of audio stream types in audio_stream_type_t:
     // system/media/audio/include/system/audio_effects/audio_effects_conf.h
     // AUDIO_STREAM_DEFAULT_TAG is not listed here because according to SYS_RESERVED_DEFAULT in
@@ -238,6 +253,19 @@
         if (typeIter != sAudioSourceTable.end()) {
             return typeIter->second;
         }
+    } else if (typeTag == Processing::Type::device) {
+        audio_devices_t deviceType;
+        if (!audio_device_from_string(type.c_str(), &deviceType)) {
+            LOG(ERROR) << __func__ << "DeviceEffect: invalid type " << type;
+            return std::nullopt;
+        }
+        auto ret = ::aidl::android::legacy2aidl_audio_device_AudioDevice(deviceType, address);
+        if (!ret.ok()) {
+            LOG(ERROR) << __func__ << "DeviceEffect: Failed to get AudioDevice from type "
+                    << deviceType << ", address " << address;
+            return std::nullopt;
+        }
+        return ret.value();
     }
 
     return std::nullopt;
@@ -246,7 +274,10 @@
 bool EffectConfig::parseProcessing(Processing::Type::Tag typeTag, const tinyxml2::XMLElement& xml) {
     LOG(VERBOSE) << __func__ << dump(xml);
     const char* typeStr = xml.Attribute("type");
-    auto aidlType = stringToProcessingType(typeTag, typeStr);
+    const char* addressStr = xml.Attribute("address");
+    // For device effect, device address is optional, match will be done for the given device type
+    // with empty address.
+    auto aidlType = stringToProcessingType(typeTag, typeStr, addressStr ? addressStr : "");
     RETURN_VALUE_IF(!aidlType.has_value(), false, "illegalStreamType");
     RETURN_VALUE_IF(0 != mProcessingMap.count(aidlType.value()), false, "duplicateStreamType");
 
diff --git a/audio/aidl/default/EffectContext.cpp b/audio/aidl/default/EffectContext.cpp
index 7b8cfb1..26c88b2 100644
--- a/audio/aidl/default/EffectContext.cpp
+++ b/audio/aidl/default/EffectContext.cpp
@@ -63,13 +63,18 @@
 }
 
 void EffectContext::dupeFmqWithReopen(IEffect::OpenEffectReturn* effectRet) {
+    const size_t inBufferSizeInFloat = mCommon.input.frameCount * mInputFrameSize / sizeof(float);
+    const size_t outBufferSizeInFloat =
+            mCommon.output.frameCount * mOutputFrameSize / sizeof(float);
+    const size_t bufferSize = std::max(inBufferSizeInFloat, outBufferSizeInFloat);
     if (!mInputMQ) {
-        mInputMQ = std::make_shared<DataMQ>(mCommon.input.frameCount * mInputFrameSize /
-                                            sizeof(float));
+        mInputMQ = std::make_shared<DataMQ>(inBufferSizeInFloat);
     }
     if (!mOutputMQ) {
-        mOutputMQ = std::make_shared<DataMQ>(mCommon.output.frameCount * mOutputFrameSize /
-                                             sizeof(float));
+        mOutputMQ = std::make_shared<DataMQ>(outBufferSizeInFloat);
+    }
+    if (mWorkBuffer.size() != bufferSize) {
+        mWorkBuffer.resize(bufferSize);
     }
     dupeFmq(effectRet);
 }
@@ -222,8 +227,6 @@
     }
 
     if (needUpdateMq) {
-        mWorkBuffer.resize(std::max(common.input.frameCount * mInputFrameSize / sizeof(float),
-                                    common.output.frameCount * mOutputFrameSize / sizeof(float)));
         return notifyDataMqUpdate();
     }
     return RetCode::SUCCESS;
@@ -242,4 +245,17 @@
     LOG(VERBOSE) << __func__ << " : signal client for reopen";
     return RetCode::SUCCESS;
 }
+
+RetCode EffectContext::enable() {
+    return RetCode::SUCCESS;
+}
+
+RetCode EffectContext::disable() {
+    return RetCode::SUCCESS;
+}
+
+RetCode EffectContext::reset() {
+    return RetCode::SUCCESS;
+}
+
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/EffectImpl.cpp b/audio/aidl/default/EffectImpl.cpp
index 7192d97..3e61335 100644
--- a/audio/aidl/default/EffectImpl.cpp
+++ b/audio/aidl/default/EffectImpl.cpp
@@ -246,7 +246,6 @@
             startThread();
             break;
         case CommandId::STOP:
-        case CommandId::RESET:
             RETURN_OK_IF(mState == State::IDLE);
             mState = State::IDLE;
             RETURN_IF(notifyEventFlag(mDataMqNotEmptyEf) != RetCode::SUCCESS, EX_ILLEGAL_STATE,
@@ -254,6 +253,13 @@
             stopThread();
             RETURN_IF_ASTATUS_NOT_OK(commandImpl(command), "commandImplFailed");
             break;
+        case CommandId::RESET:
+            mState = State::IDLE;
+            RETURN_IF(notifyEventFlag(mDataMqNotEmptyEf) != RetCode::SUCCESS, EX_ILLEGAL_STATE,
+                      "notifyEventFlagNotEmptyFailed");
+            stopThread();
+            RETURN_IF_ASTATUS_NOT_OK(commandImpl(command), "commandImplFailed");
+            break;
         default:
             LOG(ERROR) << getEffectNameWithVersion() << __func__ << " instance still processing";
             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
@@ -266,8 +272,22 @@
 
 ndk::ScopedAStatus EffectImpl::commandImpl(CommandId command) {
     RETURN_IF(!mImplContext, EX_NULL_POINTER, "nullContext");
-    if (command == CommandId::RESET) {
-        mImplContext->resetBuffer();
+    switch (command) {
+        case CommandId::START:
+            mImplContext->enable();
+            break;
+        case CommandId::STOP:
+            mImplContext->disable();
+            break;
+        case CommandId::RESET:
+            mImplContext->disable();
+            mImplContext->reset();
+            mImplContext->resetBuffer();
+            break;
+        default:
+            LOG(ERROR) << __func__ << " commandId " << toString(command) << " not supported";
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "commandIdNotSupported");
     }
     return ndk::ScopedAStatus::ok();
 }
diff --git a/audio/aidl/default/EffectMain.cpp b/audio/aidl/default/EffectMain.cpp
index a300cfd..7a6141a 100644
--- a/audio/aidl/default/EffectMain.cpp
+++ b/audio/aidl/default/EffectMain.cpp
@@ -38,7 +38,7 @@
             candidatePath.append(apexName).append("/etc/").append(kDefaultConfigName);
             LOG(DEBUG) << __func__ << " effect lib path " << candidatePath;
             if (access(candidatePath.c_str(), R_OK) == 0) {
-                return std::move(candidatePath);
+                return candidatePath;
             }
         }
     } else {
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/Module.cpp b/audio/aidl/default/Module.cpp
index 0d6151e..c14d06e 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -36,6 +36,7 @@
 
 using aidl::android::hardware::audio::common::frameCountFromDurationMs;
 using aidl::android::hardware::audio::common::getFrameSizeInBytes;
+using aidl::android::hardware::audio::common::hasMmapFlag;
 using aidl::android::hardware::audio::common::isBitPositionFlagSet;
 using aidl::android::hardware::audio::common::isValidAudioMode;
 using aidl::android::hardware::audio::common::SinkMetadata;
@@ -205,35 +206,31 @@
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     const auto& flags = portConfigIt->flags.value();
-    if ((flags.getTag() == AudioIoFlags::Tag::input &&
-         !isBitPositionFlagSet(flags.get<AudioIoFlags::Tag::input>(),
-                               AudioInputFlags::MMAP_NOIRQ)) ||
-        (flags.getTag() == AudioIoFlags::Tag::output &&
-         !isBitPositionFlagSet(flags.get<AudioIoFlags::Tag::output>(),
-                               AudioOutputFlags::MMAP_NOIRQ))) {
-        StreamContext::DebugParameters params{mDebug.streamTransientStateDelayMs,
-                                              mVendorDebug.forceTransientBurst,
-                                              mVendorDebug.forceSynchronousDrain};
-        std::shared_ptr<ISoundDose> soundDose;
-        if (!getSoundDose(&soundDose).isOk()) {
-            LOG(ERROR) << __func__ << ": could not create sound dose instance";
-            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-        }
-        StreamContext temp(
-                std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
-                std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
-                portConfigIt->format.value(), portConfigIt->channelMask.value(),
-                portConfigIt->sampleRate.value().value, flags, nominalLatencyMs,
-                portConfigIt->ext.get<AudioPortExt::mix>().handle,
-                std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
-                asyncCallback, outEventCallback, mSoundDose.getInstance(), params);
-        if (temp.isValid()) {
-            *out_context = std::move(temp);
-        } else {
-            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-        }
+    StreamContext::DebugParameters params{mDebug.streamTransientStateDelayMs,
+                                          mVendorDebug.forceTransientBurst,
+                                          mVendorDebug.forceSynchronousDrain};
+    std::unique_ptr<StreamContext::DataMQ> dataMQ = nullptr;
+    std::shared_ptr<IStreamCallback> streamAsyncCallback = nullptr;
+    std::shared_ptr<ISoundDose> soundDose;
+    if (!getSoundDose(&soundDose).isOk()) {
+        LOG(ERROR) << __func__ << ": could not create sound dose instance";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if (!hasMmapFlag(flags)) {
+        dataMQ = std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames);
+        streamAsyncCallback = asyncCallback;
+    }
+    StreamContext temp(
+            std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
+            std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
+            portConfigIt->format.value(), portConfigIt->channelMask.value(),
+            portConfigIt->sampleRate.value().value, flags, nominalLatencyMs,
+            portConfigIt->ext.get<AudioPortExt::mix>().handle, std::move(dataMQ),
+            streamAsyncCallback, outEventCallback, mSoundDose.getInstance(), params);
+    if (temp.isValid()) {
+        *out_context = std::move(temp);
     } else {
-        // TODO: Implement simulation of MMAP buffer allocation
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     }
     return ndk::ScopedAStatus::ok();
 }
@@ -373,6 +370,13 @@
     return kLatencyMs;
 }
 
+ndk::ScopedAStatus Module::createMmapBuffer(
+        const ::aidl::android::hardware::audio::core::StreamContext& context __unused,
+        ::aidl::android::hardware::audio::core::StreamDescriptor* desc __unused) {
+    LOG(ERROR) << __func__ << ": " << mType << ": is not implemented";
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
 std::vector<AudioRoute*> Module::getAudioRoutesForAudioPortImpl(int32_t portId) {
     std::vector<AudioRoute*> result;
     auto& routes = getConfig().routes;
@@ -387,7 +391,7 @@
 
 Module::Configuration& Module::getConfig() {
     if (!mConfig) {
-        mConfig = std::move(initializeConfig());
+        mConfig = initializeConfig();
     }
     return *mConfig;
 }
@@ -866,6 +870,9 @@
     RETURN_STATUS_IF_ERROR(createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames,
                                                nullptr, nullptr, &context));
     context.fillDescriptor(&_aidl_return->desc);
+    if (hasMmapFlag(context.getFlags())) {
+        RETURN_STATUS_IF_ERROR(createMmapBuffer(context, &_aidl_return->desc));
+    }
     std::shared_ptr<StreamIn> stream;
     RETURN_STATUS_IF_ERROR(createInputStream(std::move(context), in_args.sinkMetadata,
                                              getMicrophoneInfos(), &stream));
@@ -913,6 +920,9 @@
                                                isNonBlocking ? in_args.callback : nullptr,
                                                in_args.eventCallback, &context));
     context.fillDescriptor(&_aidl_return->desc);
+    if (hasMmapFlag(context.getFlags())) {
+        RETURN_STATUS_IF_ERROR(createMmapBuffer(context, &_aidl_return->desc));
+    }
     std::shared_ptr<StreamOut> stream;
     RETURN_STATUS_IF_ERROR(createOutputStream(std::move(context), in_args.sourceMetadata,
                                               in_args.offloadInfo, &stream));
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index 31b0645..3e4650d 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -30,6 +30,7 @@
 using aidl::android::hardware::audio::common::AudioOffloadMetadata;
 using aidl::android::hardware::audio::common::getChannelCount;
 using aidl::android::hardware::audio::common::getFrameSizeInBytes;
+using aidl::android::hardware::audio::common::hasMmapFlag;
 using aidl::android::hardware::audio::common::isBitPositionFlagSet;
 using aidl::android::hardware::audio::common::SinkMetadata;
 using aidl::android::hardware::audio::common::SourceMetadata;
@@ -46,6 +47,17 @@
 
 namespace aidl::android::hardware::audio::core {
 
+namespace {
+
+template <typename MQTypeError>
+auto fmqErrorHandler(const char* mqName) {
+    return [m = std::string(mqName)](MQTypeError fmqError, std::string&& errorMessage) {
+        CHECK_EQ(fmqError, MQTypeError::NONE) << m << ": " << errorMessage;
+    };
+}
+
+}  // namespace
+
 void StreamContext::fillDescriptor(StreamDescriptor* desc) {
     if (mCommandMQ) {
         desc->command = mCommandMQ->dupeDesc();
@@ -84,7 +96,7 @@
         LOG(ERROR) << "frame size is invalid";
         return false;
     }
-    if (mDataMQ && !mDataMQ->isValid()) {
+    if (!hasMmapFlag(mFlags) && mDataMQ && !mDataMQ->isValid()) {
         LOG(ERROR) << "data FMQ is invalid";
         return false;
     }
@@ -116,17 +128,19 @@
 std::string StreamWorkerCommonLogic::init() {
     if (mContext->getCommandMQ() == nullptr) return "Command MQ is null";
     if (mContext->getReplyMQ() == nullptr) return "Reply MQ is null";
-    StreamContext::DataMQ* const dataMQ = mContext->getDataMQ();
-    if (dataMQ == nullptr) return "Data MQ is null";
-    if (sizeof(DataBufferElement) != dataMQ->getQuantumSize()) {
-        return "Unexpected Data MQ quantum size: " + std::to_string(dataMQ->getQuantumSize());
-    }
-    mDataBufferSize = dataMQ->getQuantumCount() * dataMQ->getQuantumSize();
-    mDataBuffer.reset(new (std::nothrow) DataBufferElement[mDataBufferSize]);
-    if (mDataBuffer == nullptr) {
-        return "Failed to allocate data buffer for element count " +
-               std::to_string(dataMQ->getQuantumCount()) +
-               ", size in bytes: " + std::to_string(mDataBufferSize);
+    if (!hasMmapFlag(mContext->getFlags())) {
+        StreamContext::DataMQ* const dataMQ = mContext->getDataMQ();
+        if (dataMQ == nullptr) return "Data MQ is null";
+        if (sizeof(DataBufferElement) != dataMQ->getQuantumSize()) {
+            return "Unexpected Data MQ quantum size: " + std::to_string(dataMQ->getQuantumSize());
+        }
+        mDataBufferSize = dataMQ->getQuantumCount() * dataMQ->getQuantumSize();
+        mDataBuffer.reset(new (std::nothrow) DataBufferElement[mDataBufferSize]);
+        if (mDataBuffer == nullptr) {
+            return "Failed to allocate data buffer for element count " +
+                   std::to_string(dataMQ->getQuantumCount()) +
+                   ", size in bytes: " + std::to_string(mDataBufferSize);
+        }
     }
     if (::android::status_t status = mDriver->init(); status != STATUS_OK) {
         return "Failed to initialize the driver: " + std::to_string(status);
@@ -136,16 +150,26 @@
 
 void StreamWorkerCommonLogic::populateReply(StreamDescriptor::Reply* reply,
                                             bool isConnected) const {
+    static const StreamDescriptor::Position kUnknownPosition = {
+            .frames = StreamDescriptor::Position::UNKNOWN,
+            .timeNs = StreamDescriptor::Position::UNKNOWN};
     reply->status = STATUS_OK;
     if (isConnected) {
         reply->observable.frames = mContext->getFrameCount();
         reply->observable.timeNs = ::android::uptimeNanos();
-        if (auto status = mDriver->refinePosition(&reply->observable); status == ::android::OK) {
-            return;
+        if (auto status = mDriver->refinePosition(&reply->observable); status != ::android::OK) {
+            reply->observable = kUnknownPosition;
+        }
+    } else {
+        reply->observable = reply->hardware = kUnknownPosition;
+    }
+    if (hasMmapFlag(mContext->getFlags())) {
+        if (auto status = mDriver->getMmapPositionAndLatency(&reply->hardware, &reply->latencyMs);
+            status != ::android::OK) {
+            reply->hardware = kUnknownPosition;
+            reply->latencyMs = StreamDescriptor::LATENCY_UNKNOWN;
         }
     }
-    reply->observable.frames = StreamDescriptor::Position::UNKNOWN;
-    reply->observable.timeNs = StreamDescriptor::Position::UNKNOWN;
 }
 
 void StreamWorkerCommonLogic::populateReplyWrongState(
@@ -224,7 +248,9 @@
                     mState == StreamDescriptor::State::ACTIVE ||
                     mState == StreamDescriptor::State::PAUSED ||
                     mState == StreamDescriptor::State::DRAINING) {
-                    if (!read(fmqByteCount, &reply)) {
+                    if (hasMmapFlag(mContext->getFlags())) {
+                        populateReply(&reply, mIsConnected);
+                    } else if (!read(fmqByteCount, &reply)) {
                         mState = StreamDescriptor::State::ERROR;
                     }
                     if (mState == StreamDescriptor::State::IDLE ||
@@ -317,11 +343,7 @@
 bool StreamInWorkerLogic::read(size_t clientSize, StreamDescriptor::Reply* reply) {
     ATRACE_CALL();
     StreamContext::DataMQ* const dataMQ = mContext->getDataMQ();
-    StreamContext::DataMQ::Error fmqError = StreamContext::DataMQ::Error::NONE;
-    std::string fmqErrorMsg;
-    const size_t byteCount = std::min(
-            {clientSize, dataMQ->availableToWrite(&fmqError, &fmqErrorMsg), mDataBufferSize});
-    CHECK(fmqError == StreamContext::DataMQ::Error::NONE) << fmqErrorMsg;
+    const size_t byteCount = std::min({clientSize, dataMQ->availableToWrite(), mDataBufferSize});
     const bool isConnected = mIsConnected;
     const size_t frameSize = mContext->getFrameSize();
     size_t actualFrameCount = 0;
@@ -470,7 +492,9 @@
                 if (mState != StreamDescriptor::State::ERROR &&
                     mState != StreamDescriptor::State::TRANSFERRING &&
                     mState != StreamDescriptor::State::TRANSFER_PAUSED) {
-                    if (!write(fmqByteCount, &reply)) {
+                    if (hasMmapFlag(mContext->getFlags())) {
+                        populateReply(&reply, mIsConnected);
+                    } else if (!write(fmqByteCount, &reply)) {
                         mState = StreamDescriptor::State::ERROR;
                     }
                     std::shared_ptr<IStreamCallback> asyncCallback = mContext->getAsyncCallback();
@@ -595,10 +619,7 @@
 bool StreamOutWorkerLogic::write(size_t clientSize, StreamDescriptor::Reply* reply) {
     ATRACE_CALL();
     StreamContext::DataMQ* const dataMQ = mContext->getDataMQ();
-    StreamContext::DataMQ::Error fmqError = StreamContext::DataMQ::Error::NONE;
-    std::string fmqErrorMsg;
-    const size_t readByteCount = dataMQ->availableToRead(&fmqError, &fmqErrorMsg);
-    CHECK(fmqError == StreamContext::DataMQ::Error::NONE) << fmqErrorMsg;
+    const size_t readByteCount = dataMQ->availableToRead();
     const size_t frameSize = mContext->getFrameSize();
     bool fatal = false;
     int32_t latency = mContext->getNominalLatencyMs();
@@ -646,10 +667,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.";
     }
 }
 
@@ -657,6 +682,7 @@
         const std::shared_ptr<StreamCommonInterface>& delegate) {
     mCommon = ndk::SharedRefBase::make<StreamCommonDelegator>(delegate);
     if (!mWorker->start()) {
+        LOG(ERROR) << __func__ << ": Worker start error: " << mWorker->getError();
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     }
     if (auto flags = getContext().getFlags();
@@ -697,6 +723,14 @@
             LOG(WARNING) << __func__ << ": invalid worker tid: " << workerTid;
         }
     }
+    getContext().getCommandMQ()->setErrorHandler(
+            fmqErrorHandler<StreamContext::CommandMQ::Error>("CommandMQ"));
+    getContext().getReplyMQ()->setErrorHandler(
+            fmqErrorHandler<StreamContext::ReplyMQ::Error>("ReplyMQ"));
+    if (getContext().getDataMQ() != nullptr) {
+        getContext().getDataMQ()->setErrorHandler(
+                fmqErrorHandler<StreamContext::DataMQ::Error>("DataMQ"));
+    }
     return ndk::ScopedAStatus::ok();
 }
 
@@ -752,10 +786,7 @@
 ndk::ScopedAStatus StreamCommonImpl::close() {
     LOG(DEBUG) << __func__;
     if (!isClosed()) {
-        stopWorker();
-        LOG(DEBUG) << __func__ << ": joining the worker thread...";
-        mWorker->stop();
-        LOG(DEBUG) << __func__ << ": worker thread joined";
+        stopAndJoinWorker();
         onClose(mWorker->setClosed());
         return ndk::ScopedAStatus::ok();
     } else {
@@ -773,6 +804,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...";
@@ -787,6 +832,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..372e38a 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;
 }
@@ -71,6 +75,10 @@
     }
     decltype(mAlsaDeviceProxies) alsaDeviceProxies;
     for (const auto& device : getDeviceProfiles()) {
+        if ((device.direction == PCM_OUT && mIsInput) ||
+            (device.direction == PCM_IN && !mIsInput)) {
+            continue;
+        }
         alsa::DeviceProxy proxy;
         if (device.isExternal) {
             // Always ask alsa configure as required since the configuration should be supported
@@ -88,6 +96,9 @@
         }
         alsaDeviceProxies.push_back(std::move(proxy));
     }
+    if (alsaDeviceProxies.empty()) {
+        return ::android::NO_INIT;
+    }
     mAlsaDeviceProxies = std::move(alsaDeviceProxies);
     return ::android::OK;
 }
diff --git a/audio/aidl/default/alsa/Utils.cpp b/audio/aidl/default/alsa/Utils.cpp
index c08836c..8eaf162 100644
--- a/audio/aidl/default/alsa/Utils.cpp
+++ b/audio/aidl/default/alsa/Utils.cpp
@@ -80,11 +80,8 @@
 
 const AudioChannelCountToMaskMap& getSupportedChannelOutLayoutMap() {
     static const std::set<AudioChannelLayout> supportedOutChannelLayouts = {
-            DEFINE_CHANNEL_LAYOUT_MASK(MONO),          DEFINE_CHANNEL_LAYOUT_MASK(STEREO),
-            DEFINE_CHANNEL_LAYOUT_MASK(2POINT1),       DEFINE_CHANNEL_LAYOUT_MASK(QUAD),
-            DEFINE_CHANNEL_LAYOUT_MASK(PENTA),         DEFINE_CHANNEL_LAYOUT_MASK(5POINT1),
-            DEFINE_CHANNEL_LAYOUT_MASK(6POINT1),       DEFINE_CHANNEL_LAYOUT_MASK(7POINT1),
-            DEFINE_CHANNEL_LAYOUT_MASK(7POINT1POINT4), DEFINE_CHANNEL_LAYOUT_MASK(22POINT2),
+            DEFINE_CHANNEL_LAYOUT_MASK(MONO),
+            DEFINE_CHANNEL_LAYOUT_MASK(STEREO),
     };
     static const AudioChannelCountToMaskMap outLayouts =
             make_ChannelCountToMaskMap(supportedOutChannelLayouts);
diff --git a/audio/aidl/default/android.hardware.audio.service-aidl.xml b/audio/aidl/default/android.hardware.audio.service-aidl.xml
index 5278e4f..27f48e2 100644
--- a/audio/aidl/default/android.hardware.audio.service-aidl.xml
+++ b/audio/aidl/default/android.hardware.audio.service-aidl.xml
@@ -1,39 +1,39 @@
 <manifest version="1.0" type="device">
   <hal format="aidl">
     <name>android.hardware.audio.core</name>
-    <version>2</version>
+    <version>3</version>
     <fqname>IModule/default</fqname>
   </hal>
   <hal format="aidl">
     <name>android.hardware.audio.core</name>
-    <version>2</version>
+    <version>3</version>
     <fqname>IModule/r_submix</fqname>
   </hal>
   <hal format="aidl">
     <name>android.hardware.audio.core</name>
-    <version>2</version>
+    <version>3</version>
     <fqname>IModule/bluetooth</fqname>
   </hal>
   <hal format="aidl">
     <name>android.hardware.audio.core</name>
-    <version>2</version>
+    <version>3</version>
     <fqname>IConfig/default</fqname>
   </hal>
   <!-- Uncomment when these modules present in the configuration
   <hal format="aidl">
     <name>android.hardware.audio.core</name>
-    <version>1</version>
+    <version>3</version>
     <fqname>IModule/stub</fqname>
   </hal>
   <hal format="aidl">
     <name>android.hardware.audio.core</name>
-    <version>1</version>
+    <version>3</version>
     <fqname>IModule/usb</fqname>
   </hal>
   -->
   <hal format="aidl">
     <name>android.hardware.audio.effect</name>
-    <version>2</version>
+    <version>3</version>
     <fqname>IFactory/default</fqname>
   </hal>
 </manifest>
diff --git a/audio/aidl/default/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml
index c01eb3f..a54f4db 100644
--- a/audio/aidl/default/audio_effects_config.xml
+++ b/audio/aidl/default/audio_effects_config.xml
@@ -88,7 +88,6 @@
         <effect name="extension_effect" library="extensioneffect" uuid="fa81dd00-588b-11ed-9b6a-0242ac120002" type="fa81de0e-588b-11ed-9b6a-0242ac120002"/>
         <effect name="acoustic_echo_canceler" library="pre_processing" uuid="bb392ec0-8d4d-11e0-a896-0002a5d5c51b"/>
         <effect name="noise_suppression" library="pre_processing" uuid="c06c8400-8e06-11e0-9cb6-0002a5d5c51b"/>
-        <effect name="spatializer" library="spatializersw" uuid="fa81a880-588b-11ed-9b6a-0242ac120002"/>
     </effects>
 
     <preprocess>
@@ -141,4 +140,37 @@
         </postprocess>
     -->
 
+    <!-- Device pre/post processor configurations.
+         The device pre/post processor configuration is described in a deviceEffects element and
+         consists in a list of elements each describing pre/post processor settings for a given
+         device.
+         Each device element has a "type" attribute corresponding to the device type (e.g.
+         speaker, bus), an "address" attribute corresponding to the device address and contains a
+         list of "apply" elements indicating one effect to apply.
+         If the device is a source, only pre processing effects are expected, if the
+         device is a sink, only post processing effects are expected.
+         The effect to apply is designated by its name in the "effects" elements.
+         The effect will be enabled by default and the audio framework will automatically add
+         and activate the effect if the given port is involved in an audio patch.
+         If the patch is "HW", the effect must be HW accelerated.
+         Note:
+         -Device are not expected to be always attached. It may be loaded dynamically. As the device
+         effect manager is getting called on any audio patch operation, it will ensure if the given
+         device is involved in an audio patch and attach the requested effect.
+         -Address is optional. If not set, the match to instantiate the device effect will be done
+         using the given type and device (of this type) with empty address only.
+
+       <deviceEffects>
+           <device type="AUDIO_DEVICE_OUT_BUS" address="BUS00_USAGE_MAIN">
+               <apply effect="equalizer"/>
+           </device>
+           <device type="AUDIO_DEVICE_OUT_BUS" address="BUS04_USAGE_VOICE">
+               <apply effect="volume"/>
+           </device>
+           <device type="AUDIO_DEVICE_IN_BUILTIN_MIC" address="bottom">
+               <apply effect="agc"/>
+           </device>
+       </deviceEffects>
+   -->
+
 </audio_effects_conf>
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/Module.h b/audio/aidl/default/include/core-impl/Module.h
index a326217..00eeb4e 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -205,6 +205,9 @@
     virtual std::unique_ptr<Configuration> initializeConfig();
     virtual int32_t getNominalLatencyMs(
             const ::aidl::android::media::audio::common::AudioPortConfig& portConfig);
+    virtual ndk::ScopedAStatus createMmapBuffer(
+            const ::aidl::android::hardware::audio::core::StreamContext& context,
+            ::aidl::android::hardware::audio::core::StreamDescriptor* desc);
 
     // Utility and helper functions accessible to subclasses.
     static int32_t calculateBufferSizeFrames(int32_t latencyMs, int32_t sampleRateHz) {
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index 21e63f9..100b4c8 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -177,6 +177,11 @@
     virtual ::android::status_t refinePosition(StreamDescriptor::Position* /*position*/) {
         return ::android::OK;
     }
+    // Implement 'getMmapPositionAndLatency' is necessary if driver can support mmap stream.
+    virtual ::android::status_t getMmapPositionAndLatency(StreamDescriptor::Position* /*position*/,
+                                                          int32_t* /*latency*/) {
+        return ::android::OK;
+    }
     virtual void shutdown() = 0;  // This function is only called once.
 };
 
@@ -240,7 +245,8 @@
     virtual StreamDescriptor::State setClosed() = 0;
     virtual bool start() = 0;
     virtual pid_t getTid() = 0;
-    virtual void stop() = 0;
+    virtual void join() = 0;
+    virtual std::string getError() = 0;
 };
 
 template <class WorkerLogic>
@@ -259,7 +265,8 @@
         return WorkerImpl::start(WorkerImpl::kThreadName, ANDROID_PRIORITY_URGENT_AUDIO);
     }
     pid_t getTid() override { return WorkerImpl::getTid(); }
-    void stop() override { return WorkerImpl::stop(); }
+    void join() override { return WorkerImpl::join(); }
+    std::string getError() override { return WorkerImpl::getError(); }
 };
 
 class StreamInWorkerLogic : public StreamWorkerCommonLogic {
@@ -450,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;
@@ -457,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/StreamPrimary.h b/audio/aidl/default/include/core-impl/StreamPrimary.h
index 8d5c57d..600c377 100644
--- a/audio/aidl/default/include/core-impl/StreamPrimary.h
+++ b/audio/aidl/default/include/core-impl/StreamPrimary.h
@@ -25,7 +25,8 @@
 
 class StreamPrimary : public StreamAlsa {
   public:
-    StreamPrimary(StreamContext* context, const Metadata& metadata);
+    StreamPrimary(StreamContext* context, const Metadata& metadata,
+                  const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices);
 
     ::android::status_t start() override;
     ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
@@ -39,6 +40,11 @@
     int64_t mStartTimeNs = 0;
     long mFramesSinceStart = 0;
     bool mSkipNextTransfer = false;
+
+  private:
+    static std::pair<int, int> getCardAndDeviceId(
+            const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices);
+    const std::pair<int, int> mCardAndDeviceId;
 };
 
 class StreamInPrimary final : public StreamIn, public StreamSwitcher, public StreamInHwGainHelper {
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/include/effect-impl/EffectContext.h b/audio/aidl/default/include/effect-impl/EffectContext.h
index 275378e..02a4caa 100644
--- a/audio/aidl/default/include/effect-impl/EffectContext.h
+++ b/audio/aidl/default/include/effect-impl/EffectContext.h
@@ -82,6 +82,10 @@
 
     virtual ::android::hardware::EventFlag* getStatusEventFlag();
 
+    virtual RetCode enable();
+    virtual RetCode disable();
+    virtual RetCode reset();
+
   protected:
     int mVersion = 0;
     size_t mInputFrameSize = 0;
diff --git a/audio/aidl/default/include/effectFactory-impl/EffectConfig.h b/audio/aidl/default/include/effectFactory-impl/EffectConfig.h
index 7456b99..60bb9be 100644
--- a/audio/aidl/default/include/effectFactory-impl/EffectConfig.h
+++ b/audio/aidl/default/include/effectFactory-impl/EffectConfig.h
@@ -81,7 +81,7 @@
     /* Parsed Effects result */
     std::unordered_map<std::string, struct EffectLibraries> mEffectsMap;
     /**
-     * For parsed pre/post processing result: {key: AudioStreamType/AudioSource, value:
+     * For parsed pre/post processing result: {key: AudioStreamType/AudioSource/AudioDevice, value:
      * EffectLibraries}
      */
     ProcessingLibrariesMap mProcessingMap;
@@ -110,7 +110,8 @@
     bool resolveLibrary(const std::string& path, std::string* resolvedPath);
 
     std::optional<Processing::Type> stringToProcessingType(Processing::Type::Tag typeTag,
-                                                           const std::string& type);
+                                                           const std::string& type,
+                                                           const std::string& address);
 };
 
 }  // namespace aidl::android::hardware::audio::effect
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..801bbb8 100644
--- a/audio/aidl/default/primary/StreamPrimary.cpp
+++ b/audio/aidl/default/primary/StreamPrimary.cpp
@@ -15,7 +15,11 @@
  */
 
 #define LOG_TAG "AHAL_StreamPrimary"
+
+#include <cstdio>
+
 #include <android-base/logging.h>
+#include <android-base/parseint.h>
 #include <android-base/properties.h>
 #include <audio_utils/clock.h>
 #include <error/Result.h>
@@ -28,6 +32,7 @@
 using aidl::android::hardware::audio::common::SinkMetadata;
 using aidl::android::hardware::audio::common::SourceMetadata;
 using aidl::android::media::audio::common::AudioDevice;
+using aidl::android::media::audio::common::AudioDeviceAddress;
 using aidl::android::media::audio::common::AudioDeviceDescription;
 using aidl::android::media::audio::common::AudioDeviceType;
 using aidl::android::media::audio::common::AudioOffloadInfo;
@@ -36,9 +41,15 @@
 
 namespace aidl::android::hardware::audio::core {
 
-StreamPrimary::StreamPrimary(StreamContext* context, const Metadata& metadata)
+const static constexpr std::pair<int, int> kDefaultCardAndDeviceId = {
+        primary::PrimaryMixer::kAlsaCard, primary::PrimaryMixer::kAlsaDevice};
+
+StreamPrimary::StreamPrimary(
+        StreamContext* context, const Metadata& metadata,
+        const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices)
     : StreamAlsa(context, metadata, 3 /*readWriteRetries*/),
-      mIsAsynchronous(!!getContext().getAsyncCallback()) {
+      mIsAsynchronous(!!getContext().getAsyncCallback()),
+      mCardAndDeviceId(getCardAndDeviceId(devices)) {
     context->startStreamDataProcessor();
 }
 
@@ -92,17 +103,27 @@
 }
 
 std::vector<alsa::DeviceProfile> StreamPrimary::getDeviceProfiles() {
-    static const std::vector<alsa::DeviceProfile> kBuiltInSource{
-            alsa::DeviceProfile{.card = primary::PrimaryMixer::kAlsaCard,
-                                .device = primary::PrimaryMixer::kAlsaDevice,
-                                .direction = PCM_IN,
+    return {alsa::DeviceProfile{.card = mCardAndDeviceId.first,
+                                .device = mCardAndDeviceId.second,
+                                .direction = mIsInput ? PCM_IN : PCM_OUT,
                                 .isExternal = false}};
-    static const std::vector<alsa::DeviceProfile> kBuiltInSink{
-            alsa::DeviceProfile{.card = primary::PrimaryMixer::kAlsaCard,
-                                .device = primary::PrimaryMixer::kAlsaDevice,
-                                .direction = PCM_OUT,
-                                .isExternal = false}};
-    return mIsInput ? kBuiltInSource : kBuiltInSink;
+}
+
+std::pair<int, int> StreamPrimary::getCardAndDeviceId(const std::vector<AudioDevice>& devices) {
+    if (devices.empty() || devices[0].address.getTag() != AudioDeviceAddress::id) {
+        return kDefaultCardAndDeviceId;
+    }
+    std::string deviceAddress = devices[0].address.get<AudioDeviceAddress::id>();
+    std::pair<int, int> cardAndDeviceId;
+    if (const size_t suffixPos = deviceAddress.rfind("CARD_");
+        suffixPos == std::string::npos ||
+        sscanf(deviceAddress.c_str() + suffixPos, "CARD_%d_DEV_%d", &cardAndDeviceId.first,
+               &cardAndDeviceId.second) != 2) {
+        return kDefaultCardAndDeviceId;
+    }
+    LOG(DEBUG) << __func__ << ": parsed with card id " << cardAndDeviceId.first << ", device id "
+               << cardAndDeviceId.second;
+    return cardAndDeviceId;
 }
 
 StreamInPrimary::StreamInPrimary(StreamContext&& context, const SinkMetadata& sinkMetadata,
@@ -116,8 +137,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(
@@ -145,7 +165,7 @@
                 new InnerStreamWrapper<StreamStub>(context, metadata));
     }
     return std::unique_ptr<StreamCommonInterfaceEx>(
-            new InnerStreamWrapper<StreamPrimary>(context, metadata));
+            new InnerStreamWrapper<StreamPrimary>(context, metadata, devices));
 }
 
 ndk::ScopedAStatus StreamInPrimary::getHwGain(std::vector<float>* _aidl_return) {
@@ -188,8 +208,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(
@@ -217,7 +236,7 @@
                 new InnerStreamWrapper<StreamStub>(context, metadata));
     }
     return std::unique_ptr<StreamCommonInterfaceEx>(
-            new InnerStreamWrapper<StreamPrimary>(context, metadata));
+            new InnerStreamWrapper<StreamPrimary>(context, metadata, devices));
 }
 
 ndk::ScopedAStatus StreamOutPrimary::getHwVolume(std::vector<float>* _aidl_return) {
diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
index ca3f91a..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) {
@@ -285,9 +289,12 @@
     char* buff = (char*)buffer;
     size_t actuallyRead = 0;
     long remainingFrames = frameCount;
-    const int64_t deadlineTimeNs =
-            ::android::uptimeNanos() +
-            getDelayInUsForFrameCount(frameCount) * NANOS_PER_MICROSECOND / 2;
+    // Try to wait as long as possible for the audio duration, but leave some time for the call to
+    // 'transfer' to complete. 'kReadAttemptSleepUs' is a good constant for this purpose because it
+    // is by definition "strictly inferior" to the typical buffer duration.
+    const long durationUs =
+            std::max(0L, getDelayInUsForFrameCount(frameCount) - kReadAttemptSleepUs);
+    const int64_t deadlineTimeNs = ::android::uptimeNanos() + durationUs * NANOS_PER_MICROSECOND;
     while (remainingFrames > 0) {
         ssize_t framesRead = source->read(buff, remainingFrames);
         LOG(VERBOSE) << __func__ << ": frames read " << framesRead;
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/sounddose/Android.bp b/audio/aidl/sounddose/Android.bp
index de3ed64..8b2d74b 100644
--- a/audio/aidl/sounddose/Android.bp
+++ b/audio/aidl/sounddose/Android.bp
@@ -56,11 +56,11 @@
         // IMPORTANT: Update latest_android_hardware_audio_sounddose every time you
         // add the latest frozen version to versions_with_info
     ],
-    frozen: true,
+    frozen: false,
 }
 
 // Note: This should always be one version ahead of the last frozen version
-latest_android_hardware_audio_sounddose = "android.hardware.audio.sounddose-V2"
+latest_android_hardware_audio_sounddose = "android.hardware.audio.sounddose-V3"
 
 // Modules that depend on android.hardware.audio.sounddose directly can include
 // the following cc_defaults to avoid explicitly managing dependency versions
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index cbd42c0..85d400e 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -136,6 +136,9 @@
     name: "VtsHalHapticGeneratorTargetTest",
     defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalHapticGeneratorTargetTest.cpp"],
+    shared_libs: [
+        "libaudioutils",
+    ],
 }
 
 cc_test {
diff --git a/audio/aidl/vts/EffectHelper.h b/audio/aidl/vts/EffectHelper.h
index 72a4667..01f73fc 100644
--- a/audio/aidl/vts/EffectHelper.h
+++ b/audio/aidl/vts/EffectHelper.h
@@ -83,6 +83,8 @@
     return prefix;
 }
 
+static constexpr float kMaxAudioSampleValue = 1;
+
 class EffectHelper {
   public:
     void create(std::shared_ptr<IFactory> factory, std::shared_ptr<IEffect>& effect,
@@ -92,6 +94,7 @@
         ASSERT_STATUS(status, factory->createEffect(id.uuid, &effect));
         if (status == EX_NONE) {
             ASSERT_NE(effect, nullptr) << toString(id.uuid);
+            ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
         }
         mIsSpatializer = id.type == getEffectTypeUuidSpatializer();
         mDescriptor = desc;
@@ -111,11 +114,17 @@
         ASSERT_STATUS(status, factory->destroyEffect(effect));
     }
 
-    static void open(std::shared_ptr<IEffect> effect, const Parameter::Common& common,
-                     const std::optional<Parameter::Specific>& specific,
-                     IEffect::OpenEffectReturn* ret, binder_status_t status = EX_NONE) {
+    void open(std::shared_ptr<IEffect> effect, const Parameter::Common& common,
+              const std::optional<Parameter::Specific>& specific, IEffect::OpenEffectReturn* ret,
+              binder_status_t status = EX_NONE) {
         ASSERT_NE(effect, nullptr);
         ASSERT_STATUS(status, effect->open(common, specific, ret));
+        if (status != EX_NONE) {
+            return;
+        }
+
+        ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+        updateFrameSize(common);
     }
 
     void open(std::shared_ptr<IEffect> effect, int session = 0, binder_status_t status = EX_NONE) {
@@ -125,21 +134,37 @@
         ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, status));
     }
 
+    void reopen(std::shared_ptr<IEffect> effect, const Parameter::Common& common,
+                IEffect::OpenEffectReturn* ret, binder_status_t status = EX_NONE) {
+        ASSERT_NE(effect, nullptr);
+        ASSERT_STATUS(status, effect->reopen(ret));
+        if (status != EX_NONE) {
+            return;
+        }
+        updateFrameSize(common);
+    }
+
     static void closeIgnoreRet(std::shared_ptr<IEffect> effect) {
         if (effect) {
             effect->close();
         }
     }
+
     static void close(std::shared_ptr<IEffect> effect, binder_status_t status = EX_NONE) {
         if (effect) {
             ASSERT_STATUS(status, effect->close());
+            if (status == EX_NONE) {
+                ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
+            }
         }
     }
+
     static void getDescriptor(std::shared_ptr<IEffect> effect, Descriptor& desc,
                               binder_status_t status = EX_NONE) {
         ASSERT_NE(effect, nullptr);
         ASSERT_STATUS(status, effect->getDescriptor(&desc));
     }
+
     static void expectState(std::shared_ptr<IEffect> effect, State expectState,
                             binder_status_t status = EX_NONE) {
         ASSERT_NE(effect, nullptr);
@@ -147,27 +172,35 @@
         ASSERT_STATUS(status, effect->getState(&state));
         ASSERT_EQ(expectState, state);
     }
+
     static void commandIgnoreRet(std::shared_ptr<IEffect> effect, CommandId command) {
         if (effect) {
             effect->command(command);
         }
     }
+
     static void command(std::shared_ptr<IEffect> effect, CommandId command,
                         binder_status_t status = EX_NONE) {
         ASSERT_NE(effect, nullptr);
         ASSERT_STATUS(status, effect->command(command));
+        if (status != EX_NONE) {
+            return;
+        }
+
+        switch (command) {
+            case CommandId::START:
+                ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+                break;
+            case CommandId::STOP:
+                FALLTHROUGH_INTENDED;
+            case CommandId::RESET:
+                ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+                break;
+            default:
+                return;
+        }
     }
-    static void allocateInputData(const Parameter::Common common, std::unique_ptr<DataMQ>& mq,
-                                  std::vector<float>& buffer) {
-        ASSERT_NE(mq, nullptr);
-        auto frameSize = ::aidl::android::hardware::audio::common::getFrameSizeInBytes(
-                common.input.base.format, common.input.base.channelMask);
-        const size_t floatsToWrite = mq->availableToWrite();
-        ASSERT_NE(0UL, floatsToWrite);
-        ASSERT_EQ(frameSize * common.input.frameCount, floatsToWrite * sizeof(float));
-        buffer.resize(floatsToWrite);
-        std::fill(buffer.begin(), buffer.end(), 0x5a);
-    }
+
     static void writeToFmq(std::unique_ptr<StatusMQ>& statusMq, std::unique_ptr<DataMQ>& dataMq,
                            const std::vector<float>& buffer, int version) {
         const size_t available = dataMq->availableToWrite();
@@ -184,6 +217,7 @@
                                                          : kEventFlagNotEmpty);
         ASSERT_EQ(::android::OK, EventFlag::deleteEventFlag(&efGroup));
     }
+
     static void readFromFmq(std::unique_ptr<StatusMQ>& statusMq, size_t statusNum,
                             std::unique_ptr<DataMQ>& dataMq, size_t expectFloats,
                             std::vector<float>& buffer,
@@ -204,6 +238,7 @@
             ASSERT_TRUE(dataMq->read(buffer.data(), expectFloats));
         }
     }
+
     static void expectDataMqUpdateEventFlag(std::unique_ptr<StatusMQ>& statusMq) {
         EventFlag* efGroup;
         ASSERT_EQ(::android::OK,
@@ -218,8 +253,10 @@
     Parameter::Common createParamCommon(int session = 0, int ioHandle = -1, int iSampleRate = 48000,
                                         int oSampleRate = 48000, long iFrameCount = 0x100,
                                         long oFrameCount = 0x100) {
-        AudioChannelLayout defaultLayout = AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+        AudioChannelLayout inputLayout = AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
                 AudioChannelLayout::LAYOUT_STEREO);
+        AudioChannelLayout outputLayout = inputLayout;
+
         // query supported input layout and use it as the default parameter in common
         if (mIsSpatializer && isRangeValid<Range::spatializer>(Spatializer::supportedChannelLayout,
                                                                mDescriptor.capability)) {
@@ -229,12 +266,14 @@
                 layoutRange &&
                 0 != (layouts = layoutRange->min.get<Spatializer::supportedChannelLayout>())
                                 .size()) {
-                defaultLayout = layouts[0];
+                inputLayout = layouts[0];
             }
         }
+
         return createParamCommon(session, ioHandle, iSampleRate, oSampleRate, iFrameCount,
-                                 oFrameCount, defaultLayout, defaultLayout);
+                                 oFrameCount, inputLayout, outputLayout);
     }
+
     static Parameter::Common createParamCommon(int session, int ioHandle, int iSampleRate,
                                                int oSampleRate, long iFrameCount, long oFrameCount,
                                                AudioChannelLayout inputChannelLayout,
@@ -333,33 +372,38 @@
 
     static void processAndWriteToOutput(std::vector<float>& inputBuffer,
                                         std::vector<float>& outputBuffer,
-                                        const std::shared_ptr<IEffect>& mEffect,
-                                        IEffect::OpenEffectReturn* mOpenEffectReturn) {
+                                        const std::shared_ptr<IEffect>& effect,
+                                        IEffect::OpenEffectReturn* openEffectReturn,
+                                        int version = -1, int times = 1) {
         // Initialize AidlMessagequeues
-        auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(mOpenEffectReturn->statusMQ);
+        auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(openEffectReturn->statusMQ);
         ASSERT_TRUE(statusMQ->isValid());
-        auto inputMQ = std::make_unique<EffectHelper::DataMQ>(mOpenEffectReturn->inputDataMQ);
+        auto inputMQ = std::make_unique<EffectHelper::DataMQ>(openEffectReturn->inputDataMQ);
         ASSERT_TRUE(inputMQ->isValid());
-        auto outputMQ = std::make_unique<EffectHelper::DataMQ>(mOpenEffectReturn->outputDataMQ);
+        auto outputMQ = std::make_unique<EffectHelper::DataMQ>(openEffectReturn->outputDataMQ);
         ASSERT_TRUE(outputMQ->isValid());
 
         // Enabling the process
-        ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-        ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+        ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
 
         // Write from buffer to message queues and calling process
-        EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, inputBuffer, [&]() {
-            int version = 0;
-            return (mEffect && mEffect->getInterfaceVersion(&version).isOk()) ? version : 0;
-        }()));
+        if (version == -1) {
+            ASSERT_IS_OK(effect->getInterfaceVersion(&version));
+        }
 
-        // Read the updated message queues into buffer
-        EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 1, outputMQ,
-                                                          outputBuffer.size(), outputBuffer));
+        for (int i = 0; i < times; i++) {
+            EXPECT_NO_FATAL_FAILURE(
+                    EffectHelper::writeToFmq(statusMQ, inputMQ, inputBuffer, version));
+            // Read the updated message queues into buffer
+            EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 1, outputMQ,
+                                                              outputBuffer.size(), outputBuffer));
+        }
 
         // Disable the process
-        ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
-        ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+        ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+        EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, outputBuffer));
+
+        ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
     }
 
     // Find FFT bin indices for testFrequencies and get bin center frequencies
@@ -371,6 +415,19 @@
         }
     }
 
+    // Fill inputBuffer with random values between -maxAudioSampleValue to maxAudioSampleValue
+    void generateInputBuffer(std::vector<float>& inputBuffer, size_t startPosition, bool isStrip,
+                             size_t channelCount,
+                             float maxAudioSampleValue = kMaxAudioSampleValue) {
+        size_t increment = isStrip ? 1 /*Fill input at all the channels*/
+                                   : channelCount /*Fill input at only one channel*/;
+
+        for (size_t i = startPosition; i < inputBuffer.size(); i += increment) {
+            inputBuffer[i] =
+                    ((static_cast<float>(std::rand()) / RAND_MAX) * 2 - 1) * maxAudioSampleValue;
+        }
+    }
+
     // Generate multitone input between -1 to +1 using testFrequencies
     void generateMultiTone(const std::vector<int>& testFrequencies, std::vector<float>& input,
                            const int samplingFrequency) {
@@ -403,6 +460,28 @@
         return bufferMag;
     }
 
+    void updateFrameSize(const Parameter::Common& common) {
+        mInputFrameSize = ::aidl::android::hardware::audio::common::getFrameSizeInBytes(
+                common.input.base.format, common.input.base.channelMask);
+        mInputSamples = common.input.frameCount * mInputFrameSize / sizeof(float);
+        mOutputFrameSize = ::aidl::android::hardware::audio::common::getFrameSizeInBytes(
+                common.output.base.format, common.output.base.channelMask);
+        mOutputSamples = common.output.frameCount * mOutputFrameSize / sizeof(float);
+    }
+
+    void generateInput(std::vector<float>& input, float inputFrequency, float samplingFrequency,
+                       size_t inputSize = 0) {
+        if (inputSize == 0 || inputSize > input.size()) {
+            inputSize = input.size();
+        }
+
+        for (size_t i = 0; i < inputSize; i++) {
+            input[i] = sin(2 * M_PI * inputFrequency * i / samplingFrequency);
+        }
+    }
+
     bool mIsSpatializer;
     Descriptor mDescriptor;
+    size_t mInputFrameSize, mOutputFrameSize;
+    size_t mInputSamples, mOutputSamples;
 };
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 d576c7c..2bf70c7 100644
--- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -56,6 +56,7 @@
 using namespace android;
 using aidl::android::hardware::audio::common::AudioOffloadMetadata;
 using aidl::android::hardware::audio::common::getChannelCount;
+using aidl::android::hardware::audio::common::hasMmapFlag;
 using aidl::android::hardware::audio::common::isAnyBitPositionFlagSet;
 using aidl::android::hardware::audio::common::isBitPositionFlagSet;
 using aidl::android::hardware::audio::common::isTelephonyDeviceType;
@@ -637,19 +638,39 @@
           mCommandMQ(new CommandMQ(descriptor.command)),
           mReplyMQ(new ReplyMQ(descriptor.reply)),
           mBufferSizeFrames(descriptor.bufferSizeFrames),
-          mDataMQ(maybeCreateDataMQ(descriptor)) {}
+          mDataMQ(maybeCreateDataMQ(descriptor)),
+          mIsMmapped(isMmapped(descriptor)),
+          mSharedMemoryFd(maybeGetMmapFd(descriptor)) {
+        if (isMmapped()) {
+            mSharedMemory = (int8_t*)mmap(nullptr, getBufferSizeBytes(), PROT_READ | PROT_WRITE,
+                                          MAP_SHARED, mSharedMemoryFd, 0);
+            if (mSharedMemory == MAP_FAILED) {
+                PLOG(ERROR) << __func__ << ": mmap() failed.";
+                mSharedMemory = nullptr;
+            }
+        }
+    }
+    ~StreamContext() {
+        if (mSharedMemory != nullptr) {
+            munmap(mSharedMemory, getBufferSizeBytes());
+        }
+    }
     void checkIsValid() const {
         EXPECT_NE(0UL, mFrameSizeBytes);
         ASSERT_NE(nullptr, mCommandMQ);
         EXPECT_TRUE(mCommandMQ->isValid());
         ASSERT_NE(nullptr, mReplyMQ);
         EXPECT_TRUE(mReplyMQ->isValid());
-        if (mDataMQ != nullptr) {
-            EXPECT_TRUE(mDataMQ->isValid());
-            EXPECT_GE(mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize(),
-                      mFrameSizeBytes * mBufferSizeFrames)
-                    << "Data MQ actual buffer size is "
-                       "less than the buffer size as specified by the descriptor";
+        if (isMmapped()) {
+            ASSERT_NE(nullptr, mSharedMemory);
+        } else {
+            if (mDataMQ != nullptr) {
+                EXPECT_TRUE(mDataMQ->isValid());
+                EXPECT_GE(mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize(),
+                          mFrameSizeBytes * mBufferSizeFrames)
+                        << "Data MQ actual buffer size is "
+                           "less than the buffer size as specified by the descriptor";
+            }
         }
     }
     size_t getBufferSizeBytes() const { return mFrameSizeBytes * mBufferSizeFrames; }
@@ -658,6 +679,8 @@
     DataMQ* getDataMQ() const { return mDataMQ.get(); }
     size_t getFrameSizeBytes() const { return mFrameSizeBytes; }
     ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
+    bool isMmapped() const { return mIsMmapped; }
+    int8_t* getMmapMemory() const { return mSharedMemory; }
 
   private:
     static std::unique_ptr<DataMQ> maybeCreateDataMQ(const StreamDescriptor& descriptor) {
@@ -667,12 +690,26 @@
         }
         return nullptr;
     }
+    static bool isMmapped(const StreamDescriptor& descriptor) {
+        using Tag = StreamDescriptor::AudioBuffer::Tag;
+        return descriptor.audio.getTag() == Tag::mmap;
+    }
+    static int32_t maybeGetMmapFd(const StreamDescriptor& descriptor) {
+        using Tag = StreamDescriptor::AudioBuffer::Tag;
+        if (descriptor.audio.getTag() == Tag::mmap) {
+            return descriptor.audio.get<Tag::mmap>().sharedMemory.fd.get();
+        }
+        return -1;
+    }
 
     const size_t mFrameSizeBytes;
     std::unique_ptr<CommandMQ> mCommandMQ;
     std::unique_ptr<ReplyMQ> mReplyMQ;
     const size_t mBufferSizeFrames;
     std::unique_ptr<DataMQ> mDataMQ;
+    const bool mIsMmapped;
+    const int32_t mSharedMemoryFd;
+    int8_t* mSharedMemory = nullptr;
 };
 
 struct StreamEventReceiver {
@@ -868,12 +905,15 @@
           mDataMQ(context.getDataMQ()),
           mData(context.getBufferSizeBytes()),
           mDriver(driver),
-          mEventReceiver(eventReceiver) {}
+          mEventReceiver(eventReceiver),
+          mIsMmapped(context.isMmapped()),
+          mSharedMemory(context.getMmapMemory()) {}
     StreamContext::CommandMQ* getCommandMQ() const { return mCommandMQ; }
     StreamContext::ReplyMQ* getReplyMQ() const { return mReplyMQ; }
     StreamContext::DataMQ* getDataMQ() const { return mDataMQ; }
     StreamLogicDriver* getDriver() const { return mDriver; }
     StreamEventReceiver* getEventReceiver() const { return mEventReceiver; }
+    bool isMmapped() const { return mIsMmapped; }
 
     std::string init() override {
         LOG(DEBUG) << __func__;
@@ -914,6 +954,22 @@
         LOG(ERROR) << __func__ << ": writing of " << mData.size() << " bytes to MQ failed";
         return false;
     }
+    bool readDataFromMmap(size_t readCount) {
+        if (mSharedMemory != nullptr) {
+            std::memcpy(mData.data(), mSharedMemory, readCount);
+            return true;
+        }
+        LOG(ERROR) << __func__ << ": reading of " << readCount << " bytes from mmap failed";
+        return false;
+    }
+    bool writeDataToMmap() {
+        if (mSharedMemory != nullptr) {
+            std::memcpy(mSharedMemory, mData.data(), mData.size());
+            return true;
+        }
+        LOG(ERROR) << __func__ << ": writing of " << mData.size() << " bytes to mmap failed";
+        return false;
+    }
 
   private:
     StreamContext::CommandMQ* mCommandMQ;
@@ -923,6 +979,8 @@
     StreamLogicDriver* const mDriver;
     StreamEventReceiver* const mEventReceiver;
     int mLastEventSeq = StreamEventReceiver::kEventSeqInit;
+    const bool mIsMmapped;
+    int8_t* mSharedMemory = nullptr;
 };
 
 class StreamReaderLogic : public StreamCommonLogic {
@@ -970,7 +1028,8 @@
                        << ": received invalid byte count in the reply: " << reply.fmqByteCount;
             return Status::ABORT;
         }
-        if (static_cast<size_t>(reply.fmqByteCount) != getDataMQ()->availableToRead()) {
+        if (!isMmapped() &&
+            static_cast<size_t>(reply.fmqByteCount) != getDataMQ()->availableToRead()) {
             LOG(ERROR) << __func__
                        << ": the byte count in the reply is not the same as the amount of "
                        << "data available in the MQ: " << reply.fmqByteCount
@@ -991,8 +1050,10 @@
             return Status::ABORT;
         }
         const bool acceptedReply = getDriver()->processValidReply(reply);
-        if (const size_t readCount = getDataMQ()->availableToRead(); readCount > 0) {
-            if (readDataFromMQ(readCount)) {
+        if (const size_t readCount =
+                    !isMmapped() ? getDataMQ()->availableToRead() : reply.fmqByteCount;
+            readCount > 0) {
+            if (isMmapped() ? readDataFromMmap(readCount) : readDataFromMQ(readCount)) {
                 goto checkAcceptedReply;
             }
             LOG(ERROR) << __func__ << ": reading of " << readCount << " data bytes from MQ failed";
@@ -1028,8 +1089,10 @@
             LOG(ERROR) << __func__ << ": no next command";
             return Status::ABORT;
         }
-        if (actualSize != 0 && !writeDataToMQ()) {
-            return Status::ABORT;
+        if (actualSize != 0) {
+            if (isMmapped() ? !writeDataToMmap() : !writeDataToMQ()) {
+                return Status::ABORT;
+            }
         }
         LOG(DEBUG) << "Writing command: " << command.toString();
         if (!getCommandMQ()->writeBlocking(&command, 1)) {
@@ -1058,7 +1121,7 @@
             return Status::ABORT;
         }
         // It is OK for the implementation to leave data in the MQ when the stream is paused.
-        if (reply.state != StreamDescriptor::State::PAUSED &&
+        if (!isMmapped() && reply.state != StreamDescriptor::State::PAUSED &&
             getDataMQ()->availableToWrite() != getDataMQ()->getQuantumCount()) {
             LOG(ERROR) << __func__ << ": the HAL module did not consume all data from the data MQ: "
                        << "available to write " << getDataMQ()->availableToWrite()
@@ -2904,15 +2967,24 @@
 
 class StreamLogicDefaultDriver : public StreamLogicDriver {
   public:
-    StreamLogicDefaultDriver(std::shared_ptr<StateSequence> commands, size_t frameSizeBytes)
-        : mCommands(commands), mFrameSizeBytes(frameSizeBytes) {
+    StreamLogicDefaultDriver(std::shared_ptr<StateSequence> commands, size_t frameSizeBytes,
+                             bool isMmap)
+        : mCommands(commands), mFrameSizeBytes(frameSizeBytes), mIsMmap(isMmap) {
         mCommands->rewind();
     }
 
-    // The three methods below is intended to be called after the worker
+    // 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 hasRetrogradeObservablePosition() 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 ? mHardware.hasPositionIncrease : true;
+    }
+    bool hasHardwareRetrogradePosition() const {
+        // For non-MMap, always return false to pass the validation.
+        return mIsMmap ? mHardware.hasRetrogradePosition : false;
+    }
     std::string getUnexpectedStateTransition() const { return mUnexpectedTransition; }
 
     bool done() override { return mCommands->done(); }
@@ -2939,15 +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 (mPreviousFrames.has_value()) {
-                if (reply.observable.frames > mPreviousFrames.value()) {
-                    mObservablePositionIncrease = true;
-                } else if (reply.observable.frames < mPreviousFrames.value()) {
-                    mRetrogradeObservablePosition = true;
-                }
-            }
-            mPreviousFrames = reply.observable.frames;
+        mObservable.update(reply.observable.frames);
+        if (mIsMmap) {
+            mHardware.update(reply.hardware.frames);
         }
 
         auto expected = mCommands->getExpectedStates();
@@ -2972,12 +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> mPreviousFrames;
-    bool mObservablePositionIncrease = false;
-    bool mRetrogradeObservablePosition = false;
+    FramesCounter mObservable;
+    FramesCounter mHardware;
     std::string mUnexpectedTransition;
 };
 
@@ -3029,8 +3113,8 @@
 
     void StartWorkerToSendBurstCommands() {
         const StreamContext* context = mStream->getStreamContext();
-        mWorkerDriver = std::make_unique<StreamLogicDefaultDriver>(makeBurstCommands(mIsSync),
-                                                                   context->getFrameSizeBytes());
+        mWorkerDriver = std::make_unique<StreamLogicDefaultDriver>(
+                makeBurstCommands(mIsSync), context->getFrameSizeBytes(), context->isMmapped());
         mWorker = std::make_unique<typename IOTraits<Stream>::Worker>(
                 *context, mWorkerDriver.get(), mStream->getStreamEventReceiver());
         LOG(DEBUG) << __func__ << ": starting " << IOTraits<Stream>::directionStr << " worker...";
@@ -3047,10 +3131,10 @@
         EXPECT_FALSE(mWorker->hasError()) << mWorker->getError();
         EXPECT_EQ("", mWorkerDriver->getUnexpectedStateTransition());
         if (validatePosition) {
-            if (IOTraits<Stream>::is_input) {
-                EXPECT_TRUE(mWorkerDriver->hasObservablePositionIncrease());
-            }
-            EXPECT_FALSE(mWorkerDriver->hasRetrogradeObservablePosition());
+            EXPECT_TRUE(mWorkerDriver->hasObservablePositionIncrease());
+            EXPECT_TRUE(mWorkerDriver->hasHardwarePositionIncrease());
+            EXPECT_FALSE(mWorkerDriver->hasObservableRetrogradePosition());
+            EXPECT_FALSE(mWorkerDriver->hasHardwareRetrogradePosition());
         }
         mWorker.reset();
         mWorkerDriver.reset();
@@ -3984,7 +4068,7 @@
         }
     }
 
-    bool ValidateObservablePosition(const AudioDevice& device) {
+    bool ValidatePosition(const AudioDevice& device) {
         return !isTelephonyDeviceType(device.type.type);
     }
 
@@ -3998,7 +4082,8 @@
         if (skipStreamIoTestForDevice(stream.getDevice())) return;
         ASSERT_EQ("", stream.skipTestReason());
         StreamLogicDefaultDriver driver(commandsAndStates,
-                                        stream.getStreamContext()->getFrameSizeBytes());
+                                        stream.getStreamContext()->getFrameSizeBytes(),
+                                        stream.getStreamContext()->isMmapped());
         typename IOTraits<Stream>::Worker worker(*stream.getStreamContext(), &driver,
                                                  stream.getStreamEventReceiver());
 
@@ -4008,11 +4093,13 @@
         worker.join();
         EXPECT_FALSE(worker.hasError()) << worker.getError();
         EXPECT_EQ("", driver.getUnexpectedStateTransition());
-        if (ValidateObservablePosition(stream.getDevice())) {
+        if (ValidatePosition(stream.getDevice())) {
             if (validatePositionIncrease) {
                 EXPECT_TRUE(driver.hasObservablePositionIncrease());
+                EXPECT_TRUE(driver.hasHardwarePositionIncrease());
             }
-            EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
+            EXPECT_FALSE(driver.hasObservableRetrogradePosition());
+            EXPECT_FALSE(driver.hasHardwareRetrogradePosition());
         }
     }
 
@@ -4028,7 +4115,8 @@
         ASSERT_EQ("", stream.skipTestReason());
         ASSERT_NO_FATAL_FAILURE(stream.TeardownPatchSetUpStream(module.get()));
         StreamLogicDefaultDriver driver(commandsAndStates,
-                                        stream.getStreamContext()->getFrameSizeBytes());
+                                        stream.getStreamContext()->getFrameSizeBytes(),
+                                        stream.getStreamContext()->isMmapped());
         typename IOTraits<Stream>::Worker worker(*stream.getStreamContext(), &driver,
                                                  stream.getStreamEventReceiver());
         ASSERT_NO_FATAL_FAILURE(stream.ReconnectPatch(module.get()));
@@ -4039,11 +4127,13 @@
         worker.join();
         EXPECT_FALSE(worker.hasError()) << worker.getError();
         EXPECT_EQ("", driver.getUnexpectedStateTransition());
-        if (ValidateObservablePosition(stream.getDevice())) {
+        if (ValidatePosition(stream.getDevice())) {
             if (validatePositionIncrease) {
                 EXPECT_TRUE(driver.hasObservablePositionIncrease());
+                EXPECT_TRUE(driver.hasHardwarePositionIncrease());
             }
-            EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
+            EXPECT_FALSE(driver.hasObservableRetrogradePosition());
+            EXPECT_FALSE(driver.hasHardwareRetrogradePosition());
         }
     }
 };
diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
index 2f47d07..d23bdc9 100644
--- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -200,7 +200,6 @@
 // An effect instance is in INIT state by default after it was created.
 TEST_P(AudioEffectTest, InitStateAfterCreation) {
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::INIT));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
@@ -208,7 +207,6 @@
 TEST_P(AudioEffectTest, IdleStateAfterOpen) {
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
     ASSERT_NO_FATAL_FAILURE(open(mEffect));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(close(mEffect));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
@@ -216,11 +214,8 @@
 // An effect instance is in PROCESSING state after it receive an START command.
 TEST_P(AudioEffectTest, ProcessingStateAfterStart) {
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::INIT));
     ASSERT_NO_FATAL_FAILURE(open(mEffect));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
     ASSERT_NO_FATAL_FAILURE(close(mEffect));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
@@ -231,9 +226,7 @@
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
     ASSERT_NO_FATAL_FAILURE(open(mEffect));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(close(mEffect));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
@@ -243,9 +236,7 @@
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
     ASSERT_NO_FATAL_FAILURE(open(mEffect));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(close(mEffect));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
@@ -257,7 +248,6 @@
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
     ASSERT_NO_FATAL_FAILURE(close(mEffect));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::INIT));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
@@ -274,9 +264,7 @@
 TEST_P(AudioEffectTest, StopCommandInIdleStateNoOp) {
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
     ASSERT_NO_FATAL_FAILURE(open(mEffect));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(close(mEffect));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
@@ -285,9 +273,7 @@
 TEST_P(AudioEffectTest, ResetCommandInIdleStateNoOp) {
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
     ASSERT_NO_FATAL_FAILURE(open(mEffect));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(close(mEffect));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
@@ -296,16 +282,11 @@
 TEST_P(AudioEffectTest, RepeatStartAndStop) {
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
     ASSERT_NO_FATAL_FAILURE(open(mEffect));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(close(mEffect));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
@@ -314,16 +295,10 @@
 TEST_P(AudioEffectTest, RepeatStartAndReset) {
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
     ASSERT_NO_FATAL_FAILURE(open(mEffect));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
-
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(close(mEffect));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
@@ -332,14 +307,11 @@
 TEST_P(AudioEffectTest, CloseProcessingStateEffects) {
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
     ASSERT_NO_FATAL_FAILURE(open(mEffect));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
     ASSERT_NO_FATAL_FAILURE(close(mEffect, EX_ILLEGAL_STATE));
 
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(close(mEffect));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
@@ -348,8 +320,6 @@
 TEST_P(AudioEffectTest, DestroyOpenEffects) {
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
     ASSERT_NO_FATAL_FAILURE(open(mEffect));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
-
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect, EX_ILLEGAL_STATE));
 
     // cleanup
@@ -361,32 +331,22 @@
 TEST_P(AudioEffectTest, DestroyProcessingEffects) {
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
     ASSERT_NO_FATAL_FAILURE(open(mEffect));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
-
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect, EX_ILLEGAL_STATE));
 
     // cleanup
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(close(mEffect));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 TEST_P(AudioEffectTest, NormalSequenceStates) {
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::INIT));
     ASSERT_NO_FATAL_FAILURE(open(mEffect));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(close(mEffect));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
@@ -430,7 +390,6 @@
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
     ASSERT_NO_FATAL_FAILURE(open(mEffect));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
     Parameter::Common common = createParamCommon(0 /* session */, 1 /* ioHandle */,
                                                  44100 /* iSampleRate */, 44100 /* oSampleRate */);
@@ -447,9 +406,7 @@
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
     ASSERT_NO_FATAL_FAILURE(open(mEffect));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
     Parameter::Common common = createParamCommon(0 /* session */, 1 /* ioHandle */,
                                                  44100 /* iSampleRate */, 44100 /* oSampleRate */);
@@ -465,7 +422,6 @@
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
     ASSERT_NO_FATAL_FAILURE(open(mEffect));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
     Parameter::Common common = createParamCommon(0 /* session */, 1 /* ioHandle */,
                                                  44100 /* iSampleRate */, 44100 /* oSampleRate */);
@@ -473,7 +429,6 @@
     ASSERT_NO_FATAL_FAILURE(setAndGetParameter(id, Parameter::make<Parameter::common>(common)));
 
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(close(mEffect));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
@@ -484,7 +439,6 @@
     ASSERT_NO_FATAL_FAILURE(open(mEffect));
 
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
     Parameter::Common common = createParamCommon(0 /* session */, 1 /* ioHandle */,
                                                  44100 /* iSampleRate */, 44100 /* oSampleRate */);
@@ -492,12 +446,10 @@
     ASSERT_NO_FATAL_FAILURE(setAndGetParameter(id, Parameter::make<Parameter::common>(common)));
 
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
     ASSERT_NO_FATAL_FAILURE(setAndGetParameter(id, Parameter::make<Parameter::common>(common)));
 
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(close(mEffect));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
@@ -511,9 +463,7 @@
 
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
     ASSERT_NO_FATAL_FAILURE(open(mEffect));
-
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
     std::vector<AudioDeviceDescription> deviceDescs = {
             {.type = AudioDeviceType::IN_DEFAULT,
@@ -525,7 +475,6 @@
             setAndGetParameter(id, Parameter::make<Parameter::deviceDescription>(deviceDescs)));
 
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(close(mEffect));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
@@ -541,7 +490,6 @@
     ASSERT_NO_FATAL_FAILURE(open(mEffect));
 
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
     Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::mode);
     ASSERT_NO_FATAL_FAILURE(
@@ -550,7 +498,6 @@
             setAndGetParameter(id, Parameter::make<Parameter::mode>(AudioMode::IN_COMMUNICATION)));
 
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(close(mEffect));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
@@ -564,9 +511,7 @@
 
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
     ASSERT_NO_FATAL_FAILURE(open(mEffect));
-
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
     Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::source);
     ASSERT_NO_FATAL_FAILURE(
@@ -575,7 +520,6 @@
             id, Parameter::make<Parameter::source>(AudioSource::VOICE_RECOGNITION)));
 
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(close(mEffect));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
@@ -589,9 +533,7 @@
 
     ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
     ASSERT_NO_FATAL_FAILURE(open(mEffect));
-
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
     Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::volumeStereo);
     Parameter::VolumeStereo volume = {.left = 10.0, .right = 10.0};
@@ -605,7 +547,6 @@
     }
 
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(close(mEffect));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
@@ -638,7 +579,7 @@
     ASSERT_NO_FATAL_FAILURE(setAndGetParameter(id, Parameter::make<Parameter::common>(common)));
     ASSERT_TRUE(statusMQ->isValid());
     expectDataMqUpdateEventFlag(statusMQ);
-    EXPECT_IS_OK(mEffect->reopen(&ret));
+    ASSERT_NO_FATAL_FAILURE(reopen(mEffect, common, &ret));
     inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
     outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
     ASSERT_TRUE(statusMQ->isValid());
@@ -649,7 +590,7 @@
     ASSERT_NO_FATAL_FAILURE(setAndGetParameter(id, Parameter::make<Parameter::common>(common)));
     ASSERT_TRUE(statusMQ->isValid());
     expectDataMqUpdateEventFlag(statusMQ);
-    EXPECT_IS_OK(mEffect->reopen(&ret));
+    ASSERT_NO_FATAL_FAILURE(reopen(mEffect, common, &ret));
     inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
     outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
     ASSERT_TRUE(statusMQ->isValid());
@@ -671,26 +612,9 @@
             kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
     IEffect::OpenEffectReturn ret;
     ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
-    auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
-    ASSERT_TRUE(statusMQ->isValid());
-    auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
-    ASSERT_TRUE(inputMQ->isValid());
-    auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
-    ASSERT_TRUE(outputMQ->isValid());
-
-    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
-
-    std::vector<float> buffer;
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer, mVersion));
-    EXPECT_NO_FATAL_FAILURE(
-            EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
-
-    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer));
-
+    std::vector<float> inputBuffer(mInputSamples), outputBuffer(mOutputSamples);
+    ASSERT_NO_FATAL_FAILURE(
+            processAndWriteToOutput(inputBuffer, outputBuffer, mEffect, &ret, mVersion));
     ASSERT_NO_FATAL_FAILURE(close(mEffect));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
@@ -705,31 +629,12 @@
             kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
     IEffect::OpenEffectReturn ret;
     ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
-    auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
-    ASSERT_TRUE(statusMQ->isValid());
-    auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
-    ASSERT_TRUE(inputMQ->isValid());
-    auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
-    ASSERT_TRUE(outputMQ->isValid());
 
-    std::vector<float> buffer;
-    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
-    EXPECT_NO_FATAL_FAILURE(
-            EffectHelper::readFromFmq(statusMQ, 0, outputMQ, buffer.size(), buffer));
-    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
-
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer, mVersion));
-    EXPECT_NO_FATAL_FAILURE(
-            EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
-
-    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer));
+    std::vector<float> inputBuffer(mInputSamples), outputBuffer(mOutputSamples);
+    ASSERT_NO_FATAL_FAILURE(
+            processAndWriteToOutput(inputBuffer, outputBuffer, mEffect, &ret, mVersion));
+    ASSERT_NO_FATAL_FAILURE(
+            processAndWriteToOutput(inputBuffer, outputBuffer, mEffect, &ret, mVersion));
 
     ASSERT_NO_FATAL_FAILURE(close(mEffect));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
@@ -751,18 +656,10 @@
     ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
     auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
     ASSERT_TRUE(statusMQ->isValid());
-    auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
-    ASSERT_TRUE(inputMQ->isValid());
-    auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
-    ASSERT_TRUE(outputMQ->isValid());
 
-    std::vector<float> buffer;
-    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer, mVersion));
-    EXPECT_NO_FATAL_FAILURE(
-            EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
+    std::vector<float> inputBuffer(mInputSamples), outputBuffer(mOutputSamples);
+    ASSERT_NO_FATAL_FAILURE(
+            processAndWriteToOutput(inputBuffer, outputBuffer, mEffect, &ret, mVersion));
 
     // set a new common parameter with different IO frameCount, reopen
     Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::common);
@@ -771,22 +668,12 @@
     ASSERT_NO_FATAL_FAILURE(setAndGetParameter(id, Parameter::make<Parameter::common>(common)));
     ASSERT_TRUE(statusMQ->isValid());
     expectDataMqUpdateEventFlag(statusMQ);
-    EXPECT_IS_OK(mEffect->reopen(&ret));
-    inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
-    outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
-    ASSERT_TRUE(statusMQ->isValid());
-    ASSERT_TRUE(inputMQ->isValid());
-    ASSERT_TRUE(outputMQ->isValid());
+    ASSERT_NO_FATAL_FAILURE(reopen(mEffect, common, &ret));
 
-    // verify data consume again
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer, mVersion));
-    EXPECT_NO_FATAL_FAILURE(
-            EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
-
-    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer));
+    inputBuffer.resize(mInputSamples);
+    outputBuffer.resize(mOutputSamples);
+    ASSERT_NO_FATAL_FAILURE(
+            processAndWriteToOutput(inputBuffer, outputBuffer, mEffect, &ret, mVersion));
 
     ASSERT_NO_FATAL_FAILURE(close(mEffect));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
@@ -809,19 +696,15 @@
     auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
     ASSERT_TRUE(outputMQ->isValid());
 
-    std::vector<float> buffer;
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer, mVersion));
+    std::vector<float> inputBuffer(mInputSamples), outputBuffer(mOutputSamples);
+    ASSERT_NO_FATAL_FAILURE(
+            processAndWriteToOutput(inputBuffer, outputBuffer, mEffect, &ret, mVersion));
 
+    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, inputBuffer, mVersion));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
-
     EXPECT_NO_FATAL_FAILURE(
-            EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
-
+            EffectHelper::readFromFmq(statusMQ, 1, outputMQ, outputBuffer.size(), outputBuffer));
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
-
     ASSERT_NO_FATAL_FAILURE(close(mEffect));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
@@ -836,31 +719,10 @@
             kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
     IEffect::OpenEffectReturn ret;
     ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
-    auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
-    ASSERT_TRUE(statusMQ->isValid());
-    auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
-    ASSERT_TRUE(inputMQ->isValid());
-    auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
-    ASSERT_TRUE(outputMQ->isValid());
+    std::vector<float> inputBuffer(mInputSamples), outputBuffer(mOutputSamples);
 
-    std::vector<float> buffer;
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer, mVersion));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer));
-
-    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
-
-    EXPECT_NO_FATAL_FAILURE(
-            EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
-
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer, mVersion));
-    EXPECT_NO_FATAL_FAILURE(
-            EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
-
-    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer));
+    ASSERT_NO_FATAL_FAILURE(
+            processAndWriteToOutput(inputBuffer, outputBuffer, mEffect, &ret, mVersion, 2));
 
     ASSERT_NO_FATAL_FAILURE(close(mEffect));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
@@ -876,33 +738,12 @@
             kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
     IEffect::OpenEffectReturn ret;
     ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
-    auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
-    ASSERT_TRUE(statusMQ->isValid());
-    auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
-    ASSERT_TRUE(inputMQ->isValid());
-    auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
-    ASSERT_TRUE(outputMQ->isValid());
+    std::vector<float> inputBuffer(mInputSamples), outputBuffer(mOutputSamples);
 
-    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
-    std::vector<float> buffer;
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer, mVersion));
-    EXPECT_NO_FATAL_FAILURE(
-            EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
-
-    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer, mVersion));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer));
-
-    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
-    EXPECT_NO_FATAL_FAILURE(
-            EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
-
-    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(
+            processAndWriteToOutput(inputBuffer, outputBuffer, mEffect, &ret, mVersion, 2));
+    ASSERT_NO_FATAL_FAILURE(
+            processAndWriteToOutput(inputBuffer, outputBuffer, mEffect, &ret, mVersion, 2));
 
     ASSERT_NO_FATAL_FAILURE(close(mEffect));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
@@ -918,6 +759,7 @@
             kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
     IEffect::OpenEffectReturn ret;
     ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
+    std::vector<float> inputBuffer(mInputSamples), outputBuffer(mOutputSamples);
     ASSERT_NO_FATAL_FAILURE(close(mEffect));
 
     auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
@@ -927,10 +769,8 @@
     auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
     ASSERT_TRUE(outputMQ->isValid());
 
-    std::vector<float> buffer;
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer, mVersion));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer));
+    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, inputBuffer, mVersion));
+    EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, outputBuffer));
 
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
@@ -951,42 +791,19 @@
     IEffect::OpenEffectReturn ret1, ret2;
     ASSERT_NO_FATAL_FAILURE(open(effect1, common1, std::nullopt /* specific */, &ret1, EX_NONE));
     ASSERT_NO_FATAL_FAILURE(open(effect2, common2, std::nullopt /* specific */, &ret2, EX_NONE));
-    ASSERT_NO_FATAL_FAILURE(command(effect1, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect1, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(effect2, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect2, State::PROCESSING));
+    std::vector<float> inputBuffer1(kInputFrameCount * mInputFrameSize / sizeof(float)),
+            outputBuffer1(kOutputFrameCount * mOutputFrameSize / sizeof(float));
+    std::vector<float> inputBuffer2(2 * kInputFrameCount * mInputFrameSize / sizeof(float)),
+            outputBuffer2(2 * kOutputFrameCount * mOutputFrameSize / sizeof(float));
 
-    auto statusMQ1 = std::make_unique<EffectHelper::StatusMQ>(ret1.statusMQ);
-    ASSERT_TRUE(statusMQ1->isValid());
-    auto inputMQ1 = std::make_unique<EffectHelper::DataMQ>(ret1.inputDataMQ);
-    ASSERT_TRUE(inputMQ1->isValid());
-    auto outputMQ1 = std::make_unique<EffectHelper::DataMQ>(ret1.outputDataMQ);
-    ASSERT_TRUE(outputMQ1->isValid());
+    ASSERT_NO_FATAL_FAILURE(
+            processAndWriteToOutput(inputBuffer1, outputBuffer1, effect1, &ret1, mVersion, 2));
+    ASSERT_NO_FATAL_FAILURE(
+            processAndWriteToOutput(inputBuffer2, outputBuffer2, effect2, &ret2, mVersion, 2));
 
-    std::vector<float> buffer1, buffer2;
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common1, inputMQ1, buffer1));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ1, inputMQ1, buffer1, mVersion));
-    EXPECT_NO_FATAL_FAILURE(
-            EffectHelper::readFromFmq(statusMQ1, 1, outputMQ1, buffer1.size(), buffer1));
-
-    auto statusMQ2 = std::make_unique<EffectHelper::StatusMQ>(ret2.statusMQ);
-    ASSERT_TRUE(statusMQ2->isValid());
-    auto inputMQ2 = std::make_unique<EffectHelper::DataMQ>(ret2.inputDataMQ);
-    ASSERT_TRUE(inputMQ2->isValid());
-    auto outputMQ2 = std::make_unique<EffectHelper::DataMQ>(ret2.outputDataMQ);
-    ASSERT_TRUE(outputMQ2->isValid());
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common2, inputMQ2, buffer2));
-    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ2, inputMQ2, buffer2, mVersion));
-    EXPECT_NO_FATAL_FAILURE(
-            EffectHelper::readFromFmq(statusMQ2, 1, outputMQ2, buffer2.size(), buffer2));
-
-    ASSERT_NO_FATAL_FAILURE(command(effect1, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect1, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(close(effect1));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect1));
 
-    ASSERT_NO_FATAL_FAILURE(command(effect2, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect2, State::IDLE));
     ASSERT_NO_FATAL_FAILURE(close(effect2));
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect2));
 }
diff --git a/audio/aidl/vts/VtsHalAudioTargetTestTemplate.xml b/audio/aidl/vts/VtsHalAudioTargetTestTemplate.xml
index c92e852..4170b4c 100644
--- a/audio/aidl/vts/VtsHalAudioTargetTestTemplate.xml
+++ b/audio/aidl/vts/VtsHalAudioTargetTestTemplate.xml
@@ -33,6 +33,6 @@
     <test class="com.android.tradefed.testtype.GTest" >
         <option name="native-test-device-path" value="/data/local/tmp" />
         <option name="module-name" value="{MODULE}" />
-        <option name="native-test-timeout" value="10m" />
+        <option name="native-test-timeout" value="30m" />
     </test>
 </configuration>
diff --git a/audio/aidl/vts/VtsHalDownmixTargetTest.cpp b/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
index 844a340..bf22839 100644
--- a/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
@@ -96,8 +96,7 @@
         Parameter::Specific specific = getDefaultParamSpecific();
         Parameter::Common common = EffectHelper::createParamCommon(
                 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
-                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */,
-                inputChannelLayout,
+                kFrameCount /* iFrameCount */, kFrameCount /* oFrameCount */, inputChannelLayout,
                 AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
                         AudioChannelLayout::LAYOUT_STEREO));
         ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &mOpenEffectReturn, EX_NONE));
@@ -139,33 +138,17 @@
     }
 
     void setDataTestParams(int32_t layoutType) {
-        mInputBuffer.resize(kBufferSize);
-
         // Get the number of channels used
         mInputChannelCount = getChannelCount(
                 AudioChannelLayout::make<AudioChannelLayout::layoutMask>(layoutType));
+        mInputBufferSize = kFrameCount * mInputChannelCount;
+        mInputBuffer.resize(mInputBufferSize);
 
         // In case of downmix, output is always configured to stereo layout.
-        mOutputBufferSize = (mInputBuffer.size() / mInputChannelCount) * kOutputChannelCount;
+        mOutputBufferSize = kFrameCount * kOutputChannelCount;
         mOutputBuffer.resize(mOutputBufferSize);
     }
 
-    // Generate mInputBuffer values between -kMaxDownmixSample to kMaxDownmixSample
-    void generateInputBuffer(size_t position, bool isStrip) {
-        size_t increment;
-        if (isStrip)
-            // Fill input at all the channels
-            increment = 1;
-        else
-            // Fill input at only one channel
-            increment = mInputChannelCount;
-
-        for (size_t i = position; i < mInputBuffer.size(); i += increment) {
-            mInputBuffer[i] =
-                    ((static_cast<float>(std::rand()) / RAND_MAX) * 2 - 1) * kMaxDownmixSample;
-        }
-    }
-
     bool isLayoutValid(int32_t inputLayout) {
         if (inputLayout & kMaxChannelMask) {
             return false;
@@ -173,7 +156,12 @@
         return true;
     }
 
-    static constexpr long kInputFrameCount = 100, kOutputFrameCount = 100;
+    static const long kFrameCount = 256;
+    static constexpr float kMaxDownmixSample = 1;
+    static constexpr int kOutputChannelCount = 2;
+    // Mask for layouts greater than MAX_INPUT_CHANNELS_SUPPORTED
+    static constexpr int32_t kMaxChannelMask =
+            ~((1 << ChannelMix<AUDIO_CHANNEL_OUT_STEREO>::MAX_INPUT_CHANNELS_SUPPORTED) - 1);
     std::shared_ptr<IFactory> mFactory;
     Descriptor mDescriptor;
     std::shared_ptr<IEffect> mEffect;
@@ -183,12 +171,7 @@
     std::vector<float> mOutputBuffer;
     size_t mInputChannelCount;
     size_t mOutputBufferSize;
-    static constexpr size_t kBufferSize = 128;
-    static constexpr float kMaxDownmixSample = 1;
-    static constexpr int kOutputChannelCount = 2;
-    // Mask for layouts greater than MAX_INPUT_CHANNELS_SUPPORTED
-    static constexpr int32_t kMaxChannelMask =
-            ~((1 << ChannelMix<AUDIO_CHANNEL_OUT_STEREO>::MAX_INPUT_CHANNELS_SUPPORTED) - 1);
+    size_t mInputBufferSize;
 };
 
 /**
@@ -366,7 +349,8 @@
 
     for (int32_t channel : supportedChannels) {
         size_t position = std::distance(supportedChannels.begin(), supportedChannels.find(channel));
-        generateInputBuffer(position, false /*isStripe*/);
+        generateInputBuffer(mInputBuffer, position, false /*isStripe*/,
+                            mInputChannelCount /*channelCount*/, kMaxDownmixSample);
         ASSERT_NO_FATAL_FAILURE(
                 processAndWriteToOutput(mInputBuffer, mOutputBuffer, mEffect, &mOpenEffectReturn));
         validateOutput(channel, position);
@@ -401,9 +385,9 @@
     void TearDown() override { TearDownDownmix(); }
 
     void validateOutput() {
-        ASSERT_EQ(kBufferSize, mInputBuffer.size());
-        ASSERT_GE(kBufferSize, mOutputBufferSize);
-        for (size_t i = 0, j = 0; i < kBufferSize && j < mOutputBufferSize;
+        ASSERT_EQ(mInputBufferSize, mInputBuffer.size());
+        ASSERT_GE(mInputBufferSize, mOutputBufferSize);
+        for (size_t i = 0, j = 0; i < mInputBufferSize && j < mOutputBufferSize;
              i += mInputChannelCount, j += kOutputChannelCount) {
             ASSERT_EQ(mOutputBuffer[j], mInputBuffer[i]);
             ASSERT_EQ(mOutputBuffer[j + 1], mInputBuffer[i + 1]);
@@ -418,7 +402,8 @@
     ASSERT_NO_FATAL_FAILURE(setParameters(Downmix::Type::STRIP));
 
     // Generate input buffer, call process and compare outputs
-    generateInputBuffer(0 /*position*/, true /*isStripe*/);
+    generateInputBuffer(mInputBuffer, 0 /*position*/, true /*isStripe*/,
+                        mInputChannelCount /*channelCount*/, kMaxDownmixSample);
     ASSERT_NO_FATAL_FAILURE(
             processAndWriteToOutput(mInputBuffer, mOutputBuffer, mEffect, &mOpenEffectReturn));
     validateOutput();
diff --git a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
index c7c6505..e31aae6 100644
--- a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
@@ -17,7 +17,9 @@
 #define LOG_TAG "VtsHalEnvironmentalReverbTest"
 #include <android-base/logging.h>
 #include <audio_utils/power.h>
+#include <audio_utils/primitives.h>
 #include <system/audio.h>
+#include <numeric>
 
 #include "EffectHelper.h"
 
@@ -39,7 +41,6 @@
 static constexpr int kMinDelay = 0;
 
 static const std::vector<TagVectorPair> kParamsIncreasingVector = {
-
         {EnvironmentalReverb::roomLevelMb, {-3500, -2800, -2100, -1400, -700, 0}},
         {EnvironmentalReverb::roomHfLevelMb, {-4000, -3200, -2400, -1600, -800, 0}},
         {EnvironmentalReverb::decayTimeMs, {800, 1600, 2400, 3200, 4000}},
@@ -47,6 +48,11 @@
         {EnvironmentalReverb::levelMb, {-3500, -2800, -2100, -1400, -700, 0}},
 };
 
+static const TagVectorPair kDiffusionParam = {EnvironmentalReverb::diffusionPm,
+                                              {200, 400, 600, 800, 1000}};
+static const TagVectorPair kDensityParam = {EnvironmentalReverb::densityPm,
+                                            {0, 200, 400, 600, 800, 1000}};
+
 static const std::vector<TagValuePair> kParamsMinimumValue = {
         {EnvironmentalReverb::roomLevelMb, kMinRoomLevel},
         {EnvironmentalReverb::decayTimeMs, kMinDecayTime},
@@ -347,8 +353,14 @@
         mInput.resize(kBufferSize);
         generateSineWaveInput(mInput);
     }
-    void SetUp() override { SetUpReverb(); }
-    void TearDown() override { TearDownReverb(); }
+    void SetUp() override {
+        SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
+        SetUpReverb();
+    }
+    void TearDown() override {
+        SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
+        TearDownReverb();
+    }
 
     void assertEnergyIncreasingWithParameter(bool bypass) {
         createEnvParam(EnvironmentalReverb::bypass, bypass);
@@ -412,12 +424,16 @@
         std::tie(mTag, mValue) = std::get<TAG_VALUE_PAIR>(GetParam());
     }
     void SetUp() override {
+        SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
         SetUpReverb();
         createEnvParam(EnvironmentalReverb::roomLevelMb, kMinRoomLevel);
         ASSERT_NO_FATAL_FAILURE(
                 setAndVerifyParam(EX_NONE, mEnvParam, EnvironmentalReverb::roomLevelMb));
     }
-    void TearDown() override { TearDownReverb(); }
+    void TearDown() override {
+        SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
+        TearDownReverb();
+    }
 
     EnvironmentalReverb::Tag mTag;
     int mValue;
@@ -452,6 +468,151 @@
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbMinimumParamTest);
 
+class EnvironmentalReverbDiffusionTest
+    : public ::testing::TestWithParam<
+              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, TagVectorPair>>,
+      public EnvironmentalReverbHelper {
+  public:
+    EnvironmentalReverbDiffusionTest()
+        : EnvironmentalReverbHelper(std::get<DESCRIPTOR_INDEX>(GetParam())) {
+        std::tie(mTag, mParamValues) = std::get<TAG_VALUE_PAIR>(GetParam());
+        mInput.resize(kBufferSize);
+        generateSineWaveInput(mInput);
+    }
+    void SetUp() override {
+        SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
+        SetUpReverb();
+    }
+    void TearDown() override {
+        SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
+        TearDownReverb();
+    }
+
+    float getMean(std::vector<float>& buffer) {
+        return std::accumulate(buffer.begin(), buffer.end(), 0.0) / buffer.size();
+    }
+
+    float getVariance(std::vector<float>& buffer) {
+        if (isAuxiliary()) {
+            accumulate_float(buffer.data(), mInput.data(), buffer.size());
+        }
+        float mean = getMean(buffer);
+        float squaredDeltas =
+                std::accumulate(buffer.begin(), buffer.end(), 0.0,
+                                [mean](float a, float b) { return a + pow(b - mean, 2); });
+
+        return squaredDeltas / buffer.size();
+    }
+
+    EnvironmentalReverb::Tag mTag;
+    std::vector<int> mParamValues;
+    std::vector<float> mInput;
+};
+
+TEST_P(EnvironmentalReverbDiffusionTest, DecreasingVarianceTest) {
+    std::vector<float> baseOutput(kBufferSize);
+    setParameterAndProcess(mInput, baseOutput, kMinDiffusion, mTag);
+    ASSERT_EQ(baseOutput.size(),
+              static_cast<size_t>(mFrameCount) * static_cast<size_t>(mStereoChannelCount));
+    float baseVariance = getVariance(baseOutput);
+    for (int value : mParamValues) {
+        std::vector<float> output(kBufferSize);
+        setParameterAndProcess(mInput, output, value, mTag);
+        ASSERT_EQ(output.size(),
+                  static_cast<size_t>(mFrameCount) * static_cast<size_t>(mStereoChannelCount));
+        float variance = getVariance(output);
+        ASSERT_LT(variance, baseVariance);
+        baseVariance = variance;
+    }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        EnvironmentalReverbTest, EnvironmentalReverbDiffusionTest,
+        ::testing::Combine(
+                testing::ValuesIn(kDescPair = EffectFactoryHelper::getAllEffectDescriptors(
+                                          IFactory::descriptor, getEffectTypeUuidEnvReverb())),
+                testing::Values(kDiffusionParam)),
+        [](const testing::TestParamInfo<EnvironmentalReverbDiffusionTest::ParamType>& info) {
+            auto descriptor = std::get<DESCRIPTOR_INDEX>(info.param).second;
+            auto tag = std::get<TAG_VALUE_PAIR>(info.param).first;
+            std::string name = getPrefix(descriptor) + "_Tag_" + toString(tag);
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDiffusionTest);
+
+enum ParamDensityTest { DESCRIPTOR, TAG_DENSITY_VALUE, PARAM_DENSITY_VALUE, IS_INPUT_MUTE };
+
+class EnvironmentalReverbDensityTest
+    : public ::testing::TestWithParam<std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
+                                                 EnvironmentalReverb::Tag, int, bool>>,
+      public EnvironmentalReverbHelper {
+  public:
+    EnvironmentalReverbDensityTest() : EnvironmentalReverbHelper(std::get<DESCRIPTOR>(GetParam())) {
+        mTag = std::get<TAG_DENSITY_VALUE>(GetParam());
+        mParamValues = std::get<PARAM_DENSITY_VALUE>(GetParam());
+        mIsInputMute = (std::get<IS_INPUT_MUTE>(GetParam()));
+        mInput.resize(kBufferSize);
+        if (mIsInputMute) {
+            std::fill(mInput.begin(), mInput.end(), 0);
+        } else {
+            generateSineWaveInput(mInput);
+        }
+    }
+    void SetUp() override {
+        SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
+        SetUpReverb();
+    }
+    void TearDown() override {
+        SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
+        TearDownReverb();
+    }
+
+    EnvironmentalReverb::Tag mTag;
+    int mParamValues;
+    std::vector<float> mInput;
+    bool mIsInputMute;
+};
+
+TEST_P(EnvironmentalReverbDensityTest, DensityOutput) {
+    float inputRmse =
+            audio_utils_compute_energy_mono(mInput.data(), AUDIO_FORMAT_PCM_FLOAT, mInput.size());
+
+    std::vector<float> output(kBufferSize);
+    setParameterAndProcess(mInput, output, mParamValues, mTag);
+
+    if (isAuxiliary() && !mIsInputMute) {
+        accumulate_float(output.data(), mInput.data(), output.size());
+    }
+
+    float outputRmse =
+            audio_utils_compute_energy_mono(output.data(), AUDIO_FORMAT_PCM_FLOAT, output.size());
+    if (inputRmse != 0) {
+        EXPECT_GT(outputRmse, 0);
+    } else {
+        EXPECT_EQ(outputRmse, inputRmse);
+    }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        EnvironmentalReverbTest, EnvironmentalReverbDensityTest,
+        ::testing::Combine(
+                testing::ValuesIn(kDescPair = EffectFactoryHelper::getAllEffectDescriptors(
+                                          IFactory::descriptor, getEffectTypeUuidEnvReverb())),
+                testing::Values(kDensityParam.first), testing::ValuesIn(kDensityParam.second),
+                testing::Bool()),
+        [](const testing::TestParamInfo<EnvironmentalReverbDensityTest::ParamType>& info) {
+            auto descriptor = std::get<DESCRIPTOR>(info.param).second;
+            auto tag = std::get<TAG_DENSITY_VALUE>(info.param);
+            auto value = std::get<PARAM_DENSITY_VALUE>(info.param);
+            std::string isInputMute = std::to_string(std::get<IS_INPUT_MUTE>(info.param));
+            std::string name = getPrefix(descriptor) + "_Tag_" + toString(tag) + "_Value_" +
+                               std::to_string(value) + "_isInputMute_" + isInputMute;
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDensityTest);
+
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
     ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
diff --git a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
index 6af326d..2802bf9 100644
--- a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
@@ -21,11 +21,13 @@
 #define LOG_TAG "VtsHalHapticGeneratorTargetTest"
 #include <android-base/logging.h>
 #include <android/binder_enums.h>
+#include <audio_utils/power.h>
 
 #include "EffectHelper.h"
 
 using namespace android;
 
+using aidl::android::hardware::audio::common::getChannelCount;
 using aidl::android::hardware::audio::effect::Descriptor;
 using aidl::android::hardware::audio::effect::getEffectTypeUuidHapticGenerator;
 using aidl::android::hardware::audio::effect::HapticGenerator;
@@ -34,400 +36,412 @@
 using aidl::android::hardware::audio::effect::Parameter;
 using android::hardware::audio::common::testing::detail::TestExecutionTracer;
 
-/**
- * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
- * VtsAudioEffectTargetTest.
- */
-enum ParamName {
-    PARAM_INSTANCE_NAME,
-    PARAM_HAPTIC_SCALE_ID,
-    PARAM_HAPTIC_SCALE_VIBRATOR_SCALE,
-    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>;
-
-/*
- * Testing parameter range, assuming the parameter supported by effect is in this range.
- * Parameter should be within the valid range defined in the documentation,
- * for any supported value test expects EX_NONE from IEffect.setParameter(),
- * otherwise expect EX_ILLEGAL_ARGUMENT.
- */
-
-// TODO : Update the test values once range/capability is updated by implementation
 const int MIN_ID = std::numeric_limits<int>::min();
 const int MAX_ID = std::numeric_limits<int>::max();
 const float MIN_FLOAT = std::numeric_limits<float>::min();
 const float MAX_FLOAT = std::numeric_limits<float>::max();
 
-const std::vector<int> kHapticScaleIdValues = {MIN_ID, 0, MAX_ID};
-const std::vector<HapticGenerator::VibratorScale> kVibratorScaleValues = {
+std::vector<HapticGenerator::VibratorScale> kScaleValues = {
         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};
 
-class HapticGeneratorParamTest : public ::testing::TestWithParam<HapticGeneratorParamTestParam>,
-                                 public EffectHelper {
+constexpr int HAPTIC_SCALE_FACTORS_EFFECT_MIN_VERSION = 3;
+
+static const std::vector<int32_t> kHapticOutputLayouts = {
+        AudioChannelLayout::LAYOUT_MONO_HAPTIC_A, AudioChannelLayout::LAYOUT_MONO_HAPTIC_AB,
+        AudioChannelLayout::LAYOUT_STEREO_HAPTIC_A, AudioChannelLayout::LAYOUT_STEREO_HAPTIC_AB};
+
+class HapticGeneratorHelper : public EffectHelper {
   public:
-    HapticGeneratorParamTest()
-        : mParamHapticScaleId(std::get<PARAM_HAPTIC_SCALE_ID>(GetParam())),
-          mParamVibratorScale(std::get<PARAM_HAPTIC_SCALE_VIBRATOR_SCALE>(GetParam())),
-          mParamResonantFrequency(
-                  std::get<PARAM_VIBRATION_INFORMATION_RESONANT_FREQUENCY>(GetParam())),
-          mParamQFactor(std::get<PARAM_VIBRATION_INFORMATION_Q_FACTOR>(GetParam())),
-          mParamMaxAmplitude(std::get<PARAM_VIBRATION_INFORMATION_MAX_AMPLITUDE>(GetParam())) {
-        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
-    }
-    void SetUp() override {
+    void SetUpHapticGenerator(int32_t chMask = AudioChannelLayout::CHANNEL_HAPTIC_A) {
         ASSERT_NE(nullptr, mFactory);
         ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+        EXPECT_STATUS(EX_NONE, mEffect->getInterfaceVersion(&mEffectInterfaceVersion));
+
+        AudioChannelLayout layout =
+                AudioChannelLayout::make<AudioChannelLayout::layoutMask>(chMask);
 
         Parameter::Common common = createParamCommon(
-                0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
-                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
-        IEffect::OpenEffectReturn ret;
+                0 /* session */, 1 /* ioHandle */, kSamplingFrequency /* iSampleRate */,
+                kSamplingFrequency /* oSampleRate */, kFrameCount /* iFrameCount */,
+                kFrameCount /* oFrameCount */, layout, layout);
         ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt, &ret, EX_NONE));
         ASSERT_NE(nullptr, mEffect);
     }
 
-    void TearDown() override {
+    void TearDownHapticGenerator() {
         ASSERT_NO_FATAL_FAILURE(close(mEffect));
         ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+        ret = IEffect::OpenEffectReturn{};
     }
 
-    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
-    std::shared_ptr<IFactory> mFactory;
-    std::shared_ptr<IEffect> mEffect;
-    Descriptor mDescriptor;
-    int mParamHapticScaleId = 0;
-    HapticGenerator::VibratorScale mParamVibratorScale = HapticGenerator::VibratorScale::MUTE;
-    float mParamResonantFrequency = 0;
-    float mParamQFactor = 0;
-    float mParamMaxAmplitude = 0;
+    Parameter createScaleParam(const std::vector<HapticGenerator::HapticScale>& hapticScales) {
+        return Parameter::make<Parameter::specific>(
+                Parameter::Specific::make<Parameter::Specific::hapticGenerator>(
+                        HapticGenerator::make<HapticGenerator::hapticScales>(hapticScales)));
+    }
 
-    void SetAndGetHapticGeneratorParameters() {
-        for (auto& it : mTags) {
-            auto& tag = std::get<ParamTestEnum::PARAM_TEST_TAG>(it);
-            auto& setHg = std::get<ParamTestEnum::PARAM_TEST_TARGET>(it);
+    Parameter createVibratorParam(HapticGenerator::VibratorInformation vibrationInfo) {
+        return Parameter::make<Parameter::specific>(
+                Parameter::Specific::make<Parameter::Specific::hapticGenerator>(
+                        HapticGenerator::make<HapticGenerator::vibratorInfo>(vibrationInfo)));
+    }
 
-            // set parameter
-            Parameter expectParam;
-            Parameter::Specific specific;
-            specific.set<Parameter::Specific::hapticGenerator>(setHg);
-            expectParam.set<Parameter::specific>(specific);
-            EXPECT_STATUS(EX_NONE, mEffect->setParameter(expectParam)) << expectParam.toString();
-
+    void setAndVerifyParameter(Parameter hapticParameter, HapticGenerator::Tag tag,
+                               binder_exception_t expected = EX_NONE) {
+        EXPECT_STATUS(expected, mEffect->setParameter(hapticParameter))
+                << hapticParameter.toString();
+        if (expected == EX_NONE) {
             // get parameter
             Parameter getParam;
-            Parameter::Id id;
-            HapticGenerator::Id hgId;
-            hgId.set<HapticGenerator::Id::commonTag>(tag);
-            id.set<Parameter::Id::hapticGeneratorTag>(hgId);
-            EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
-            EXPECT_EQ(expectParam, getParam) << expectParam.toString() << "\n"
-                                             << getParam.toString();
+            auto second = Parameter::Id::make<Parameter::Id::hapticGeneratorTag>(
+                    HapticGenerator::Id::make<HapticGenerator::Id::commonTag>(
+                            HapticGenerator::Tag(tag)));
+            // If the set is successful, get param should match
+            EXPECT_STATUS(expected, mEffect->getParameter(second, &getParam));
+            EXPECT_EQ(hapticParameter, getParam) << "\nexpectedParam:" << hapticParameter.toString()
+                                                 << "\ngetParam:" << getParam.toString();
         }
     }
 
-    void addHapticScaleParam(int id, HapticGenerator::VibratorScale scale) {
-        HapticGenerator setHg;
-        std::vector<HapticGenerator::HapticScale> hapticScales = {{.id = id, .scale = scale}};
-        setHg.set<HapticGenerator::hapticScales>(hapticScales);
-        mTags.push_back({HapticGenerator::hapticScales, setHg});
+    HapticGenerator::VibratorInformation createVibratorInfo(float resonantFrequency, float qFactor,
+                                                            float amplitude) {
+        return HapticGenerator::VibratorInformation(resonantFrequency, qFactor, amplitude);
     }
 
-    void addVibratorInformationParam(float resonantFrequencyHz, float qFactor, float maxAmplitude) {
-        HapticGenerator hg;
-        HapticGenerator::VibratorInformation vibrationInfo = {
-                .resonantFrequencyHz = resonantFrequencyHz,
-                .qFactor = qFactor,
-                .maxAmplitude = maxAmplitude};
-        hg.set<HapticGenerator::vibratorInfo>(vibrationInfo);
-        mTags.push_back({HapticGenerator::vibratorInfo, hg});
-    }
-
-  private:
-    enum ParamTestEnum { PARAM_TEST_TAG, PARAM_TEST_TARGET };
-    std::vector<std::tuple<HapticGenerator::Tag, HapticGenerator>> mTags;
-
-    void CleanUp() { mTags.clear(); }
-};
-
-TEST_P(HapticGeneratorParamTest, SetAndGetHapticScale) {
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(mParamHapticScaleId, mParamVibratorScale));
-    SetAndGetHapticGeneratorParameters();
-}
-
-TEST_P(HapticGeneratorParamTest, SetAndGetMultipleHapticScales) {
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(mParamHapticScaleId, mParamVibratorScale));
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(mParamHapticScaleId, mParamVibratorScale));
-    SetAndGetHapticGeneratorParameters();
-}
-
-TEST_P(HapticGeneratorParamTest, SetAndGetVibratorInformation) {
-    EXPECT_NO_FATAL_FAILURE(addVibratorInformationParam(mParamResonantFrequency, mParamQFactor,
-                                                        mParamMaxAmplitude));
-    SetAndGetHapticGeneratorParameters();
-}
-
-INSTANTIATE_TEST_SUITE_P(
-        HapticGeneratorValidTest, HapticGeneratorParamTest,
-        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
-                                   IFactory::descriptor, getEffectTypeUuidHapticGenerator())),
-                           testing::ValuesIn(kHapticScaleIdValues),
-                           testing::ValuesIn(kVibratorScaleValues),
-                           testing::ValuesIn(kResonantFrequencyValues),
-                           testing::ValuesIn(kQFactorValues), testing::ValuesIn(kMaxAmplitude)),
-        [](const testing::TestParamInfo<HapticGeneratorParamTest::ParamType>& info) {
-            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
-            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 resonantFrequency = std::to_string(
-                    std::get<PARAM_VIBRATION_INFORMATION_RESONANT_FREQUENCY>(info.param));
-            std::string qFactor =
-                    std::to_string(std::get<PARAM_VIBRATION_INFORMATION_Q_FACTOR>(info.param));
-            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" +
-                               resonantFrequency + "_qFactor" + qFactor + "_maxAmplitude" +
-                               maxAmplitude;
-            std::replace_if(
-                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
-            return name;
-        });
-
-INSTANTIATE_TEST_SUITE_P(
-        HapticGeneratorInvalidTest, HapticGeneratorParamTest,
-        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
-                                   IFactory::descriptor, getEffectTypeUuidHapticGenerator())),
-                           testing::Values(MIN_ID),
-                           testing::Values(HapticGenerator::VibratorScale::NONE),
-                           testing::Values(MIN_FLOAT), testing::Values(MIN_FLOAT),
-                           testing::Values(MIN_FLOAT)),
-        [](const testing::TestParamInfo<HapticGeneratorParamTest::ParamType>& info) {
-            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
-            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 resonantFrequency = std::to_string(
-                    std::get<PARAM_VIBRATION_INFORMATION_RESONANT_FREQUENCY>(info.param));
-            std::string qFactor =
-                    std::to_string(std::get<PARAM_VIBRATION_INFORMATION_Q_FACTOR>(info.param));
-            std::string maxAmplitude =
-                    std::to_string(std::get<PARAM_VIBRATION_INFORMATION_MAX_AMPLITUDE>(info.param));
-            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
-                               descriptor.common.name + "_UUID_" +
-                               toString(descriptor.common.id.uuid) + "_hapticScaleId" +
-                               hapticScaleID + "_hapticScaleVibScale" + hapticScaleVibScale +
-                               "_resonantFrequency" + resonantFrequency + "_qFactor" + qFactor +
-                               "_maxAmplitude" + maxAmplitude;
-            std::replace_if(
-                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
-            return name;
-        });
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorParamTest);
-
-// Test HapticScale[] hapticScales parameter
-using HapticGeneratorScalesTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>>;
-class HapticGeneratorScalesTest : public ::testing::TestWithParam<HapticGeneratorScalesTestParam>,
-                                  public EffectHelper {
-  public:
-    HapticGeneratorScalesTest() {
-        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
-    }
-
-    void SetUp() override {
-        ASSERT_NE(nullptr, mFactory);
-        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
-
-        Parameter::Common common = createParamCommon(
-                0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
-                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
-        IEffect::OpenEffectReturn ret;
-        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt, &ret, EX_NONE));
-        ASSERT_NE(nullptr, mEffect);
-    }
-
-    void TearDown() override {
-        ASSERT_NO_FATAL_FAILURE(close(mEffect));
-        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
-        CleanUp();
-    }
-
-    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    static const long kFrameCount = 10000;
+    static constexpr int kSamplingFrequency = 44100;
+    static constexpr int kDefaultScaleID = 0;
+    static constexpr float kDefaultMaxAmp = 1;
+    static constexpr float kDefaultResonantFrequency = 150;
+    static constexpr float kDefaultQfactor = 8;
+    static constexpr HapticGenerator::VibratorScale kDefaultScale =
+            HapticGenerator::VibratorScale::NONE;
     std::shared_ptr<IFactory> mFactory;
     std::shared_ptr<IEffect> mEffect;
-    Descriptor mDescriptor;
-
-    void addHapticScaleParam(std::vector<HapticGenerator::HapticScale> scales) {
-        mHapticScales.push_back(HapticGenerator::make<HapticGenerator::hapticScales>(scales));
-        for (const auto& scale : scales) {
-            expectMap.insert_or_assign(scale.id, scale.scale);
-        }
-    }
-
-    void SetHapticScaleParameters() {
-        // std::unordered_set<HapticGenerator::HapticScale> target;
-        for (auto& it : mHapticScales) {
-            Parameter::Specific specific =
-                    Parameter::Specific::make<Parameter::Specific::hapticGenerator>(it);
-            Parameter param = Parameter::make<Parameter::specific>(specific);
-            EXPECT_STATUS(EX_NONE, mEffect->setParameter(param)) << param.toString();
-        }
-    }
-
-    void checkHapticScaleParameter() {
-        // get parameter
-        Parameter targetParam;
-        HapticGenerator::Id hgId = HapticGenerator::Id::make<HapticGenerator::Id::commonTag>(
-                HapticGenerator::hapticScales);
-        Parameter::Id id = Parameter::Id::make<Parameter::Id::hapticGeneratorTag>(hgId);
-        EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &targetParam));
-        ASSERT_EQ(Parameter::specific, targetParam.getTag());
-        Parameter::Specific specific = targetParam.get<Parameter::specific>();
-        ASSERT_EQ(Parameter::Specific::hapticGenerator, specific.getTag());
-        HapticGenerator hg = specific.get<Parameter::Specific::hapticGenerator>();
-        ASSERT_EQ(HapticGenerator::hapticScales, hg.getTag());
-        std::vector<HapticGenerator::HapticScale> scales = hg.get<HapticGenerator::hapticScales>();
-        ASSERT_EQ(scales.size(), expectMap.size());
-        for (const auto& scale : scales) {
-            auto itor = expectMap.find(scale.id);
-            ASSERT_NE(expectMap.end(), itor);
-            ASSERT_EQ(scale.scale, itor->second);
-            expectMap.erase(scale.id);
-        }
-        ASSERT_EQ(0ul, expectMap.size());
-    }
-
-    const static HapticGenerator::HapticScale kHapticScaleWithMinId;
-    const static HapticGenerator::HapticScale kHapticScaleWithMinIdNew;
-    const static HapticGenerator::HapticScale kHapticScale;
-    const static HapticGenerator::HapticScale kHapticScaleNew;
-    const static HapticGenerator::HapticScale kHapticScaleWithMaxId;
-    const static HapticGenerator::HapticScale kHapticScaleWithMaxIdNew;
-
-    std::vector<HapticGenerator> mHapticScales;
-
-    void CleanUp() {
-        mHapticScales.clear();
-        expectMap.clear();
-    }
-
-  private:
-    std::map<int /* trackID */, HapticGenerator::VibratorScale> expectMap;
+    IEffect::OpenEffectReturn ret;
+    Parameter mHapticSpecificParameter;
+    Parameter::Id mHapticIdParameter;
+    int mEffectInterfaceVersion;
 };
 
-const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleWithMinId = {
-        .id = MIN_ID, .scale = HapticGenerator::VibratorScale::MUTE};
-const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleWithMinIdNew = {
-        .id = MIN_ID, .scale = HapticGenerator::VibratorScale::VERY_LOW};
-const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScale = {
-        .id = 1, .scale = HapticGenerator::VibratorScale::LOW};
-const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleNew = {
-        .id = 1, .scale = HapticGenerator::VibratorScale::NONE};
-const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleWithMaxId = {
-        .id = MAX_ID, .scale = HapticGenerator::VibratorScale::VERY_HIGH};
-const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleWithMaxIdNew = {
-        .id = MAX_ID, .scale = HapticGenerator::VibratorScale::MUTE};
+/**
+ *Tests do the following:
+ * -Testing parameter range supported by the effect.
+ * -For any supported value test expects EX_NONE from IEffect.setParameter(),
+ *  otherwise expect EX_ILLEGAL_ARGUMENT.
+ * -Validating the effect by comparing the output energies of the supported parameters.
+ **/
 
-TEST_P(HapticGeneratorScalesTest, SetAndUpdateOne) {
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScale}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleNew}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+using EffectInstance = std::pair<std::shared_ptr<IFactory>, Descriptor>;
 
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMinId}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMinIdNew}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+class HapticGeneratorScaleParamTest : public ::testing::TestWithParam<EffectInstance>,
+                                      public HapticGeneratorHelper {
+  public:
+    HapticGeneratorScaleParamTest() { std::tie(mFactory, mDescriptor) = GetParam(); }
+    void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpHapticGenerator()); }
+    void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownHapticGenerator()); }
+};
 
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMaxId}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMaxIdNew}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-
-    EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
+TEST_P(HapticGeneratorScaleParamTest, SetAndGetScales) {
+    std::vector<HapticGenerator::HapticScale> hapticScales;
+    for (int i = 0; i < static_cast<int>(kScaleValues.size()); i++) {
+        hapticScales.push_back({.id = i, .scale = kScaleValues[i]});
+    }
+    ASSERT_NO_FATAL_FAILURE(
+            setAndVerifyParameter(createScaleParam(hapticScales), HapticGenerator::hapticScales));
 }
 
-TEST_P(HapticGeneratorScalesTest, SetAndUpdateVector) {
-    EXPECT_NO_FATAL_FAILURE(
-            addHapticScaleParam({kHapticScale, kHapticScaleWithMaxId, kHapticScaleWithMinId}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(
-            {kHapticScaleNew, kHapticScaleWithMaxIdNew, kHapticScaleWithMinIdNew}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+TEST_P(HapticGeneratorScaleParamTest, SetAndGetScaleFactors) {
+    if (mEffectInterfaceVersion < HAPTIC_SCALE_FACTORS_EFFECT_MIN_VERSION) {
+        GTEST_SKIP() << "Skipping HapticGenerator ScaleFactors test for effect version "
+                     << std::to_string(mEffectInterfaceVersion);
+    }
 
-    EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
+    std::vector<HapticGenerator::HapticScale> hapticScales;
+    for (int i = 0; i < static_cast<int>(kScaleFactorValues.size()); i++) {
+        hapticScales.push_back(
+                {.id = i, .scale = kScaleValues[0], .scaleFactor = kScaleFactorValues[i]});
+    }
+    ASSERT_NO_FATAL_FAILURE(
+            setAndVerifyParameter(createScaleParam(hapticScales), HapticGenerator::hapticScales));
 }
 
-TEST_P(HapticGeneratorScalesTest, SetAndUpdateMultipleVector) {
-    EXPECT_NO_FATAL_FAILURE(
-            addHapticScaleParam({kHapticScale, kHapticScaleWithMaxId, kHapticScaleWithMinId}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(
-            {kHapticScaleNew, kHapticScaleWithMaxIdNew, kHapticScaleWithMinIdNew}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-    EXPECT_NO_FATAL_FAILURE(
-            addHapticScaleParam({kHapticScale, kHapticScaleWithMaxId, kHapticScaleWithMinId}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+TEST_P(HapticGeneratorScaleParamTest, SetAndGetAdaptiveScaleFactors) {
+    if (mEffectInterfaceVersion < HAPTIC_SCALE_FACTORS_EFFECT_MIN_VERSION) {
+        GTEST_SKIP() << "Skipping HapticGenerator AdaptiveScaleFactors test for effect version "
+                     << std::to_string(mEffectInterfaceVersion);
+    }
 
-    EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
-}
-
-TEST_P(HapticGeneratorScalesTest, SetOneAndAddMoreVector) {
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScale}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMaxId, kHapticScaleWithMinId}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-
-    EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
-}
-
-TEST_P(HapticGeneratorScalesTest, SetMultipleAndAddOneVector) {
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMaxId, kHapticScaleWithMinId}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScale}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-
-    EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
-}
-
-TEST_P(HapticGeneratorScalesTest, SetMultipleVectorRepeat) {
-    EXPECT_NO_FATAL_FAILURE(
-            addHapticScaleParam({kHapticScaleWithMaxId, kHapticScale, kHapticScaleWithMinId}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-    EXPECT_NO_FATAL_FAILURE(
-            addHapticScaleParam({kHapticScaleWithMaxId, kHapticScale, kHapticScaleWithMinId}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-    EXPECT_NO_FATAL_FAILURE(
-            addHapticScaleParam({kHapticScaleWithMaxId, kHapticScale, kHapticScaleWithMinId}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-
-    EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
+    std::vector<HapticGenerator::HapticScale> hapticScales;
+    for (int i = 0; i < static_cast<int>(kAdaptiveScaleFactorValues.size()); i++) {
+        hapticScales.push_back({.id = i,
+                                .scale = kScaleValues[0],
+                                .scaleFactor = kScaleFactorValues[3],
+                                .adaptiveScaleFactor = kAdaptiveScaleFactorValues[i]});
+    }
+    ASSERT_NO_FATAL_FAILURE(
+            setAndVerifyParameter(createScaleParam(hapticScales), HapticGenerator::hapticScales));
 }
 
 INSTANTIATE_TEST_SUITE_P(
-        HapticGeneratorScalesTest, HapticGeneratorScalesTest,
+        HapticGeneratorValidTest, HapticGeneratorScaleParamTest,
+        testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                IFactory::descriptor, getEffectTypeUuidHapticGenerator())),
+        [](const testing::TestParamInfo<HapticGeneratorScaleParamTest::ParamType>& info) {
+            auto descriptor = info.param;
+            return getPrefix(descriptor.second);
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorScaleParamTest);
+
+enum VibratorParamName {
+    VIBRATOR_PARAM_INSTANCE,
+    VIBRATOR_PARAM_RESONANT_FREQUENCY,
+    VIBRATOR_PARAM_Q_FACTOR,
+    VIBRATOR_PARAM_MAX_AMPLITUDE,
+};
+
+using HapticGeneratorVibratorInfoTestParam = std::tuple<EffectInstance, float, float, float>;
+
+class HapticGeneratorVibratorInfoParamTest
+    : public ::testing::TestWithParam<HapticGeneratorVibratorInfoTestParam>,
+      public HapticGeneratorHelper {
+  public:
+    HapticGeneratorVibratorInfoParamTest()
+        : mParamResonantFrequency(std::get<VIBRATOR_PARAM_RESONANT_FREQUENCY>(GetParam())),
+          mParamQFactor(std::get<VIBRATOR_PARAM_Q_FACTOR>(GetParam())),
+          mParamMaxAmplitude(std::get<VIBRATOR_PARAM_MAX_AMPLITUDE>(GetParam())) {
+        std::tie(mFactory, mDescriptor) = std::get<VIBRATOR_PARAM_INSTANCE>(GetParam());
+    }
+    void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpHapticGenerator()); }
+    void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownHapticGenerator()); }
+
+    float mParamResonantFrequency = kDefaultResonantFrequency;
+    float mParamQFactor = kDefaultQfactor;
+    float mParamMaxAmplitude = kDefaultMaxAmp;
+};
+
+TEST_P(HapticGeneratorVibratorInfoParamTest, SetAndGetVibratorInformation) {
+    auto vibratorInfo =
+            createVibratorInfo(mParamResonantFrequency, mParamQFactor, mParamMaxAmplitude);
+    if (isParameterValid<HapticGenerator, Range::hapticGenerator>(vibratorInfo, mDescriptor)) {
+        ASSERT_NO_FATAL_FAILURE(setAndVerifyParameter(createVibratorParam(vibratorInfo),
+                                                      HapticGenerator::vibratorInfo));
+    } else {
+        ASSERT_NO_FATAL_FAILURE(setAndVerifyParameter(createVibratorParam(vibratorInfo),
+                                                      HapticGenerator::vibratorInfo,
+                                                      EX_ILLEGAL_ARGUMENT));
+    }
+}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorVibratorInfoParamTest);
+
+INSTANTIATE_TEST_SUITE_P(
+        HapticGeneratorValidTest, HapticGeneratorVibratorInfoParamTest,
         ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
-                IFactory::descriptor, getEffectTypeUuidHapticGenerator()))),
-        [](const testing::TestParamInfo<HapticGeneratorScalesTest::ParamType>& info) {
-            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
-            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
-                               descriptor.common.name + "_UUID_" +
-                               toString(descriptor.common.id.uuid);
+                                   IFactory::descriptor, getEffectTypeUuidHapticGenerator())),
+                           testing::ValuesIn(kResonantFrequencyValues),
+                           testing::ValuesIn(kQFactorValues), testing::ValuesIn(kMaxAmplitude)),
+        [](const testing::TestParamInfo<HapticGeneratorVibratorInfoParamTest::ParamType>& info) {
+            auto descriptor = std::get<VIBRATOR_PARAM_INSTANCE>(info.param).second;
+            std::string resonantFrequency =
+                    std::to_string(std::get<VIBRATOR_PARAM_RESONANT_FREQUENCY>(info.param));
+            std::string qFactor = std::to_string(std::get<VIBRATOR_PARAM_Q_FACTOR>(info.param));
+            std::string maxAmplitude =
+                    std::to_string(std::get<VIBRATOR_PARAM_MAX_AMPLITUDE>(info.param));
+            std::string name = getPrefix(descriptor) + "_resonantFrequency" + resonantFrequency +
+                               "_qFactor" + qFactor + "_maxAmplitude" + maxAmplitude;
             std::replace_if(
                     name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
             return name;
         });
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorScalesTest);
+
+/**
+ * The data tests do the following
+ * -Generate test input.
+ * -Check if the parameters are supported. Skip the unsupported parameter values.
+ * -Validate increase in haptic output energy energy.
+ **/
+
+enum DataTestParam { EFFECT_INSTANCE, LAYOUT };
+using HapticGeneratorDataTestParam = std::tuple<EffectInstance, int32_t>;
+
+class HapticGeneratorDataTest : public ::testing::TestWithParam<HapticGeneratorDataTestParam>,
+                                public HapticGeneratorHelper {
+  public:
+    HapticGeneratorDataTest() : mChMask(std::get<LAYOUT>(GetParam())) {
+        std::tie(mFactory, mDescriptor) = std::get<EFFECT_INSTANCE>(GetParam());
+        mAudioChannelCount =
+                getChannelCount(AudioChannelLayout::make<AudioChannelLayout::layoutMask>(mChMask),
+                                ~AudioChannelLayout::LAYOUT_HAPTIC_AB);
+        mHapticChannelCount =
+                getChannelCount(AudioChannelLayout::make<AudioChannelLayout::layoutMask>(mChMask),
+                                AudioChannelLayout::LAYOUT_HAPTIC_AB);
+
+        mAudioSamples = kFrameCount * mAudioChannelCount;
+        mHapticSamples = kFrameCount * mHapticChannelCount;
+        mInput.resize(mHapticSamples + mAudioSamples, 0);
+        mOutput.resize(mHapticSamples + mAudioSamples, 0);
+    }
+
+    void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpHapticGenerator(mChMask)); }
+    void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownHapticGenerator()); }
+
+    void generateSinePeriod() {
+        size_t cycleSize = kSamplingFrequency / kInputFrequency;
+        size_t startSize = 0;
+        while (startSize < mAudioSamples) {
+            for (size_t i = 0; i < cycleSize; i++) {
+                mInput[i + startSize] = sin(2 * M_PI * kInputFrequency * i / kSamplingFrequency);
+            }
+            startSize += mAudioSamples / 4;
+        }
+    }
+
+    void setBaseVibratorParam() {
+        auto vibratorInfo =
+                createVibratorInfo(kDefaultResonantFrequency, kDefaultQfactor, kDefaultMaxAmp);
+        if (isParameterValid<HapticGenerator, Range::hapticGenerator>(vibratorInfo, mDescriptor)) {
+            ASSERT_NO_FATAL_FAILURE(setAndVerifyParameter(createVibratorParam(vibratorInfo),
+                                                          HapticGenerator::vibratorInfo));
+        } else {
+            GTEST_SKIP() << "Invalid base vibrator values, skipping the test\n";
+        }
+    }
+
+    void setBaseScaleParam() {
+        ASSERT_NO_FATAL_FAILURE(setAndVerifyParameter(
+                createScaleParam({HapticGenerator::HapticScale(kDefaultScaleID, kDefaultScale)}),
+                HapticGenerator::hapticScales));
+    }
+
+    void validateIncreasingEnergy(HapticGenerator::Tag tag) {
+        float baseEnergy = -1;
+        for (auto param : mHapticParam) {
+            ASSERT_NO_FATAL_FAILURE(setAndVerifyParameter(param, tag));
+            SCOPED_TRACE("Param: " + param.toString());
+            ASSERT_NO_FATAL_FAILURE(processAndWriteToOutput(mInput, mOutput, mEffect, &ret));
+            float hapticOutputEnergy = audio_utils_compute_energy_mono(
+                    mOutput.data() + mAudioSamples, AUDIO_FORMAT_PCM_FLOAT, mHapticSamples);
+            EXPECT_GT(hapticOutputEnergy, baseEnergy);
+            baseEnergy = hapticOutputEnergy;
+        }
+    }
+
+    float findAbsMax(auto begin, auto end) {
+        return *std::max_element(begin, end,
+                                 [](float a, float b) { return std::abs(a) < std::abs(b); });
+    }
+
+    void findMaxAmplitude() {
+        for (float amp = 0.1; amp <= 1; amp += 0.1) {
+            auto vibratorInfo = createVibratorInfo(kDefaultResonantFrequency, kDefaultQfactor, amp);
+            if (!isParameterValid<HapticGenerator, Range::hapticGenerator>(vibratorInfo,
+                                                                           mDescriptor)) {
+                continue;
+            }
+            ASSERT_NO_FATAL_FAILURE(setAndVerifyParameter(createVibratorParam(vibratorInfo),
+                                                          HapticGenerator::vibratorInfo));
+            ASSERT_NO_FATAL_FAILURE(processAndWriteToOutput(mInput, mOutput, mEffect, &ret));
+            float outAmplitude = findAbsMax(mOutput.begin() + mAudioSamples, mOutput.end());
+            if (outAmplitude > mMaxAmplitude) {
+                mMaxAmplitude = outAmplitude;
+            } else {
+                break;
+            }
+        }
+    }
+
+    const int kInputFrequency = 1000;
+    float mMaxAmplitude = 0;
+    size_t mHapticSamples;
+    int32_t mChMask;
+    int32_t mAudioChannelCount;
+    int32_t mHapticChannelCount;
+    size_t mAudioSamples;
+    float mBaseHapticOutputEnergy;
+    std::vector<Parameter> mHapticParam;
+    // both input and output buffer includes audio and haptic samples
+    std::vector<float> mInput;
+    std::vector<float> mOutput;
+};
+
+TEST_P(HapticGeneratorDataTest, IncreasingVibratorScaleTest) {
+    generateInput(mInput, kInputFrequency, kSamplingFrequency, mAudioSamples);
+    ASSERT_NO_FATAL_FAILURE(setBaseVibratorParam());
+    for (HapticGenerator::VibratorScale scale : kScaleValues) {
+        mHapticParam.push_back(
+                createScaleParam({HapticGenerator::HapticScale(kDefaultScaleID, scale)}));
+    }
+    ASSERT_NO_FATAL_FAILURE(validateIncreasingEnergy(HapticGenerator::hapticScales));
+}
+
+TEST_P(HapticGeneratorDataTest, IncreasingMaxAmplitudeTest) {
+    generateInput(mInput, kInputFrequency, kSamplingFrequency, mAudioSamples);
+    ASSERT_NO_FATAL_FAILURE(setBaseScaleParam());
+    findMaxAmplitude();
+    std::vector<float> increasingAmplitudeValues = {0.25f * mMaxAmplitude, 0.5f * mMaxAmplitude,
+                                                    0.75f * mMaxAmplitude, mMaxAmplitude};
+    for (float amplitude : increasingAmplitudeValues) {
+        auto vibratorInfo =
+                createVibratorInfo(kDefaultResonantFrequency, kDefaultQfactor, amplitude);
+        if (!isParameterValid<HapticGenerator, Range::hapticGenerator>(vibratorInfo, mDescriptor)) {
+            continue;
+        }
+        mHapticParam.push_back(createVibratorParam(vibratorInfo));
+    }
+    ASSERT_NO_FATAL_FAILURE(validateIncreasingEnergy(HapticGenerator::vibratorInfo));
+}
+
+TEST_P(HapticGeneratorDataTest, DescreasingResonantFrequencyTest) {
+    std::vector<float> descreasingResonantFrequency = {800, 600, 400, 200};
+    generateInput(mInput, kInputFrequency, kSamplingFrequency, mAudioSamples);
+    ASSERT_NO_FATAL_FAILURE(setBaseScaleParam());
+    for (float resonantFrequency : descreasingResonantFrequency) {
+        auto vibratorInfo = createVibratorInfo(resonantFrequency, kDefaultQfactor, kDefaultMaxAmp);
+        if (!isParameterValid<HapticGenerator, Range::hapticGenerator>(vibratorInfo, mDescriptor)) {
+            continue;
+        }
+        mHapticParam.push_back(createVibratorParam(vibratorInfo));
+    }
+    ASSERT_NO_FATAL_FAILURE(validateIncreasingEnergy(HapticGenerator::vibratorInfo));
+}
+
+TEST_P(HapticGeneratorDataTest, IncreasingQfactorTest) {
+    std::vector<float> increasingQfactor = {16, 24, 32, 40};
+    generateSinePeriod();
+    ASSERT_NO_FATAL_FAILURE(setBaseScaleParam());
+    for (float qFactor : increasingQfactor) {
+        auto vibratorInfo = createVibratorInfo(kDefaultResonantFrequency, qFactor, kDefaultMaxAmp);
+        if (!isParameterValid<HapticGenerator, Range::hapticGenerator>(vibratorInfo, mDescriptor)) {
+            continue;
+        }
+        mHapticParam.push_back(createVibratorParam(vibratorInfo));
+    }
+    ASSERT_NO_FATAL_FAILURE(validateIncreasingEnergy(HapticGenerator::vibratorInfo));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        DataTest, HapticGeneratorDataTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, getEffectTypeUuidHapticGenerator())),
+                           testing::ValuesIn(kHapticOutputLayouts)),
+        [](const testing::TestParamInfo<HapticGeneratorDataTest::ParamType>& info) {
+            auto descriptor = std::get<EFFECT_INSTANCE>(info.param).second;
+            std::string layout = "0x" + std::format("{:x}", std::get<LAYOUT>(info.param));
+            std::string name = getPrefix(descriptor) + "_layout_" + layout;
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorDataTest);
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
diff --git a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
index 3c72dfa..4c868a9 100644
--- a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
@@ -23,6 +23,7 @@
 
 using namespace android;
 
+using aidl::android::hardware::audio::common::getChannelCount;
 using aidl::android::hardware::audio::effect::Descriptor;
 using aidl::android::hardware::audio::effect::getEffectTypeUuidLoudnessEnhancer;
 using aidl::android::hardware::audio::effect::IEffect;
@@ -31,7 +32,6 @@
 using aidl::android::hardware::audio::effect::Parameter;
 using android::hardware::audio::common::testing::detail::TestExecutionTracer;
 
-static constexpr float kMaxAudioSample = 1;
 static constexpr int kZeroGain = 0;
 static constexpr int kMaxGain = std::numeric_limits<int>::max();
 static constexpr int kMinGain = std::numeric_limits<int>::min();
@@ -50,7 +50,7 @@
         Parameter::Specific specific = getDefaultParamSpecific();
         Parameter::Common common = createParamCommon(
                 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
-                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+                kFrameCount /* iFrameCount */, kFrameCount /* oFrameCount */);
         ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &mOpenEffectReturn, EX_NONE));
         ASSERT_NE(nullptr, mEffect);
         mVersion = EffectFactoryHelper::getHalVersion(mFactory);
@@ -110,7 +110,7 @@
                                            << "\ngetParam:" << getParam.toString();
     }
 
-    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    static const long kFrameCount = 256;
     IEffect::OpenEffectReturn mOpenEffectReturn;
     std::shared_ptr<IFactory> mFactory;
     std::shared_ptr<IEffect> mEffect;
@@ -153,8 +153,14 @@
   public:
     LoudnessEnhancerDataTest() {
         std::tie(mFactory, mDescriptor) = GetParam();
-        generateInputBuffer();
-        mOutputBuffer.resize(kBufferSize);
+        size_t channelCount =
+                getChannelCount(AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+                        AudioChannelLayout::LAYOUT_STEREO));
+        mBufferSizeInFrames = kFrameCount * channelCount;
+        mInputBuffer.resize(mBufferSizeInFrames);
+        generateInputBuffer(mInputBuffer, 0, true, channelCount, kMaxAudioSampleValue);
+
+        mOutputBuffer.resize(mBufferSizeInFrames);
     }
 
     void SetUp() override {
@@ -172,14 +178,6 @@
         TearDownLoudnessEnhancer();
     }
 
-    // Fill inputBuffer with random values between -kMaxAudioSample to kMaxAudioSample
-    void generateInputBuffer() {
-        for (size_t i = 0; i < kBufferSize; i++) {
-            mInputBuffer.push_back(((static_cast<float>(std::rand()) / RAND_MAX) * 2 - 1) *
-                                   kMaxAudioSample);
-        }
-    }
-
     // Add gains to the mInputBuffer and store processed output to mOutputBuffer
     void processAndWriteToOutput() {
         // Check AidlMessageQueues are not null
@@ -215,7 +213,7 @@
     }
 
     void assertSequentialGains(const std::vector<int>& gainValues, bool isIncreasing) {
-        std::vector<float> baseOutput(kBufferSize);
+        std::vector<float> baseOutput(mBufferSizeInFrames);
 
         // Process a reference output buffer with 0 gain which gives compressed input values
         binder_exception_t expected;
@@ -252,7 +250,7 @@
 
     std::vector<float> mInputBuffer;
     std::vector<float> mOutputBuffer;
-    static constexpr float kBufferSize = 128;
+    size_t mBufferSizeInFrames;
 };
 
 TEST_P(LoudnessEnhancerDataTest, IncreasingGains) {
@@ -291,10 +289,10 @@
     setParameters(kMaxGain, expected);
     ASSERT_NO_FATAL_FAILURE(processAndWriteToOutput());
 
-    // Validate that mOutputBuffer reaches to kMaxAudioSample for INT_MAX gain
+    // Validate that mOutputBuffer reaches to kMaxAudioSampleValue for INT_MAX gain
     for (size_t i = 0; i < mOutputBuffer.size(); i++) {
         if (mInputBuffer[i] != 0) {
-            EXPECT_NEAR(kMaxAudioSample, abs(mOutputBuffer[i]), kAbsError);
+            EXPECT_NEAR(kMaxAudioSampleValue, abs(mOutputBuffer[i]), kAbsError);
         } else {
             ASSERT_EQ(mOutputBuffer[i], mInputBuffer[i]);
         }
diff --git a/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
index f215a8e..c77a228 100644
--- a/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
@@ -24,6 +24,7 @@
 
 using namespace android;
 
+using aidl::android::hardware::audio::common::getChannelCount;
 using aidl::android::hardware::audio::effect::Descriptor;
 using aidl::android::hardware::audio::effect::getEffectTypeUuidVisualizer;
 using aidl::android::hardware::audio::effect::IEffect;
@@ -56,6 +57,15 @@
           mMeasurementMode(std::get<PARAM_MEASUREMENT_MODE>(GetParam())),
           mLatency(std::get<PARAM_LATENCY>(GetParam())) {
         std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+
+        size_t channelCount =
+                getChannelCount(AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+                        AudioChannelLayout::LAYOUT_STEREO));
+        mBufferSizeInFrames = kInputFrameCount * channelCount;
+        mInputBuffer.resize(mBufferSizeInFrames);
+        generateInputBuffer(mInputBuffer, 0, true, channelCount, kMaxAudioSampleValue);
+
+        mOutputBuffer.resize(mBufferSizeInFrames);
     }
 
     void SetUp() override {
@@ -65,14 +75,15 @@
         Parameter::Common common = createParamCommon(
                 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
                 kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
-        IEffect::OpenEffectReturn ret;
-        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt, &ret, EX_NONE));
+        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt, &mOpenEffectReturn, EX_NONE));
         ASSERT_NE(nullptr, mEffect);
+        mVersion = EffectFactoryHelper::getHalVersion(mFactory);
     }
 
     void TearDown() override {
         ASSERT_NO_FATAL_FAILURE(close(mEffect));
         ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+        mOpenEffectReturn = IEffect::OpenEffectReturn{};
     }
 
     static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
@@ -83,6 +94,12 @@
     Visualizer::ScalingMode mScalingMode = Visualizer::ScalingMode::NORMALIZED;
     Visualizer::MeasurementMode mMeasurementMode = Visualizer::MeasurementMode::NONE;
     int mLatency = 0;
+    int mVersion = 0;
+    std::vector<float> mInputBuffer;
+    std::vector<float> mOutputBuffer;
+    size_t mBufferSizeInFrames;
+    IEffect::OpenEffectReturn mOpenEffectReturn;
+    bool mAllParamsValid = true;
 
     void SetAndGetParameters() {
         for (auto& it : mCommonTags) {
@@ -94,6 +111,7 @@
             ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
             const bool valid = isParameterValid<Visualizer, Range::visualizer>(vs, desc);
             const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+            if (expected == EX_ILLEGAL_ARGUMENT) mAllParamsValid = false;
 
             // set parameter
             Parameter expectParam;
@@ -153,23 +171,49 @@
 };
 
 TEST_P(VisualizerParamTest, SetAndGetCaptureSize) {
-    EXPECT_NO_FATAL_FAILURE(addCaptureSizeParam(mCaptureSize));
-    SetAndGetParameters();
+    ASSERT_NO_FATAL_FAILURE(addCaptureSizeParam(mCaptureSize));
+    ASSERT_NO_FATAL_FAILURE(SetAndGetParameters());
 }
 
 TEST_P(VisualizerParamTest, SetAndGetScalingMode) {
-    EXPECT_NO_FATAL_FAILURE(addScalingModeParam(mScalingMode));
-    SetAndGetParameters();
+    ASSERT_NO_FATAL_FAILURE(addScalingModeParam(mScalingMode));
+    ASSERT_NO_FATAL_FAILURE(SetAndGetParameters());
 }
 
 TEST_P(VisualizerParamTest, SetAndGetMeasurementMode) {
-    EXPECT_NO_FATAL_FAILURE(addMeasurementModeParam(mMeasurementMode));
-    SetAndGetParameters();
+    ASSERT_NO_FATAL_FAILURE(addMeasurementModeParam(mMeasurementMode));
+    ASSERT_NO_FATAL_FAILURE(SetAndGetParameters());
 }
 
 TEST_P(VisualizerParamTest, SetAndGetLatency) {
-    EXPECT_NO_FATAL_FAILURE(addLatencyParam(mLatency));
-    SetAndGetParameters();
+    ASSERT_NO_FATAL_FAILURE(addLatencyParam(mLatency));
+    ASSERT_NO_FATAL_FAILURE(SetAndGetParameters());
+}
+
+TEST_P(VisualizerParamTest, testCaptureSampleBufferSizeAndOutput) {
+    ASSERT_NO_FATAL_FAILURE(addCaptureSizeParam(mCaptureSize));
+    ASSERT_NO_FATAL_FAILURE(addScalingModeParam(mScalingMode));
+    ASSERT_NO_FATAL_FAILURE(addMeasurementModeParam(mMeasurementMode));
+    ASSERT_NO_FATAL_FAILURE(addLatencyParam(mLatency));
+    ASSERT_NO_FATAL_FAILURE(SetAndGetParameters());
+
+    Parameter getParam;
+    Parameter::Id id;
+    Visualizer::Id vsId;
+    vsId.set<Visualizer::Id::commonTag>(Visualizer::captureSampleBuffer);
+    id.set<Parameter::Id::visualizerTag>(vsId);
+    EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam)) << " with: " << id.toString();
+
+    ASSERT_NO_FATAL_FAILURE(processAndWriteToOutput(mInputBuffer, mOutputBuffer, mEffect,
+                                                    &mOpenEffectReturn, mVersion));
+    ASSERT_EQ(mInputBuffer, mOutputBuffer);
+
+    if (mAllParamsValid) {
+        std::vector<uint8_t> captureBuffer = getParam.get<Parameter::specific>()
+                                                     .get<Parameter::Specific::visualizer>()
+                                                     .get<Visualizer::captureSampleBuffer>();
+        ASSERT_EQ((size_t)mCaptureSize, captureBuffer.size());
+    }
 }
 
 std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kDescPair;
diff --git a/audio/common/all-versions/default/7.0/HidlUtils.cpp b/audio/common/all-versions/default/7.0/HidlUtils.cpp
index f89c898..bc056e2 100644
--- a/audio/common/all-versions/default/7.0/HidlUtils.cpp
+++ b/audio/common/all-versions/default/7.0/HidlUtils.cpp
@@ -1025,7 +1025,7 @@
             result = BAD_VALUE;
         }
     }
-    std::string fullHalTags{std::move(halTagsBuffer.str())};
+    std::string fullHalTags{halTagsBuffer.str()};
     strncpy(halTags, fullHalTags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE);
     CONVERT_CHECKED(fullHalTags.length() <= AUDIO_ATTRIBUTES_TAGS_MAX_SIZE ? NO_ERROR : BAD_VALUE,
                     result);
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/TEST_MAPPING b/automotive/TEST_MAPPING
index c64c880..483a85f 100644
--- a/automotive/TEST_MAPPING
+++ b/automotive/TEST_MAPPING
@@ -19,10 +19,58 @@
     	"name": "CtsCarBuiltinApiHostTestCases"
     },
     {
-      "name": "CarServiceTest"
+      "name": "CarServiceAudioTest"
+    },
+    {
+      "name": "CarServiceCarTest"
+    },
+    {
+      "name": "CarServiceClusterTest"
+    },
+    {
+      "name": "CarServiceDiagnosticTest"
+    },
+    {
+      "name": "CarServiceDrivingStateTest"
+    },
+    {
+      "name": "CarServiceEvsTest"
+    },
+    {
+      "name": "CarServiceGarageModeTest"
+    },
+    {
+      "name": "CarServiceInputTest"
+    },
+    {
+      "name": "CarServiceOsTest"
+    },
+    {
+      "name": "CarServicePmTest"
+    },
+    {
+      "name": "CarServicePowerTest"
+    },
+    {
+      "name": "CarServicePropertyTest"
+    },
+    {
+      "name": "CarServiceRemoteAccessTest"
+    },
+    {
+      "name": "CarServiceStorageMonitoringTest"
+    },
+    {
+      "name": "CarServiceTelemetryTest"
     },
     {
       "name": "CarServiceUnitTest"
+    },
+    {
+      "name": "CarServiceVmsTest"
+    },
+    {
+      "name": "CarServiceWatchdogTest"
     }
   ]
 }
\ No newline at end of file
diff --git a/automotive/audiocontrol/aidl/Android.bp b/automotive/audiocontrol/aidl/Android.bp
index 0eb17fe..edb29c9 100644
--- a/automotive/audiocontrol/aidl/Android.bp
+++ b/automotive/audiocontrol/aidl/Android.bp
@@ -62,12 +62,12 @@
         },
 
     ],
-    frozen: true,
+    frozen: false,
 
 }
 
 // Note: This should always be one version ahead of the last frozen version
-latest_android_hardware_automotive_audiocontrol = "android.hardware.automotive.audiocontrol-V4"
+latest_android_hardware_automotive_audiocontrol = "android.hardware.automotive.audiocontrol-V5"
 
 cc_defaults {
     name: "latest_android_hardware_automotive_audiocontrol_cpp_static",
diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp
index 520670a..fb598ff 100644
--- a/automotive/evs/1.1/default/EvsCamera.cpp
+++ b/automotive/evs/1.1/default/EvsCamera.cpp
@@ -495,7 +495,7 @@
         }
         if (!stored) {
             // Add a BufferRecord wrapping this handle to our set of available buffers
-            mBuffers.push_back(std::move(BufferRecord(memHandle)));
+            mBuffers.push_back(BufferRecord(memHandle));
         }
 
         mFramesAllowed++;
diff --git a/automotive/evs/aidl/Android.bp b/automotive/evs/aidl/Android.bp
index dfb15c6..5b2f82f 100644
--- a/automotive/evs/aidl/Android.bp
+++ b/automotive/evs/aidl/Android.bp
@@ -44,6 +44,9 @@
         ndk: {
             min_sdk_version: "29",
         },
+        rust: {
+            enabled: true,
+        },
     },
     versions_with_info: [
         {
diff --git a/automotive/evs/aidl/impl/default/manifest_evs-default-service.xml b/automotive/evs/aidl/impl/default/manifest_evs-default-service.xml
index 50692f7..9ddc6ad 100644
--- a/automotive/evs/aidl/impl/default/manifest_evs-default-service.xml
+++ b/automotive/evs/aidl/impl/default/manifest_evs-default-service.xml
@@ -2,6 +2,6 @@
     <hal format="aidl">
         <name>android.hardware.automotive.evs</name>
         <fqname>IEvsEnumerator/hw/0</fqname>
-        <version>1</version>
+        <version>2</version>
     </hal>
 </manifest>
diff --git a/automotive/evs/aidl/impl/default/src/ConfigManager.cpp b/automotive/evs/aidl/impl/default/src/ConfigManager.cpp
index ba4cdc0..d8961d0 100644
--- a/automotive/evs/aidl/impl/default/src/ConfigManager.cpp
+++ b/automotive/evs/aidl/impl/default/src/ConfigManager.cpp
@@ -199,8 +199,8 @@
 
             CameraParam aParam;
             if (ConfigManagerUtil::convertToEvsCameraParam(nameAttr, aParam)) {
-                aCamera->controls.insert_or_assign(
-                        aParam, std::move(std::make_tuple(minVal, maxVal, stepVal)));
+                aCamera->controls.insert_or_assign(aParam,
+                                                   std::make_tuple(minVal, maxVal, stepVal));
             }
 
             ctrlElem = ctrlElem->NextSiblingElement("control");
@@ -583,8 +583,8 @@
         CameraCtrl* ptr = reinterpret_cast<CameraCtrl*>(p);
         for (size_t idx = 0; idx < sz; ++idx) {
             CameraCtrl temp = *ptr++;
-            aCamera->controls.insert_or_assign(
-                    temp.cid, std::move(std::make_tuple(temp.min, temp.max, temp.step)));
+            aCamera->controls.insert_or_assign(temp.cid,
+                                               std::make_tuple(temp.min, temp.max, temp.step));
         }
         p = reinterpret_cast<char*>(ptr);
 
@@ -689,8 +689,8 @@
         CameraCtrl* ptr = reinterpret_cast<CameraCtrl*>(p);
         for (size_t idx = 0; idx < sz; ++idx) {
             CameraCtrl temp = *ptr++;
-            aCamera->controls.insert_or_assign(
-                    temp.cid, std::move(std::make_tuple(temp.min, temp.max, temp.step)));
+            aCamera->controls.insert_or_assign(temp.cid,
+                                               std::make_tuple(temp.min, temp.max, temp.step));
         }
         p = reinterpret_cast<char*>(ptr);
 
diff --git a/automotive/evs/aidl/impl/default/src/EvsGlDisplay.cpp b/automotive/evs/aidl/impl/default/src/EvsGlDisplay.cpp
index 5b5cbcc..cf94e38 100644
--- a/automotive/evs/aidl/impl/default/src/EvsGlDisplay.cpp
+++ b/automotive/evs/aidl/impl/default/src/EvsGlDisplay.cpp
@@ -353,7 +353,7 @@
             .buffer =
                     {
                             .description = mBuffer.description,
-                            .handle = std::move(::android::dupToAidl(mBuffer.handle)),
+                            .handle = ::android::dupToAidl(mBuffer.handle),
                     },
             .pixelSizeBytes = 4,  // RGBA_8888 is 4-byte-per-pixel format
             .bufferId = mBuffer.fingerprint,
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/automotive/evs/aidl/rust_impl/Android.bp
similarity index 60%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
copy to automotive/evs/aidl/rust_impl/Android.bp
index c7be950..ac8b90f 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ b/automotive/evs/aidl/rust_impl/Android.bp
@@ -14,22 +14,17 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
-
-import android.hardware.biometrics.fingerprint.AcquiredInfo;
-
-/**
- * @hide
- */
-@VintfStability
-union AcquiredInfoAndVendorCode {
-    /**
-     * Acquired info as specified in AcqauiredInfo.aidl
-     */
-    AcquiredInfo acquiredInfo = AcquiredInfo.UNKNOWN;
-
-    /**
-     * Vendor specific code
-     */
-    int vendorCode;
+rust_binary {
+    name: "android.hardware.automotive.evs-aidl-rust-service",
+    relative_install_path: "hw",
+    vendor: true,
+    srcs: ["src/*.rs"],
+    crate_root: "src/main.rs",
+    vintf_fragments: ["manifest_evs-rust-service.xml"],
+    init_rc: ["evs-rust-service.rc"],
+    rustlibs: [
+        "android.hardware.automotive.evs-V2-rust",
+        "libbinder_rs",
+        "liblog_rust",
+    ],
 }
diff --git a/automotive/evs/aidl/rust_impl/README.md b/automotive/evs/aidl/rust_impl/README.md
new file mode 100644
index 0000000..bf00aed
--- /dev/null
+++ b/automotive/evs/aidl/rust_impl/README.md
@@ -0,0 +1,21 @@
+# Rust Skeleton EVS HAL implementation.
+
+WARNING: This is not a reference EVS HAL implementation and therefore does not
+provide any actual functionality.
+
+This folder contains a skeleton EVS HAL implementation in Rust to demonstrate
+how vendors could implement their EVS HAL in Rust. To compile and run this
+implementation, please include below package to the device build script:
+
+* `android.hardware.automotive.evs-aidl-rust-service`
+
+Please note that this service will attempt to register the service as
+`IEvsEnumerator/rust/0` and therefore is also required to be declared in the
+service context by adding below line to a proper `service_contexts` file:
+
+> android.hardware.automotive.evs.IEvsEnumerator/rust/0 u:object_r:hal_evs_service:s0
+
+This implementation intentionally returns `binder::StatusCode::UNKNOWN_ERROR`
+for any API call except deprecated API for ultrasonics; the process will be
+panicked on these methods instead. Hence, this implementation does not comply
+with VTS tests and vendors must replace each method with actual implementation.
diff --git a/automotive/evs/aidl/rust_impl/evs-rust-service.rc b/automotive/evs/aidl/rust_impl/evs-rust-service.rc
new file mode 100644
index 0000000..3741b21
--- /dev/null
+++ b/automotive/evs/aidl/rust_impl/evs-rust-service.rc
@@ -0,0 +1,8 @@
+service vendor.evs-hal-rust-default /vendor/bin/hw/android.hardware.automotive.evs-aidl-rust-service
+    class early_hal
+    priority -20
+    user graphics
+    group automotive_evs camera
+    onrestart restart cardisplayproxyd
+    onrestart restart evsmanagerd
+    disabled
diff --git a/automotive/evs/aidl/rust_impl/manifest_evs-rust-service.xml b/automotive/evs/aidl/rust_impl/manifest_evs-rust-service.xml
new file mode 100644
index 0000000..813cbb2
--- /dev/null
+++ b/automotive/evs/aidl/rust_impl/manifest_evs-rust-service.xml
@@ -0,0 +1,7 @@
+<manifest version="2.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.automotive.evs</name>
+        <version>2</version>
+        <fqname>IEvsEnumerator/rust/0</fqname>
+    </hal>
+</manifest>
diff --git a/automotive/evs/aidl/rust_impl/src/default_evs_hal.rs b/automotive/evs/aidl/rust_impl/src/default_evs_hal.rs
new file mode 100644
index 0000000..72b2d53
--- /dev/null
+++ b/automotive/evs/aidl/rust_impl/src/default_evs_hal.rs
@@ -0,0 +1,113 @@
+//
+// 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.
+//
+
+use android_hardware_automotive_evs::aidl::android::hardware::automotive::evs::{
+    CameraDesc::CameraDesc, DisplayState::DisplayState, IEvsCamera::IEvsCamera,
+    IEvsDisplay::IEvsDisplay, IEvsEnumerator::IEvsEnumerator,
+    IEvsEnumeratorStatusCallback::IEvsEnumeratorStatusCallback,
+    IEvsUltrasonicsArray::IEvsUltrasonicsArray, Stream::Stream,
+    UltrasonicsArrayDesc::UltrasonicsArrayDesc,
+};
+
+pub struct DefaultEvsHal {}
+
+impl binder::Interface for DefaultEvsHal {}
+
+impl IEvsEnumerator for DefaultEvsHal {
+    fn closeCamera(
+        &self,
+        _: &binder::Strong<(dyn IEvsCamera + 'static)>,
+    ) -> std::result::Result<(), binder::Status> {
+        Err(binder::StatusCode::UNKNOWN_ERROR.into())
+    }
+
+    fn closeDisplay(
+        &self,
+        _: &binder::Strong<(dyn IEvsDisplay + 'static)>,
+    ) -> std::result::Result<(), binder::Status> {
+        Err(binder::StatusCode::UNKNOWN_ERROR.into())
+    }
+
+    fn closeUltrasonicsArray(
+        &self,
+        _: &binder::Strong<(dyn IEvsUltrasonicsArray + 'static)>,
+    ) -> std::result::Result<(), binder::Status> {
+        unimplemented!()
+    }
+
+    fn getCameraList(&self) -> std::result::Result<std::vec::Vec<CameraDesc>, binder::Status> {
+        Err(binder::StatusCode::UNKNOWN_ERROR.into())
+    }
+
+    fn getDisplayIdList(&self) -> std::result::Result<std::vec::Vec<u8>, binder::Status> {
+        Err(binder::StatusCode::UNKNOWN_ERROR.into())
+    }
+
+    fn getDisplayState(&self) -> std::result::Result<DisplayState, binder::Status> {
+        Err(binder::StatusCode::UNKNOWN_ERROR.into())
+    }
+
+    fn getStreamList(
+        &self,
+        _: &CameraDesc,
+    ) -> std::result::Result<std::vec::Vec<Stream>, binder::Status> {
+        Err(binder::StatusCode::UNKNOWN_ERROR.into())
+    }
+
+    fn getUltrasonicsArrayList(
+        &self,
+    ) -> std::result::Result<std::vec::Vec<UltrasonicsArrayDesc>, binder::Status> {
+        unimplemented!()
+    }
+
+    fn isHardware(&self) -> std::result::Result<bool, binder::Status> {
+        Err(binder::StatusCode::UNKNOWN_ERROR.into())
+    }
+
+    fn openCamera(
+        &self,
+        _: &str,
+        _: &Stream,
+    ) -> std::result::Result<binder::Strong<(dyn IEvsCamera + 'static)>, binder::Status> {
+        Err(binder::StatusCode::UNKNOWN_ERROR.into())
+    }
+
+    fn openDisplay(
+        &self,
+        _: i32,
+    ) -> std::result::Result<binder::Strong<(dyn IEvsDisplay + 'static)>, binder::Status> {
+        Err(binder::StatusCode::UNKNOWN_ERROR.into())
+    }
+
+    fn openUltrasonicsArray(
+        &self,
+        _: &str,
+    ) -> std::result::Result<binder::Strong<(dyn IEvsUltrasonicsArray + 'static)>, binder::Status>
+    {
+        unimplemented!()
+    }
+
+    fn registerStatusCallback(
+        &self,
+        _: &binder::Strong<(dyn IEvsEnumeratorStatusCallback + 'static)>,
+    ) -> std::result::Result<(), binder::Status> {
+        Err(binder::StatusCode::UNKNOWN_ERROR.into())
+    }
+
+    fn getDisplayStateById(&self, _: i32) -> std::result::Result<DisplayState, binder::Status> {
+        Err(binder::StatusCode::UNKNOWN_ERROR.into())
+    }
+}
diff --git a/automotive/evs/aidl/rust_impl/src/main.rs b/automotive/evs/aidl/rust_impl/src/main.rs
new file mode 100644
index 0000000..df312c0
--- /dev/null
+++ b/automotive/evs/aidl/rust_impl/src/main.rs
@@ -0,0 +1,42 @@
+//
+// 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.
+//
+
+mod default_evs_hal;
+
+use crate::default_evs_hal::DefaultEvsHal;
+
+use android_hardware_automotive_evs::aidl::android::hardware::automotive::evs::IEvsEnumerator::BnEvsEnumerator;
+
+use log::info;
+
+fn main() {
+    binder::ProcessState::start_thread_pool();
+
+    let service = DefaultEvsHal {};
+
+    // Register HAL implementation as rust/0 instance.
+    let service_name = "android.hardware.automotive.evs.IEvsEnumerator/rust/0";
+    let service_binder = BnEvsEnumerator::new_binder(service, binder::BinderFeatures::default());
+
+    binder::add_service(service_name, service_binder.as_binder())
+        .expect(format!("Failed to register {}.", service_name).as_str());
+    info!("EVS Hardware Enumerator is ready");
+
+    binder::ProcessState::join_thread_pool();
+
+    // In normal operation, we don't expect the thread pool to exit.
+    info!("EVS Hardware Enumerator is shutting down");
+}
diff --git a/automotive/evs/aidl/vts/FrameHandler.cpp b/automotive/evs/aidl/vts/FrameHandler.cpp
index e51be67..88c3643 100644
--- a/automotive/evs/aidl/vts/FrameHandler.cpp
+++ b/automotive/evs/aidl/vts/FrameHandler.cpp
@@ -50,12 +50,12 @@
         }
     } else {
         for (auto i = 0; i < handle.fds.size(); ++i) {
-            dup.fds[i] = std::move(handle.fds[i].dup());
+            dup.fds[i] = handle.fds[i].dup();
         }
     }
     dup.ints = handle.ints;
 
-    return std::move(dup);
+    return dup;
 }
 
 HardwareBuffer dupHardwareBuffer(const HardwareBuffer& buffer, bool doDup) {
@@ -64,7 +64,7 @@
             .handle = dupNativeHandle(buffer.handle, doDup),
     };
 
-    return std::move(dup);
+    return dup;
 }
 
 BufferDesc dupBufferDesc(const BufferDesc& src, bool doDup) {
@@ -77,7 +77,7 @@
             .metadata = src.metadata,
     };
 
-    return std::move(dup);
+    return dup;
 }
 
 bool comparePayload(const EvsEventDesc& l, const EvsEventDesc& r) {
diff --git a/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp b/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
index 477de31..dc78ed6 100644
--- a/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
+++ b/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
@@ -317,12 +317,20 @@
             // Verify methods for extended info
             const auto id = 0xFFFFFFFF;  // meaningless id
             std::vector<uint8_t> values;
+            bool isSupported = false;
             auto status = pCam->setExtendedInfo(id, values);
             if (isLogicalCam) {
                 EXPECT_TRUE(!status.isOk() && status.getServiceSpecificError() ==
                                                       static_cast<int>(EvsResult::NOT_SUPPORTED));
             } else {
-                EXPECT_TRUE(status.isOk());
+                if (status.isOk()) {
+                    // 0xFFFFFFFF is valid for EVS HAL implementation under
+                    // test.
+                    isSupported = true;
+                } else {
+                    EXPECT_TRUE(status.getServiceSpecificError() ==
+                                static_cast<int>(EvsResult::INVALID_ARG));
+                }
             }
 
             status = pCam->getExtendedInfo(id, &values);
@@ -330,7 +338,12 @@
                 EXPECT_TRUE(!status.isOk() && status.getServiceSpecificError() ==
                                                       static_cast<int>(EvsResult::NOT_SUPPORTED));
             } else {
-                EXPECT_TRUE(status.isOk());
+                if (isSupported) {
+                    EXPECT_TRUE(status.isOk());
+                } else {
+                    EXPECT_TRUE(!status.isOk() && status.getServiceSpecificError() ==
+                                                    static_cast<int>(EvsResult::INVALID_ARG));
+                }
             }
 
             // Explicitly close the camera so resources are released right away
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/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index 94a5882..76d44f8 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -290,7 +290,8 @@
     ],
     fuzz_config: {
         cc: [
-            "android-media-fuzzing-reports@google.com",
+            "ericjeong@google.com",
+            "shanyu@google.com",
         ],
         componentid: 533764,
         hotlists: [
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
index e34e692..3d6e475 100644
--- a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
@@ -583,12 +583,12 @@
     while (*index < options.size()) {
         std::string option = options[*index];
         if (kSetPropOptions.find(option) != kSetPropOptions.end()) {
-            return std::move(values);
+            return values;
         }
         values.push_back(option);
         (*index)++;
     }
-    return std::move(values);
+    return values;
 }
 
 bool VehicleHalManager::parseSetPropOptions(int fd, const hidl_vec<hidl_string>& options,
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHalServer.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHalServer.cpp
index 4704917..86fc70a 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHalServer.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHalServer.cpp
@@ -509,7 +509,7 @@
     int64_t timestamp;
     int32_t areaId = 0;
     if (options[1] == "--setint") {
-        updatedPropValue = std::move(createVehiclePropValue(VehiclePropertyType::INT32, 1));
+        updatedPropValue = createVehiclePropValue(VehiclePropertyType::INT32, 1);
         if (!android::base::ParseInt(options[3], &intValue)) {
             result.buffer += "failed to parse value as int: \"" + options[3] + "\"\n";
             result.buffer += getHelpInfo();
@@ -517,7 +517,7 @@
         }
         updatedPropValue->value.int32Values[0] = intValue;
     } else if (options[1] == "--setbool") {
-        updatedPropValue = std::move(createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1));
+        updatedPropValue = createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1);
         if (options[3] == "true" || options[3] == "True") {
             updatedPropValue->value.int32Values[0] = 1;
         } else if (options[3] == "false" || options[3] == "False") {
@@ -529,7 +529,7 @@
             return result;
         }
     } else {
-        updatedPropValue = std::move(createVehiclePropValue(VehiclePropertyType::FLOAT, 1));
+        updatedPropValue = createVehiclePropValue(VehiclePropertyType::FLOAT, 1);
         if (!android::base::ParseFloat(options[3], &floatValue)) {
             result.buffer += "failed to parse value as float: \"" + options[3] + "\"\n";
             result.buffer += getHelpInfo();
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/TEST_MAPPING b/automotive/vehicle/TEST_MAPPING
index 77629a9..d848774 100644
--- a/automotive/vehicle/TEST_MAPPING
+++ b/automotive/vehicle/TEST_MAPPING
@@ -45,6 +45,9 @@
       "name": "FakeVehicleHardwareTest"
     },
     {
+      "name": "GRPCVehicleHardwareUnitTest"
+    },
+    {
       "name": "CarServiceUnitTest",
       "options" : [
         {
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/emu_metadata/android.hardware.automotive.vehicle-types-meta.json b/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json
index de0e398..8ef440d 100644
--- a/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json
+++ b/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json
@@ -501,7 +501,7 @@
             {
                 "name": "AP_POWER_STATE_REQ",
                 "value": 289475072,
-                "description": "Property to control power state of application processor\nIt is assumed that AP's power state is controlled by a separate power controller.\nFor configuration information, VehiclePropConfig.configArray must have bit flag combining values in VehicleApPowerStateConfigFlag.\nint32Values[0] : VehicleApPowerStateReq enum value int32Values[1] : additional parameter relevant for each state, 0 if not used."
+                "description": "Property to control power state of application processor\nIt is assumed that AP's power state is controlled by a separate power controller.\nFor configuration information, VehiclePropConfig.configArray must have bit flag combining values in VehicleApPowerStateConfigFlag.\nconfigArray[0] : Bit flag combining values in VehicleApPowerStateConfigFlag, 0x0 if not used, 0x1 for enabling suspend to ram, 0x2 for supporting powering on AP from off state after timeout. 0x4 for enabling suspend to disk,\nint32Values[0] : VehicleApPowerStateReq enum value int32Values[1] : additional parameter relevant for each state, 0 if not used."
             },
             {
                 "name": "AP_POWER_STATE_REPORT",
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/JsonConfigLoader/test/Android.bp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/Android.bp
index abf15c5..90ea027 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/Android.bp
@@ -27,8 +27,6 @@
         "VehicleHalJsonConfigLoader",
         "VehicleHalUtils",
         "libgtest",
-    ],
-    shared_libs: [
         "libjsoncpp",
     ],
     defaults: ["VehicleHalDefaults"],
@@ -43,8 +41,6 @@
         "VehicleHalJsonConfigLoaderEnableTestProperties",
         "VehicleHalUtils",
         "libgtest",
-    ],
-    shared_libs: [
         "libjsoncpp",
     ],
     defaults: ["VehicleHalDefaults"],
diff --git a/automotive/vehicle/aidl/impl/default_config/TEST_MAPPING b/automotive/vehicle/aidl/impl/default_config/TEST_MAPPING
new file mode 100644
index 0000000..15ac9cb
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/default_config/TEST_MAPPING
@@ -0,0 +1,8 @@
+{
+    "ravenwood-presubmit": [
+        {
+            "name": "CarServiceHostUnitTest",
+            "host": true
+        }
+    ]
+}
diff --git a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
index 2d1e9ab..489d638 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
+++ b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
@@ -3195,19 +3195,22 @@
             }
         },
         {
-            "property": "VehicleProperty::DISPLAY_BRIGHTNESS",
+            "property": "VehicleProperty::PER_DISPLAY_BRIGHTNESS"
+        },
+        {
+            "property": "VehicleProperty::PER_DISPLAY_MAX_BRIGHTNESS",
             "defaultValue": {
                 "int32Values": [
+                    0,
+                    100,
+                    1,
+                    100,
+                    2,
+                    100,
+                    3,
                     100
                 ]
-            },
-            "areas": [
-                {
-                    "areaId": 0,
-                    "minInt32Value": 0,
-                    "maxInt32Value": 100
-                }
-            ]
+            }
         },
         {
             "property": "VehicleProperty::VALET_MODE_ENABLED",
diff --git a/automotive/vehicle/aidl/impl/default_config/test/Android.bp b/automotive/vehicle/aidl/impl/default_config/test/Android.bp
index 70933be..a88913e 100644
--- a/automotive/vehicle/aidl/impl/default_config/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/default_config/test/Android.bp
@@ -29,12 +29,10 @@
         "VehicleHalUtils",
         "libgmock",
         "libgtest",
+        "libjsoncpp",
     ],
     header_libs: [
-        "IVehicleGeneratedHeaders-V3",
-    ],
-    shared_libs: [
-        "libjsoncpp",
+        "IVehicleGeneratedHeaders-V4",
     ],
     data: [
         ":VehicleHalDefaultProperties_JSON",
@@ -52,15 +50,13 @@
         "VehicleHalUtils",
         "libgmock",
         "libgtest",
+        "libjsoncpp",
     ],
     cflags: [
         "-DENABLE_VEHICLE_HAL_TEST_PROPERTIES",
     ],
     header_libs: [
-        "IVehicleGeneratedHeaders-V3",
-    ],
-    shared_libs: [
-        "libjsoncpp",
+        "IVehicleGeneratedHeaders-V4",
     ],
     data: [
         ":VehicleHalDefaultProperties_JSON",
diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/Android.bp
index 4bc0b12..0d814ea 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/Android.bp
@@ -28,8 +28,6 @@
         "VehicleHalUtils",
         "FakeVehicleHalValueGenerators",
         "FakeObd2Frame",
-    ],
-    shared_libs: [
         "libjsoncpp",
     ],
     data: [
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
index 79d3e77..5916307 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -56,6 +56,13 @@
     FakeVehicleHardware(std::string defaultConfigDir, std::string overrideConfigDir,
                         bool forceOverride);
 
+    // s2rS2dConfig is the config for whether S2R or S2D is supported, must be a bit flag combining
+    // values from VehicleApPowerStateConfigFlag.
+    // The default implementation is reading this from system property:
+    // "ro.vendor.fake_vhal.ap_power_state_req.config".
+    FakeVehicleHardware(std::string defaultConfigDir, std::string overrideConfigDir,
+                        bool forceOverride, int32_t s2rS2dConfig);
+
     ~FakeVehicleHardware();
 
     // Get all the property configs.
@@ -193,7 +200,7 @@
     // provides power controlling related properties.
     std::string mPowerControllerServiceAddress = "";
 
-    void init();
+    void init(int32_t s2rS2dConfig);
     // Stores the initial value to property store.
     void storePropInitialValue(const ConfigDeclaration& config);
     // The callback that would be called when a vehicle property value change happens.
@@ -327,6 +334,8 @@
     static android::base::Result<float> safelyParseFloat(int index, const std::string& s);
     static android::base::Result<int32_t> parsePropId(const std::vector<std::string>& options,
                                                       size_t index);
+    static android::base::Result<int32_t> parseAreaId(const std::vector<std::string>& options,
+                                                      size_t index, int32_t propId);
 };
 
 }  // namespace fake
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index 4f060e2..6695d7a 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -348,6 +348,13 @@
 
 FakeVehicleHardware::FakeVehicleHardware(std::string defaultConfigDir,
                                          std::string overrideConfigDir, bool forceOverride)
+    : FakeVehicleHardware(defaultConfigDir, overrideConfigDir, forceOverride,
+                          /*s2rS2dConfig=*/
+                          GetIntProperty(POWER_STATE_REQ_CONFIG_PROPERTY, /*default_value=*/0)) {}
+
+FakeVehicleHardware::FakeVehicleHardware(std::string defaultConfigDir,
+                                         std::string overrideConfigDir, bool forceOverride,
+                                         int32_t s2rS2dConfig)
     : mValuePool(std::make_unique<VehiclePropValuePool>()),
       mServerSidePropStore(new VehiclePropertyStore(mValuePool)),
       mDefaultConfigDir(defaultConfigDir),
@@ -360,7 +367,7 @@
       mPendingGetValueRequests(this),
       mPendingSetValueRequests(this),
       mForceOverride(forceOverride) {
-    init();
+    init(s2rS2dConfig);
 }
 
 FakeVehicleHardware::~FakeVehicleHardware() {
@@ -388,7 +395,7 @@
     return configsByPropId;
 }
 
-void FakeVehicleHardware::init() {
+void FakeVehicleHardware::init(int32_t s2rS2dConfig) {
     maybeGetGrpcServiceInfo(&mPowerControllerServiceAddress);
 
     for (auto& [_, configDeclaration] : loadConfigDeclarations()) {
@@ -396,8 +403,7 @@
         VehiclePropertyStore::TokenFunction tokenFunction = nullptr;
 
         if (cfg.prop == toInt(VehicleProperty::AP_POWER_STATE_REQ)) {
-            int config = GetIntProperty(POWER_STATE_REQ_CONFIG_PROPERTY, /*default_value=*/0);
-            cfg.configArray[0] = config;
+            cfg.configArray[0] = s2rS2dConfig;
         } else if (cfg.prop == OBD2_FREEZE_FRAME) {
             tokenFunction = [](const VehiclePropValue& propValue) { return propValue.timestamp; };
         }
@@ -1047,6 +1053,10 @@
     VhalResult<void> isAdasPropertyAvailableResult;
     VhalResult<bool> isCruiseControlTypeStandardResult;
     switch (propId) {
+        case toInt(VehicleProperty::DISPLAY_BRIGHTNESS):
+        case toInt(VehicleProperty::PER_DISPLAY_BRIGHTNESS):
+            ALOGD("DISPLAY_BRIGHTNESS: %s", value.toString().c_str());
+            return {};
         case toInt(VehicleProperty::AP_POWER_STATE_REPORT):
             *isSpecialValue = true;
             return setApPowerStateReport(value);
@@ -1902,6 +1912,37 @@
     return safelyParseInt<int32_t>(index, propIdStr);
 }
 
+// Parses areaId option ("-a"). It can be an Integer or a string in the form of "AREA_1" or
+// "AREA_1 | AREA_2 | ..."
+Result<int32_t> FakeVehicleHardware::parseAreaId(const std::vector<std::string>& options,
+                                                 size_t index, int32_t propId) {
+    const std::string& areaIdStr = options[index];
+    auto result = safelyParseInt<int32_t>(index, areaIdStr);
+    if (result.ok()) {
+        return result;
+    }
+
+    // Check for pattern matching "AREA_1 | AREA_2 | AREA_3".
+    std::regex pattern(R"(^\w+(?:( )?\|( )?\w+)*$)");
+    std::smatch match;
+    int32_t areaId = 0;
+    if (!std::regex_match(areaIdStr, match, pattern)) {
+        return result;
+    }
+    pattern = R"(\w+)";
+
+    std::sregex_iterator end;
+    for (std::sregex_iterator it(areaIdStr.begin(), areaIdStr.end(), pattern); it != end; it++) {
+        // Parse each areas contained in this areaId.
+        auto result = stringToArea(it->str(), propId);
+        if (!result.ok()) {
+            return result;
+        }
+        areaId |= result.value();
+    }
+    return areaId;
+}
+
 std::string FakeVehicleHardware::dumpSpecificProperty(const std::vector<std::string>& options) {
     if (auto result = checkArgumentsSize(options, /*minSize=*/2); !result.ok()) {
         return getErrorMsg(result);
@@ -1958,6 +1999,7 @@
     prop.status = VehiclePropertyStatus::AVAILABLE;
     optionIndex++;
     std::unordered_set<std::string> parsedOptions;
+    int32_t areaIdIndex = -1;
 
     while (optionIndex < options.size()) {
         std::string argType = options[optionIndex];
@@ -2032,13 +2074,7 @@
             if (argValuesSize != 1) {
                 return Error() << "Expect exact one value when using \"-a\"\n";
             }
-            auto int32Result = safelyParseInt<int32_t>(currentIndex, argValues[0]);
-            if (!int32Result.ok()) {
-                return Error() << StringPrintf("Area ID: \"%s\" is not a valid int: %s\n",
-                                               argValues[0].c_str(),
-                                               getErrorMsg(int32Result).c_str());
-            }
-            prop.areaId = int32Result.value();
+            areaIdIndex = currentIndex;
         } else if (EqualsIgnoreCase(argType, "-t")) {
             if (argValuesSize != 1) {
                 return Error() << "Expect exact one value when using \"-t\"\n";
@@ -2055,6 +2091,17 @@
         }
     }
 
+    if (areaIdIndex != -1) {
+        auto int32Result = parseAreaId(options, areaIdIndex, prop.prop);
+        if (!int32Result.ok()) {
+            return Error() << StringPrintf(
+                           "Area ID: \"%s\" is not a valid int or "
+                           "one or more area names: %s\n",
+                           options[areaIdIndex].c_str(), getErrorMsg(int32Result).c_str());
+        }
+        prop.areaId = int32Result.value();
+    }
+
     return prop;
 }
 
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
index 9f002dd..62c1147 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
@@ -40,10 +40,10 @@
         "FakeUserHal",
         "libgtest",
         "libgmock",
+        "libjsoncpp",
     ],
     shared_libs: [
         "libgrpc++",
-        "libjsoncpp",
         "libprotobuf-cpp-full",
     ],
     data: [
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
index 0924360..f6098ca 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -20,6 +20,7 @@
 #include <FakeUserHal.h>
 #include <PropertyUtils.h>
 
+#include <aidl/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.h>
 #include <aidl/android/hardware/automotive/vehicle/VehicleApPowerStateShutdownParam.h>
 #include <android/hardware/automotive/vehicle/TestVendorProperty.h>
 
@@ -73,10 +74,12 @@
 using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
 using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
+using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateConfigFlag;
 using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReport;
 using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq;
 using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateShutdownParam;
 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaMirror;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaSeat;
 using ::aidl::android::hardware::automotive::vehicle::VehicleHwKeyInputAction;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
@@ -1870,7 +1873,7 @@
 
 TEST_F(FakeVehicleHardwareTest, testGetHvacPropNotAvailable) {
     FakeVehicleHardwareTestHelper helper(getHardware());
-    auto hvacPowerOnConfig = std::move(getVehiclePropConfig(toInt(VehicleProperty::HVAC_POWER_ON)));
+    auto hvacPowerOnConfig = getVehiclePropConfig(toInt(VehicleProperty::HVAC_POWER_ON));
     EXPECT_NE(hvacPowerOnConfig, nullptr);
     for (auto& hvacPowerOnAreaConfig : hvacPowerOnConfig->areaConfigs) {
         int hvacPowerAreaId = hvacPowerOnAreaConfig.areaId;
@@ -1881,7 +1884,7 @@
         EXPECT_EQ(status, StatusCode::OK);
 
         for (auto& powerPropId : helper.getHvacPowerDependentProps()) {
-            auto powerPropConfig = std::move(getVehiclePropConfig(powerPropId));
+            auto powerPropConfig = getVehiclePropConfig(powerPropId);
             EXPECT_NE(powerPropConfig, nullptr);
             if (powerPropConfig->access == VehiclePropertyAccess::WRITE) {
                 continue;
@@ -1917,7 +1920,7 @@
 
 TEST_F(FakeVehicleHardwareTest, testSetHvacPropNotAvailable) {
     FakeVehicleHardwareTestHelper helper(getHardware());
-    auto hvacPowerOnConfig = std::move(getVehiclePropConfig(toInt(VehicleProperty::HVAC_POWER_ON)));
+    auto hvacPowerOnConfig = getVehiclePropConfig(toInt(VehicleProperty::HVAC_POWER_ON));
     EXPECT_NE(hvacPowerOnConfig, nullptr);
     for (auto& hvacPowerOnAreaConfig : hvacPowerOnConfig->areaConfigs) {
         int hvacPowerAreaId = hvacPowerOnAreaConfig.areaId;
@@ -1928,7 +1931,7 @@
         EXPECT_EQ(status, StatusCode::OK);
 
         for (auto& powerPropId : helper.getHvacPowerDependentProps()) {
-            auto powerPropConfig = std::move(getVehiclePropConfig(powerPropId));
+            auto powerPropConfig = getVehiclePropConfig(powerPropId);
             EXPECT_NE(powerPropConfig, nullptr);
             if (powerPropConfig->access == VehiclePropertyAccess::READ) {
                 continue;
@@ -1967,7 +1970,7 @@
 
 TEST_F(FakeVehicleHardwareTest, testHvacPowerOnSendCurrentHvacPropValues) {
     FakeVehicleHardwareTestHelper helper(getHardware());
-    auto hvacPowerOnConfig = std::move(getVehiclePropConfig(toInt(VehicleProperty::HVAC_POWER_ON)));
+    auto hvacPowerOnConfig = getVehiclePropConfig(toInt(VehicleProperty::HVAC_POWER_ON));
     EXPECT_NE(hvacPowerOnConfig, nullptr);
     for (auto& hvacPowerOnAreaConfig : hvacPowerOnConfig->areaConfigs) {
         int hvacPowerAreaId = hvacPowerOnAreaConfig.areaId;
@@ -2006,9 +2009,9 @@
 }
 
 TEST_F(FakeVehicleHardwareTest, testHvacDualOnSynchronizesTemp) {
-    auto hvacDualOnConfig = std::move(getVehiclePropConfig(toInt(VehicleProperty::HVAC_DUAL_ON)));
+    auto hvacDualOnConfig = getVehiclePropConfig(toInt(VehicleProperty::HVAC_DUAL_ON));
     auto hvacTemperatureSetConfig =
-            std::move(getVehiclePropConfig(toInt(VehicleProperty::HVAC_TEMPERATURE_SET)));
+            getVehiclePropConfig(toInt(VehicleProperty::HVAC_TEMPERATURE_SET));
     EXPECT_NE(hvacDualOnConfig, nullptr);
     EXPECT_NE(hvacTemperatureSetConfig, nullptr);
     for (auto& hvacTemperatureSetConfig : hvacTemperatureSetConfig->areaConfigs) {
@@ -2781,6 +2784,8 @@
 
 std::vector<SetPropTestCase> GenSetPropParams() {
     std::string infoMakeProperty = std::to_string(toInt(VehicleProperty::INFO_MAKE));
+    std::string testVendorProperty =
+            std::to_string(toInt(TestVendorProperty::VENDOR_EXTENSION_FLOAT_PROPERTY));
     return {
             {"success_set_string", {"--set", infoMakeProperty, "-s", CAR_MAKE}, true},
             {"success_set_with_name", {"--set", "INFO_MAKE", "-s", CAR_MAKE}, true},
@@ -2889,6 +2894,14 @@
              {"--set", infoMakeProperty, "-a", "-s", CAR_MAKE},
              false,
              "Expect exact one value"},
+            {"fail_invalid_area_name",
+             {"--set", testVendorProperty, "-a", "ROW_1_LEFT|NO_SUCH_AREA", "-f", "1.234"},
+             false,
+             "not a valid int or one or more area names"},
+            {"fail_invalid_area_format",
+             {"--set", testVendorProperty, "-a", "ROW_1_LEFT|||ROW_2_LEFT", "-f", "1.234"},
+             false,
+             "not a valid int or one or more area names"},
     };
 }
 
@@ -2933,6 +2946,86 @@
     ASSERT_EQ(3.402823466E+38f, value.value.floatValues[2]);
 }
 
+TEST_F(FakeVehicleHardwareTest, SetPropertyWithPropertyNameAreaId) {
+    int32_t areaId = toInt(VehicleAreaSeat::ROW_1_LEFT);
+    getHardware()->dump(
+            {"--set", "HVAC_TEMPERATURE_SET", "-a", std::to_string(areaId), "-f", "22.345"});
+
+    VehiclePropValue requestProp;
+    requestProp.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET);
+    requestProp.areaId = areaId;
+    auto result = getValue(requestProp);
+
+    ASSERT_TRUE(result.ok());
+    VehiclePropValue value = result.value();
+    ASSERT_EQ(value.prop, toInt(VehicleProperty::HVAC_TEMPERATURE_SET));
+    ASSERT_EQ(value.areaId, areaId);
+    ASSERT_EQ(1u, value.value.floatValues.size());
+    ASSERT_EQ(22.345f, value.value.floatValues[0]);
+}
+
+TEST_F(FakeVehicleHardwareTest, SetPropertyWithPropertyNameAreaName) {
+    int32_t areaId = toInt(VehicleAreaSeat::ROW_1_LEFT);
+    getHardware()->dump({"--set", "HVAC_TEMPERATURE_SET", "-a", "ROW_1_LEFT", "-f", "22.345"});
+
+    VehiclePropValue requestProp;
+    requestProp.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET);
+    requestProp.areaId = areaId;
+    auto result = getValue(requestProp);
+
+    ASSERT_TRUE(result.ok());
+    VehiclePropValue value = result.value();
+    ASSERT_EQ(value.prop, toInt(VehicleProperty::HVAC_TEMPERATURE_SET));
+    ASSERT_EQ(value.areaId, areaId);
+    ASSERT_EQ(1u, value.value.floatValues.size());
+    ASSERT_EQ(22.345f, value.value.floatValues[0]);
+}
+
+TEST_F(FakeVehicleHardwareTest, GetPropertyWithPropertyNameAreaName) {
+    auto result = getHardware()->dump({"--get", "HVAC_TEMPERATURE_SET", "-a", "ROW_1_LEFT"});
+
+    // Default value is 17
+    ASSERT_THAT(result.buffer, ContainsRegex("17"));
+
+    getHardware()->dump({"--set", "HVAC_TEMPERATURE_SET", "-a", "ROW_1_LEFT", "-f", "22"});
+    result = getHardware()->dump({"--get", "HVAC_TEMPERATURE_SET", "-a", "ROW_1_LEFT"});
+
+    ASSERT_THAT(result.buffer, ContainsRegex("22"));
+}
+
+TEST_F(FakeVehicleHardwareTest, SetPropertyWithPropertyNameTwoAreasInOneId) {
+    int32_t propId = toInt(TestVendorProperty::VENDOR_EXTENSION_FLOAT_PROPERTY);
+    std::string testVendorProperty = std::to_string(propId);
+    getHardware()->dump({"--set", testVendorProperty, "-a", "ROW_1_LEFT|ROW_2_LEFT|ROW_2_CENTER",
+                         "-f", "1.234"});
+
+    VehiclePropValue requestProp;
+    requestProp.prop = propId;
+    int32_t areaId = toInt(VehicleAreaSeat::ROW_1_LEFT) | toInt(VehicleAreaSeat::ROW_2_LEFT) |
+                     toInt(VehicleAreaSeat::ROW_2_CENTER);
+    requestProp.areaId = areaId;
+    auto result = getValue(requestProp);
+
+    ASSERT_TRUE(result.ok());
+    VehiclePropValue value = result.value();
+    ASSERT_EQ(value.prop, propId);
+    ASSERT_EQ(value.areaId, areaId);
+    ASSERT_EQ(1u, value.value.floatValues.size());
+    ASSERT_EQ(1.234f, value.value.floatValues[0]);
+
+    // Ignore space between two areas.
+    getHardware()->dump({"--set", testVendorProperty, "-a",
+                         "ROW_1_LEFT | ROW_2_LEFT | ROW_2_CENTER", "-f", "2.345"});
+    result = getValue(requestProp);
+
+    ASSERT_TRUE(result.ok());
+    value = result.value();
+    ASSERT_EQ(value.prop, propId);
+    ASSERT_EQ(value.areaId, areaId);
+    ASSERT_EQ(1u, value.value.floatValues.size());
+    ASSERT_EQ(2.345f, value.value.floatValues[0]);
+}
+
 struct OptionsTestCase {
     std::string name;
     std::vector<std::string> options;
@@ -3514,7 +3607,7 @@
     // Config array values from HVAC_TEMPERATURE_SET in DefaultProperties.json
     auto configs = getHardware()->getAllPropertyConfigs();
     auto hvacTemperatureSetConfig =
-            std::move(getVehiclePropConfig(toInt(VehicleProperty::HVAC_TEMPERATURE_SET)));
+            getVehiclePropConfig(toInt(VehicleProperty::HVAC_TEMPERATURE_SET));
     EXPECT_NE(hvacTemperatureSetConfig, nullptr);
 
     auto& hvacTemperatureSetConfigArray = hvacTemperatureSetConfig->configArray;
@@ -3772,6 +3865,25 @@
     }
 }
 
+TEST_F(FakeVehicleHardwareTest, testOverrideApPowerStateReqConfig) {
+    auto hardware = std::make_unique<FakeVehicleHardware>(
+            android::base::GetExecutableDirectory(),
+            /*overrideConfigDir=*/"",
+            /*forceOverride=*/false,
+            toInt(VehicleApPowerStateConfigFlag::ENABLE_DEEP_SLEEP_FLAG) |
+                    toInt(VehicleApPowerStateConfigFlag::ENABLE_HIBERNATION_FLAG));
+
+    std::vector<VehiclePropConfig> configs = hardware->getAllPropertyConfigs();
+
+    for (const auto& config : configs) {
+        if (config.prop != toInt(VehicleProperty::AP_POWER_STATE_REQ)) {
+            continue;
+        }
+        ASSERT_EQ(config.configArray[0], 0x5);
+        break;
+    }
+}
+
 }  // namespace fake
 }  // namespace vehicle
 }  // namespace automotive
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
index f44573a..8750375 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
@@ -20,6 +20,7 @@
 
 #include <android-base/logging.h>
 #include <grpc++/grpc++.h>
+#include <utils/SystemClock.h>
 
 #include <cstdlib>
 #include <mutex>
@@ -28,11 +29,16 @@
 
 namespace android::hardware::automotive::vehicle::virtualization {
 
-static std::shared_ptr<::grpc::ChannelCredentials> getChannelCredentials() {
-    // TODO(chenhaosjtuacm): get secured credentials here
+namespace {
+
+constexpr size_t MAX_RETRY_COUNT = 5;
+
+std::shared_ptr<::grpc::ChannelCredentials> getChannelCredentials() {
     return ::grpc::InsecureChannelCredentials();
 }
 
+}  // namespace
+
 GRPCVehicleHardware::GRPCVehicleHardware(std::string service_addr)
     : mServiceAddr(std::move(service_addr)),
       mGrpcChannel(::grpc::CreateChannel(mServiceAddr, getChannelCredentials())),
@@ -40,11 +46,13 @@
       mValuePollingThread([this] { ValuePollingLoop(); }) {}
 
 // Only used for unit testing.
-GRPCVehicleHardware::GRPCVehicleHardware(std::unique_ptr<proto::VehicleServer::StubInterface> stub)
-    : mServiceAddr(""),
-      mGrpcChannel(nullptr),
-      mGrpcStub(std::move(stub)),
-      mValuePollingThread([] {}) {}
+GRPCVehicleHardware::GRPCVehicleHardware(std::unique_ptr<proto::VehicleServer::StubInterface> stub,
+                                         bool startValuePollingLoop)
+    : mServiceAddr(""), mGrpcChannel(nullptr), mGrpcStub(std::move(stub)) {
+    if (startValuePollingLoop) {
+        mValuePollingThread = std::thread([this] { ValuePollingLoop(); });
+    }
+}
 
 GRPCVehicleHardware::~GRPCVehicleHardware() {
     {
@@ -52,7 +60,9 @@
         mShuttingDownFlag.store(true);
     }
     mShutdownCV.notify_all();
-    mValuePollingThread.join();
+    if (mValuePollingThread.joinable()) {
+        mValuePollingThread.join();
+    }
 }
 
 std::vector<aidlvhal::VehiclePropConfig> GRPCVehicleHardware::getAllPropertyConfigs() const {
@@ -73,6 +83,17 @@
     return configs;
 }
 
+std::optional<aidlvhal::VehiclePropConfig> GRPCVehicleHardware::getPropertyConfig(
+        int32_t propId) const {
+    // TODO(b/354055835): Use GRPC call to get one config instead of getting all the configs.
+    for (const auto& config : getAllPropertyConfigs()) {
+        if (config.prop == propId) {
+            return config;
+        }
+    }
+    return std::nullopt;
+}
+
 aidlvhal::StatusCode GRPCVehicleHardware::setValues(
         std::shared_ptr<const SetValuesCallback> callback,
         const std::vector<aidlvhal::SetValueRequest>& requests) {
@@ -109,36 +130,117 @@
 aidlvhal::StatusCode GRPCVehicleHardware::getValues(
         std::shared_ptr<const GetValuesCallback> callback,
         const std::vector<aidlvhal::GetValueRequest>& requests) const {
-    ::grpc::ClientContext context;
+    std::vector<aidlvhal::GetValueResult> results;
+    auto status = getValuesWithRetry(requests, &results, /*retryCount=*/0);
+    if (status != aidlvhal::StatusCode::OK) {
+        return status;
+    }
+    if (!results.empty()) {
+        (*callback)(std::move(results));
+    }
+    return status;
+}
+
+aidlvhal::StatusCode GRPCVehicleHardware::getValuesWithRetry(
+        const std::vector<aidlvhal::GetValueRequest>& requests,
+        std::vector<aidlvhal::GetValueResult>* results, size_t retryCount) const {
+    if (retryCount == MAX_RETRY_COUNT) {
+        LOG(ERROR) << __func__ << ": GRPC GetValues Failed, failed to get the latest value after "
+                   << retryCount << " retries";
+        return aidlvhal::StatusCode::TRY_AGAIN;
+    }
+
     proto::VehiclePropValueRequests protoRequests;
-    proto::GetValueResults protoResults;
+    std::unordered_map<int64_t, const aidlvhal::GetValueRequest*> requestById;
     for (const auto& request : requests) {
         auto& protoRequest = *protoRequests.add_requests();
         protoRequest.set_request_id(request.requestId);
         proto_msg_converter::aidlToProto(request.prop, protoRequest.mutable_value());
+        requestById[request.requestId] = &request;
     }
+
     // TODO(chenhaosjtuacm): Make it Async.
+    ::grpc::ClientContext context;
+    proto::GetValueResults protoResults;
     auto grpc_status = mGrpcStub->GetValues(&context, protoRequests, &protoResults);
     if (!grpc_status.ok()) {
         LOG(ERROR) << __func__ << ": GRPC GetValues Failed: " << grpc_status.error_message();
         return aidlvhal::StatusCode::INTERNAL_ERROR;
     }
-    std::vector<aidlvhal::GetValueResult> results;
+
+    std::vector<aidlvhal::GetValueRequest> retryRequests;
     for (const auto& protoResult : protoResults.results()) {
-        auto& result = results.emplace_back();
-        result.requestId = protoResult.request_id();
-        result.status = static_cast<aidlvhal::StatusCode>(protoResult.status());
-        if (protoResult.has_value()) {
-            aidlvhal::VehiclePropValue value;
-            proto_msg_converter::protoToAidl(protoResult.value(), &value);
-            result.prop = std::move(value);
+        int64_t requestId = protoResult.request_id();
+        auto it = requestById.find(requestId);
+        if (it == requestById.end()) {
+            LOG(ERROR) << __func__
+                       << "Invalid getValue request with unknown request ID: " << requestId
+                       << ", ignore";
+            continue;
         }
+
+        if (!protoResult.has_value()) {
+            auto& result = results->emplace_back();
+            result.requestId = requestId;
+            result.status = static_cast<aidlvhal::StatusCode>(protoResult.status());
+            continue;
+        }
+
+        aidlvhal::VehiclePropValue value;
+        proto_msg_converter::protoToAidl(protoResult.value(), &value);
+
+        // VHAL proxy server uses a different timestamp then AAOS timestamp, so we have to reset
+        // the timestamp.
+        // TODO(b/350822044): Remove this once we use timestamp from proxy server.
+        if (!setAndroidTimestamp(&value)) {
+            // This is a rare case when we receive a property update event reflecting a new value
+            // for the property before we receive the get value result. This means that the result
+            // is already outdated, hence we should retry getting the latest value again.
+            LOG(WARNING) << __func__ << "getValue result for propId: " << value.prop
+                         << " areaId: " << value.areaId << " is oudated, retry";
+            retryRequests.push_back(*(it->second));
+            continue;
+        }
+
+        auto& result = results->emplace_back();
+        result.requestId = requestId;
+        result.status = static_cast<aidlvhal::StatusCode>(protoResult.status());
+        result.prop = std::move(value);
     }
-    (*callback)(std::move(results));
+
+    if (retryRequests.size() != 0) {
+        return getValuesWithRetry(retryRequests, results, retryCount++);
+    }
 
     return aidlvhal::StatusCode::OK;
 }
 
+bool GRPCVehicleHardware::setAndroidTimestamp(aidlvhal::VehiclePropValue* propValue) const {
+    PropIdAreaId propIdAreaId = {
+            .propId = propValue->prop,
+            .areaId = propValue->areaId,
+    };
+    int64_t now = elapsedRealtimeNano();
+    int64_t externalTimestamp = propValue->timestamp;
+
+    {
+        std::lock_guard lck(mLatestUpdateTimestampsMutex);
+        auto it = mLatestUpdateTimestamps.find(propIdAreaId);
+        if (it == mLatestUpdateTimestamps.end() || externalTimestamp > (it->second).first) {
+            mLatestUpdateTimestamps[propIdAreaId].first = externalTimestamp;
+            mLatestUpdateTimestamps[propIdAreaId].second = now;
+            propValue->timestamp = now;
+            return true;
+        }
+        if (externalTimestamp == (it->second).first) {
+            propValue->timestamp = (it->second).second;
+            return true;
+        }
+    }
+    // externalTimestamp < (it->second).first, the value is outdated.
+    return false;
+}
+
 void GRPCVehicleHardware::registerOnPropertyChangeEvent(
         std::unique_ptr<const PropertyChangeCallback> callback) {
     std::lock_guard lck(mCallbackMutex);
@@ -174,6 +276,7 @@
     return {
             .callerShouldDumpState = protoDumpResult.caller_should_dump_state(),
             .buffer = protoDumpResult.buffer(),
+            .refreshPropertyConfigs = protoDumpResult.refresh_property_configs(),
     };
 }
 
@@ -248,46 +351,61 @@
 
 void GRPCVehicleHardware::ValuePollingLoop() {
     while (!mShuttingDownFlag.load()) {
-        ::grpc::ClientContext context;
-
-        bool rpc_stopped{false};
-        std::thread shuttingdown_watcher([this, &rpc_stopped, &context]() {
-            std::unique_lock<std::mutex> lck(mShutdownMutex);
-            mShutdownCV.wait(lck, [this, &rpc_stopped]() {
-                return rpc_stopped || mShuttingDownFlag.load();
-            });
-            context.TryCancel();
-        });
-
-        auto value_stream =
-                mGrpcStub->StartPropertyValuesStream(&context, ::google::protobuf::Empty());
-        LOG(INFO) << __func__ << ": GRPC Value Streaming Started";
-        proto::VehiclePropValues protoValues;
-        while (!mShuttingDownFlag.load() && value_stream->Read(&protoValues)) {
-            std::vector<aidlvhal::VehiclePropValue> values;
-            for (const auto protoValue : protoValues.values()) {
-                values.push_back(aidlvhal::VehiclePropValue());
-                proto_msg_converter::protoToAidl(protoValue, &values.back());
-            }
-            std::shared_lock lck(mCallbackMutex);
-            if (mOnPropChange) {
-                (*mOnPropChange)(values);
-            }
-        }
-
-        {
-            std::lock_guard lck(mShutdownMutex);
-            rpc_stopped = true;
-        }
-        mShutdownCV.notify_all();
-        shuttingdown_watcher.join();
-
-        auto grpc_status = value_stream->Finish();
-        // never reach here until connection lost
-        LOG(ERROR) << __func__ << ": GRPC Value Streaming Failed: " << grpc_status.error_message();
-
+        pollValue();
         // try to reconnect
     }
 }
 
+void GRPCVehicleHardware::pollValue() {
+    ::grpc::ClientContext context;
+
+    bool rpc_stopped{false};
+    std::thread shuttingdown_watcher([this, &rpc_stopped, &context]() {
+        std::unique_lock<std::mutex> lck(mShutdownMutex);
+        mShutdownCV.wait(
+                lck, [this, &rpc_stopped]() { return rpc_stopped || mShuttingDownFlag.load(); });
+        context.TryCancel();
+    });
+
+    auto value_stream = mGrpcStub->StartPropertyValuesStream(&context, ::google::protobuf::Empty());
+    LOG(INFO) << __func__ << ": GRPC Value Streaming Started";
+    proto::VehiclePropValues protoValues;
+    while (!mShuttingDownFlag.load() && value_stream->Read(&protoValues)) {
+        std::vector<aidlvhal::VehiclePropValue> values;
+        for (const auto protoValue : protoValues.values()) {
+            aidlvhal::VehiclePropValue aidlValue = {};
+            proto_msg_converter::protoToAidl(protoValue, &aidlValue);
+
+            // VHAL proxy server uses a different timestamp then AAOS timestamp, so we have to
+            // reset the timestamp.
+            // TODO(b/350822044): Remove this once we use timestamp from proxy server.
+            if (!setAndroidTimestamp(&aidlValue)) {
+                LOG(WARNING) << __func__ << ": property event for propId: " << aidlValue.prop
+                             << " areaId: " << aidlValue.areaId << " is outdated, ignore";
+                continue;
+            }
+
+            values.push_back(std::move(aidlValue));
+        }
+        if (values.empty()) {
+            continue;
+        }
+        std::shared_lock lck(mCallbackMutex);
+        if (mOnPropChange) {
+            (*mOnPropChange)(values);
+        }
+    }
+
+    {
+        std::lock_guard lck(mShutdownMutex);
+        rpc_stopped = true;
+    }
+    mShutdownCV.notify_all();
+    shuttingdown_watcher.join();
+
+    auto grpc_status = value_stream->Finish();
+    // never reach here until connection lost
+    LOG(ERROR) << __func__ << ": GRPC Value Streaming Failed: " << grpc_status.error_message();
+}
+
 }  // namespace android::hardware::automotive::vehicle::virtualization
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
index 9750f62..15f473c 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
@@ -20,6 +20,7 @@
 #include <VehicleHalTypes.h>
 #include <VehicleUtils.h>
 #include <android-base/result.h>
+#include <android-base/thread_annotations.h>
 
 #include "VehicleServer.grpc.pb.h"
 #include "VehicleServer.pb.h"
@@ -33,6 +34,7 @@
 #include <shared_mutex>
 #include <string>
 #include <thread>
+#include <unordered_map>
 #include <vector>
 
 namespace android::hardware::automotive::vehicle::virtualization {
@@ -43,14 +45,15 @@
   public:
     explicit GRPCVehicleHardware(std::string service_addr);
 
-    // Only used for unit testing.
-    explicit GRPCVehicleHardware(std::unique_ptr<proto::VehicleServer::StubInterface> stub);
-
     ~GRPCVehicleHardware();
 
     // Get all the property configs.
     std::vector<aidlvhal::VehiclePropConfig> getAllPropertyConfigs() const override;
 
+    // Get the config for the specified propId.
+    std::optional<aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
+    getPropertyConfig(int32_t propId) const override;
+
     // Set property values asynchronously. Server could return before the property set requests
     // are sent to vehicle bus or before property set confirmation is received. The callback is
     // safe to be called after the function returns and is safe to be called in a different thread.
@@ -94,7 +97,7 @@
     std::unique_ptr<const PropertyChangeCallback> mOnPropChange;
 
   private:
-    void ValuePollingLoop();
+    friend class GRPCVehicleHardwareUnitTest;
 
     std::string mServiceAddr;
     std::shared_ptr<::grpc::Channel> mGrpcChannel;
@@ -106,6 +109,31 @@
     std::mutex mShutdownMutex;
     std::condition_variable mShutdownCV;
     std::atomic<bool> mShuttingDownFlag{false};
+
+    mutable std::mutex mLatestUpdateTimestampsMutex;
+
+    // A map from [propId, areaId] to the latest timestamp this property is updated.
+    // The key is a tuple, the first element is the external timestamp (timestamp set by VHAL
+    // server), the second element is the Android timestamp (elapsedRealtimeNano).
+    mutable std::unordered_map<PropIdAreaId, std::pair<int64_t, int64_t>,
+                               PropIdAreaIdHash> mLatestUpdateTimestamps
+            GUARDED_BY(mLatestUpdateTimestampsMutex);
+
+    // Only used for unit testing.
+    GRPCVehicleHardware(std::unique_ptr<proto::VehicleServer::StubInterface> stub,
+                        bool startValuePollingLoop);
+
+    void ValuePollingLoop();
+    void pollValue();
+
+    aidlvhal::StatusCode getValuesWithRetry(const std::vector<aidlvhal::GetValueRequest>& requests,
+                                            std::vector<aidlvhal::GetValueResult>* results,
+                                            size_t retryCount) const;
+
+    // Check the external timestamp of propValue against the latest updated external timestamp, if
+    // this is an outdated value, return false. Otherwise, update the external timestamp to the
+    // Android timestamp and return true.
+    bool setAndroidTimestamp(aidlvhal::VehiclePropValue* propValue) const;
 };
 
 }  // namespace android::hardware::automotive::vehicle::virtualization
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
index a6abfa3..7697c03 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
@@ -40,7 +40,11 @@
 
 GrpcVehicleProxyServer::GrpcVehicleProxyServer(std::string serverAddr,
                                                std::unique_ptr<IVehicleHardware>&& hardware)
-    : mServiceAddr(std::move(serverAddr)), mHardware(std::move(hardware)) {
+    : GrpcVehicleProxyServer(std::vector<std::string>({serverAddr}), std::move(hardware)){};
+
+GrpcVehicleProxyServer::GrpcVehicleProxyServer(std::vector<std::string> serverAddrs,
+                                               std::unique_ptr<IVehicleHardware>&& hardware)
+    : mServiceAddrs(std::move(serverAddrs)), mHardware(std::move(hardware)) {
     mHardware->registerOnPropertyChangeEvent(
             std::make_unique<const IVehicleHardware::PropertyChangeCallback>(
                     [this](std::vector<aidlvhal::VehiclePropValue> values) {
@@ -65,10 +69,13 @@
                                                  const proto::VehiclePropValueRequests* requests,
                                                  proto::SetValueResults* results) {
     std::vector<aidlvhal::SetValueRequest> aidlRequests;
+    std::unordered_set<int64_t> requestIds;
     for (const auto& protoRequest : requests->requests()) {
         auto& aidlRequest = aidlRequests.emplace_back();
-        aidlRequest.requestId = protoRequest.request_id();
+        int64_t requestId = protoRequest.request_id();
+        aidlRequest.requestId = requestId;
         proto_msg_converter::protoToAidl(protoRequest.value(), &aidlRequest.value);
+        requestIds.insert(requestId);
     }
     auto waitMtx = std::make_shared<std::mutex>();
     auto waitCV = std::make_shared<std::condition_variable>();
@@ -76,19 +83,27 @@
     auto tmpResults = std::make_shared<proto::SetValueResults>();
     auto aidlStatus = mHardware->setValues(
             std::make_shared<const IVehicleHardware::SetValuesCallback>(
-                    [waitMtx, waitCV, complete,
-                     tmpResults](std::vector<aidlvhal::SetValueResult> setValueResults) {
-                        for (const auto& aidlResult : setValueResults) {
-                            auto& protoResult = *tmpResults->add_results();
-                            protoResult.set_request_id(aidlResult.requestId);
-                            protoResult.set_status(
-                                    static_cast<proto::StatusCode>(aidlResult.status));
-                        }
+                    [waitMtx, waitCV, complete, tmpResults,
+                     &requestIds](std::vector<aidlvhal::SetValueResult> setValueResults) {
+                        bool receivedAllResults = false;
                         {
                             std::lock_guard lck(*waitMtx);
-                            *complete = true;
+                            for (const auto& aidlResult : setValueResults) {
+                                auto& protoResult = *tmpResults->add_results();
+                                int64_t requestIdForResult = aidlResult.requestId;
+                                protoResult.set_request_id(requestIdForResult);
+                                protoResult.set_status(
+                                        static_cast<proto::StatusCode>(aidlResult.status));
+                                requestIds.erase(requestIdForResult);
+                            }
+                            if (requestIds.empty()) {
+                                receivedAllResults = true;
+                                *complete = true;
+                            }
                         }
-                        waitCV->notify_all();
+                        if (receivedAllResults) {
+                            waitCV->notify_all();
+                        }
                     }),
             aidlRequests);
     if (aidlStatus != aidlvhal::StatusCode::OK) {
@@ -110,10 +125,13 @@
                                                  const proto::VehiclePropValueRequests* requests,
                                                  proto::GetValueResults* results) {
     std::vector<aidlvhal::GetValueRequest> aidlRequests;
+    std::unordered_set<int64_t> requestIds;
     for (const auto& protoRequest : requests->requests()) {
         auto& aidlRequest = aidlRequests.emplace_back();
-        aidlRequest.requestId = protoRequest.request_id();
+        int64_t requestId = protoRequest.request_id();
+        aidlRequest.requestId = requestId;
         proto_msg_converter::protoToAidl(protoRequest.value(), &aidlRequest.prop);
+        requestIds.insert(requestId);
     }
     auto waitMtx = std::make_shared<std::mutex>();
     auto waitCV = std::make_shared<std::condition_variable>();
@@ -121,23 +139,31 @@
     auto tmpResults = std::make_shared<proto::GetValueResults>();
     auto aidlStatus = mHardware->getValues(
             std::make_shared<const IVehicleHardware::GetValuesCallback>(
-                    [waitMtx, waitCV, complete,
-                     tmpResults](std::vector<aidlvhal::GetValueResult> getValueResults) {
-                        for (const auto& aidlResult : getValueResults) {
-                            auto& protoResult = *tmpResults->add_results();
-                            protoResult.set_request_id(aidlResult.requestId);
-                            protoResult.set_status(
-                                    static_cast<proto::StatusCode>(aidlResult.status));
-                            if (aidlResult.prop) {
-                                auto* valuePtr = protoResult.mutable_value();
-                                proto_msg_converter::aidlToProto(*aidlResult.prop, valuePtr);
-                            }
-                        }
+                    [waitMtx, waitCV, complete, tmpResults,
+                     &requestIds](std::vector<aidlvhal::GetValueResult> getValueResults) {
+                        bool receivedAllResults = false;
                         {
                             std::lock_guard lck(*waitMtx);
-                            *complete = true;
+                            for (const auto& aidlResult : getValueResults) {
+                                auto& protoResult = *tmpResults->add_results();
+                                int64_t requestIdForResult = aidlResult.requestId;
+                                protoResult.set_request_id(requestIdForResult);
+                                protoResult.set_status(
+                                        static_cast<proto::StatusCode>(aidlResult.status));
+                                if (aidlResult.prop) {
+                                    auto* valuePtr = protoResult.mutable_value();
+                                    proto_msg_converter::aidlToProto(*aidlResult.prop, valuePtr);
+                                }
+                                requestIds.erase(requestIdForResult);
+                            }
+                            if (requestIds.empty()) {
+                                receivedAllResults = true;
+                                *complete = true;
+                            }
                         }
-                        waitCV->notify_all();
+                        if (receivedAllResults) {
+                            waitCV->notify_all();
+                        }
                     }),
             aidlRequests);
     if (aidlStatus != aidlvhal::StatusCode::OK) {
@@ -200,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;
 }
 
@@ -254,7 +281,9 @@
     }
     ::grpc::ServerBuilder builder;
     builder.RegisterService(this);
-    builder.AddListeningPort(mServiceAddr, getServerCredentials());
+    for (const std::string& serviceAddr : mServiceAddrs) {
+        builder.AddListeningPort(serviceAddr, getServerCredentials());
+    }
     mServer = builder.BuildAndStart();
     CHECK(mServer) << __func__ << ": failed to create the GRPC server, "
                    << "please make sure the configuration and permissions are correct";
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h
index dd9e2aa..5ffb531 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h
@@ -41,6 +41,9 @@
   public:
     GrpcVehicleProxyServer(std::string serverAddr, std::unique_ptr<IVehicleHardware>&& hardware);
 
+    GrpcVehicleProxyServer(std::vector<std::string> serverAddrs,
+                           std::unique_ptr<IVehicleHardware>&& hardware);
+
     ::grpc::Status GetAllPropertyConfig(
             ::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
             ::grpc::ServerWriter<proto::VehiclePropConfig>* stream) override;
@@ -116,7 +119,7 @@
         static std::atomic<uint64_t> connection_id_counter_;
     };
 
-    std::string mServiceAddr;
+    std::vector<std::string> mServiceAddrs;
     std::unique_ptr<::grpc::Server> mServer{nullptr};
     std::unique_ptr<IVehicleHardware> mHardware;
 
diff --git a/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp b/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp
index 3bd7e0e..20af231 100644
--- a/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp
@@ -19,8 +19,10 @@
 
 #include <gmock/gmock.h>
 #include <grpc++/grpc++.h>
+#include <grpcpp/test/mock_stream.h>
 #include <gtest/gtest.h>
 
+#include <utils/SystemClock.h>
 #include <chrono>
 #include <memory>
 #include <string>
@@ -31,98 +33,48 @@
 
 using ::testing::_;
 using ::testing::DoAll;
+using ::testing::ElementsAre;
 using ::testing::NiceMock;
 using ::testing::Return;
 using ::testing::SaveArg;
 using ::testing::SetArgPointee;
+using ::testing::SizeIs;
+
+using ::grpc::testing::MockClientReader;
 
 using proto::MockVehicleServerStub;
 
-const std::string kFakeServerAddr = "0.0.0.0:54321";
-
-class FakeVehicleServer : public proto::VehicleServer::Service {
-  public:
-    ::grpc::Status StartPropertyValuesStream(
-            ::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
-            ::grpc::ServerWriter<proto::VehiclePropValues>* stream) override {
-        stream->Write(proto::VehiclePropValues());
-        // A fake disconnection.
-        return ::grpc::Status(::grpc::StatusCode::ABORTED, "Connection lost.");
-    }
-
-    // Functions that we do not care.
-    ::grpc::Status GetAllPropertyConfig(
-            ::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
-            ::grpc::ServerWriter<proto::VehiclePropConfig>* stream) override {
-        return ::grpc::Status::OK;
-    }
-
-    ::grpc::Status SetValues(::grpc::ServerContext* context,
-                             const proto::VehiclePropValueRequests* requests,
-                             proto::SetValueResults* results) override {
-        return ::grpc::Status::OK;
-    }
-
-    ::grpc::Status GetValues(::grpc::ServerContext* context,
-                             const proto::VehiclePropValueRequests* requests,
-                             proto::GetValueResults* results) override {
-        return ::grpc::Status::OK;
-    }
-};
-
-TEST(GRPCVehicleHardwareUnitTest, Reconnect) {
-    auto receivedUpdate = std::make_shared<std::atomic<int>>(0);
-    auto vehicleHardware = std::make_unique<GRPCVehicleHardware>(kFakeServerAddr);
-    vehicleHardware->registerOnPropertyChangeEvent(
-            std::make_unique<const IVehicleHardware::PropertyChangeCallback>(
-                    [receivedUpdate](const auto&) { receivedUpdate->fetch_add(1); }));
-
-    constexpr size_t kServerRestartTimes = 5;
-    for (size_t serverStart = 0; serverStart < kServerRestartTimes; ++serverStart) {
-        EXPECT_EQ(receivedUpdate->load(), 0);
-        auto fakeServer = std::make_unique<FakeVehicleServer>();
-        ::grpc::ServerBuilder builder;
-        builder.RegisterService(fakeServer.get());
-        builder.AddListeningPort(kFakeServerAddr, ::grpc::InsecureServerCredentials());
-        auto grpcServer = builder.BuildAndStart();
-
-        // Wait until the vehicle hardware received the second update (after one fake
-        // disconnection).
-        constexpr auto kMaxWaitTime = std::chrono::seconds(5);
-        auto startTime = std::chrono::steady_clock::now();
-        while (receivedUpdate->load() <= 1 &&
-               std::chrono::steady_clock::now() - startTime < kMaxWaitTime)
-            ;
-
-        grpcServer->Shutdown();
-        grpcServer->Wait();
-        EXPECT_GT(receivedUpdate->load(), 1);
-
-        // Reset for the next round.
-        receivedUpdate->store(0);
-    }
-}
-
-class GRPCVehicleHardwareMockServerUnitTest : public ::testing::Test {
+class GRPCVehicleHardwareUnitTest : public ::testing::Test {
   protected:
     NiceMock<MockVehicleServerStub>* mGrpcStub;
     std::unique_ptr<GRPCVehicleHardware> mHardware;
 
     void SetUp() override {
         auto stub = std::make_unique<NiceMock<MockVehicleServerStub>>();
-        ;
         mGrpcStub = stub.get();
-        mHardware = std::make_unique<GRPCVehicleHardware>(std::move(stub));
+        // Cannot use make_unique here since the constructor is a private method.
+        mHardware = std::unique_ptr<GRPCVehicleHardware>(
+                new GRPCVehicleHardware(std::move(stub), /*startValuePollingLoop=*/false));
     }
 
     void TearDown() override { mHardware.reset(); }
+
+    // Access GRPCVehicleHardware private method.
+    void pollValue() { mHardware->pollValue(); }
+
+    void startValuePollingLoop(std::unique_ptr<proto::VehicleServer::StubInterface> stub) {
+        mHardware = std::unique_ptr<GRPCVehicleHardware>(
+                new GRPCVehicleHardware(std::move(stub), /*startValuePollingLoop=*/true));
+    }
+
+    void generatePropertyUpdateEvent(int32_t propId, int64_t timestamp);
 };
 
 MATCHER_P(RepeatedInt32Eq, expected_values, "") {
     return std::vector<int32_t>(arg.begin(), arg.end()) == expected_values;
 }
 
-TEST_F(GRPCVehicleHardwareMockServerUnitTest, Subscribe) {
+TEST_F(GRPCVehicleHardwareUnitTest, TestSubscribe) {
     proto::VehicleHalCallStatus protoStatus;
     protoStatus.set_status_code(proto::StatusCode::OK);
     proto::SubscribeRequest actualRequest;
@@ -147,7 +99,7 @@
     EXPECT_EQ(protoOptions.enable_variable_update_rate(), true);
 }
 
-TEST_F(GRPCVehicleHardwareMockServerUnitTest, SubscribeLegacyServer) {
+TEST_F(GRPCVehicleHardwareUnitTest, TestSubscribeLegacyServer) {
     EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
             .WillOnce(Return(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")));
 
@@ -157,7 +109,7 @@
     EXPECT_EQ(status, aidlvhal::StatusCode::OK);
 }
 
-TEST_F(GRPCVehicleHardwareMockServerUnitTest, SubscribeGrpcFailure) {
+TEST_F(GRPCVehicleHardwareUnitTest, TestSubscribeGrpcFailure) {
     EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
             .WillOnce(Return(::grpc::Status(::grpc::StatusCode::INTERNAL, "GRPC Error")));
 
@@ -167,7 +119,7 @@
     EXPECT_EQ(status, aidlvhal::StatusCode::INTERNAL_ERROR);
 }
 
-TEST_F(GRPCVehicleHardwareMockServerUnitTest, SubscribeProtoFailure) {
+TEST_F(GRPCVehicleHardwareUnitTest, TestSubscribeProtoFailure) {
     proto::VehicleHalCallStatus protoStatus;
     protoStatus.set_status_code(proto::StatusCode::NOT_AVAILABLE_SPEED_LOW);
 
@@ -181,7 +133,7 @@
     EXPECT_EQ(status, aidlvhal::StatusCode::NOT_AVAILABLE_SPEED_LOW);
 }
 
-TEST_F(GRPCVehicleHardwareMockServerUnitTest, Unsubscribe) {
+TEST_F(GRPCVehicleHardwareUnitTest, TestUnsubscribe) {
     proto::VehicleHalCallStatus protoStatus;
     protoStatus.set_status_code(proto::StatusCode::OK);
     proto::UnsubscribeRequest actualRequest;
@@ -199,7 +151,7 @@
     EXPECT_EQ(actualRequest.area_id(), areaId);
 }
 
-TEST_F(GRPCVehicleHardwareMockServerUnitTest, UnsubscribeLegacyServer) {
+TEST_F(GRPCVehicleHardwareUnitTest, TestUnsubscribeLegacyServer) {
     EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
             .WillOnce(Return(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")));
 
@@ -208,7 +160,7 @@
     EXPECT_EQ(status, aidlvhal::StatusCode::OK);
 }
 
-TEST_F(GRPCVehicleHardwareMockServerUnitTest, UnsubscribeGrpcFailure) {
+TEST_F(GRPCVehicleHardwareUnitTest, TestUnsubscribeGrpcFailure) {
     EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
             .WillOnce(Return(::grpc::Status(::grpc::StatusCode::INTERNAL, "GRPC Error")));
 
@@ -217,7 +169,7 @@
     EXPECT_EQ(status, aidlvhal::StatusCode::INTERNAL_ERROR);
 }
 
-TEST_F(GRPCVehicleHardwareMockServerUnitTest, UnsubscribeProtoFailure) {
+TEST_F(GRPCVehicleHardwareUnitTest, TestUnsubscribeProtoFailure) {
     proto::VehicleHalCallStatus protoStatus;
     protoStatus.set_status_code(proto::StatusCode::NOT_AVAILABLE_SPEED_LOW);
 
@@ -230,4 +182,264 @@
     EXPECT_EQ(status, aidlvhal::StatusCode::NOT_AVAILABLE_SPEED_LOW);
 }
 
+TEST_F(GRPCVehicleHardwareUnitTest, TestPollValue) {
+    int64_t testTimestamp = 12345;
+    int32_t testPropId = 54321;
+    int64_t startTimestamp = elapsedRealtimeNano();
+
+    // This will be converted to a unique_ptr in StartPropertyValuesStream. The ownership is passed
+    // there.
+    auto clientReader = new MockClientReader<proto::VehiclePropValues>();
+    EXPECT_CALL(*mGrpcStub, StartPropertyValuesStreamRaw(_, _)).WillOnce(Return(clientReader));
+    EXPECT_CALL(*clientReader, Read(_))
+            .WillOnce([testTimestamp, testPropId](proto::VehiclePropValues* values) {
+                values->Clear();
+                auto value = values->add_values();
+                value->set_timestamp(testTimestamp);
+                value->set_prop(testPropId);
+                return true;
+            })
+            .WillOnce(Return(false));
+    EXPECT_CALL(*clientReader, Finish()).WillOnce(Return(::grpc::Status::OK));
+
+    std::vector<aidlvhal::VehiclePropValue> propertyEvents;
+
+    mHardware->registerOnPropertyChangeEvent(
+            std::make_unique<GRPCVehicleHardware::PropertyChangeCallback>(
+                    [&propertyEvents](const std::vector<aidlvhal::VehiclePropValue>& events) {
+                        for (const auto& event : events) {
+                            propertyEvents.push_back(event);
+                        }
+                    }));
+
+    pollValue();
+
+    ASSERT_THAT(propertyEvents, SizeIs(1));
+    EXPECT_EQ(propertyEvents[0].prop, testPropId);
+    EXPECT_GT(propertyEvents[0].timestamp, startTimestamp)
+            << "Timestamp must be updated to Android timestamp";
+    EXPECT_LT(propertyEvents[0].timestamp, elapsedRealtimeNano())
+            << "Timestamp must be updated to Android timestamp";
+}
+
+TEST_F(GRPCVehicleHardwareUnitTest, TestPollValueIgnoreOutdatedValue) {
+    int64_t testTimestamp1 = 12345;
+    int32_t value1 = 1324;
+    int64_t testTimestamp2 = 12340;
+    int32_t value2 = 1423;
+    int32_t testPropId = 54321;
+    int64_t startTimestamp = elapsedRealtimeNano();
+
+    // This will be converted to a unique_ptr in StartPropertyValuesStream. The ownership is passed
+    // there.
+    auto clientReader = new MockClientReader<proto::VehiclePropValues>();
+    EXPECT_CALL(*mGrpcStub, StartPropertyValuesStreamRaw(_, _)).WillOnce(Return(clientReader));
+    EXPECT_CALL(*clientReader, Read(_))
+            .WillOnce([testTimestamp1, value1, testPropId](proto::VehiclePropValues* values) {
+                values->Clear();
+                auto value = values->add_values();
+                value->set_timestamp(testTimestamp1);
+                value->set_prop(testPropId);
+                value->add_int32_values(value1);
+                return true;
+            })
+            .WillOnce([testTimestamp2, value2, testPropId](proto::VehiclePropValues* values) {
+                values->Clear();
+                // This event is outdated, must be ignored.
+                auto value = values->add_values();
+                value->set_timestamp(testTimestamp2);
+                value->set_prop(testPropId);
+                value->add_int32_values(value2);
+                return true;
+            })
+            .WillOnce(Return(false));
+    EXPECT_CALL(*clientReader, Finish()).WillOnce(Return(::grpc::Status::OK));
+
+    std::vector<aidlvhal::VehiclePropValue> propertyEvents;
+
+    mHardware->registerOnPropertyChangeEvent(
+            std::make_unique<GRPCVehicleHardware::PropertyChangeCallback>(
+                    [&propertyEvents](const std::vector<aidlvhal::VehiclePropValue>& events) {
+                        for (const auto& event : events) {
+                            propertyEvents.push_back(event);
+                        }
+                    }));
+
+    pollValue();
+
+    ASSERT_THAT(propertyEvents, SizeIs(1)) << "Outdated event must be ignored";
+    EXPECT_EQ(propertyEvents[0].prop, testPropId);
+    EXPECT_GT(propertyEvents[0].timestamp, startTimestamp);
+    EXPECT_LT(propertyEvents[0].timestamp, elapsedRealtimeNano());
+    EXPECT_THAT(propertyEvents[0].value.int32Values, ElementsAre(value1));
+}
+
+TEST_F(GRPCVehicleHardwareUnitTest, TestValuePollingLoop) {
+    int64_t testTimestamp = 12345;
+    int32_t testPropId = 54321;
+    auto stub = std::make_unique<NiceMock<MockVehicleServerStub>>();
+
+    // This will be converted to a unique_ptr in StartPropertyValuesStream. The ownership is passed
+    // there.
+    auto clientReader = new MockClientReader<proto::VehiclePropValues>();
+    EXPECT_CALL(*stub, StartPropertyValuesStreamRaw(_, _)).WillOnce(Return(clientReader));
+    EXPECT_CALL(*clientReader, Read(_))
+            .WillRepeatedly([testTimestamp, testPropId](proto::VehiclePropValues* values) {
+                // Sleep for 10ms and always return the same property event.
+                std::this_thread::sleep_for(std::chrono::milliseconds(10));
+                values->Clear();
+                auto value = values->add_values();
+                value->set_timestamp(testTimestamp);
+                value->set_prop(testPropId);
+                return true;
+            });
+    EXPECT_CALL(*clientReader, Finish()).WillOnce(Return(::grpc::Status::OK));
+
+    startValuePollingLoop(std::move(stub));
+
+    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+    // This must stop the loop and wait for the thread to finish.
+    mHardware.reset();
+}
+
+TEST_F(GRPCVehicleHardwareUnitTest, TestGetValues) {
+    int64_t testRequestId = 1234;
+    int32_t testPropId = 4321;
+    int32_t testValue = 123456;
+    proto::VehiclePropValueRequests gotRequests;
+    EXPECT_CALL(*mGrpcStub, GetValues(_, _, _))
+            .WillOnce([&gotRequests, testRequestId, testPropId, testValue](
+                              ::grpc::ClientContext* context,
+                              const proto::VehiclePropValueRequests& request,
+                              proto::GetValueResults* response) {
+                gotRequests = request;
+                response->Clear();
+                auto* resultPtr = response->add_results();
+                resultPtr->set_request_id(testRequestId);
+                resultPtr->set_status(proto::StatusCode::OK);
+                auto* valuePtr = resultPtr->mutable_value();
+                valuePtr->set_prop(testPropId);
+                valuePtr->add_int32_values(testValue);
+                return ::grpc::Status::OK;
+            });
+
+    std::vector<aidlvhal::GetValueRequest> requests;
+    requests.push_back(aidlvhal::GetValueRequest{.requestId = testRequestId,
+                                                 .prop = {
+                                                         .prop = testPropId,
+                                                 }});
+
+    std::vector<aidlvhal::GetValueResult> gotResults;
+
+    auto status = mHardware->getValues(
+            std::make_shared<GRPCVehicleHardware::GetValuesCallback>(
+                    [&gotResults](std::vector<aidlvhal::GetValueResult> results) {
+                        for (const auto& result : results) {
+                            gotResults.push_back(result);
+                        }
+                    }),
+            requests);
+
+    ASSERT_EQ(status, aidlvhal::StatusCode::OK);
+    ASSERT_THAT(gotRequests.requests(), SizeIs(1));
+    EXPECT_THAT(gotRequests.requests(0).request_id(), testRequestId);
+    EXPECT_THAT(gotRequests.requests(0).value().prop(), testPropId);
+
+    ASSERT_THAT(gotResults, SizeIs(1));
+    EXPECT_EQ(gotResults[0].requestId, testRequestId);
+    EXPECT_EQ(gotResults[0].status, aidlvhal::StatusCode::OK);
+    EXPECT_EQ(gotResults[0].prop->prop, testPropId);
+    EXPECT_THAT(gotResults[0].prop->value.int32Values, ElementsAre(testValue));
+}
+
+void GRPCVehicleHardwareUnitTest::generatePropertyUpdateEvent(int32_t propId, int64_t timestamp) {
+    // This will be converted to a unique_ptr in StartPropertyValuesStream. The ownership is passed
+    // there.
+    auto clientReader = new MockClientReader<proto::VehiclePropValues>();
+    EXPECT_CALL(*mGrpcStub, StartPropertyValuesStreamRaw(_, _)).WillOnce(Return(clientReader));
+    EXPECT_CALL(*clientReader, Read(_))
+            .WillOnce([timestamp, propId](proto::VehiclePropValues* values) {
+                values->Clear();
+                auto value = values->add_values();
+                value->set_timestamp(timestamp);
+                value->set_prop(propId);
+                return true;
+            })
+            .WillOnce(Return(false));
+    EXPECT_CALL(*clientReader, Finish()).WillOnce(Return(::grpc::Status::OK));
+
+    pollValue();
+}
+
+TEST_F(GRPCVehicleHardwareUnitTest, TestGetValuesOutdatedRetry) {
+    int64_t startTimestamp = elapsedRealtimeNano();
+    int64_t testRequestId = 1234;
+    int32_t testPropId = 4321;
+    int32_t testValue1 = 123456;
+    int32_t testValue2 = 654321;
+    int32_t testTimestamp1 = 1000;
+    int32_t testTimestamp2 = 2000;
+
+    // A property update event for testTimestamp2 happens before getValues returns.
+    generatePropertyUpdateEvent(testPropId, testTimestamp2);
+
+    // GetValues first returns an outdated result, then an up-to-date result.
+    EXPECT_CALL(*mGrpcStub, GetValues(_, _, _))
+            .WillOnce([testRequestId, testPropId, testValue1, testTimestamp1](
+                              ::grpc::ClientContext* context,
+                              const proto::VehiclePropValueRequests& request,
+                              proto::GetValueResults* response) {
+                response->Clear();
+                auto* resultPtr = response->add_results();
+                resultPtr->set_request_id(testRequestId);
+                resultPtr->set_status(proto::StatusCode::OK);
+                auto* valuePtr = resultPtr->mutable_value();
+                valuePtr->set_prop(testPropId);
+                valuePtr->set_timestamp(testTimestamp1);
+                valuePtr->add_int32_values(testValue1);
+                return ::grpc::Status::OK;
+            })
+            .WillOnce([testRequestId, testPropId, testValue2, testTimestamp2](
+                              ::grpc::ClientContext* context,
+                              const proto::VehiclePropValueRequests& request,
+                              proto::GetValueResults* response) {
+                response->Clear();
+                auto* resultPtr = response->add_results();
+                resultPtr->set_request_id(testRequestId);
+                resultPtr->set_status(proto::StatusCode::OK);
+                auto* valuePtr = resultPtr->mutable_value();
+                valuePtr->set_prop(testPropId);
+                valuePtr->set_timestamp(testTimestamp2);
+                valuePtr->add_int32_values(testValue2);
+                return ::grpc::Status::OK;
+            });
+
+    std::vector<aidlvhal::GetValueRequest> requests;
+    requests.push_back(aidlvhal::GetValueRequest{.requestId = testRequestId,
+                                                 .prop = {
+                                                         .prop = testPropId,
+                                                 }});
+
+    std::vector<aidlvhal::GetValueResult> gotResults;
+
+    auto status = mHardware->getValues(
+            std::make_shared<GRPCVehicleHardware::GetValuesCallback>(
+                    [&gotResults](std::vector<aidlvhal::GetValueResult> results) {
+                        for (const auto& result : results) {
+                            gotResults.push_back(result);
+                        }
+                    }),
+            requests);
+
+    ASSERT_EQ(status, aidlvhal::StatusCode::OK);
+    ASSERT_THAT(gotResults, SizeIs(1));
+    EXPECT_EQ(gotResults[0].requestId, testRequestId);
+    EXPECT_EQ(gotResults[0].status, aidlvhal::StatusCode::OK);
+    EXPECT_EQ(gotResults[0].prop->prop, testPropId);
+    EXPECT_THAT(gotResults[0].prop->value.int32Values, ElementsAre(testValue2));
+    EXPECT_GT(gotResults[0].prop->timestamp, startTimestamp);
+    EXPECT_LT(gotResults[0].prop->timestamp, elapsedRealtimeNano());
+}
+
 }  // namespace android::hardware::automotive::vehicle::virtualization
diff --git a/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h b/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
index f49d91b..0684655 100644
--- a/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
@@ -20,6 +20,7 @@
 #include <VehicleHalTypes.h>
 
 #include <memory>
+#include <optional>
 #include <vector>
 
 namespace android {
@@ -46,33 +47,53 @@
     int32_t areaId;
 };
 
+namespace aidlvhal = ::aidl::android::hardware::automotive::vehicle;
+
 // An abstract interface to access vehicle hardware.
 // For virtualized VHAL, GrpcVehicleHardware would communicate with a VehicleHardware
 // implementation in another VM through GRPC. For non-virtualzied VHAL, VHAL directly communicates
 // with a VehicleHardware through this interface.
 class IVehicleHardware {
   public:
-    using SetValuesCallback = std::function<void(
-            std::vector<aidl::android::hardware::automotive::vehicle::SetValueResult>)>;
-    using GetValuesCallback = std::function<void(
-            std::vector<aidl::android::hardware::automotive::vehicle::GetValueResult>)>;
-    using PropertyChangeCallback = std::function<void(
-            std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>)>;
+    using SetValuesCallback = std::function<void(std::vector<aidlvhal::SetValueResult>)>;
+    using GetValuesCallback = std::function<void(std::vector<aidlvhal::GetValueResult>)>;
+    using PropertyChangeCallback = std::function<void(std::vector<aidlvhal::VehiclePropValue>)>;
     using PropertySetErrorCallback = std::function<void(std::vector<SetValueErrorEvent>)>;
 
     virtual ~IVehicleHardware() = default;
 
     // Get all the property configs.
-    virtual std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
-    getAllPropertyConfigs() const = 0;
+    virtual std::vector<aidlvhal::VehiclePropConfig> getAllPropertyConfigs() const = 0;
+
+    // Get the property configs for the specified propId. This is used for early-boot
+    // native VHAL clients to access certain property configs when not all property configs are
+    // available. For example, a config discovery process might be required to determine the
+    // property config for HVAC. However, for early boot properties, e.g. VHAL_HEARTBEAT, it
+    // could return before the config discovery process.
+    //
+    // Currently Android system may try to access the following properties during early boot:
+    // STORAGE_ENCRYPTION_BINDING_SEED, WATCHDOG_ALIVE, WATCHDOG_TERMINATE_PROCESS, VHAL_HEARTBEAT,
+    // CURRENT_POWER_POLICY, POWER_POLICY_REQ, POWER_POLICY_GROUP_REQ. They should return
+    // quickly otherwise the whole bootup process might be blocked.
+    virtual std::optional<aidlvhal::VehiclePropConfig> getPropertyConfig(int32_t propId) const {
+        // The default implementation is to use getAllPropertyConfigs(). This should be
+        // overridden if getAllPropertyConfigs() takes a while to return for initial boot or
+        // relies on ethernet or other communication channel that is not available during early
+        // boot.
+        for (const auto& config : getAllPropertyConfigs()) {
+            if (config.prop == propId) {
+                return config;
+            }
+        }
+        return std::nullopt;
+    }
 
     // Set property values asynchronously. Server could return before the property set requests
     // are sent to vehicle bus or before property set confirmation is received. The callback is
     // safe to be called after the function returns and is safe to be called in a different thread.
-    virtual aidl::android::hardware::automotive::vehicle::StatusCode setValues(
+    virtual aidlvhal::StatusCode setValues(
             std::shared_ptr<const SetValuesCallback> callback,
-            const std::vector<aidl::android::hardware::automotive::vehicle::SetValueRequest>&
-                    requests) = 0;
+            const std::vector<aidlvhal::SetValueRequest>& requests) = 0;
 
     // Get property values asynchronously. Server could return before the property values are ready.
     // The callback is safe to be called after the function returns and is safe to be called in a
@@ -86,7 +107,7 @@
     virtual DumpResult dump(const std::vector<std::string>& options) = 0;
 
     // Check whether the system is healthy, return {@code StatusCode::OK} for healthy.
-    virtual aidl::android::hardware::automotive::vehicle::StatusCode checkHealth() = 0;
+    virtual aidlvhal::StatusCode checkHealth() = 0;
 
     // Register a callback that would be called when there is a property change event from vehicle.
     // This function must only be called once during initialization.
@@ -179,16 +200,14 @@
     // 5. The second subscriber is removed, 'unsubscribe' is called.
     //    The impl can optionally disable the polling for vehicle speed.
     //
-    virtual aidl::android::hardware::automotive::vehicle::StatusCode subscribe(
-            [[maybe_unused]] aidl::android::hardware::automotive::vehicle::SubscribeOptions
-                    options) {
-        return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
+    virtual aidlvhal::StatusCode subscribe([[maybe_unused]] aidlvhal::SubscribeOptions options) {
+        return aidlvhal::StatusCode::OK;
     }
 
     // A [propId, areaId] is unsubscribed. This applies for both continuous or on-change property.
-    virtual aidl::android::hardware::automotive::vehicle::StatusCode unsubscribe(
-            [[maybe_unused]] int32_t propId, [[maybe_unused]] int32_t areaId) {
-        return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
+    virtual aidlvhal::StatusCode unsubscribe([[maybe_unused]] int32_t propId,
+                                             [[maybe_unused]] int32_t areaId) {
+        return aidlvhal::StatusCode::OK;
     }
 
     // This function is deprecated, subscribe/unsubscribe should be used instead.
@@ -216,10 +235,10 @@
     //
     // If the impl is always polling at {@code maxSampleRate} as specified in config, then this
     // function can be a no-op.
-    virtual aidl::android::hardware::automotive::vehicle::StatusCode updateSampleRate(
-            [[maybe_unused]] int32_t propId, [[maybe_unused]] int32_t areaId,
-            [[maybe_unused]] float sampleRate) {
-        return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
+    virtual aidlvhal::StatusCode updateSampleRate([[maybe_unused]] int32_t propId,
+                                                  [[maybe_unused]] int32_t areaId,
+                                                  [[maybe_unused]] float sampleRate) {
+        return aidlvhal::StatusCode::OK;
     }
 };
 
diff --git a/automotive/vehicle/aidl/impl/proto/Android.bp b/automotive/vehicle/aidl/impl/proto/Android.bp
index b2edf75..0d3df49 100644
--- a/automotive/vehicle/aidl/impl/proto/Android.bp
+++ b/automotive/vehicle/aidl/impl/proto/Android.bp
@@ -106,3 +106,21 @@
         "-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,
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
+    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/utils/common/include/VehicleUtils.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
index f48bb2a..90a7c46 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
@@ -337,6 +337,9 @@
 // This is for debug purpose only.
 android::base::Result<int32_t> stringToPropId(const std::string& propName);
 
+// This is for debug purpose only. Converts an area's name to its enum definition.
+android::base::Result<int32_t> stringToArea(const std::string& areaName, int32_t propId);
+
 template <typename T>
 void roundToNearestResolution(std::vector<T>& arrayToSanitize, float resolution) {
     if (resolution == 0) {
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
index a7caeb1..c3a46c6 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
@@ -289,7 +289,7 @@
 
     for (auto const& [_, record] : mRecordsByPropId) {
         for (auto const& [_, value] : record.values) {
-            allValues.push_back(std::move(mValuePool->obtain(*value)));
+            allValues.push_back(mValuePool->obtain(*value));
         }
     }
 
@@ -308,7 +308,7 @@
     }
 
     for (auto const& [_, value] : record->values) {
-        values.push_back(std::move(mValuePool->obtain(*value)));
+        values.push_back(mValuePool->obtain(*value));
     }
     return values;
 }
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp
index 4d06e4e..7814c99 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp
@@ -25,7 +25,13 @@
 
 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
 using ::aidl::android::hardware::automotive::vehicle::toString;
+using ::aidl::android::hardware::automotive::vehicle::VehicleArea;
 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaDoor;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaMirror;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaSeat;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaWheel;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaWindow;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup;
@@ -44,7 +50,7 @@
         return instance;
     }
 
-    Result<int32_t> getPropertyId(const std::string& name) {
+    Result<int32_t> getPropertyId(const std::string& name) const {
         auto it = mPropertyIdByName.find(name);
         if (it == mPropertyIdByName.end()) {
             return Error();
@@ -66,6 +72,52 @@
     }
 };
 
+class AreaByNameSingleton {
+  public:
+    static AreaByNameSingleton& getInstance() {
+        static AreaByNameSingleton instance;
+        return instance;
+    }
+
+    Result<int32_t> getArea(const std::string& name, int32_t propId) const {
+        VehicleArea areaType = getPropArea(propId);
+
+        auto mapIt = mAreaByNameByAreaType.find(areaType);
+        if (mapIt == mAreaByNameByAreaType.end()) {
+            return Error() << "Invalid area type for property ID: " << propIdToString(propId);
+        }
+
+        const auto& areaByName = mapIt->second;
+        auto it = areaByName.find(name);
+        if (it == areaByName.end()) {
+            return Error() << "Invalid area name for property " << propIdToString(propId) << ": "
+                           << name;
+        }
+        return it->second;
+    }
+
+    AreaByNameSingleton(AreaByNameSingleton const&) = delete;
+    void operator=(AreaByNameSingleton const&) = delete;
+
+  private:
+    std::unordered_map<VehicleArea, std::unordered_map<std::string, int32_t>> mAreaByNameByAreaType;
+
+    AreaByNameSingleton() {
+        populateMap(VehicleArea::WINDOW, ndk::internal::enum_values<VehicleAreaWindow>);
+        populateMap(VehicleArea::MIRROR, ndk::internal::enum_values<VehicleAreaMirror>);
+        populateMap(VehicleArea::SEAT, ndk::internal::enum_values<VehicleAreaSeat>);
+        populateMap(VehicleArea::DOOR, ndk::internal::enum_values<VehicleAreaDoor>);
+        populateMap(VehicleArea::WHEEL, ndk::internal::enum_values<VehicleAreaWheel>);
+    }
+
+    template <class T, std::size_t N>
+    void populateMap(VehicleArea areaType, std::array<T, N> values) {
+        for (unsigned int i = 0; i < values.size(); i++) {
+            mAreaByNameByAreaType[areaType].emplace(toString(values[i]), toInt(values[i]));
+        }
+    }
+};
+
 }  // namespace
 
 Result<void> checkPropValue(const VehiclePropValue& value, const VehiclePropConfig* config) {
@@ -254,6 +306,10 @@
     return PropertyIdByNameSingleton::getInstance().getPropertyId(propName);
 }
 
+Result<int32_t> stringToArea(const std::string& areaName, int32_t propId) {
+    return AreaByNameSingleton::getInstance().getArea(areaName, propId);
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
index 6646b7e..22f5c73 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
@@ -328,7 +328,7 @@
 TEST_F(VehiclePropertyStoreTest, testRemoveValuesForProperty) {
     auto values = getTestPropValues();
     for (const auto& value : values) {
-        ASSERT_RESULT_OK(mStore->writeValue(std::move(mValuePool->obtain(value))));
+        ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(value)));
     }
 
     mStore->removeValuesForProperty(toInt(VehicleProperty::INFO_FUEL_CAPACITY));
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/aidl/impl/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
index fa2a310..932a2e2 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
@@ -31,6 +31,7 @@
 #include <android-base/thread_annotations.h>
 #include <android/binder_auto_utils.h>
 
+#include <functional>
 #include <memory>
 #include <mutex>
 #include <shared_mutex>
@@ -138,12 +139,11 @@
     // Only used for testing.
     int32_t mTestInterfaceVersion = 0;
 
-    // mConfigsByPropId and mConfigFile is lazy initialized.
-    mutable std::mutex mConfigInitLock;
-    mutable bool mConfigInit GUARDED_BY(mConfigInitLock) = false;
+    mutable std::atomic<bool> mConfigInit = false;
+    mutable std::shared_timed_mutex mConfigLock;
     mutable std::unordered_map<int32_t, aidlvhal::VehiclePropConfig> mConfigsByPropId
-            GUARDED_BY(mConfigInitLock);
-    mutable std::unique_ptr<ndk::ScopedFileDescriptor> mConfigFile GUARDED_BY(mConfigInitLock);
+            GUARDED_BY(mConfigLock);
+    mutable std::unique_ptr<ndk::ScopedFileDescriptor> mConfigFile GUARDED_BY(mConfigLock);
 
     std::mutex mLock;
     std::unordered_map<const AIBinder*, std::unique_ptr<OnBinderDiedContext>> mOnBinderDiedContexts
@@ -175,7 +175,10 @@
 
     android::base::Result<std::vector<int64_t>> checkDuplicateRequests(
             const std::vector<aidlvhal::SetValueRequest>& requests);
-    VhalResult<void> checkSubscribeOptions(const std::vector<aidlvhal::SubscribeOptions>& options);
+    VhalResult<void> checkSubscribeOptions(
+            const std::vector<aidlvhal::SubscribeOptions>& options,
+            const std::unordered_map<int32_t, aidlvhal::VehiclePropConfig>& configsByPropId)
+            REQUIRES_SHARED(mConfigLock);
 
     VhalResult<void> checkPermissionHelper(const aidlvhal::VehiclePropValue& value,
                                            aidlvhal::VehiclePropertyAccess accessToTest) const;
@@ -184,7 +187,7 @@
 
     VhalResult<void> checkWritePermission(const aidlvhal::VehiclePropValue& value) const;
 
-    android::base::Result<const aidlvhal::VehiclePropConfig*> getConfig(int32_t propId) const;
+    android::base::Result<aidlvhal::VehiclePropConfig> getConfig(int32_t propId) const;
 
     void onBinderDiedWithContext(const AIBinder* clientId);
 
@@ -196,7 +199,9 @@
 
     bool checkDumpPermission();
 
-    bool getAllPropConfigsFromHardwareLocked() const REQUIRES(mConfigInitLock);
+    bool isConfigSupportedForCurrentVhalVersion(const aidlvhal::VehiclePropConfig& config) const;
+
+    bool getAllPropConfigsFromHardwareLocked() const EXCLUDES(mConfigLock);
 
     // The looping handler function to process all onBinderDied or onBinderUnlinked events in
     // mBinderEvents.
@@ -209,10 +214,12 @@
 
     int32_t getVhalInterfaceVersion() const;
 
-    // Gets mConfigsByPropId, lazy init it if necessary.
-    const std::unordered_map<int32_t, aidlvhal::VehiclePropConfig>& getConfigsByPropId() const;
-    // Gets mConfigFile, lazy init it if necessary.
-    const ndk::ScopedFileDescriptor* getConfigFile() const;
+    // Gets mConfigsByPropId, lazy init it if necessary. Note that the reference is only valid in
+    // the scope of the callback and it is guaranteed that read lock is obtained during the
+    // callback.
+    void getConfigsByPropId(
+            std::function<void(const std::unordered_map<int32_t, aidlvhal::VehiclePropConfig>&)>
+                    callback) const EXCLUDES(mConfigLock);
 
     // Puts the property change events into a queue so that they can handled in batch.
     static void batchPropertyChangeEvent(
@@ -239,6 +246,12 @@
 
     static void onBinderUnlinked(void* cookie);
 
+    static void parseSubscribeOptions(
+            const std::vector<aidlvhal::SubscribeOptions>& options,
+            const std::unordered_map<int32_t, aidlvhal::VehiclePropConfig>& configsByPropId,
+            std::vector<aidlvhal::SubscribeOptions>& onChangeSubscriptions,
+            std::vector<aidlvhal::SubscribeOptions>& continuousSubscriptions);
+
     // Test-only
     // Set the default timeout for pending requests.
     void setTimeout(int64_t timeoutInNano);
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index 9dc039d..0ead819 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -95,6 +95,18 @@
     return sampleRateHz;
 }
 
+class SCOPED_CAPABILITY SharedScopedLockAssertion {
+  public:
+    SharedScopedLockAssertion(std::shared_timed_mutex& mutex) ACQUIRE_SHARED(mutex) {}
+    ~SharedScopedLockAssertion() RELEASE() {}
+};
+
+class SCOPED_CAPABILITY UniqueScopedLockAssertion {
+  public:
+    UniqueScopedLockAssertion(std::shared_timed_mutex& mutex) ACQUIRE(mutex) {}
+    ~UniqueScopedLockAssertion() RELEASE() {}
+};
+
 }  // namespace
 
 DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> vehicleHardware)
@@ -328,95 +340,127 @@
     return myVersion;
 }
 
-bool DefaultVehicleHal::getAllPropConfigsFromHardwareLocked() const {
-    ALOGD("Get all property configs from hardware");
-    auto configs = mVehicleHardware->getAllPropertyConfigs();
-    std::vector<VehiclePropConfig> filteredConfigs;
+bool DefaultVehicleHal::isConfigSupportedForCurrentVhalVersion(
+        const VehiclePropConfig& config) const {
     int32_t myVersion = getVhalInterfaceVersion();
-    for (auto& config : configs) {
-        if (!isSystemProp(config.prop)) {
-            filteredConfigs.push_back(std::move(config));
-            continue;
-        }
-        VehicleProperty property = static_cast<VehicleProperty>(config.prop);
-        std::string propertyName = aidl::android::hardware::automotive::vehicle::toString(property);
-        auto it = VersionForVehicleProperty.find(property);
-        if (it == VersionForVehicleProperty.end()) {
-            ALOGE("The property: %s is not a supported system property, ignore",
-                  propertyName.c_str());
-            continue;
-        }
-        int requiredVersion = it->second;
-        if (myVersion < requiredVersion) {
-            ALOGE("The property: %s is not supported for current client VHAL version, "
-                  "require %d, current version: %d, ignore",
-                  propertyName.c_str(), requiredVersion, myVersion);
-            continue;
-        }
-        filteredConfigs.push_back(std::move(config));
+    if (!isSystemProp(config.prop)) {
+        return true;
     }
-    for (auto& config : filteredConfigs) {
-        mConfigsByPropId[config.prop] = config;
-    }
-    VehiclePropConfigs vehiclePropConfigs;
-    vehiclePropConfigs.payloads = std::move(filteredConfigs);
-    auto result = LargeParcelableBase::parcelableToStableLargeParcelable(vehiclePropConfigs);
-    if (!result.ok()) {
-        ALOGE("failed to convert configs to shared memory file, error: %s, code: %d",
-              result.error().message().c_str(), static_cast<int>(result.error().code()));
-        mConfigFile = nullptr;
+    VehicleProperty property = static_cast<VehicleProperty>(config.prop);
+    std::string propertyName = aidl::android::hardware::automotive::vehicle::toString(property);
+    auto it = VersionForVehicleProperty.find(property);
+    if (it == VersionForVehicleProperty.end()) {
+        ALOGE("The property: %s is not a supported system property, ignore", propertyName.c_str());
         return false;
     }
-
-    if (result.value() != nullptr) {
-        mConfigFile = std::move(result.value());
+    int requiredVersion = it->second;
+    if (myVersion < requiredVersion) {
+        ALOGE("The property: %s is not supported for current client VHAL version, "
+              "require %d, current version: %d, ignore",
+              propertyName.c_str(), requiredVersion, myVersion);
+        return false;
     }
     return true;
 }
 
-const ScopedFileDescriptor* DefaultVehicleHal::getConfigFile() const {
-    std::scoped_lock lockGuard(mConfigInitLock);
-    if (!mConfigInit) {
-        CHECK(getAllPropConfigsFromHardwareLocked())
-                << "Failed to get property configs from hardware";
-        mConfigInit = true;
+bool DefaultVehicleHal::getAllPropConfigsFromHardwareLocked() const {
+    ALOGD("Get all property configs from hardware");
+    auto configs = mVehicleHardware->getAllPropertyConfigs();
+    std::vector<VehiclePropConfig> filteredConfigs;
+    for (const auto& config : configs) {
+        if (isConfigSupportedForCurrentVhalVersion(config)) {
+            filteredConfigs.push_back(std::move(config));
+        }
     }
-    return mConfigFile.get();
+
+    {
+        std::unique_lock<std::shared_timed_mutex> configWriteLock(mConfigLock);
+        UniqueScopedLockAssertion lockAssertion(mConfigLock);
+
+        for (auto& config : filteredConfigs) {
+            mConfigsByPropId[config.prop] = config;
+        }
+        VehiclePropConfigs vehiclePropConfigs;
+        vehiclePropConfigs.payloads = std::move(filteredConfigs);
+        auto result = LargeParcelableBase::parcelableToStableLargeParcelable(vehiclePropConfigs);
+        if (!result.ok()) {
+            ALOGE("failed to convert configs to shared memory file, error: %s, code: %d",
+                  result.error().message().c_str(), static_cast<int>(result.error().code()));
+            mConfigFile = nullptr;
+            return false;
+        }
+
+        if (result.value() != nullptr) {
+            mConfigFile = std::move(result.value());
+        }
+    }
+
+    mConfigInit = true;
+    return true;
 }
 
-const std::unordered_map<int32_t, VehiclePropConfig>& DefaultVehicleHal::getConfigsByPropId()
-        const {
-    std::scoped_lock lockGuard(mConfigInitLock);
+void DefaultVehicleHal::getConfigsByPropId(
+        std::function<void(const std::unordered_map<int32_t, VehiclePropConfig>&)> callback) const {
     if (!mConfigInit) {
         CHECK(getAllPropConfigsFromHardwareLocked())
                 << "Failed to get property configs from hardware";
-        mConfigInit = true;
     }
-    return mConfigsByPropId;
+
+    std::shared_lock<std::shared_timed_mutex> configReadLock(mConfigLock);
+    SharedScopedLockAssertion lockAssertion(mConfigLock);
+
+    callback(mConfigsByPropId);
 }
 
 ScopedAStatus DefaultVehicleHal::getAllPropConfigs(VehiclePropConfigs* output) {
-    const ScopedFileDescriptor* configFile = getConfigFile();
-    const auto& configsByPropId = getConfigsByPropId();
-    if (configFile != nullptr) {
+    if (!mConfigInit) {
+        CHECK(getAllPropConfigsFromHardwareLocked())
+                << "Failed to get property configs from hardware";
+    }
+
+    std::shared_lock<std::shared_timed_mutex> configReadLock(mConfigLock);
+    SharedScopedLockAssertion lockAssertion(mConfigLock);
+
+    if (mConfigFile != nullptr) {
         output->payloads.clear();
-        output->sharedMemoryFd.set(dup(configFile->get()));
+        output->sharedMemoryFd.set(dup(mConfigFile->get()));
         return ScopedAStatus::ok();
     }
-    output->payloads.reserve(configsByPropId.size());
-    for (const auto& [_, config] : configsByPropId) {
+
+    output->payloads.reserve(mConfigsByPropId.size());
+    for (const auto& [_, config] : mConfigsByPropId) {
         output->payloads.push_back(config);
     }
     return ScopedAStatus::ok();
 }
 
-Result<const VehiclePropConfig*> DefaultVehicleHal::getConfig(int32_t propId) const {
-    const auto& configsByPropId = getConfigsByPropId();
-    auto it = configsByPropId.find(propId);
-    if (it == configsByPropId.end()) {
-        return Error() << "no config for property, ID: " << propId;
+Result<VehiclePropConfig> DefaultVehicleHal::getConfig(int32_t propId) const {
+    Result<VehiclePropConfig> result;
+
+    if (!mConfigInit) {
+        std::optional<VehiclePropConfig> config = mVehicleHardware->getPropertyConfig(propId);
+        if (!config.has_value()) {
+            return Error() << "no config for property, ID: " << propId;
+        }
+        if (!isConfigSupportedForCurrentVhalVersion(config.value())) {
+            return Error() << "property not supported for current VHAL interface, ID: " << propId;
+        }
+
+        return config.value();
     }
-    return &(it->second);
+
+    getConfigsByPropId([this, &result, propId](const auto& configsByPropId) {
+        SharedScopedLockAssertion lockAssertion(mConfigLock);
+
+        auto it = configsByPropId.find(propId);
+        if (it == configsByPropId.end()) {
+            result = Error() << "no config for property, ID: " << propId;
+            return;
+        }
+        // Copy the VehiclePropConfig
+        result = it->second;
+    });
+    return result;
 }
 
 Result<void> DefaultVehicleHal::checkProperty(const VehiclePropValue& propValue) {
@@ -425,15 +469,15 @@
     if (!result.ok()) {
         return result.error();
     }
-    const VehiclePropConfig* config = result.value();
-    const VehicleAreaConfig* areaConfig = getAreaConfig(propValue, *config);
+    const VehiclePropConfig& config = result.value();
+    const VehicleAreaConfig* areaConfig = getAreaConfig(propValue, config);
     if (!isGlobalProp(propId) && areaConfig == nullptr) {
         // Ignore areaId for global property. For non global property, check whether areaId is
         // allowed. areaId must appear in areaConfig.
         return Error() << "invalid area ID: " << propValue.areaId << " for prop ID: " << propId
                        << ", not listed in config";
     }
-    if (auto result = checkPropValue(propValue, config); !result.ok()) {
+    if (auto result = checkPropValue(propValue, &config); !result.ok()) {
         return Error() << "invalid property value: " << propValue.toString()
                        << ", error: " << getErrorMsg(result);
     }
@@ -659,17 +703,43 @@
 ScopedAStatus DefaultVehicleHal::getPropConfigs(const std::vector<int32_t>& props,
                                                 VehiclePropConfigs* output) {
     std::vector<VehiclePropConfig> configs;
-    const auto& configsByPropId = getConfigsByPropId();
-    for (int32_t prop : props) {
-        auto it = configsByPropId.find(prop);
-        if (it != configsByPropId.end()) {
-            configs.push_back(it->second);
-        } else {
-            return ScopedAStatus::fromServiceSpecificErrorWithMessage(
-                    toInt(StatusCode::INVALID_ARG),
-                    StringPrintf("no config for property, ID: %" PRId32, prop).c_str());
+
+    if (!mConfigInit) {
+        for (int32_t prop : props) {
+            auto maybeConfig = mVehicleHardware->getPropertyConfig(prop);
+            if (!maybeConfig.has_value() ||
+                !isConfigSupportedForCurrentVhalVersion(maybeConfig.value())) {
+                return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                        toInt(StatusCode::INVALID_ARG),
+                        StringPrintf("no config for property, ID: %" PRId32, prop).c_str());
+            }
+            configs.push_back(maybeConfig.value());
         }
+
+        return vectorToStableLargeParcelable(std::move(configs), output);
     }
+
+    ScopedAStatus status = ScopedAStatus::ok();
+    getConfigsByPropId([this, &configs, &status, &props](const auto& configsByPropId) {
+        SharedScopedLockAssertion lockAssertion(mConfigLock);
+
+        for (int32_t prop : props) {
+            auto it = configsByPropId.find(prop);
+            if (it != configsByPropId.end()) {
+                configs.push_back(it->second);
+            } else {
+                status = ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                        toInt(StatusCode::INVALID_ARG),
+                        StringPrintf("no config for property, ID: %" PRId32, prop).c_str());
+                return;
+            }
+        }
+    });
+
+    if (!status.isOk()) {
+        return status;
+    }
+
     return vectorToStableLargeParcelable(std::move(configs), output);
 }
 
@@ -691,8 +761,8 @@
 }
 
 VhalResult<void> DefaultVehicleHal::checkSubscribeOptions(
-        const std::vector<SubscribeOptions>& options) {
-    const auto& configsByPropId = getConfigsByPropId();
+        const std::vector<SubscribeOptions>& options,
+        const std::unordered_map<int32_t, VehiclePropConfig>& configsByPropId) {
     for (const auto& option : options) {
         int32_t propId = option.propId;
         auto it = configsByPropId.find(propId);
@@ -757,23 +827,15 @@
             }
         }
     }
+
     return {};
 }
 
-ScopedAStatus DefaultVehicleHal::subscribe(const CallbackType& callback,
-                                           const std::vector<SubscribeOptions>& options,
-                                           [[maybe_unused]] int32_t maxSharedMemoryFileCount) {
-    // TODO(b/205189110): Use shared memory file count.
-    if (callback == nullptr) {
-        return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
-    }
-    if (auto result = checkSubscribeOptions(options); !result.ok()) {
-        ALOGE("subscribe: invalid subscribe options: %s", getErrorMsg(result).c_str());
-        return toScopedAStatus(result);
-    }
-    std::vector<SubscribeOptions> onChangeSubscriptions;
-    std::vector<SubscribeOptions> continuousSubscriptions;
-    const auto& configsByPropId = getConfigsByPropId();
+void DefaultVehicleHal::parseSubscribeOptions(
+        const std::vector<SubscribeOptions>& options,
+        const std::unordered_map<int32_t, VehiclePropConfig>& configsByPropId,
+        std::vector<SubscribeOptions>& onChangeSubscriptions,
+        std::vector<SubscribeOptions>& continuousSubscriptions) {
     for (const auto& option : options) {
         int32_t propId = option.propId;
         // We have already validate config exists.
@@ -831,6 +893,34 @@
             onChangeSubscriptions.push_back(std::move(optionCopy));
         }
     }
+}
+
+ScopedAStatus DefaultVehicleHal::subscribe(const CallbackType& callback,
+                                           const std::vector<SubscribeOptions>& options,
+                                           [[maybe_unused]] int32_t maxSharedMemoryFileCount) {
+    // TODO(b/205189110): Use shared memory file count.
+    if (callback == nullptr) {
+        return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
+    }
+    std::vector<SubscribeOptions> onChangeSubscriptions;
+    std::vector<SubscribeOptions> continuousSubscriptions;
+    ScopedAStatus returnStatus = ScopedAStatus::ok();
+    getConfigsByPropId([this, &returnStatus, &options, &onChangeSubscriptions,
+                        &continuousSubscriptions](const auto& configsByPropId) {
+        SharedScopedLockAssertion lockAssertion(mConfigLock);
+
+        if (auto result = checkSubscribeOptions(options, configsByPropId); !result.ok()) {
+            ALOGE("subscribe: invalid subscribe options: %s", getErrorMsg(result).c_str());
+            returnStatus = toScopedAStatus(result);
+            return;
+        }
+        parseSubscribeOptions(options, configsByPropId, onChangeSubscriptions,
+                              continuousSubscriptions);
+    });
+
+    if (!returnStatus.isOk()) {
+        return returnStatus;
+    }
 
     {
         // Lock to make sure onBinderDied would not be called concurrently.
@@ -891,13 +981,13 @@
         return StatusError(StatusCode::INVALID_ARG) << getErrorMsg(result);
     }
 
-    const VehiclePropConfig* config = result.value();
-    const VehicleAreaConfig* areaConfig = getAreaConfig(value, *config);
+    const VehiclePropConfig& config = result.value();
+    const VehicleAreaConfig* areaConfig = getAreaConfig(value, config);
 
     if (areaConfig == nullptr && !isGlobalProp(propId)) {
         return StatusError(StatusCode::INVALID_ARG) << "no config for area ID: " << value.areaId;
     }
-    if (!hasRequiredAccess(config->access, accessToTest) &&
+    if (!hasRequiredAccess(config.access, accessToTest) &&
         (areaConfig == nullptr || !hasRequiredAccess(areaConfig->access, accessToTest))) {
         return StatusError(StatusCode::ACCESS_DENIED)
                << StringPrintf("Property %" PRId32 " does not have the following access: %" PRId32,
@@ -966,7 +1056,6 @@
     }
     DumpResult result = mVehicleHardware->dump(options);
     if (result.refreshPropertyConfigs) {
-        std::scoped_lock lockGuard(mConfigInitLock);
         getAllPropConfigsFromHardwareLocked();
     }
     dprintf(fd, "%s", (result.buffer + "\n").c_str());
@@ -974,11 +1063,16 @@
         return STATUS_OK;
     }
     dprintf(fd, "Vehicle HAL State: \n");
-    const auto& configsByPropId = getConfigsByPropId();
+    std::unordered_map<int32_t, VehiclePropConfig> configsByPropIdCopy;
+    getConfigsByPropId([this, &configsByPropIdCopy](const auto& configsByPropId) {
+        SharedScopedLockAssertion lockAssertion(mConfigLock);
+
+        configsByPropIdCopy = configsByPropId;
+    });
     {
         std::scoped_lock<std::mutex> lockGuard(mLock);
         dprintf(fd, "Interface version: %" PRId32 "\n", getVhalInterfaceVersion());
-        dprintf(fd, "Containing %zu property configs\n", configsByPropId.size());
+        dprintf(fd, "Containing %zu property configs\n", configsByPropIdCopy.size());
         dprintf(fd, "Currently have %zu getValues clients\n", mGetValuesClients.size());
         dprintf(fd, "Currently have %zu setValues clients\n", mSetValuesClients.size());
         dprintf(fd, "Currently have %zu subscribe clients\n", countSubscribeClients());
diff --git a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
index 11a8fc7..4891bf5 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
@@ -650,6 +650,8 @@
 
     auto hardware = std::make_unique<MockVehicleHardware>();
     hardware->setPropertyConfigs(testConfigs);
+    // Store the pointer for testing. We are sure it is valid.
+    MockVehicleHardware* hardwarePtr = hardware.get();
     auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
     std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
 
@@ -658,6 +660,7 @@
 
     ASSERT_TRUE(status.isOk()) << "getPropConfigs failed: " << status.getMessage();
     ASSERT_EQ(output.payloads, testConfigs);
+    ASSERT_FALSE(hardwarePtr->getAllPropertyConfigsCalled());
 }
 
 TEST_F(DefaultVehicleHalTest, testGetPropConfigsInvalidArg) {
@@ -704,6 +707,34 @@
     ASSERT_TRUE(maybeGetValueResults.has_value()) << "no results in callback";
     EXPECT_EQ(maybeGetValueResults.value().payloads, expectedResults) << "results mismatch";
     EXPECT_EQ(countClients(), static_cast<size_t>(1));
+    ASSERT_FALSE(getHardware()->getAllPropertyConfigsCalled());
+}
+
+TEST_F(DefaultVehicleHalTest, testGetValuesSmall_AfterGetAllPropConfigs) {
+    GetValueRequests requests;
+    std::vector<GetValueResult> expectedResults;
+    std::vector<GetValueRequest> expectedHardwareRequests;
+
+    // If we already called getAllPropConfigs, the configs will be cached.
+    VehiclePropConfigs output;
+    getClient()->getAllPropConfigs(&output);
+
+    ASSERT_TRUE(getValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
+
+    getHardware()->addGetValueResponses(expectedResults);
+
+    auto status = getClient()->getValues(getCallbackClient(), requests);
+
+    ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage();
+
+    EXPECT_EQ(getHardware()->nextGetValueRequests(), expectedHardwareRequests)
+            << "requests to hardware mismatch";
+
+    auto maybeGetValueResults = getCallback()->nextGetValueResults();
+    ASSERT_TRUE(maybeGetValueResults.has_value()) << "no results in callback";
+    EXPECT_EQ(maybeGetValueResults.value().payloads, expectedResults) << "results mismatch";
+    EXPECT_EQ(countClients(), static_cast<size_t>(1));
+    ASSERT_TRUE(getHardware()->getAllPropertyConfigsCalled());
 }
 
 TEST_F(DefaultVehicleHalTest, testGetValuesLarge) {
@@ -1016,6 +1047,34 @@
     ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results in callback";
     ASSERT_EQ(maybeSetValueResults.value().payloads, expectedResults) << "results mismatch";
     EXPECT_EQ(countClients(), static_cast<size_t>(1));
+    ASSERT_FALSE(getHardware()->getAllPropertyConfigsCalled());
+}
+
+TEST_F(DefaultVehicleHalTest, testSetValuesSmall_AfterGetAllPropConfigs) {
+    SetValueRequests requests;
+    std::vector<SetValueResult> expectedResults;
+    std::vector<SetValueRequest> expectedHardwareRequests;
+
+    // If we already called getAllPropConfigs, the configs will be cached.
+    VehiclePropConfigs output;
+    getClient()->getAllPropConfigs(&output);
+
+    ASSERT_TRUE(setValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
+
+    getHardware()->addSetValueResponses(expectedResults);
+
+    auto status = getClient()->setValues(getCallbackClient(), requests);
+
+    ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+    EXPECT_EQ(getHardware()->nextSetValueRequests(), expectedHardwareRequests)
+            << "requests to hardware mismatch";
+
+    auto maybeSetValueResults = getCallback()->nextSetValueResults();
+    ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results in callback";
+    ASSERT_EQ(maybeSetValueResults.value().payloads, expectedResults) << "results mismatch";
+    EXPECT_EQ(countClients(), static_cast<size_t>(1));
+    ASSERT_TRUE(getHardware()->getAllPropertyConfigsCalled());
 }
 
 TEST_F(DefaultVehicleHalTest, testSetValuesLarge) {
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
index db15c89..e796ce5 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
@@ -45,9 +45,20 @@
 
 std::vector<VehiclePropConfig> MockVehicleHardware::getAllPropertyConfigs() const {
     std::scoped_lock<std::mutex> lockGuard(mLock);
+    mGetAllPropertyConfigsCalled = true;
     return mPropertyConfigs;
 }
 
+std::optional<VehiclePropConfig> MockVehicleHardware::getPropertyConfig(int32_t propId) const {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    for (const auto& config : mPropertyConfigs) {
+        if (config.prop == propId) {
+            return config;
+        }
+    }
+    return std::nullopt;
+}
+
 StatusCode MockVehicleHardware::setValues(std::shared_ptr<const SetValuesCallback> callback,
                                           const std::vector<SetValueRequest>& requests) {
     std::scoped_lock<std::mutex> lockGuard(mLock);
@@ -336,6 +347,11 @@
     (*mPropertySetErrorCallback)(errorEvents);
 }
 
+bool MockVehicleHardware::getAllPropertyConfigsCalled() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return mGetAllPropertyConfigsCalled;
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
index eeca582..06e01a8 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
@@ -47,6 +47,8 @@
 
     std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
     getAllPropertyConfigs() const override;
+    std::optional<aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
+    getPropertyConfig(int32_t propId) const override;
     aidl::android::hardware::automotive::vehicle::StatusCode setValues(
             std::shared_ptr<const SetValuesCallback> callback,
             const std::vector<aidl::android::hardware::automotive::vehicle::SetValueRequest>&
@@ -98,6 +100,9 @@
     std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions>
     getSubscribeOptions();
     void clearSubscribeOptions();
+    // Whether getAllPropertyConfigs() has been called, which blocks all all property configs
+    // being ready.
+    bool getAllPropertyConfigsCalled();
 
   private:
     mutable std::mutex mLock;
@@ -143,6 +148,8 @@
 
     DumpResult mDumpResult;
 
+    mutable bool mGetAllPropertyConfigsCalled GUARDED_BY(mLock) = false;
+
     // RecurrentTimer is thread-safe.
     std::shared_ptr<RecurrentTimer> mRecurrentTimer;
     std::unordered_map<int32_t, std::unordered_map<int32_t, std::shared_ptr<std::function<void()>>>>
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
index 0863adf..e5c09b0 100644
--- a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -1677,6 +1677,12 @@
      * For configuration information, VehiclePropConfig.configArray must have bit flag combining
      * values in VehicleApPowerStateConfigFlag.
      *
+     *   configArray[0] : Bit flag combining values in VehicleApPowerStateConfigFlag,
+     *                    0x0 if not used,
+     *                    0x1 for enabling suspend to ram,
+     *                    0x2 for supporting powering on AP from off state after timeout.
+     *                    0x4 for enabling suspend to disk,
+     *
      *   int32Values[0] : VehicleApPowerStateReq enum value
      *   int32Values[1] : additional parameter relevant for each state,
      *                    0 if not used.
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/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
index 608a328..fb3c8cd 100644
--- a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
+++ b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
@@ -95,7 +95,7 @@
             std::lock_guard<std::mutex> lockGuard(mLock);
             for (auto& value : values) {
                 int32_t propId = value->getPropId();
-                mEvents[propId].push_back(std::move(value->clone()));
+                mEvents[propId].push_back(value->clone());
             }
         }
         mEventCond.notify_one();
@@ -122,7 +122,7 @@
             return events;
         }
         for (const auto& eventPtr : mEvents[propId]) {
-            events.push_back(std::move(eventPtr->clone()));
+            events.push_back(eventPtr->clone());
         }
         return events;
     }
diff --git a/biometrics/common/aidl/Android.bp b/biometrics/common/aidl/Android.bp
index 246bcf2..8c9a357 100644
--- a/biometrics/common/aidl/Android.bp
+++ b/biometrics/common/aidl/Android.bp
@@ -22,6 +22,15 @@
         cpp: {
             enabled: false,
         },
+        ndk: {
+            apex_available: [
+                "//apex_available:anyapex",
+                "//apex_available:platform",
+            ],
+        },
+        rust: {
+            enabled: true,
+        },
     },
     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/config/include/config/Config.h b/biometrics/common/config/include/config/Config.h
index 0367832..b1affdc 100644
--- a/biometrics/common/config/include/config/Config.h
+++ b/biometrics/common/config/include/config/Config.h
@@ -100,7 +100,11 @@
         } else if (std::holds_alternative<OptIntVec>(v)) {
             for (auto x : std::get<OptIntVec>(v))
                 if (x.has_value()) os << x.value() << " ";
+        } else if (std::holds_alternative<OptString>(v)) {
+            OptString ov = std::get<OptString>(v);
+            if (ov.has_value()) os << ov.value();
         }
+
         return os.str();
     }
     std::string toString() const {
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/face/aidl/Android.bp b/biometrics/face/aidl/Android.bp
index fadcde7..54d01a7 100644
--- a/biometrics/face/aidl/Android.bp
+++ b/biometrics/face/aidl/Android.bp
@@ -11,7 +11,7 @@
     name: "android.hardware.biometrics.face",
     vendor_available: true,
     srcs: [
-        "android/hardware/biometrics/face/**/*.aidl",
+        "android/hardware/biometrics/face/*.aidl",
     ],
     imports: [
         "android.hardware.biometrics.common-V4",
@@ -36,6 +36,10 @@
             additional_shared_libraries: [
                 "libnativewindow",
             ],
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.hardware.biometrics.face.virtual",
+            ],
         },
     },
     versions_with_info: [
@@ -74,5 +78,39 @@
 
     ],
     frozen: true,
+}
 
+aidl_interface {
+    name: "android.hardware.biometrics.face.virtualhal",
+    srcs: [
+        "android/hardware/biometrics/face/virtualhal/*.aidl",
+    ],
+    imports: [
+        "android.hardware.biometrics.common-V4",
+        "android.hardware.keymaster-V4",
+        "android.hardware.biometrics.face-V4",
+    ],
+    vendor_available: true,
+    unstable: true,
+    backend: {
+        java: {
+            platform_apis: true,
+        },
+        rust: {
+            enabled: false,
+        },
+        cpp: {
+            enabled: false,
+        },
+        ndk: {
+            additional_shared_libraries: [
+                "libnativewindow",
+            ],
+            apex_available: [
+                "com.android.hardware.biometrics.face.virtual",
+                "//apex_available:platform",
+            ],
+        },
+    },
+    frozen: false,
 }
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
index 26cb361..0dbf052 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
@@ -73,7 +73,7 @@
      * Note that this interface allows multiple in-flight challenges. Invoking generateChallenge
      * twice does not invalidate the first challenge. The challenge is invalidated only when:
      *   1) Its lifespan exceeds the challenge timeout defined in the TEE.
-     *   2) IFingerprint#revokeChallenge is invoked
+     *   2) IFace#revokeChallenge is invoked
      *
      * For example, the following is a possible table of valid challenges:
      * ----------------------------------------------
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/AcquiredInfoAndVendorCode.aidl
similarity index 86%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
copy to biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/AcquiredInfoAndVendorCode.aidl
index c7be950..a254120 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/AcquiredInfoAndVendorCode.aidl
@@ -14,14 +14,13 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+package android.hardware.biometrics.face.virtualhal;
 
-import android.hardware.biometrics.fingerprint.AcquiredInfo;
+import android.hardware.biometrics.face.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/face/aidl/android/hardware/biometrics/face/virtualhal/EnrollmentProgressStep.aidl
similarity index 82%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/EnrollmentProgressStep.aidl
index bf038f6..7fbcf5d 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/EnrollmentProgressStep.aidl
@@ -14,14 +14,13 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+package android.hardware.biometrics.face.virtualhal;
 
-import android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode;
+import android.hardware.biometrics.face.virtualhal.AcquiredInfoAndVendorCode;
 
 /**
  * @hide
  */
-@VintfStability
 parcelable EnrollmentProgressStep {
     /**
      * The duration of the enrollment step in milli-seconds
@@ -30,7 +29,7 @@
 
     /**
      * The sequence of acquired info and vendor code to be issued by HAL during the step.
-     * The codes are evenly spreaded over the duration
+     * The codes are evenly spread over the duration
      */
     AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
 }
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IVirtualHal.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/IVirtualHal.aidl
similarity index 71%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IVirtualHal.aidl
copy to biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/IVirtualHal.aidl
index cb9135e..1d3d934 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IVirtualHal.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/IVirtualHal.aidl
@@ -14,19 +14,18 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+package android.hardware.biometrics.face.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.SensorLocation;
+import android.hardware.biometrics.face.FaceSensorType;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.virtualhal.AcquiredInfoAndVendorCode;
+import android.hardware.biometrics.face.virtualhal.NextEnrollment;
 
 /**
  * @hide
  */
-@VintfStability
-oneway interface IVirtualHal {
+interface IVirtualHal {
     /**
      * The operation failed due to invalid input parameters, the error messages should
      * gives more details
@@ -34,13 +33,13 @@
     const int STATUS_INVALID_PARAMETER = 1;
 
     /**
-     * Set Fingerprint Virtual HAL behavior parameters
+     * Set Face Virtual HAL behavior parameters
      */
 
     /**
      * setEnrollments
      *
-     * Set the ids of the fingerprints that were currently enrolled in the Virtual HAL,
+     * Set the ids of the faces that were currently enrolled in the Virtual HAL,
      *
      * @param ids ids can contain 1 or more ids, each must be larger than 0
      */
@@ -49,7 +48,7 @@
     /**
      * setEnrollmentHit
      *
-     * Set current fingerprint enrollment ids in Fingerprint Virtual HAL,
+     * Set current face enrollment ids in Face Virtual HAL,
      *
      * @param ids ids can contain 1 or more ids, each must be larger than 0
      */
@@ -67,7 +66,7 @@
     /**
      * setAuthenticatorId
      *
-     * Set authenticator id in virtual HAL, the id is returned in ISession#getAuthenticatorId() call
+     * Set authenticator id in virtual HAL, the id is returned in ISession#AuthenticatorId() call
      *
      * @param id authenticator id value, only applied to the sensor with SensorStrength::STRONG.
      */
@@ -116,7 +115,7 @@
      * setOperationAuthenticateDuration
      *
      * Set authentication duration covering the HAL authetication from start to end, including
-     * fingerprint capturing, and matching, acquired info reporting. In case a sequence of acquired
+     * face capturing, and matching, acquired info reporting. In case a sequence of acquired
      * info code are specified via setOperationAuthenticateAcquired(), the reporting is evenly
      * distributed over the duration.
      *
@@ -130,7 +129,9 @@
      * setOperationAuthenticateError
      *
      * Force authentication to error out for non-zero error
-     * Check hardware/interfaces/biometrics/fingerprint/aidl/default/README.md for valid error codes
+     * Check
+     * hardware/interfaces/biometrics/face/aidl/default/aidl/android/hardware/biometrics/face/Error.aidl
+     * for valid error codes
      *
      * @param error if error < 1000
      *                  non-vendor error
@@ -143,27 +144,15 @@
      * setOperationAuthenticateAcquired
      *
      * Set one of more acquired info codes for the virtual hal to report during authentication
-     * Check hardware/interfaces/biometrics/fingerprint/aidl/default/README.md for valid acquired
-     * info codes
+     * Check
+     * hardware/interfaces/biometrics/face/aidl/aidl/android/hardware/biometrics/face/AcquiredInfo.aidl
+     * for valid acquired info codes
      *
      * @param acquired[], one or more acquired info codes
      */
     void setOperationAuthenticateAcquired(in AcquiredInfoAndVendorCode[] acquired);
 
     /**
-     * setOperationEnrollError
-     *
-     * Force enrollment operation to error out for non-zero error
-     * Check hardware/interfaces/biometrics/fingerprint/aidl/default/README.md for valid error codes
-     *
-     * @param error if error < 1000
-     *                  non-vendor error
-     *              else
-     *                  vendor error
-     */
-    void setOperationEnrollError(in int error);
-
-    /**
      * setOperationEnrollLatency
      *
      * Set enrollment latency in the virtual hal in a fixed value (single element) or random
@@ -202,42 +191,11 @@
     void setOperationDetectInteractionLatency(in int[] latencyMs);
 
     /**
-     * setOperationDetectInteractionError
+     * setOperationDetectInteractionFails
      *
-     * Force detect interaction operation to error out for non-zero error
-     * Check hardware/interfaces/biometrics/fingerprint/aidl/default/README.md for valid error codes
-     *
-     * @param error if error < 1000
-     *                  non-vendor error
-     *              else
-     *                  vendor error
+     * Force detect interaction operation to fail
      */
-    void setOperationDetectInteractionError(in int error);
-
-    /**
-     * setOperationDetectInteractionDuration
-     *
-     * Set detect interaction duration covering the HAL authetication from start to end, including
-     * fingerprint detect and acquired info reporting. In case a sequence of acquired info code are
-     * specified via setOperationDetectInteractionAcquired(), the reporting is evenly distributed
-     * over the duration.
-     *
-     * This method fails with STATUS_INVALID_PARAMETERS if the passed-in value is negative
-     *
-     * @param duration  value is in milli-seconds
-     */
-    void setOperationDetectInteractionDuration(in int durationMs);
-
-    /**
-     * setOperationDetectInteractionAcquired
-     *
-     * Set one of more acquired info codes for the virtual hal to report during detect interaction
-     * Check hardware/interfaces/biometrics/fingerprint/aidl/default/README.md for valid acquired
-     * info codes
-     *
-     * @param acquired[], one or more acquired info codes
-     */
-    void setOperationDetectInteractionAcquired(in AcquiredInfoAndVendorCode[] acquired);
+    void setOperationDetectInteractionFails(in boolean error);
 
     /**
      * setLockout
@@ -261,6 +219,15 @@
     void setLockoutEnable(in boolean enable);
 
     /**
+     * setLockoutTimedEnable
+     *
+     * Whether to enable authentication-fail-based time-based-lockout tracking or not.
+     *
+     * @param enable, set true to enable the time-basedlockout tracking
+     */
+    void setLockoutTimedEnable(in boolean enable);
+
+    /**
      * setLockoutTimedThreshold
      *
      * Set the number of consecutive authentication failures that triggers the timed-based lock to
@@ -303,16 +270,28 @@
     void resetConfigurations();
 
     /**
-     * The following functions are used to configure Fingerprint Virtual HAL sensor properties
-     *  refer to SensorProps.aidl and CommonProps.aidl for details of each property
+     * setType
+     *
+     * Configure virtual face sensor type
+     *
+     * @param type, sensor type as specified in FaceSensorType.aidl
+     *
      */
-    void setType(in FingerprintSensorType type);
-    void setSensorId(in int id);
+    void setType(in FaceSensorType type);
+
+    /**
+     *  setSensorStrength
+     *
+     *  Configure virtual face sensor strength
+     *
+     * @param sensor strength as specified in common/SensorStrength.aidl
+     */
     void setSensorStrength(in SensorStrength strength);
-    void setMaxEnrollmentPerUser(in int max);
-    void setSensorLocation(in SensorLocation loc);
-    void setNavigationGuesture(in boolean v);
-    void setDetectInteraction(in boolean v);
-    void setDisplayTouch(in boolean v);
-    void setControlIllumination(in boolean v);
+
+    /**
+     * getFaceHal
+     *
+     * @return IFace interface associated with IVirtualHal instance
+     */
+    IFace getFaceHal();
 }
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/NextEnrollment.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/NextEnrollment.aidl
similarity index 87%
rename from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/NextEnrollment.aidl
rename to biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/NextEnrollment.aidl
index 4b50850..d3547a8 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/NextEnrollment.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/NextEnrollment.aidl
@@ -14,12 +14,11 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+package android.hardware.biometrics.face.virtualhal;
 
 /**
  * @hide
  */
-@VintfStability
 parcelable NextEnrollment {
     /**
      *  Identifier of the next enrollment if successful
@@ -31,7 +30,7 @@
      *  and sequence of acquired info codes to be generated by HAL.
      *  See EnrollmentProgressStep.aidl for more details
      */
-    android.hardware.biometrics.fingerprint.EnrollmentProgressStep[] progressSteps;
+    android.hardware.biometrics.face.virtualhal.EnrollmentProgressStep[] progressSteps;
 
     /**
      * Success or failure of the next enrollment
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/README.md b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/README.md
new file mode 100644
index 0000000..bf1a4b1
--- /dev/null
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/README.md
@@ -0,0 +1,3 @@
+The aidl files in this directory are used to control/configure face virtual hal
+via IVirtualHal interface
+
diff --git a/biometrics/face/aidl/default/Android.bp b/biometrics/face/aidl/default/Android.bp
index 685639c..bed0405 100644
--- a/biometrics/face/aidl/default/Android.bp
+++ b/biometrics/face/aidl/default/Android.bp
@@ -9,21 +9,13 @@
 }
 
 filegroup {
-    name: "face-example.rc",
-    srcs: ["face-example.rc"],
+    name: "face-virtual.rc",
+    srcs: ["face-virtual.rc"],
 }
 
-filegroup {
-    name: "face-example.xml",
-    srcs: ["face-example.xml"],
-}
-
-cc_binary {
-    name: "android.hardware.biometrics.face-service.example",
-    relative_install_path: "hw",
-    init_rc: [":face-example.rc"],
-    vintf_fragments: [":face-example.xml"],
-    vendor: true,
+cc_library_static {
+    name: "android.hardware.biometrics.face-service.lib",
+    vendor_available: true,
 
     shared_libs: [
         "libbinder_ndk",
@@ -32,32 +24,80 @@
     ],
     srcs: [
         "FakeLockoutTracker.cpp",
-        "main.cpp",
         "Face.cpp",
         "FakeFaceEngine.cpp",
         "Session.cpp",
+        "FaceConfig.cpp",
+        "VirtualHal.cpp",
+        "main.cpp",
     ],
     include_dirs: [
         "frameworks/native/aidl/gui",
     ],
     stl: "c++_static",
-    static_libs: [
+    whole_static_libs: [
         "android.hardware.biometrics.common-V4-ndk",
+        "android.hardware.biometrics.common.config",
         "android.hardware.biometrics.common.thread",
         "android.hardware.biometrics.common.util",
+        "android.hardware.biometrics.face.virtualhal-ndk",
         "android.hardware.biometrics.face-V4-ndk",
         "android.hardware.common-V2-ndk",
         "android.hardware.keymaster-V4-ndk",
         "libandroid.hardware.biometrics.face.VirtualProps",
         "libbase",
     ],
+    apex_available: [
+        "com.android.hardware.biometrics.face.virtual",
+        "//apex_available:platform",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.biometrics.face-service.example",
+    system_ext_specific: true,
+    relative_install_path: "hw",
+
+    shared_libs: [
+        "libbinder_ndk",
+        "liblog",
+        "libnativewindow",
+    ],
+    whole_static_libs: [
+        "android.hardware.biometrics.face-service.lib",
+    ],
+    installable: false, // install APEX instead
+    apex_available: [
+        "com.android.hardware.biometrics.face.virtual",
+        "//apex_available:platform",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.biometrics.face-service.default",
+    vendor: true,
+    relative_install_path: "hw",
+    init_rc: ["face-default.rc"],
+    vintf_fragments: ["face-default.xml"],
+    shared_libs: [
+        "libbinder_ndk",
+        "liblog",
+        "libnativewindow",
+    ],
+    whole_static_libs: [
+        "android.hardware.biometrics.face-service.lib",
+    ],
 }
 
 sysprop_library {
     name: "android.hardware.biometrics.face.VirtualProps",
     srcs: ["face.sysprop"],
-    property_owner: "Vendor",
-    vendor: true,
+    property_owner: "Platform",
+    vendor_available: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.hardware.biometrics.face.virtual",
+    ],
 }
 
 cc_test {
@@ -66,6 +106,7 @@
         "tests/FakeFaceEngineTest.cpp",
         "FakeFaceEngine.cpp",
         "FakeLockoutTracker.cpp",
+        "FaceConfig.cpp",
     ],
     shared_libs: [
         "libbase",
@@ -81,6 +122,8 @@
         "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"],
@@ -92,6 +135,7 @@
     srcs: [
         "tests/FakeLockoutTrackerTest.cpp",
         "FakeLockoutTracker.cpp",
+        "FaceConfig.cpp",
     ],
     shared_libs: [
         "libbase",
@@ -107,8 +151,45 @@
         "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,
 }
+
+cc_test {
+    name: "android.hardware.biometrics.face.VirtualHalTest",
+    srcs: [
+        "tests/VirtualHalTest.cpp",
+        "FakeLockoutTracker.cpp",
+        "Face.cpp",
+        "FakeFaceEngine.cpp",
+        "Session.cpp",
+        "VirtualHal.cpp",
+        "FaceConfig.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libnativewindow",
+        "liblog",
+    ],
+    include_dirs: [
+        "frameworks/native/aidl/gui",
+    ],
+    static_libs: [
+        "android.hardware.biometrics.common-V4-ndk",
+        "android.hardware.biometrics.common.config",
+        "android.hardware.biometrics.common.thread",
+        "android.hardware.biometrics.common.util",
+        "android.hardware.biometrics.face-V4-ndk",
+        "android.hardware.common-V2-ndk",
+        "android.hardware.keymaster-V4-ndk",
+        "libandroid.hardware.biometrics.face.VirtualProps",
+        "android.hardware.biometrics.face.virtualhal-ndk",
+    ],
+    test_suites: ["general-tests"],
+    require_root: true,
+}
diff --git a/biometrics/face/aidl/default/Face.cpp b/biometrics/face/aidl/default/Face.cpp
index 5ae0df6..1543007 100644
--- a/biometrics/face/aidl/default/Face.cpp
+++ b/biometrics/face/aidl/default/Face.cpp
@@ -34,9 +34,7 @@
 namespace aidl::android::hardware::biometrics::face {
 
 const int kSensorId = 4;
-const common::SensorStrength kSensorStrength = FakeFaceEngine::GetSensorStrength();
 const int kMaxEnrollmentsPerUser = 5;
-const FaceSensorType kSensorType = FakeFaceEngine::GetSensorType();
 const bool kHalControlsPreview = true;
 const std::string kHwComponentId = "faceSensor";
 const std::string kHardwareVersion = "vendor/model/revision";
@@ -62,13 +60,13 @@
 
     common::CommonProps commonProps;
     commonProps.sensorId = kSensorId;
-    commonProps.sensorStrength = kSensorStrength;
+    commonProps.sensorStrength = FakeFaceEngine::GetSensorStrength();
     commonProps.maxEnrollmentsPerUser = kMaxEnrollmentsPerUser;
     commonProps.componentInfo = {std::move(hw_component_info), std::move(sw_component_info)};
 
     SensorProps props;
     props.commonProps = std::move(commonProps);
-    props.sensorType = kSensorType;
+    props.sensorType = FakeFaceEngine::GetSensorType();
     props.halControlsPreview = kHalControlsPreview;
     props.enrollPreviewWidth = 1080;
     props.enrollPreviewHeight = 1920;
@@ -141,6 +139,30 @@
     return STATUS_OK;
 }
 
+const char* Face::type2String(FaceSensorType type) {
+    switch (type) {
+        case FaceSensorType::RGB:
+            return "rgb";
+        case FaceSensorType::IR:
+            return "ir";
+        default:
+            return "unknown";
+    }
+}
+
+const char* Face::strength2String(common::SensorStrength strength) {
+    switch (strength) {
+        case common::SensorStrength::STRONG:
+            return "STRONG";
+        case common::SensorStrength::WEAK:
+            return "WEAK";
+        case common::SensorStrength::CONVENIENCE:
+            return "CONVENIENCE";
+        default:
+            return "unknown";
+    }
+}
+
 void Face::onHelp(int fd) {
     dprintf(fd, "Virtual Face HAL commands:\n");
     dprintf(fd, "         help: print this help\n");
@@ -167,7 +189,6 @@
     RESET_CONFIG_O(lockout);
     RESET_CONFIG_O(operation_authenticate_fails);
     RESET_CONFIG_O(operation_detect_interaction_fails);
-    RESET_CONFIG_O(operation_enroll_fails);
     RESET_CONFIG_V(operation_authenticate_latency);
     RESET_CONFIG_V(operation_detect_interaction_latency);
     RESET_CONFIG_V(operation_enroll_latency);
diff --git a/biometrics/face/aidl/default/Face.h b/biometrics/face/aidl/default/Face.h
index 93fddb0..dbe6341 100644
--- a/biometrics/face/aidl/default/Face.h
+++ b/biometrics/face/aidl/default/Face.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <aidl/android/hardware/biometrics/face/BnFace.h>
+#include "FaceConfig.h"
 #include "Session.h"
 
 namespace aidl::android::hardware::biometrics::face {
@@ -33,9 +34,20 @@
     binder_status_t dump(int fd, const char** args, uint32_t numArgs);
     binder_status_t handleShellCommand(int in, int out, int err, const char** argv, uint32_t argc);
 
+    static FaceConfig& cfg() {
+        static FaceConfig* cfg = nullptr;
+        if (cfg == nullptr) {
+            cfg = new FaceConfig();
+            cfg->init();
+        }
+        return *cfg;
+    }
+    void resetConfigToDefault();
+    static const char* type2String(FaceSensorType type);
+    static const char* strength2String(common::SensorStrength strength);
+
   private:
     std::shared_ptr<Session> mSession;
-    void resetConfigToDefault();
     void onHelp(int);
 };
 
diff --git a/biometrics/face/aidl/default/FaceConfig.cpp b/biometrics/face/aidl/default/FaceConfig.cpp
new file mode 100644
index 0000000..a91d7cc
--- /dev/null
+++ b/biometrics/face/aidl/default/FaceConfig.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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 "FaceConfig"
+
+#include "FaceConfig.h"
+
+#include <android-base/logging.h>
+
+#include <face.sysprop.h>
+
+using namespace ::android::face::virt;
+
+namespace aidl::android::hardware::biometrics::face {
+
+// Wrapper to system property access functions
+#define CREATE_GETTER_SETTER_WRAPPER(_NAME_, _T_)           \
+    ConfigValue _NAME_##Getter() {                          \
+        return FaceHalProperties::_NAME_();                 \
+    }                                                       \
+    bool _NAME_##Setter(const ConfigValue& v) {             \
+        return FaceHalProperties::_NAME_(std::get<_T_>(v)); \
+    }
+
+CREATE_GETTER_SETTER_WRAPPER(type, OptString)
+CREATE_GETTER_SETTER_WRAPPER(enrollments, OptIntVec)
+CREATE_GETTER_SETTER_WRAPPER(enrollment_hit, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(next_enrollment, OptString)
+CREATE_GETTER_SETTER_WRAPPER(authenticator_id, OptInt64)
+CREATE_GETTER_SETTER_WRAPPER(challenge, OptInt64)
+CREATE_GETTER_SETTER_WRAPPER(strength, OptString)
+CREATE_GETTER_SETTER_WRAPPER(operation_authenticate_fails, OptBool)
+CREATE_GETTER_SETTER_WRAPPER(operation_authenticate_latency, OptIntVec)
+CREATE_GETTER_SETTER_WRAPPER(operation_authenticate_duration, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(operation_authenticate_error, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(operation_authenticate_acquired, OptString)
+CREATE_GETTER_SETTER_WRAPPER(operation_enroll_latency, OptIntVec)
+CREATE_GETTER_SETTER_WRAPPER(operation_detect_interaction_fails, OptBool)
+CREATE_GETTER_SETTER_WRAPPER(operation_detect_interaction_latency, OptIntVec)
+CREATE_GETTER_SETTER_WRAPPER(lockout, OptBool)
+CREATE_GETTER_SETTER_WRAPPER(lockout_enable, OptBool)
+CREATE_GETTER_SETTER_WRAPPER(lockout_timed_enable, OptBool)
+CREATE_GETTER_SETTER_WRAPPER(lockout_timed_threshold, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(lockout_timed_duration, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(lockout_permanent_threshold, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(features, OptIntVec)
+
+// Name, Getter, Setter, Parser and default value
+#define NGS(_NAME_) #_NAME_, _NAME_##Getter, _NAME_##Setter
+static Config::Data configData[] = {
+        {NGS(type), &Config::parseString, "rgb"},
+        {NGS(enrollments), &Config::parseIntVec, ""},
+        {NGS(enrollment_hit), &Config::parseInt32, "0"},
+        {NGS(next_enrollment), &Config::parseString,
+         "1:1000-[21,7,1,1103],1500-[1108,1],2000-[1113,1],2500-[1118,1]:true"},
+        {NGS(authenticator_id), &Config::parseInt64, "0"},
+        {NGS(challenge), &Config::parseInt64, ""},
+        {NGS(strength), &Config::parseString, "strong"},
+        {NGS(operation_authenticate_fails), &Config::parseBool, "false"},
+        {NGS(operation_authenticate_latency), &Config::parseIntVec, ""},
+        {NGS(operation_authenticate_duration), &Config::parseInt32, "500"},
+        {NGS(operation_authenticate_error), &Config::parseInt32, "0"},
+        {NGS(operation_authenticate_acquired), &Config::parseString, ""},
+        {NGS(operation_enroll_latency), &Config::parseIntVec, ""},
+        {NGS(operation_detect_interaction_latency), &Config::parseIntVec, ""},
+        {NGS(operation_detect_interaction_fails), &Config::parseBool, "false"},
+        {NGS(lockout), &Config::parseBool, "false"},
+        {NGS(lockout_enable), &Config::parseBool, "false"},
+        {NGS(lockout_timed_enable), &Config::parseBool, "false"},
+        {NGS(lockout_timed_threshold), &Config::parseInt32, "3"},
+        {NGS(lockout_timed_duration), &Config::parseInt32, "10000"},
+        {NGS(lockout_permanent_threshold), &Config::parseInt32, "5"},
+        {NGS(features), &Config::parseIntVec, ""}};
+
+Config::Data* FaceConfig::getConfigData(int* size) {
+    *size = sizeof(configData) / sizeof(configData[0]);
+    return configData;
+}
+
+}  // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/biometrics/face/aidl/default/FaceConfig.h
similarity index 62%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
copy to biometrics/face/aidl/default/FaceConfig.h
index c7be950..64b62e0 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ b/biometrics/face/aidl/default/FaceConfig.h
@@ -14,22 +14,14 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+#pragma once
 
-import android.hardware.biometrics.fingerprint.AcquiredInfo;
+#include "config/Config.h"
 
-/**
- * @hide
- */
-@VintfStability
-union AcquiredInfoAndVendorCode {
-    /**
-     * Acquired info as specified in AcqauiredInfo.aidl
-     */
-    AcquiredInfo acquiredInfo = AcquiredInfo.UNKNOWN;
+namespace aidl::android::hardware::biometrics::face {
 
-    /**
-     * Vendor specific code
-     */
-    int vendorCode;
-}
+class FaceConfig : public Config {
+    Config::Data* getConfigData(int* size) override;
+};
+
+}  // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/FakeFaceEngine.cpp b/biometrics/face/aidl/default/FakeFaceEngine.cpp
index bf75874..70d9f2d 100644
--- a/biometrics/face/aidl/default/FakeFaceEngine.cpp
+++ b/biometrics/face/aidl/default/FakeFaceEngine.cpp
@@ -23,6 +23,7 @@
 
 #include <face.sysprop.h>
 
+#include "Face.h"
 #include "util/CancellationSignal.h"
 #include "util/Util.h"
 
@@ -31,23 +32,23 @@
 namespace aidl::android::hardware::biometrics::face {
 
 FaceSensorType FakeFaceEngine::GetSensorType() {
-    std::string type = FaceHalProperties::type().value_or("");
+    std::string type = Face::cfg().get<std::string>("type");
     if (type == "IR") {
         return FaceSensorType::IR;
     } else {
-        FaceHalProperties::type("RGB");
+        Face::cfg().set<std::string>("type", "RGB");
         return FaceSensorType::RGB;
     }
 }
 
 common::SensorStrength FakeFaceEngine::GetSensorStrength() {
-    std::string strength = FaceHalProperties::strength().value_or("");
+    std::string strength = Face::cfg().get<std::string>("strength");
     if (strength == "convenience") {
         return common::SensorStrength::CONVENIENCE;
     } else if (strength == "weak") {
         return common::SensorStrength::WEAK;
     } else {
-        FaceHalProperties::strength("strong");
+        // Face::cfg().set<std::string>("strength", "strong");
         return common::SensorStrength::STRONG;
     }
 }
@@ -56,13 +57,13 @@
     BEGIN_OP(0);
     std::uniform_int_distribution<int64_t> dist;
     auto challenge = dist(mRandom);
-    FaceHalProperties::challenge(challenge);
+    Face::cfg().set<int64_t>("challenge", challenge);
     cb->onChallengeGenerated(challenge);
 }
 
 void FakeFaceEngine::revokeChallengeImpl(ISessionCallback* cb, int64_t challenge) {
     BEGIN_OP(0);
-    FaceHalProperties::challenge({});
+    Face::cfg().set<int64_t>("challenge", 0);
     cb->onChallengeRevoked(challenge);
 }
 void FakeFaceEngine::getEnrollmentConfigImpl(ISessionCallback* /*cb*/,
@@ -71,7 +72,7 @@
                                 EnrollmentType /*enrollmentType*/,
                                 const std::vector<Feature>& /*features*/,
                                 const std::future<void>& cancel) {
-    BEGIN_OP(getLatency(FaceHalProperties::operation_enroll_latency()));
+    BEGIN_OP(getLatency(Face::cfg().getopt<OptIntVec>("operation_enroll_latency")));
 
     // Do proper HAT verification in the real implementation.
     if (hat.mac.empty()) {
@@ -80,18 +81,19 @@
         return;
     }
 
-    // Format: <id>:<progress_ms-[acquiredInfo,...],...:<success>
-    // ------:-----------------------------------------:--------------
-    //          |           |                              |--->enrollment success (true/false)
-    //          |           |--> progress_steps
+    // Format:
+    //    <id>:<progress_ms-[acquiredInfo,...],...:<success>
+    //    -------:--------------------------------------------------:--------------
+    //          |           |                                                   |--->enrollment
+    //          success (true/false) |           |--> progress_steps
     //          |
     //          |-->enrollment id
     //
     //
-    //   progress_steps
+    //   progress_steps:
     //        <progress_duration>-[acquiredInfo,...]+
     //        ----------------------------  ---------------------
-    //                 |                            |-> sequence of acquiredInfo code
+    //                 |                              |-> sequence of acquiredInfo code
     //                 | --> time duration of the step in ms
     //
     //        E.g.   1:2000-[21,1108,5,6,1],1000-[1113,4,1]:true
@@ -101,7 +103,7 @@
     //
     std::string defaultNextEnrollment =
             "1:1000-[21,7,1,1103],1500-[1108,1],2000-[1113,1],2500-[1118,1]:true";
-    auto nextEnroll = FaceHalProperties::next_enrollment().value_or(defaultNextEnrollment);
+    auto nextEnroll = Face::cfg().get<std::string>("next_enrollment");
     auto parts = Util::split(nextEnroll, ":");
     if (parts.size() != 3) {
         LOG(ERROR) << "Fail: invalid next_enrollment:" << nextEnroll;
@@ -137,19 +139,19 @@
 
         if (left == 0 && !IS_TRUE(parts[2])) {  // end and failed
             LOG(ERROR) << "Fail: requested by caller: " << nextEnroll;
-            FaceHalProperties::next_enrollment({});
+            Face::cfg().setopt<OptString>("next_enrollment", std::nullopt);
             cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
         } else {  // progress and update props if last time
             LOG(INFO) << "onEnroll: " << enrollmentId << " left: " << left;
             if (left == 0) {
-                auto enrollments = FaceHalProperties::enrollments();
+                auto enrollments = Face::cfg().getopt<OptIntVec>("enrollments");
                 enrollments.emplace_back(enrollmentId);
-                FaceHalProperties::enrollments(enrollments);
-                FaceHalProperties::next_enrollment({});
+                Face::cfg().setopt<OptIntVec>("enrollments", enrollments);
+                Face::cfg().setopt<OptString>("next_enrollment", std::nullopt);
                 // change authenticatorId after new enrollment
-                auto id = FaceHalProperties::authenticator_id().value_or(0);
+                auto id = Face::cfg().get<std::int64_t>("authenticator_id");
                 auto newId = id + 1;
-                FaceHalProperties::authenticator_id(newId);
+                Face::cfg().set<std::int64_t>("authenticator_id", newId);
                 LOG(INFO) << "Enrolled: " << enrollmentId;
             }
             cb->onEnrollmentProgress(enrollmentId, left);
@@ -159,10 +161,12 @@
 
 void FakeFaceEngine::authenticateImpl(ISessionCallback* cb, int64_t /*operationId*/,
                                       const std::future<void>& cancel) {
-    BEGIN_OP(getLatency(FaceHalProperties::operation_authenticate_latency()));
+    BEGIN_OP(getLatency(Face::cfg().getopt<OptIntVec>("operation_authenticate_latency")));
 
-    auto id = FaceHalProperties::enrollment_hit().value_or(0);
-    auto enrolls = FaceHalProperties::enrollments();
+    // SLEEP_MS(3000);  //emulate hw HAL
+
+    auto id = Face::cfg().get<std::int32_t>("enrollment_hit");
+    auto enrolls = Face::cfg().getopt<OptIntVec>("enrollments");
     auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
 
     auto vec2str = [](std::vector<AcquiredInfo> va) {
@@ -192,10 +196,12 @@
     }
 
     int64_t now = Util::getSystemNanoTime();
-    int64_t duration =
-            FaceHalProperties::operation_authenticate_duration().value_or(defaultAuthDuration);
-    auto acquired =
-            FaceHalProperties::operation_authenticate_acquired().value_or(defaultAcquiredInfo);
+    int64_t duration = Face::cfg().get<std::int32_t>("operation_authenticate_duration");
+    auto acquired = Face::cfg().get<std::string>("operation_authenticate_acquired");
+    if (acquired.empty()) {
+        Face::cfg().set<std::string>("operation_authenticate_acquired", defaultAcquiredInfo);
+        acquired = defaultAcquiredInfo;
+    }
     auto acquiredInfos = Util::parseIntSequence(acquired);
     int N = acquiredInfos.size();
 
@@ -211,21 +217,21 @@
 
     int i = 0;
     do {
-        if (FaceHalProperties::lockout().value_or(false)) {
+        if (Face::cfg().get<bool>("lockout")) {
             LOG(ERROR) << "Fail: lockout";
             cb->onLockoutPermanent();
             cb->onError(Error::HW_UNAVAILABLE, 0 /* vendorError */);
             return;
         }
 
-        if (FaceHalProperties::operation_authenticate_fails().value_or(false)) {
+        if (Face::cfg().get<bool>("operation_authenticate_fails")) {
             LOG(ERROR) << "Fail: operation_authenticate_fails";
             mLockoutTracker.addFailedAttempt(cb);
             cb->onAuthenticationFailed();
             return;
         }
 
-        auto err = FaceHalProperties::operation_authenticate_error().value_or(0);
+        auto err = Face::cfg().get<std::int32_t>("operation_authenticate_error");
         if (err != 0) {
             LOG(ERROR) << "Fail: operation_authenticate_error";
             auto ec = convertError(err);
@@ -249,6 +255,15 @@
             LOG(INFO) << "AcquiredInfo:" << i << ": (" << (int)ac.first << "," << (int)ac.second
                       << ")";
             i++;
+
+            // the captured face id may change during authentication period
+            auto idnew = Face::cfg().get<std::int32_t>("enrollment_hit");
+            if (id != idnew) {
+                isEnrolled = std::find(enrolls.begin(), enrolls.end(), idnew) != enrolls.end();
+                LOG(INFO) << "enrollment_hit changed from " << id << " to " << idnew;
+                id = idnew;
+                break;
+            }
         }
 
         SLEEP_MS(duration / N);
@@ -292,9 +307,9 @@
 }
 
 void FakeFaceEngine::detectInteractionImpl(ISessionCallback* cb, const std::future<void>& cancel) {
-    BEGIN_OP(getLatency(FaceHalProperties::operation_detect_interaction_latency()));
+    BEGIN_OP(getLatency(Face::cfg().getopt<OptIntVec>("operation_detect_interaction_latency")));
 
-    if (FaceHalProperties::operation_detect_interaction_fails().value_or(false)) {
+    if (Face::cfg().get<bool>("operation_detect_interaction_fails")) {
         LOG(ERROR) << "Fail: operation_detect_interaction_fails";
         cb->onError(Error::VENDOR, 0 /* vendorError */);
         return;
@@ -306,8 +321,8 @@
         return;
     }
 
-    auto id = FaceHalProperties::enrollment_hit().value_or(0);
-    auto enrolls = FaceHalProperties::enrollments();
+    auto id = Face::cfg().get<std::int32_t>("enrollment_hit");
+    auto enrolls = Face::cfg().getopt<OptIntVec>("enrollments");
     auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
     if (id <= 0 || !isEnrolled) {
         LOG(ERROR) << "Fail: not enrolled";
@@ -321,7 +336,7 @@
 void FakeFaceEngine::enumerateEnrollmentsImpl(ISessionCallback* cb) {
     BEGIN_OP(0);
     std::vector<int32_t> enrollments;
-    for (const auto& enrollmentId : FaceHalProperties::enrollments()) {
+    for (const auto& enrollmentId : Face::cfg().getopt<OptIntVec>("enrollments")) {
         if (enrollmentId) {
             enrollments.push_back(*enrollmentId);
         }
@@ -334,20 +349,20 @@
     BEGIN_OP(0);
 
     std::vector<std::optional<int32_t>> newEnrollments;
-    for (const auto& enrollment : FaceHalProperties::enrollments()) {
+    for (const auto& enrollment : Face::cfg().getopt<OptIntVec>("enrollments")) {
         auto id = enrollment.value_or(0);
         if (std::find(enrollmentIds.begin(), enrollmentIds.end(), id) == enrollmentIds.end()) {
             newEnrollments.emplace_back(id);
         }
     }
-    FaceHalProperties::enrollments(newEnrollments);
+    Face::cfg().setopt<OptIntVec>("enrollments", newEnrollments);
     cb->onEnrollmentsRemoved(enrollmentIds);
 }
 
 void FakeFaceEngine::getFeaturesImpl(ISessionCallback* cb) {
     BEGIN_OP(0);
 
-    if (FaceHalProperties::enrollments().empty()) {
+    if (Face::cfg().getopt<OptIntVec>("enrollments").empty()) {
         cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
         return;
     }
@@ -365,7 +380,7 @@
                                     Feature feature, bool enabled) {
     BEGIN_OP(0);
 
-    if (FaceHalProperties::enrollments().empty()) {
+    if (Face::cfg().getopt<OptIntVec>("enrollments").empty()) {
         LOG(ERROR) << "Unable to set feature, enrollments are empty";
         cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
         return;
@@ -377,7 +392,7 @@
         return;
     }
 
-    auto features = FaceHalProperties::features();
+    auto features = Face::cfg().getopt<OptIntVec>("features");
 
     auto itr = std::find_if(features.begin(), features.end(), [feature](const auto& theFeature) {
         return *theFeature == (int)feature;
@@ -389,7 +404,7 @@
         features.push_back((int)feature);
     }
 
-    FaceHalProperties::features(features);
+    Face::cfg().setopt<OptIntVec>("features", features);
     cb->onFeatureSet(feature);
 }
 
@@ -399,22 +414,22 @@
     if (GetSensorStrength() != common::SensorStrength::STRONG) {
         cb->onAuthenticatorIdRetrieved(0);
     } else {
-        cb->onAuthenticatorIdRetrieved(FaceHalProperties::authenticator_id().value_or(0));
+        cb->onAuthenticatorIdRetrieved(Face::cfg().get<std::int64_t>("authenticator_id"));
     }
 }
 
 void FakeFaceEngine::invalidateAuthenticatorIdImpl(ISessionCallback* cb) {
     BEGIN_OP(0);
-    int64_t authenticatorId = FaceHalProperties::authenticator_id().value_or(0);
+    int64_t authenticatorId = Face::cfg().get<std::int64_t>("authenticator_id");
     int64_t newId = authenticatorId + 1;
-    FaceHalProperties::authenticator_id(newId);
+    Face::cfg().set<std::int64_t>("authenticator_id", newId);
     cb->onAuthenticatorIdInvalidated(newId);
 }
 
 void FakeFaceEngine::resetLockoutImpl(ISessionCallback* cb,
                                       const keymaster::HardwareAuthToken& /*hat*/) {
     BEGIN_OP(0);
-    FaceHalProperties::lockout(false);
+    Face::cfg().set<bool>("lockout", false);
     mLockoutTracker.reset();
     cb->onLockoutCleared();
 }
diff --git a/biometrics/face/aidl/default/FakeLockoutTracker.cpp b/biometrics/face/aidl/default/FakeLockoutTracker.cpp
index 70bf08e..35d7c28 100644
--- a/biometrics/face/aidl/default/FakeLockoutTracker.cpp
+++ b/biometrics/face/aidl/default/FakeLockoutTracker.cpp
@@ -19,6 +19,7 @@
 #include "FakeLockoutTracker.h"
 #include <android-base/logging.h>
 #include <face.sysprop.h>
+#include "Face.h"
 #include "util/Util.h"
 
 using namespace ::android::face::virt;
@@ -36,15 +37,15 @@
 }
 
 void FakeLockoutTracker::addFailedAttempt(ISessionCallback* cb) {
-    bool lockoutEnabled = FaceHalProperties::lockout_enable().value_or(false);
-    bool timedLockoutenabled = FaceHalProperties::lockout_timed_enable().value_or(false);
+    bool lockoutEnabled = Face::cfg().get<bool>("lockout_enable");
+    bool timedLockoutenabled = Face::cfg().get<bool>("lockout_timed_enable");
     if (lockoutEnabled) {
         mFailedCount++;
         mTimedFailedCount++;
         mLastFailedTime = Util::getSystemNanoTime();
-        int32_t lockoutTimedThreshold = FaceHalProperties::lockout_timed_threshold().value_or(3);
+        int32_t lockoutTimedThreshold = Face::cfg().get<std::int32_t>("lockout_timed_threshold");
         int32_t lockoutPermanetThreshold =
-                FaceHalProperties::lockout_permanent_threshold().value_or(5);
+                Face::cfg().get<std::int32_t>("lockout_permanent_threshold");
         if (mFailedCount >= lockoutPermanetThreshold) {
             mCurrentMode = LockoutMode::kPermanent;
             LOG(ERROR) << "FakeLockoutTracker: lockoutPermanent";
@@ -68,7 +69,7 @@
 }
 
 int32_t FakeLockoutTracker::getTimedLockoutDuration() {
-    return FaceHalProperties::lockout_timed_duration().value_or(10 * 1000);
+    return Face::cfg().get<std::int32_t>("lockout_timed_duration");
 }
 
 int64_t FakeLockoutTracker::getLockoutTimeLeft() {
diff --git a/biometrics/face/aidl/default/VirtualHal.cpp b/biometrics/face/aidl/default/VirtualHal.cpp
new file mode 100644
index 0000000..52ac23b
--- /dev/null
+++ b/biometrics/face/aidl/default/VirtualHal.cpp
@@ -0,0 +1,275 @@
+/*
+ * 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.
+ */
+
+#include <unordered_map>
+
+#include "VirtualHal.h"
+
+#include <android-base/logging.h>
+
+#include "util/CancellationSignal.h"
+
+#undef LOG_TAG
+#define LOG_TAG "FaceVirtualHalAidl"
+
+namespace aidl::android::hardware::biometrics::face {
+using AcquiredInfoAndVendorCode = virtualhal::AcquiredInfoAndVendorCode;
+using Tag = AcquiredInfoAndVendorCode::Tag;
+
+::ndk::ScopedAStatus VirtualHal::setEnrollments(const std::vector<int32_t>& enrollments) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().setopt<OptIntVec>("enrollments", intVec2OptIntVec(enrollments));
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setEnrollmentHit(int32_t enrollment_hit) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<std::int32_t>("enrollment_hit", enrollment_hit);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setNextEnrollment(
+        const ::aidl::android::hardware::biometrics::face::NextEnrollment& next_enrollment) {
+    Face::cfg().sourcedFromAidl();
+    std::ostringstream os;
+    os << next_enrollment.id << ":";
+
+    int stepSize = next_enrollment.progressSteps.size();
+    for (int i = 0; i < stepSize; i++) {
+        auto& step = next_enrollment.progressSteps[i];
+        os << step.durationMs;
+        int acSize = step.acquiredInfoAndVendorCodes.size();
+        for (int j = 0; j < acSize; j++) {
+            if (j == 0) os << "-[";
+            auto& acquiredInfoAndVendorCode = step.acquiredInfoAndVendorCodes[j];
+            if (acquiredInfoAndVendorCode.getTag() == AcquiredInfoAndVendorCode::vendorCode)
+                os << acquiredInfoAndVendorCode.get<Tag::vendorCode>();
+            else if (acquiredInfoAndVendorCode.getTag() == AcquiredInfoAndVendorCode::acquiredInfo)
+                os << (int)acquiredInfoAndVendorCode.get<Tag::acquiredInfo>();
+            else
+                LOG(FATAL) << "ERROR: wrong AcquiredInfoAndVendorCode union tag";
+            if (j == acSize - 1)
+                os << "]";
+            else
+                os << ",";
+        }
+        if (i == stepSize - 1)
+            os << ":";
+        else
+            os << ",";
+    }
+
+    os << (next_enrollment.result ? "true" : "false");
+    Face::cfg().set<std::string>("next_enrollment", os.str());
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setAuthenticatorId(int64_t in_id) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<int64_t>("authenticator_id", in_id);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setChallenge(int64_t in_challenge) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<int64_t>("challenge", in_challenge);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setOperationAuthenticateFails(bool in_fail) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<bool>("operation_authenticate_fails", in_fail);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setOperationAuthenticateLatency(
+        const std::vector<int32_t>& in_latency) {
+    ndk::ScopedAStatus status = sanityCheckLatency(in_latency);
+    if (!status.isOk()) {
+        return status;
+    }
+
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().setopt<OptIntVec>("operation_authenticate_latency", intVec2OptIntVec(in_latency));
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setOperationAuthenticateDuration(int32_t in_duration) {
+    if (in_duration < 0) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IVirtualHal::STATUS_INVALID_PARAMETER, "Error: duration can not be negative"));
+    }
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<int32_t>("operation_authenticate_duration", in_duration);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setOperationAuthenticateError(int32_t in_error) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<int32_t>("operation_authenticate_error", in_error);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setOperationAuthenticateAcquired(
+        const std::vector<AcquiredInfoAndVendorCode>& in_acquired) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().setopt<OptIntVec>("operation_authenticate_acquired",
+                                  acquiredInfoVec2OptIntVec(in_acquired));
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setOperationEnrollLatency(const std::vector<int32_t>& in_latency) {
+    ndk::ScopedAStatus status = sanityCheckLatency(in_latency);
+    if (!status.isOk()) {
+        return status;
+    }
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().setopt<OptIntVec>("operation_enroll_latency", intVec2OptIntVec(in_latency));
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setOperationDetectInteractionLatency(
+        const std::vector<int32_t>& in_latency) {
+    ndk::ScopedAStatus status = sanityCheckLatency(in_latency);
+    if (!status.isOk()) {
+        return status;
+    }
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().setopt<OptIntVec>("operation_detect_interact_latency",
+                                  intVec2OptIntVec(in_latency));
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setOperationDetectInteractionFails(bool in_fails) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<bool>("operation_detect_interaction_fails", in_fails);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setLockout(bool in_lockout) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<bool>("lockout", in_lockout);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setLockoutEnable(bool in_enable) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<bool>("lockout_enable", in_enable);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setLockoutTimedEnable(bool in_enable) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<bool>("lockout_timed_enable", in_enable);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setLockoutTimedThreshold(int32_t in_threshold) {
+    if (in_threshold < 0) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IVirtualHal::STATUS_INVALID_PARAMETER, "Error: threshold can not be negative"));
+    }
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<int32_t>("lockout_timed_threshold", in_threshold);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setLockoutTimedDuration(int32_t in_duration) {
+    if (in_duration < 0) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IVirtualHal::STATUS_INVALID_PARAMETER, "Error: duration can not be negative"));
+    }
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<int32_t>("lockout_timed_duration", in_duration);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setLockoutPermanentThreshold(int32_t in_threshold) {
+    if (in_threshold < 0) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IVirtualHal::STATUS_INVALID_PARAMETER, "Error: threshold can not be negative"));
+    }
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<int32_t>("lockout_permanent_threshold", in_threshold);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::resetConfigurations() {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().init();
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setType(
+        ::aidl::android::hardware::biometrics::face::FaceSensorType in_type) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<std::string>("type", Face::type2String(in_type));
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setSensorStrength(common::SensorStrength in_strength) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<std::string>("strength", Face::strength2String(in_strength));
+    return ndk::ScopedAStatus::ok();
+}
+
+OptIntVec VirtualHal::intVec2OptIntVec(const std::vector<int32_t>& in_vec) {
+    OptIntVec optIntVec;
+    std::transform(in_vec.begin(), in_vec.end(), std::back_inserter(optIntVec),
+                   [](int value) { return std::optional<int>(value); });
+    return optIntVec;
+}
+
+OptIntVec VirtualHal::acquiredInfoVec2OptIntVec(
+        const std::vector<AcquiredInfoAndVendorCode>& in_vec) {
+    OptIntVec optIntVec;
+    std::transform(in_vec.begin(), in_vec.end(), std::back_inserter(optIntVec),
+                   [](AcquiredInfoAndVendorCode ac) {
+                       int value;
+                       if (ac.getTag() == AcquiredInfoAndVendorCode::acquiredInfo)
+                           value = (int)ac.get<Tag::acquiredInfo>();
+                       else if (ac.getTag() == AcquiredInfoAndVendorCode::vendorCode)
+                           value = ac.get<Tag::vendorCode>();
+                       else
+                           LOG(FATAL) << "ERROR: wrong AcquiredInfoAndVendorCode tag";
+                       return std::optional<int>(value);
+                   });
+    return optIntVec;
+}
+
+::ndk::ScopedAStatus VirtualHal::sanityCheckLatency(const std::vector<int32_t>& in_latency) {
+    if (in_latency.size() == 0 || in_latency.size() > 2) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IVirtualHal::STATUS_INVALID_PARAMETER,
+                "Error: input input array must contain 1 or 2 elements"));
+    }
+
+    for (auto x : in_latency) {
+        if (x < 0) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IVirtualHal::STATUS_INVALID_PARAMETER,
+                    "Error: input data must not be negative"));
+        }
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::getFaceHal(std::shared_ptr<IFace>* pFace) {
+    *pFace = mFp;
+    return ndk::ScopedAStatus::ok();
+}
+}  // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/VirtualHal.h b/biometrics/face/aidl/default/VirtualHal.h
new file mode 100644
index 0000000..f2ac552
--- /dev/null
+++ b/biometrics/face/aidl/default/VirtualHal.h
@@ -0,0 +1,66 @@
+/*
+ * 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/biometrics/face/virtualhal/BnVirtualHal.h>
+
+#include "Face.h"
+
+namespace aidl::android::hardware::biometrics::face {
+using namespace virtualhal;
+class VirtualHal : public BnVirtualHal {
+  public:
+    VirtualHal(std::shared_ptr<Face> 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::face::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;
+    ::ndk::ScopedAStatus setOperationAuthenticateLatency(
+            const std::vector<int32_t>& in_latency) override;
+    ::ndk::ScopedAStatus setOperationAuthenticateDuration(int32_t in_duration) override;
+    ::ndk::ScopedAStatus setOperationAuthenticateError(int32_t in_error) override;
+    ::ndk::ScopedAStatus setOperationAuthenticateAcquired(
+            const std::vector<AcquiredInfoAndVendorCode>& in_acquired) override;
+    ::ndk::ScopedAStatus setOperationEnrollLatency(const std::vector<int32_t>& in_latency) override;
+    ::ndk::ScopedAStatus setOperationDetectInteractionLatency(
+            const std::vector<int32_t>& in_latency) override;
+    ::ndk::ScopedAStatus setOperationDetectInteractionFails(bool in_fails) override;
+    ::ndk::ScopedAStatus setLockout(bool in_lockout) override;
+    ::ndk::ScopedAStatus setLockoutEnable(bool in_enable) override;
+    ::ndk::ScopedAStatus setLockoutTimedEnable(bool in_enable) override;
+    ::ndk::ScopedAStatus setLockoutTimedThreshold(int32_t in_threshold) override;
+    ::ndk::ScopedAStatus setLockoutTimedDuration(int32_t in_duration) override;
+    ::ndk::ScopedAStatus setLockoutPermanentThreshold(int32_t in_threshold) override;
+    ::ndk::ScopedAStatus resetConfigurations() override;
+    ::ndk::ScopedAStatus setType(
+            ::aidl::android::hardware::biometrics::face::FaceSensorType in_type) override;
+    ::ndk::ScopedAStatus setSensorStrength(common::SensorStrength in_strength) override;
+    ::ndk::ScopedAStatus getFaceHal(std::shared_ptr<IFace>* _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);
+    std::shared_ptr<Face> mFp;
+};
+
+}  // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/apex/Android.bp b/biometrics/face/aidl/default/apex/Android.bp
index 86c4e12..c4632d4 100644
--- a/biometrics/face/aidl/default/apex/Android.bp
+++ b/biometrics/face/aidl/default/apex/Android.bp
@@ -23,7 +23,7 @@
     key: "com.android.hardware.key",
     certificate: ":com.android.hardware.certificate",
     updatable: false,
-    vendor: true,
+    system_ext_specific: true,
 
     binaries: [
         // hal
@@ -31,9 +31,7 @@
     ],
     prebuilts: [
         // init_rc
-        "face-example-apex.rc",
-        // vintf_fragment
-        "face-example-apex.xml",
+        "face-virtual-apex.rc",
     ],
 
     overrides: [
@@ -42,21 +40,7 @@
 }
 
 prebuilt_etc {
-    name: "face-example-apex.rc",
-    src: ":gen-face-example-apex.rc",
-    installable: false,
-}
-
-genrule {
-    name: "gen-face-example-apex.rc",
-    srcs: [":face-example.rc"],
-    out: ["face-example-apex.rc"],
-    cmd: "sed -e 's@/vendor/bin/@/apex/com.android.hardware.biometrics.face.virtual/bin/@' $(in) > $(out)",
-}
-
-prebuilt_etc {
-    name: "face-example-apex.xml",
-    src: ":face-example.xml",
-    sub_dir: "vintf",
+    name: "face-virtual-apex.rc",
+    src: ":face-virtual.rc",
     installable: false,
 }
diff --git a/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt b/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt
index e69de29..6ad579c 100644
--- a/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt
+++ b/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt
@@ -0,0 +1,133 @@
+props {
+  owner: Vendor
+  module: "android.face.virt.FaceHalProperties"
+  prop {
+    api_name: "authenticator_id"
+    type: Long
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.authenticator_id"
+  }
+  prop {
+    api_name: "challenge"
+    type: Long
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.challenge"
+  }
+  prop {
+    api_name: "enrollment_hit"
+    type: Integer
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.enrollment_hit"
+  }
+  prop {
+    api_name: "enrollments"
+    type: IntegerList
+    access: ReadWrite
+    prop_name: "persist.vendor.face.virtual.enrollments"
+  }
+  prop {
+    api_name: "features"
+    type: IntegerList
+    access: ReadWrite
+    prop_name: "persist.vendor.face.virtual.features"
+  }
+  prop {
+    api_name: "lockout"
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.lockout"
+  }
+  prop {
+    api_name: "lockout_enable"
+    access: ReadWrite
+    prop_name: "persist.vendor.face.virtual.lockout_enable"
+  }
+  prop {
+    api_name: "lockout_permanent_threshold"
+    type: Integer
+    access: ReadWrite
+    prop_name: "persist.vendor.face.virtual.lockout_permanent_threshold"
+  }
+  prop {
+    api_name: "lockout_timed_duration"
+    type: Integer
+    access: ReadWrite
+    prop_name: "persist.vendor.face.virtual.lockout_timed_duration"
+  }
+  prop {
+    api_name: "lockout_timed_enable"
+    access: ReadWrite
+    prop_name: "persist.vendor.face.virtual.lockout_timed_enable"
+  }
+  prop {
+    api_name: "lockout_timed_threshold"
+    type: Integer
+    access: ReadWrite
+    prop_name: "persist.vendor.face.virtual.lockout_timed_threshold"
+  }
+  prop {
+    api_name: "next_enrollment"
+    type: String
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.next_enrollment"
+  }
+  prop {
+    api_name: "operation_authenticate_acquired"
+    type: String
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.operation_authenticate_acquired"
+  }
+  prop {
+    api_name: "operation_authenticate_duration"
+    type: Integer
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.operation_authenticate_duration"
+  }
+  prop {
+    api_name: "operation_authenticate_error"
+    type: Integer
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.operation_authenticate_error"
+  }
+  prop {
+    api_name: "operation_authenticate_fails"
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.operation_authenticate_fails"
+  }
+  prop {
+    api_name: "operation_authenticate_latency"
+    type: IntegerList
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.operation_authenticate_latency"
+  }
+  prop {
+    api_name: "operation_detect_interaction_fails"
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.operation_detect_interaction_fails"
+  }
+  prop {
+    api_name: "operation_detect_interaction_latency"
+    type: IntegerList
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.operation_detect_interaction_latency"
+  }
+  prop {
+    api_name: "operation_enroll_latency"
+    type: IntegerList
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.operation_enroll_latency"
+  }
+  prop {
+    api_name: "strength"
+    type: String
+    access: ReadWrite
+    prop_name: "persist.vendor.face.virtual.strength"
+    enum_values: "convenience|weak|strong"
+  }
+  prop {
+    api_name: "type"
+    type: String
+    access: ReadWrite
+    prop_name: "persist.vendor.face.virtual.type"
+    enum_values: "IR|RGB"
+  }
+}
diff --git a/biometrics/face/aidl/default/face-default.rc b/biometrics/face/aidl/default/face-default.rc
new file mode 100644
index 0000000..7ce4249
--- /dev/null
+++ b/biometrics/face/aidl/default/face-default.rc
@@ -0,0 +1,8 @@
+service vendor.face-default /vendor/bin/hw/android.hardware.biometrics.face-service.default default
+    class hal
+    user nobody
+    group nobody
+    interface aidl android.hardware.biometrics.face.IFace/default
+    oneshot
+    disabled
+
diff --git a/biometrics/face/aidl/default/face-example.xml b/biometrics/face/aidl/default/face-default.xml
similarity index 81%
rename from biometrics/face/aidl/default/face-example.xml
rename to biometrics/face/aidl/default/face-default.xml
index 2b39b3d..94569de 100644
--- a/biometrics/face/aidl/default/face-example.xml
+++ b/biometrics/face/aidl/default/face-default.xml
@@ -2,6 +2,6 @@
     <hal format="aidl">
         <name>android.hardware.biometrics.face</name>
         <version>4</version>
-        <fqname>IFace/virtual</fqname>
+        <fqname>IFace/default</fqname>
     </hal>
 </manifest>
diff --git a/biometrics/face/aidl/default/face-example.rc b/biometrics/face/aidl/default/face-example.rc
deleted file mode 100644
index b0d82c6..0000000
--- a/biometrics/face/aidl/default/face-example.rc
+++ /dev/null
@@ -1,8 +0,0 @@
-service vendor.face-example /vendor/bin/hw/android.hardware.biometrics.face-service.example
-    class hal
-    user nobody
-    group nobody
-    interface aidl android.hardware.biometrics.face.IFace/virtual
-    oneshot
-    disabled
-
diff --git a/biometrics/face/aidl/default/face-virtual.rc b/biometrics/face/aidl/default/face-virtual.rc
new file mode 100644
index 0000000..8fb0a7b
--- /dev/null
+++ b/biometrics/face/aidl/default/face-virtual.rc
@@ -0,0 +1,8 @@
+service face-virtual /apex/com.android.hardware.biometrics.face.virtual/bin/hw/android.hardware.biometrics.face-service.example virtual
+    class hal
+    user nobody
+    group nobody
+    interface aidl android.hardware.biometrics.face.virtualhal.IVirtualHal/virtual
+    oneshot
+    disabled
+
diff --git a/biometrics/face/aidl/default/face.sysprop b/biometrics/face/aidl/default/face.sysprop
index 997fd67..ec2b92b 100644
--- a/biometrics/face/aidl/default/face.sysprop
+++ b/biometrics/face/aidl/default/face.sysprop
@@ -7,7 +7,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.type"
     type: String
-    scope: Internal
+    scope: Public
     access: ReadWrite
     enum_values: "IR|RGB"
     api_name: "type"
@@ -17,7 +17,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.strength"
     type: String
-    scope: Internal
+    scope: Public
     access: ReadWrite
     enum_values: "convenience|weak|strong"
     api_name: "strength"
@@ -27,7 +27,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.enrollments"
     type: IntegerList
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "enrollments"
 }
@@ -36,7 +36,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.features"
     type: IntegerList
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "features"
 }
@@ -46,7 +46,7 @@
 prop {
     prop_name: "vendor.face.virtual.enrollment_hit"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "enrollment_hit"
 }
@@ -60,7 +60,7 @@
 prop {
     prop_name: "vendor.face.virtual.next_enrollment"
     type: String
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "next_enrollment"
 }
@@ -69,7 +69,7 @@
 prop {
     prop_name: "vendor.face.virtual.authenticator_id"
     type: Long
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "authenticator_id"
 }
@@ -78,7 +78,7 @@
 prop {
     prop_name: "vendor.face.virtual.challenge"
     type: Long
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "challenge"
 }
@@ -87,7 +87,7 @@
 prop {
     prop_name: "vendor.face.virtual.lockout"
     type: Boolean
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "lockout"
 }
@@ -96,7 +96,7 @@
 prop {
     prop_name: "vendor.face.virtual.operation_authenticate_fails"
     type: Boolean
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_authenticate_fails"
 }
@@ -105,27 +105,18 @@
 prop {
     prop_name: "vendor.face.virtual.operation_detect_interaction_fails"
     type: Boolean
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_detect_interaction_fails"
 }
 
-# force all enroll operations to fail
-prop {
-    prop_name: "vendor.face.virtual.operation_enroll_fails"
-    type: Boolean
-    scope: Internal
-    access: ReadWrite
-    api_name: "operation_enroll_fails"
-}
-
 # add a latency to authentication operations
 # Note that this latency is the initial authentication latency that occurs before
 # the HAL will send AcquiredInfo::START and AcquiredInfo::FIRST_FRAME_RECEIVED
 prop {
     prop_name: "vendor.face.virtual.operation_authenticate_latency"
     type: IntegerList
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_authenticate_latency"
 }
@@ -134,7 +125,7 @@
 prop {
     prop_name: "vendor.face.virtual.operation_detect_interaction_latency"
     type: IntegerList
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_detect_interaction_latency"
 }
@@ -143,7 +134,7 @@
 prop {
     prop_name: "vendor.face.virtual.operation_enroll_latency"
     type: IntegerList
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_enroll_latency"
 }
@@ -153,7 +144,7 @@
 prop {
     prop_name: "vendor.face.virtual.operation_authenticate_duration"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_authenticate_duration"
 }
@@ -162,7 +153,7 @@
 prop {
     prop_name: "vendor.face.virtual.operation_authenticate_error"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_authenticate_error"
 }
@@ -171,7 +162,7 @@
 prop {
     prop_name: "vendor.face.virtual.operation_authenticate_acquired"
     type: String
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_authenticate_acquired"
 }
@@ -180,7 +171,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.lockout_enable"
     type: Boolean
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "lockout_enable"
 }
@@ -189,7 +180,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.lockout_timed_enable"
     type: Boolean
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "lockout_timed_enable"
 }
@@ -198,7 +189,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.lockout_timed_threshold"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "lockout_timed_threshold"
 }
@@ -207,7 +198,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.lockout_timed_duration"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "lockout_timed_duration"
 }
@@ -216,7 +207,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.lockout_permanent_threshold"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "lockout_permanent_threshold"
 }
diff --git a/biometrics/face/aidl/default/main.cpp b/biometrics/face/aidl/default/main.cpp
index 38e1c63..75a4479 100644
--- a/biometrics/face/aidl/default/main.cpp
+++ b/biometrics/face/aidl/default/main.cpp
@@ -14,25 +14,49 @@
  * limitations under the License.
  */
 
+#undef LOG_TAG
+#define LOG_TAG "FaceVirtualHal"
+
 #include "Face.h"
+#include "VirtualHal.h"
 
 #include <android-base/logging.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
 
 using aidl::android::hardware::biometrics::face::Face;
+using aidl::android::hardware::biometrics::face::VirtualHal;
 
-int main() {
-    LOG(INFO) << "Face HAL started";
+int main(int argc, char** argv) {
+    if (argc < 2) {
+        LOG(ERROR) << "Missing argument -> exiting, Valid arguments:[default|virtual]";
+        return EXIT_FAILURE;
+    }
+    LOG(INFO) << "Face HAL started: " << argv[1];
     ABinderProcess_setThreadPoolMaxThreadCount(0);
     std::shared_ptr<Face> hal = ndk::SharedRefBase::make<Face>();
+    std::shared_ptr<VirtualHal> hal_vhal = ndk::SharedRefBase::make<VirtualHal>(hal);
 
-    const std::string instance = std::string(Face::descriptor) + "/virtual";
-    binder_status_t status =
-            AServiceManager_registerLazyService(hal->asBinder().get(), instance.c_str());
-    CHECK_EQ(status, STATUS_OK);
+    if (strcmp(argv[1], "default") == 0) {
+        const std::string instance = std::string(Face::descriptor) + "/default";
+        auto binder = hal->asBinder();
+        binder_status_t status =
+                AServiceManager_registerLazyService(binder.get(), instance.c_str());
+        CHECK_EQ(status, STATUS_OK);
+        LOG(INFO) << "started IFace/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);
 
     ABinderProcess_joinThreadPool();
-    return EXIT_FAILURE;  // should not reach
+    return EXIT_FAILURE;  // should not reach here
 }
diff --git a/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp b/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp
index 8c39b58..d448532 100644
--- a/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp
+++ b/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp
@@ -21,6 +21,7 @@
 #include <aidl/android/hardware/biometrics/face/BnSessionCallback.h>
 #include <android-base/logging.h>
 
+#include "Face.h"
 #include "FakeFaceEngine.h"
 #include "util/Util.h"
 
@@ -141,12 +142,12 @@
     }
 
     void TearDown() override {
-        FaceHalProperties::enrollments({});
-        FaceHalProperties::challenge({});
-        FaceHalProperties::features({});
-        FaceHalProperties::authenticator_id({});
-        FaceHalProperties::strength("");
-        FaceHalProperties::operation_detect_interaction_latency({});
+        Face::cfg().setopt<OptIntVec>("enrollments", {});
+        Face::cfg().set<std::int64_t>("challenge", 0);
+        Face::cfg().setopt<OptIntVec>("features", {});
+        Face::cfg().set<std::int64_t>("authenticator_id", 0);
+        Face::cfg().set<std::string>("strength", "");
+        Face::cfg().setopt<OptIntVec>("operation_detect_interaction_latency", {});
     }
 
     FakeFaceEngine mEngine;
@@ -160,81 +161,83 @@
 
 TEST_F(FakeFaceEngineTest, GenerateChallenge) {
     mEngine.generateChallengeImpl(mCallback.get());
-    ASSERT_EQ(FaceHalProperties::challenge().value(), mCallback->mLastChallenge);
+    ASSERT_EQ(Face::cfg().get<std::int64_t>("challenge"), mCallback->mLastChallenge);
 }
 
 TEST_F(FakeFaceEngineTest, RevokeChallenge) {
-    auto challenge = FaceHalProperties::challenge().value_or(10);
+    auto challenge = Face::cfg().get<std::int64_t>("challenge");
     mEngine.revokeChallengeImpl(mCallback.get(), challenge);
-    ASSERT_FALSE(FaceHalProperties::challenge().has_value());
+    ASSERT_FALSE(Face::cfg().get<std::int64_t>("challenge"));
     ASSERT_EQ(challenge, mCallback->mLastChallengeRevoked);
 }
 
 TEST_F(FakeFaceEngineTest, ResetLockout) {
-    FaceHalProperties::lockout(true);
+    Face::cfg().set<bool>("lockout", true);
     mEngine.resetLockoutImpl(mCallback.get(), {});
     ASSERT_FALSE(mCallback->mLockoutPermanent);
-    ASSERT_FALSE(FaceHalProperties::lockout().value_or(true));
+    ASSERT_FALSE(Face::cfg().get<bool>("lockout"));
 }
 
 TEST_F(FakeFaceEngineTest, AuthenticatorId) {
-    FaceHalProperties::authenticator_id(50);
+    Face::cfg().set<std::int64_t>("authenticator_id", 50);
     mEngine.getAuthenticatorIdImpl(mCallback.get());
     ASSERT_EQ(50, mCallback->mLastAuthenticatorId);
     ASSERT_FALSE(mCallback->mAuthenticatorIdInvalidated);
 }
 
 TEST_F(FakeFaceEngineTest, GetAuthenticatorIdWeakReturnsZero) {
-    FaceHalProperties::strength("weak");
-    FaceHalProperties::authenticator_id(500);
+    Face::cfg().set<std::string>("strength", "weak");
+    Face::cfg().set<std::int64_t>("authenticator_id", 500);
     mEngine.getAuthenticatorIdImpl(mCallback.get());
     ASSERT_EQ(0, mCallback->mLastAuthenticatorId);
     ASSERT_FALSE(mCallback->mAuthenticatorIdInvalidated);
 }
 
 TEST_F(FakeFaceEngineTest, AuthenticatorIdInvalidate) {
-    FaceHalProperties::authenticator_id(500);
+    Face::cfg().set<std::int64_t>("authenticator_id", 500);
     mEngine.invalidateAuthenticatorIdImpl(mCallback.get());
-    ASSERT_NE(500, FaceHalProperties::authenticator_id().value());
+    ASSERT_NE(500, Face::cfg().get<std::int64_t>("authenticator_id"));
     ASSERT_TRUE(mCallback->mAuthenticatorIdInvalidated);
 }
 
 TEST_F(FakeFaceEngineTest, Enroll) {
-    FaceHalProperties::next_enrollment("1,0:1000-[21,5,6,7,1],1100-[1118,1108,1]:true");
+    Face::cfg().set<std::string>("next_enrollment",
+                                 "1,0:1000-[21,5,6,7,1],1100-[1118,1108,1]:true");
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mEngine.enrollImpl(mCallback.get(), hat, {} /*enrollmentType*/, {} /*features*/,
                        mCancel.get_future());
-    ASSERT_FALSE(FaceHalProperties::next_enrollment().has_value());
-    ASSERT_EQ(1, FaceHalProperties::enrollments().size());
-    ASSERT_EQ(1, FaceHalProperties::enrollments()[0].value());
+    ASSERT_FALSE(Face::cfg().getopt<OptString>("next_enrollment").has_value());
+    ASSERT_EQ(1, Face::cfg().getopt<OptIntVec>("enrollments").size());
+    ASSERT_EQ(1, Face::cfg().getopt<OptIntVec>("enrollments")[0].value());
     ASSERT_EQ(1, mCallback->mLastEnrolled);
     ASSERT_EQ(0, mCallback->mRemaining);
 }
 
 TEST_F(FakeFaceEngineTest, EnrollFails) {
-    FaceHalProperties::next_enrollment("1,0:1000-[21,5,6,7,1],1100-[1118,1108,1]:false");
+    Face::cfg().set<std::string>("next_enrollment",
+                                 "1,0:1000-[21,5,6,7,1],1100-[1118,1108,1]:false");
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mEngine.enrollImpl(mCallback.get(), hat, {} /*enrollmentType*/, {} /*features*/,
                        mCancel.get_future());
-    ASSERT_FALSE(FaceHalProperties::next_enrollment().has_value());
-    ASSERT_EQ(0, FaceHalProperties::enrollments().size());
+    ASSERT_FALSE(Face::cfg().getopt<OptString>("next_enrollment").has_value());
+    ASSERT_EQ(0, Face::cfg().getopt<OptIntVec>("enrollments").size());
 }
 
 TEST_F(FakeFaceEngineTest, EnrollCancel) {
-    FaceHalProperties::next_enrollment("1:2000-[21,8,9],300:false");
+    Face::cfg().set<std::string>("next_enrollment", "1:2000-[21,8,9],300:false");
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mCancel.set_value();
     mEngine.enrollImpl(mCallback.get(), hat, {} /*enrollmentType*/, {} /*features*/,
                        mCancel.get_future());
     ASSERT_EQ(Error::CANCELED, mCallback->mError);
     ASSERT_EQ(-1, mCallback->mLastEnrolled);
-    ASSERT_EQ(0, FaceHalProperties::enrollments().size());
-    ASSERT_TRUE(FaceHalProperties::next_enrollment().has_value());
+    ASSERT_EQ(0, Face::cfg().getopt<OptIntVec>("enrollments").size());
+    ASSERT_FALSE(Face::cfg().get<std::string>("next_enrollment").empty());
 }
 
 TEST_F(FakeFaceEngineTest, Authenticate) {
-    FaceHalProperties::enrollments({100});
-    FaceHalProperties::enrollment_hit(100);
+    Face::cfg().setopt<OptIntVec>("enrollments", {100});
+    Face::cfg().set<std::int32_t>("enrollment_hit", 100);
     mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future());
 
     ASSERT_EQ(100, mCallback->mLastAuthenticated);
@@ -242,32 +245,32 @@
 }
 
 TEST_F(FakeFaceEngineTest, AuthenticateCancel) {
-    FaceHalProperties::enrollments({100});
-    FaceHalProperties::enrollment_hit(100);
+    Face::cfg().setopt<OptIntVec>("enrollments", {100});
+    Face::cfg().set<std::int32_t>("enrollment_hit", 100);
     mCancel.set_value();
     mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future());
     ASSERT_EQ(Error::CANCELED, mCallback->mError);
 }
 
 TEST_F(FakeFaceEngineTest, AuthenticateFailedForUnEnrolled) {
-    FaceHalProperties::enrollments({3});
-    FaceHalProperties::enrollment_hit(100);
+    Face::cfg().setopt<OptIntVec>("enrollments", {3});
+    Face::cfg().set<std::int32_t>("enrollment_hit", 100);
     mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future());
     ASSERT_EQ(Error::TIMEOUT, mCallback->mError);
     ASSERT_TRUE(mCallback->mAuthenticateFailed);
 }
 
 TEST_F(FakeFaceEngineTest, DetectInteraction) {
-    FaceHalProperties::enrollments({100});
-    FaceHalProperties::enrollment_hit(100);
+    Face::cfg().setopt<OptIntVec>("enrollments", {100});
+    Face::cfg().set<std::int32_t>("enrollment_hit", 100);
     ASSERT_EQ(0, mCallback->mInteractionDetectedCount);
     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
     ASSERT_EQ(1, mCallback->mInteractionDetectedCount);
 }
 
 TEST_F(FakeFaceEngineTest, DetectInteractionCancel) {
-    FaceHalProperties::enrollments({100});
-    FaceHalProperties::enrollment_hit(100);
+    Face::cfg().setopt<OptIntVec>("enrollments", {100});
+    Face::cfg().set<std::int32_t>("enrollment_hit", 100);
     mCancel.set_value();
     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
     ASSERT_EQ(Error::CANCELED, mCallback->mError);
@@ -279,7 +282,7 @@
 }
 
 TEST_F(FakeFaceEngineTest, SetFeature) {
-    FaceHalProperties::enrollments({1});
+    Face::cfg().setopt<OptIntVec>("enrollments", {1});
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
     auto features = mCallback->mFeatures;
@@ -294,7 +297,7 @@
 }
 
 TEST_F(FakeFaceEngineTest, ToggleFeature) {
-    FaceHalProperties::enrollments({1});
+    Face::cfg().setopt<OptIntVec>("enrollments", {1});
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
     mEngine.getFeaturesImpl(mCallback.get());
@@ -310,7 +313,7 @@
 }
 
 TEST_F(FakeFaceEngineTest, TurningOffNonExistentFeatureDoesNothing) {
-    FaceHalProperties::enrollments({1});
+    Face::cfg().setopt<OptIntVec>("enrollments", {1});
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, false);
     mEngine.getFeaturesImpl(mCallback.get());
@@ -319,7 +322,7 @@
 }
 
 TEST_F(FakeFaceEngineTest, SetMultipleFeatures) {
-    FaceHalProperties::enrollments({1});
+    Face::cfg().setopt<OptIntVec>("enrollments", {1});
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
     mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_DIVERSE_POSES, true);
@@ -335,7 +338,7 @@
 }
 
 TEST_F(FakeFaceEngineTest, SetMultipleFeaturesAndTurnOffSome) {
-    FaceHalProperties::enrollments({1});
+    Face::cfg().setopt<OptIntVec>("enrollments", {1});
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
     mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_DIVERSE_POSES, true);
@@ -352,7 +355,7 @@
 }
 
 TEST_F(FakeFaceEngineTest, Enumerate) {
-    FaceHalProperties::enrollments({120, 3});
+    Face::cfg().setopt<OptIntVec>("enrollments", {120, 3});
     mEngine.enumerateEnrollmentsImpl(mCallback.get());
     auto enrolls = mCallback->mLastEnrollmentsEnumerated;
     ASSERT_FALSE(enrolls.empty());
@@ -361,7 +364,7 @@
 }
 
 TEST_F(FakeFaceEngineTest, RemoveEnrollments) {
-    FaceHalProperties::enrollments({120, 3, 100});
+    Face::cfg().setopt<OptIntVec>("enrollments", {120, 3, 100});
     mEngine.removeEnrollmentsImpl(mCallback.get(), {120, 100});
     mEngine.enumerateEnrollmentsImpl(mCallback.get());
     auto enrolls = mCallback->mLastEnrollmentsEnumerated;
@@ -372,9 +375,9 @@
 }
 
 TEST_F(FakeFaceEngineTest, ResetLockoutWithAuth) {
-    FaceHalProperties::lockout(true);
-    FaceHalProperties::enrollments({33});
-    FaceHalProperties::enrollment_hit(33);
+    Face::cfg().set<bool>("lockout", true);
+    Face::cfg().setopt<OptIntVec>("enrollments", {33});
+    Face::cfg().set<std::int32_t>("enrollment_hit", 33);
     auto cancelFuture = mCancel.get_future();
     mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, cancelFuture);
 
@@ -382,28 +385,30 @@
 
     mEngine.resetLockoutImpl(mCallback.get(), {} /* hat */);
     ASSERT_FALSE(mCallback->mLockoutPermanent);
-    FaceHalProperties::enrollment_hit(33);
+    Face::cfg().set<std::int32_t>("enrollment_hit", 33);
     mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, cancelFuture);
     ASSERT_EQ(33, mCallback->mLastAuthenticated);
     ASSERT_FALSE(mCallback->mAuthenticateFailed);
 }
 
 TEST_F(FakeFaceEngineTest, LatencyDefault) {
-    FaceHalProperties::operation_detect_interaction_latency({});
-    ASSERT_EQ(DEFAULT_LATENCY,
-              mEngine.getLatency(FaceHalProperties::operation_detect_interaction_latency()));
+    Face::cfg().setopt<OptIntVec>("operation_detect_interaction_latency", {});
+    ASSERT_EQ(DEFAULT_LATENCY, mEngine.getLatency(Face::cfg().getopt<OptIntVec>(
+                                       "operation_detect_interaction_latency")));
 }
 
 TEST_F(FakeFaceEngineTest, LatencyFixed) {
-    FaceHalProperties::operation_detect_interaction_latency({10});
-    ASSERT_EQ(10, mEngine.getLatency(FaceHalProperties::operation_detect_interaction_latency()));
+    Face::cfg().setopt<OptIntVec>("operation_detect_interaction_latency", {10});
+    ASSERT_EQ(10, mEngine.getLatency(
+                          Face::cfg().getopt<OptIntVec>("operation_detect_interaction_latency")));
 }
 
 TEST_F(FakeFaceEngineTest, LatencyRandom) {
-    FaceHalProperties::operation_detect_interaction_latency({1, 1000});
+    Face::cfg().setopt<OptIntVec>("operation_detect_interaction_latency", {1, 1000});
     std::set<int32_t> latencySet;
     for (int i = 0; i < 100; i++) {
-        auto x = mEngine.getLatency(FaceHalProperties::operation_detect_interaction_latency());
+        auto x = mEngine.getLatency(
+                Face::cfg().getopt<OptIntVec>("operation_detect_interaction_latency"));
         ASSERT_TRUE(x >= 1 && x <= 1000);
         latencySet.insert(x);
     }
diff --git a/biometrics/face/aidl/default/tests/FakeLockoutTrackerTest.cpp b/biometrics/face/aidl/default/tests/FakeLockoutTrackerTest.cpp
index fa07d1d..8564f6b 100644
--- a/biometrics/face/aidl/default/tests/FakeLockoutTrackerTest.cpp
+++ b/biometrics/face/aidl/default/tests/FakeLockoutTrackerTest.cpp
@@ -21,6 +21,7 @@
 
 #include <android-base/logging.h>
 
+#include "Face.h"
 #include "FakeLockoutTracker.h"
 #include "util/Util.h"
 
@@ -103,19 +104,21 @@
     static constexpr int32_t LOCKOUT_TIMED_DURATION = 100;
 
     void SetUp() override {
-        FaceHalProperties::lockout_timed_threshold(LOCKOUT_TIMED_THRESHOLD);
-        FaceHalProperties::lockout_timed_duration(LOCKOUT_TIMED_DURATION);
-        FaceHalProperties::lockout_permanent_threshold(LOCKOUT_PERMANENT_THRESHOLD);
+        Face::cfg().set<std::int32_t>("lockout_timed_threshold", LOCKOUT_TIMED_THRESHOLD);
+        Face::cfg().set<std::int32_t>("lockout_timed_duration", LOCKOUT_TIMED_DURATION);
+        Face::cfg().set<std::int32_t>("lockout_permanent_threshold", LOCKOUT_PERMANENT_THRESHOLD);
+        Face::cfg().set<bool>("lockout_enable", false);
+        Face::cfg().set<bool>("lockout", false);
         mCallback = ndk::SharedRefBase::make<TestSessionCallback>();
     }
 
     void TearDown() override {
         // reset to default
-        FaceHalProperties::lockout_timed_threshold(5);
-        FaceHalProperties::lockout_timed_duration(20);
-        FaceHalProperties::lockout_permanent_threshold(10000);
-        FaceHalProperties::lockout_enable(false);
-        FaceHalProperties::lockout(false);
+        Face::cfg().set<std::int32_t>("lockout_timed_threshold", 5);
+        Face::cfg().set<std::int32_t>("lockout_timed_duration", 20);
+        Face::cfg().set<std::int32_t>("lockout_permanent_threshold", 10000);
+        Face::cfg().set<bool>("lockout_enable", false);
+        Face::cfg().set<bool>("lockout", false);
     }
 
     FakeLockoutTracker mLockoutTracker;
@@ -123,7 +126,7 @@
 };
 
 TEST_F(FakeLockoutTrackerTest, addFailedAttemptDisable) {
-    FaceHalProperties::lockout_enable(false);
+    Face::cfg().set<bool>("lockout_enable", false);
     for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD + 1; i++)
         mLockoutTracker.addFailedAttempt(mCallback.get());
     ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
@@ -131,7 +134,7 @@
 }
 
 TEST_F(FakeLockoutTrackerTest, addFailedAttemptPermanent) {
-    FaceHalProperties::lockout_enable(true);
+    Face::cfg().set<bool>("lockout_enable", true);
     ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
     for (int i = 0; i < LOCKOUT_PERMANENT_THRESHOLD - 1; i++)
         mLockoutTracker.addFailedAttempt(mCallback.get());
@@ -145,8 +148,8 @@
 }
 
 TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockoutTimed) {
-    FaceHalProperties::lockout_enable(true);
-    FaceHalProperties::lockout_timed_enable(true);
+    Face::cfg().set<bool>("lockout_enable", true);
+    Face::cfg().set<bool>("lockout_timed_enable", true);
     ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
     for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++)
         mLockoutTracker.addFailedAttempt(mCallback.get());
@@ -168,8 +171,8 @@
 }
 
 TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockout_TimedThenPermanent) {
-    FaceHalProperties::lockout_enable(true);
-    FaceHalProperties::lockout_timed_enable(true);
+    Face::cfg().set<bool>("lockout_enable", true);
+    Face::cfg().set<bool>("lockout_timed_enable", true);
     ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
     for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++)
         mLockoutTracker.addFailedAttempt(mCallback.get());
@@ -182,8 +185,8 @@
 }
 
 TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockoutTimedTwice) {
-    FaceHalProperties::lockout_enable(true);
-    FaceHalProperties::lockout_timed_enable(true);
+    Face::cfg().set<bool>("lockout_enable", true);
+    Face::cfg().set<bool>("lockout_timed_enable", true);
     ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
     ASSERT_EQ(0, mCallback->mLockoutTimed);
     for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++)
@@ -198,7 +201,7 @@
 }
 
 TEST_F(FakeLockoutTrackerTest, resetLockout) {
-    FaceHalProperties::lockout_enable(true);
+    Face::cfg().set<bool>("lockout_enable", true);
     ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
     for (int i = 0; i < LOCKOUT_PERMANENT_THRESHOLD; i++)
         mLockoutTracker.addFailedAttempt(mCallback.get());
diff --git a/biometrics/face/aidl/default/tests/VirtualHalTest.cpp b/biometrics/face/aidl/default/tests/VirtualHalTest.cpp
new file mode 100644
index 0000000..2f19805
--- /dev/null
+++ b/biometrics/face/aidl/default/tests/VirtualHalTest.cpp
@@ -0,0 +1,237 @@
+/*
+ * 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.
+ */
+
+#include <android/binder_process.h>
+#include <face.sysprop.h>
+#include <gtest/gtest.h>
+
+#include <android-base/logging.h>
+
+#include "Face.h"
+#include "VirtualHal.h"
+
+using namespace ::android::face::virt;
+using namespace ::aidl::android::hardware::biometrics::face;
+
+namespace aidl::android::hardware::biometrics::face {
+
+class VirtualHalTest : public ::testing::Test {
+  public:
+    static const int32_t STATUS_FAILED_TO_SET_PARAMETER = 2;
+
+  protected:
+    void SetUp() override {
+        mHal = ndk::SharedRefBase::make<Face>();
+        mVhal = ndk::SharedRefBase::make<VirtualHal>(mHal);
+        ASSERT_TRUE(mVhal != nullptr);
+        mHal->resetConfigToDefault();
+    }
+
+    void TearDown() override { mHal->resetConfigToDefault(); }
+
+    std::shared_ptr<VirtualHal> mVhal;
+
+    ndk::ScopedAStatus validateNonNegativeInputOfInt32(const char* name,
+                                                       ndk::ScopedAStatus (VirtualHal::*f)(int32_t),
+                                                       const std::vector<int32_t>& in_good);
+
+  private:
+    std::shared_ptr<Face> mHal;
+};
+
+ndk::ScopedAStatus VirtualHalTest::validateNonNegativeInputOfInt32(
+        const char* name, ndk::ScopedAStatus (VirtualHal::*f)(int32_t),
+        const std::vector<int32_t>& in_params_good) {
+    ndk::ScopedAStatus status;
+    for (auto& param : in_params_good) {
+        status = (*mVhal.*f)(param);
+        if (!status.isOk()) return status;
+        if (Face::cfg().get<int32_t>(name) != param) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    VirtualHalTest::STATUS_FAILED_TO_SET_PARAMETER,
+                    "Error: fail to set non-negative parameter"));
+        }
+    }
+
+    int32_t old_param = Face::cfg().get<int32_t>(name);
+    status = (*mVhal.*f)(-1);
+    if (status.isOk()) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                VirtualHalTest::STATUS_FAILED_TO_SET_PARAMETER, "Error: should return NOK"));
+    }
+    if (status.getServiceSpecificError() != IVirtualHal::STATUS_INVALID_PARAMETER) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                VirtualHalTest::STATUS_FAILED_TO_SET_PARAMETER,
+                "Error: unexpected return error code"));
+    }
+    if (Face::cfg().get<int32_t>(name) != old_param) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                VirtualHalTest::STATUS_FAILED_TO_SET_PARAMETER,
+                "Error: unexpected parameter change on failed attempt"));
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+TEST_F(VirtualHalTest, init) {
+    mVhal->setLockout(false);
+    ASSERT_TRUE(Face::cfg().get<bool>("lockout") == false);
+    ASSERT_TRUE(Face::cfg().get<std::string>("type") == "rgb");
+    ASSERT_TRUE(Face::cfg().get<std::string>("strength") == "strong");
+    std::int64_t id = Face::cfg().get<std::int64_t>("authenticator_id");
+    ASSERT_TRUE(Face::cfg().get<std::int64_t>("authenticator_id") == 0);
+    ASSERT_TRUE(Face::cfg().getopt<OptIntVec>("enrollments") == OptIntVec());
+}
+
+TEST_F(VirtualHalTest, enrollment_hit_int32) {
+    mVhal->setEnrollmentHit(11);
+    ASSERT_TRUE(Face::cfg().get<int32_t>("enrollment_hit") == 11);
+}
+
+TEST_F(VirtualHalTest, next_enrollment) {
+    struct {
+        std::string nextEnrollmentStr;
+        face::NextEnrollment nextEnrollment;
+    } testData[] = {
+            {"1:20:true", {1, {{20}}, true}},
+            {"1:50,60,70:true", {1, {{50}, {60}, {70}}, true}},
+            {"2:50-[21],60,70-[4,1002,1]:false",
+             {2,
+              {{50, {{AcquiredInfo::START}}},
+               {60},
+               {70, {{AcquiredInfo::TOO_DARK}, {1002}, {AcquiredInfo::GOOD}}}},
+              false}},
+    };
+
+    for (auto& d : testData) {
+        mVhal->setNextEnrollment(d.nextEnrollment);
+        ASSERT_TRUE(Face::cfg().get<std::string>("next_enrollment") == d.nextEnrollmentStr);
+    }
+}
+
+TEST_F(VirtualHalTest, authenticator_id_int64) {
+    mVhal->setAuthenticatorId(12345678900);
+    ASSERT_TRUE(Face::cfg().get<int64_t>("authenticator_id") == 12345678900);
+}
+
+TEST_F(VirtualHalTest, opeationAuthenticateFails_bool) {
+    mVhal->setOperationAuthenticateFails(true);
+    ASSERT_TRUE(Face::cfg().get<bool>("operation_authenticate_fails"));
+}
+
+TEST_F(VirtualHalTest, operationAuthenticateAcquired_int32_vector) {
+    using Tag = AcquiredInfoAndVendorCode::Tag;
+    std::vector<AcquiredInfoAndVendorCode> ac{
+            {AcquiredInfo::START}, {AcquiredInfo::TOO_FAR}, {1023}};
+    mVhal->setOperationAuthenticateAcquired(ac);
+    OptIntVec ac_get = Face::cfg().getopt<OptIntVec>("operation_authenticate_acquired");
+    ASSERT_TRUE(ac_get.size() == ac.size());
+    for (int i = 0; i < ac.size(); i++) {
+        int acCode = (ac[i].getTag() == Tag::acquiredInfo) ? (int)ac[i].get<Tag::acquiredInfo>()
+                                                           : ac[i].get<Tag::vendorCode>();
+        ASSERT_TRUE(acCode == ac_get[i]);
+    }
+}
+
+TEST_F(VirtualHalTest, type) {
+    struct {
+        FaceSensorType type;
+        const char* typeStr;
+    } typeMap[] = {{FaceSensorType::RGB, "rgb"},
+                   {FaceSensorType::IR, "ir"},
+                   {FaceSensorType::UNKNOWN, "unknown"}};
+    for (auto const& x : typeMap) {
+        mVhal->setType(x.type);
+        ASSERT_TRUE(Face::cfg().get<std::string>("type") == x.typeStr);
+    }
+}
+
+TEST_F(VirtualHalTest, sensorStrength) {
+    struct {
+        common::SensorStrength strength;
+        const char* strengthStr;
+    } strengths[] = {{common::SensorStrength::CONVENIENCE, "CONVENIENCE"},
+                     {common::SensorStrength::WEAK, "WEAK"},
+                     {common::SensorStrength::STRONG, "STRONG"}};
+
+    for (auto const& x : strengths) {
+        mVhal->setSensorStrength(x.strength);
+        ASSERT_TRUE(Face::cfg().get<std::string>("strength") == x.strengthStr);
+    }
+}
+
+TEST_F(VirtualHalTest, setLatency) {
+    ndk::ScopedAStatus status;
+    std::vector<int32_t> in_lats[] = {{1}, {2, 3}, {5, 4}};
+    for (auto const& in_lat : in_lats) {
+        status = mVhal->setOperationAuthenticateLatency(in_lat);
+        ASSERT_TRUE(status.isOk());
+        OptIntVec out_lat = Face::cfg().getopt<OptIntVec>("operation_authenticate_latency");
+        ASSERT_TRUE(in_lat.size() == out_lat.size());
+        for (int i = 0; i < in_lat.size(); i++) {
+            ASSERT_TRUE(in_lat[i] == out_lat[i]);
+        }
+    }
+
+    std::vector<int32_t> bad_in_lats[] = {{}, {1, 2, 3}, {1, -3}};
+    for (auto const& in_lat : bad_in_lats) {
+        status = mVhal->setOperationAuthenticateLatency(in_lat);
+        ASSERT_TRUE(!status.isOk());
+        ASSERT_TRUE(status.getServiceSpecificError() == IVirtualHal::STATUS_INVALID_PARAMETER);
+    }
+}
+
+TEST_F(VirtualHalTest, setOperationAuthenticateDuration) {
+    ndk::ScopedAStatus status = validateNonNegativeInputOfInt32(
+            "operation_authenticate_duration", &IVirtualHal::setOperationAuthenticateDuration,
+            {0, 33});
+    ASSERT_TRUE(status.isOk());
+}
+
+TEST_F(VirtualHalTest, setLockoutTimedDuration) {
+    ndk::ScopedAStatus status = validateNonNegativeInputOfInt32(
+            "lockout_timed_duration", &IVirtualHal::setLockoutTimedDuration, {0, 35});
+    ASSERT_TRUE(status.isOk());
+}
+
+TEST_F(VirtualHalTest, setLockoutTimedThreshold) {
+    ndk::ScopedAStatus status = validateNonNegativeInputOfInt32(
+            "lockout_timed_threshold", &IVirtualHal::setLockoutTimedThreshold, {0, 36});
+    ASSERT_TRUE(status.isOk());
+}
+
+TEST_F(VirtualHalTest, setLockoutPermanentThreshold) {
+    ndk::ScopedAStatus status = validateNonNegativeInputOfInt32(
+            "lockout_permanent_threshold", &IVirtualHal::setLockoutPermanentThreshold, {0, 37});
+    ASSERT_TRUE(status.isOk());
+}
+
+TEST_F(VirtualHalTest, setOthers) {
+    // Verify that there is no CHECK() failures
+    mVhal->setEnrollments({7, 6, 5});
+    mVhal->setChallenge(111222333444555666);
+    mVhal->setOperationAuthenticateError(4);
+    mVhal->setOperationEnrollLatency({4, 5});
+    mVhal->setLockout(false);
+    mVhal->setLockoutEnable(false);
+}
+
+}  // namespace aidl::android::hardware::biometrics::face
+
+int main(int argc, char** argv) {
+    testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/biometrics/fingerprint/aidl/Android.bp b/biometrics/fingerprint/aidl/Android.bp
index a395c01..9f9e723 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,15 @@
         cpp: {
             enabled: false,
         },
+        ndk: {
+            apex_available: [
+                "//apex_available:platform",
+                "//apex_available:anyapex",
+            ],
+        },
+        rust: {
+            enabled: true,
+        },
     },
     versions_with_info: [
         {
@@ -57,5 +66,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/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%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/NextEnrollment.aidl
copy 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/FakeFingerprintEngine.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
index 67eb837..7a43d7b 100644
--- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
+++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
@@ -389,10 +389,10 @@
     if (isLockoutTimerStarted) isLockoutTimerAborted = true;
 }
 
-void FakeFingerprintEngine::clearLockout(ISessionCallback* cb) {
+void FakeFingerprintEngine::clearLockout(ISessionCallback* cb, bool dueToTimeout) {
     Fingerprint::cfg().set<bool>("lockout", false);
     cb->onLockoutCleared();
-    mLockoutTracker.reset();
+    mLockoutTracker.reset(dueToTimeout);
 }
 
 ndk::ScopedAStatus FakeFingerprintEngine::onPointerDownImpl(int32_t /*pointerId*/, int32_t /*x*/,
@@ -536,7 +536,7 @@
 void FakeFingerprintEngine::lockoutTimerExpired(ISessionCallback* cb) {
     BEGIN_OP(0);
     if (!isLockoutTimerAborted) {
-        clearLockout(cb);
+        clearLockout(cb, true);
     }
     isLockoutTimerStarted = false;
     isLockoutTimerAborted = false;
diff --git a/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp b/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp
index a056db5..7d46845 100644
--- a/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp
+++ b/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp
@@ -23,8 +23,11 @@
 
 namespace aidl::android::hardware::biometrics::fingerprint {
 
-void FakeLockoutTracker::reset() {
-    mFailedCount = 0;
+void FakeLockoutTracker::reset(bool dueToTimeout) {
+    if (!dueToTimeout) {
+        mFailedCount = 0;
+    }
+    mFailedCountTimed = 0;
     mLockoutTimedStart = 0;
     mCurrentMode = LockoutMode::kNone;
 }
@@ -33,6 +36,7 @@
     bool enabled = Fingerprint::cfg().get<bool>("lockout_enable");
     if (enabled) {
         mFailedCount++;
+        mFailedCountTimed++;
         int32_t lockoutTimedThreshold =
                 Fingerprint::cfg().get<std::int32_t>("lockout_timed_threshold");
         int32_t lockoutPermanetThreshold =
@@ -40,7 +44,7 @@
         if (mFailedCount >= lockoutPermanetThreshold) {
             mCurrentMode = LockoutMode::kPermanent;
             Fingerprint::cfg().set<bool>("lockout", true);
-        } else if (mFailedCount >= lockoutTimedThreshold) {
+        } else if (mFailedCountTimed >= lockoutTimedThreshold) {
             if (mCurrentMode == LockoutMode::kNone) {
                 mCurrentMode = LockoutMode::kTimed;
                 mLockoutTimedStart = Util::getSystemNanoTime();
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/FakeFingerprintEngine.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
index 0d53575..362d0df 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
@@ -110,7 +110,7 @@
     std::pair<Error, int32_t> convertError(int32_t code);
     int32_t getRandomInRange(int32_t bound1, int32_t bound2);
     bool checkSensorLockout(ISessionCallback*);
-    void clearLockout(ISessionCallback* cb);
+    void clearLockout(ISessionCallback* cb, bool dueToTimeout = false);
     void waitForFingerDown(ISessionCallback* cb, const std::future<void>& cancel);
 
     FakeLockoutTracker mLockoutTracker;
diff --git a/biometrics/fingerprint/aidl/default/include/FakeLockoutTracker.h b/biometrics/fingerprint/aidl/default/include/FakeLockoutTracker.h
index a1b6128..a7f2f8e 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeLockoutTracker.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeLockoutTracker.h
@@ -24,12 +24,12 @@
 
 class FakeLockoutTracker {
   public:
-    FakeLockoutTracker() : mFailedCount(0) {}
+    FakeLockoutTracker() : mFailedCount(0), mFailedCountTimed(0) {}
     ~FakeLockoutTracker() {}
 
     enum class LockoutMode : int8_t { kNone = 0, kTimed, kPermanent };
 
-    void reset();
+    void reset(bool dueToTimeout = false);
     LockoutMode getMode();
     void addFailedAttempt();
     int64_t getLockoutTimeLeft();
@@ -44,6 +44,7 @@
 
   private:
     int32_t mFailedCount;
+    int32_t mFailedCountTimed;
     int64_t mLockoutTimedStart;
     LockoutMode mCurrentMode;
 };
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/FakeLockoutTrackerTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp
index 3c12b6d..4c1277b 100644
--- a/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp
+++ b/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp
@@ -75,7 +75,7 @@
         prevTimeLeft = currTimeLeft;
     }
     ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
-    mLockoutTracker.reset();
+    mLockoutTracker.reset(true);
 }
 
 TEST_F(FakeLockoutTrackerTest, addFailedAttemptPermanent) {
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/bluetooth/a2dp/1.0/Android.bp b/bluetooth/a2dp/1.0/Android.bp
deleted file mode 100644
index 6ffbefa..0000000
--- a/bluetooth/a2dp/1.0/Android.bp
+++ /dev/null
@@ -1,28 +0,0 @@
-// This file is autogenerated by hidl-gen -Landroidbp.
-
-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"],
-}
-
-hidl_interface {
-    name: "android.hardware.bluetooth.a2dp@1.0",
-    root: "android.hardware",
-    srcs: [
-        "types.hal",
-        "IBluetoothAudioHost.hal",
-        "IBluetoothAudioOffload.hal",
-    ],
-    interfaces: [
-        "android.hidl.base@1.0",
-    ],
-    gen_java: false,
-    apex_available: [
-        "//apex_available:platform",
-        "com.android.btservices",
-    ],
-}
diff --git a/bluetooth/a2dp/1.0/IBluetoothAudioHost.hal b/bluetooth/a2dp/1.0/IBluetoothAudioHost.hal
deleted file mode 100644
index 666419d..0000000
--- a/bluetooth/a2dp/1.0/IBluetoothAudioHost.hal
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.bluetooth.a2dp@1.0;
-
-/**
- * HAL interface for Bluetooth A2DP Offload functionality where
- * the encoding of the A2DP data packets is offloaded to platform
- * specific encoders. The A2DP control path is maintained in the
- * Bluetooth stack.
- *
- * This interface is from HAL server to HAL client.
- *
- * The HAL server must call into the IBluetoothAudioHost to initiate
- * the start, suspend and stop of the streaming operation. These
- * calls return immediately and the results, if any, are send over
- * the IBluetoothAudioOffload interface.
- */
-
-interface IBluetoothAudioHost {
-    /**
-     * Invoked when the start stream is requested from HAL server
-     * to HAL client. This indicates that the HAL server
-     * has initialized the platform for streaming use case, and the
-     * HAL client can proceed with the streaming procedure. The
-     * result of the operation must be provided by the HAL
-     * client using the IBluetoothAudioOffload interface.
-     */
-    oneway startStream();
-
-    /**
-     * Invoked when the suspend stream is requested from HAL server
-     * to HAL client. This indicates that the HAL server
-     * wants to suspend the streaming procedure. The result of the
-     * operation must be provided by the HAL client using the
-     * IBluetoothAudioOffload interface.
-     */
-    oneway suspendStream();
-
-    /**
-     * Invoked when the stop stream is requested from HAL server
-     * to HAL client. This indicates that the HAL server wants to
-     * stop and reset the streaming procedure. There is no result
-     * provided by the HAL client for this call.
-     */
-    oneway stopStream();
-
-};
diff --git a/bluetooth/a2dp/1.0/IBluetoothAudioOffload.hal b/bluetooth/a2dp/1.0/IBluetoothAudioOffload.hal
deleted file mode 100644
index 52a580f..0000000
--- a/bluetooth/a2dp/1.0/IBluetoothAudioOffload.hal
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.bluetooth.a2dp@1.0;
-
-import IBluetoothAudioHost;
-
-/**
- * HAL interface for Bluetooth A2DP Offload functionality where
- * the encoding of the A2DP data packets is offloaded to platform
- * specific encoders. The A2DP control path is maintained in the
- * Bluetooth stack.
- *
- * This interface is from HAL client to HAL server.
- *
- * The HAL client must provide the handle of IBluetoothAudioHost as well
- * as codec configuration to the HAL server, when its connected to an
- * active A2DP Sink device. HAL Server, based on the feedback from the Audio
- * framework must call into the commands provided by the IBluetoothAudioHost.
- * HAL client must call into IBluetoothAudioOffload to provide the status of
- * these commands. Once the device becomes inactive, the HAL client must
- * call the endSession to terminate the session with the HAL server.
- */
-interface IBluetoothAudioOffload {
-
-    /**
-     * Indicates that the HAL client is connected to an A2DP Sink device
-     * and is ready to stream audio. This function is also used to register
-     * the BluetoothAudioHost interface and the provide the current negotiated
-     * codec.
-     *
-     * |endSession| must be called to unregister the interface.
-     *
-     * @param hostIf interface used to request stream control
-     * @param codecConfig Codec configuration as negotiated with the A2DP Sink
-     *    device
-     * @return status one of the following
-     *    SUCCESS if HAL server successfully initializes the platform with the
-     *        given codec configuration
-     *    UNSUPPORTED_CODEC_CONFIGURATION if HAL server cannot initialize the
-     *        platform with the given codec configuration
-     *    FAILURE if HAL server cannot initialize the platform for any other
-     *        reason
-     */
-    startSession(IBluetoothAudioHost hostIf, CodecConfiguration codecConfig) generates (Status status);
-
-    /**
-     * Updates status for start stream request. The HAL client may need
-     * to communicate to Bluetooth Controller and remote Sink device, in which
-     * case it must update with PENDING status. Once the operation is
-     * completed, it must return with either SUCCESS or FAILURE.
-     *
-     * @param status SUCCESS, FAILURE or PENDING
-     */
-    oneway streamStarted(Status status);
-
-    /**
-     * Updates status for suspend stream request. The HAL client may need
-     * to communicate to Bluetooth Controller and remote device, in which case
-     * it must update with PENDING status. Once the operation is completed, it
-     * must return with either SUCCESS or FAILURE.
-     *
-     * @param status SUCCESS, FAILURE or PENDING
-     */
-    oneway streamSuspended(Status status);
-
-    /**
-     * Ends the current A2DP offload session and unregisters the
-     * BluetoothAudioHost interface.
-     */
-    oneway endSession();
-};
diff --git a/bluetooth/a2dp/1.0/default/Android.bp b/bluetooth/a2dp/1.0/default/Android.bp
deleted file mode 100644
index f368dd4..0000000
--- a/bluetooth/a2dp/1.0/default/Android.bp
+++ /dev/null
@@ -1,22 +0,0 @@
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "hardware_interfaces_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["hardware_interfaces_license"],
-}
-
-cc_library_shared {
-    name: "android.hardware.bluetooth.a2dp@1.0-impl.mock",
-    relative_install_path: "hw",
-    vendor: true,
-    srcs: [
-        "BluetoothAudioOffload.cpp",
-    ],
-    shared_libs: [
-        "libhidlbase",
-        "libutils",
-        "android.hardware.bluetooth.a2dp@1.0",
-    ],
-}
diff --git a/bluetooth/a2dp/1.0/default/BluetoothAudioOffload.cpp b/bluetooth/a2dp/1.0/default/BluetoothAudioOffload.cpp
deleted file mode 100644
index 9abb88d..0000000
--- a/bluetooth/a2dp/1.0/default/BluetoothAudioOffload.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BluetoothAudioOffload.h"
-
-namespace android {
-namespace hardware {
-namespace bluetooth {
-namespace a2dp {
-namespace V1_0 {
-namespace implementation {
-
-IBluetoothAudioOffload* HIDL_FETCH_IBluetoothAudioOffload(
-    const char* /* name */) {
-  return new BluetoothAudioOffload();
-}
-
-// Methods from
-// ::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioOffload follow.
-Return<::android::hardware::bluetooth::a2dp::V1_0::Status>
-BluetoothAudioOffload::startSession(
-    const sp<::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioHost>&
-        hostIf __unused,
-    const ::android::hardware::bluetooth::a2dp::V1_0::CodecConfiguration&
-        codecConfig __unused) {
-  /**
-   * Initialize the audio platform if codecConfiguration is supported.
-   * Save the the IBluetoothAudioHost interface, so that it can be used
-   * later to send stream control commands to the HAL client, based on
-   * interaction with Audio framework.
-   */
-  return ::android::hardware::bluetooth::a2dp::V1_0::Status::FAILURE;
-}
-
-Return<void> BluetoothAudioOffload::streamStarted(
-    ::android::hardware::bluetooth::a2dp::V1_0::Status status __unused) {
-  /**
-   * Streaming on control path has started,
-   * HAL server should start the streaming on data path.
-   */
-  return Void();
-}
-
-Return<void> BluetoothAudioOffload::streamSuspended(
-    ::android::hardware::bluetooth::a2dp::V1_0::Status status __unused) {
-  /**
-   * Streaming on control path has suspend,
-   * HAL server should suspend the streaming on data path.
-   */
-  return Void();
-}
-
-Return<void> BluetoothAudioOffload::endSession() {
-  /**
-   * Cleanup the audio platform as remote A2DP Sink device is no
-   * longer active
-   */
-  return Void();
-}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace a2dp
-}  // namespace bluetooth
-}  // namespace hardware
-}  // namespace android
diff --git a/bluetooth/a2dp/1.0/default/BluetoothAudioOffload.h b/bluetooth/a2dp/1.0/default/BluetoothAudioOffload.h
deleted file mode 100644
index 16a83c2..0000000
--- a/bluetooth/a2dp/1.0/default/BluetoothAudioOffload.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2018 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 ANDROID_HARDWARE_BLUETOOTH_A2DP_V1_0_BLUETOOTHAUDIOOFFLOAD_H
-#define ANDROID_HARDWARE_BLUETOOTH_A2DP_V1_0_BLUETOOTHAUDIOOFFLOAD_H
-
-#include <android/hardware/bluetooth/a2dp/1.0/IBluetoothAudioOffload.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-
-namespace android {
-namespace hardware {
-namespace bluetooth {
-namespace a2dp {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::sp;
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-
-struct BluetoothAudioOffload : public IBluetoothAudioOffload {
-  BluetoothAudioOffload() {}
-  // Methods from
-  // ::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioOffload follow.
-  Return<::android::hardware::bluetooth::a2dp::V1_0::Status> startSession(
-      const sp<::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioHost>&
-          hostIf,
-      const ::android::hardware::bluetooth::a2dp::V1_0::CodecConfiguration&
-          codecConfig) override;
-  Return<void> streamStarted(
-      ::android::hardware::bluetooth::a2dp::V1_0::Status status) override;
-  Return<void> streamSuspended(
-      ::android::hardware::bluetooth::a2dp::V1_0::Status status) override;
-  Return<void> endSession() override;
-};
-
-extern "C" IBluetoothAudioOffload* HIDL_FETCH_IBluetoothAudioOffload(
-    const char* name);
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace a2dp
-}  // namespace bluetooth
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_BLUETOOTH_A2DP_V1_0_BLUETOOTHAUDIOOFFLOAD_H
diff --git a/bluetooth/a2dp/1.0/types.hal b/bluetooth/a2dp/1.0/types.hal
deleted file mode 100644
index 6a430f0..0000000
--- a/bluetooth/a2dp/1.0/types.hal
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.bluetooth.a2dp@1.0;
-
-enum Status : uint8_t {
-    SUCCESS,
-    FAILURE,
-    /** codec configuration not supported by the audio platform */
-    UNSUPPORTED_CODEC_CONFIGURATION ,
-    /** operation is pending */
-    PENDING,
-};
-
-enum CodecType : uint32_t {
-    UNKNOWN = 0x00,
-    SBC = 0x01,
-    AAC = 0x02,
-    APTX = 0x04,
-    APTX_HD = 0x08,
-    LDAC = 0x10,
-};
-enum SampleRate : uint32_t {
-    RATE_UNKNOWN = 0x00,
-    RATE_44100 = 0x01,
-    RATE_48000 = 0x02,
-    RATE_88200 = 0x04,
-    RATE_96000 = 0x08,
-    RATE_176400 = 0x10,
-    RATE_192000 = 0x20,
-};
-enum BitsPerSample : uint8_t {
-    BITS_UNKNOWN = 0x00,
-    BITS_16 = 0x01,
-    BITS_24 = 0x02,
-    BITS_32 = 0x04,
-};
-enum ChannelMode : uint8_t {
-    UNKNOWN = 0x00,
-    MONO = 0x01,
-    STEREO = 0x02,
-};
-struct CodecConfiguration {
-    /** Bluetooth A2DP codec */
-    CodecType codecType;
-    /** Sampling rate for encoder */
-    SampleRate sampleRate;
-    /** Bits per sample for encoder */
-    BitsPerSample bitsPerSample;
-    /** Channel mode for encoder */
-    ChannelMode channelMode;
-    /**
-     * The encoded audio bitrate in bits / second.
-     * 0x00000000 - The audio bitrate is not specified / unused
-     * 0x00000001 - 0x00FFFFFF - Encoded audio bitrate in bits/second
-     * 0x01000000 - 0xFFFFFFFF - Reserved
-     */
-    uint32_t encodedAudioBitrate;
-    /** Peer MTU (in octets) */
-    uint16_t peerMtu;
-    union CodecSpecific {
-        /**
-         * SBC Codec specific information
-         * Refer to SBC Codec specific information elements in A2DP v1.3
-         * Profile Specification.
-         */
-        struct SbcData {
-            /** Block length: 4 bits | Subbands: 2 bits | Allocation Method: 2 bits */
-            uint8_t codecParameters;
-            /** Minimum bitpool value */
-            uint8_t minBitpool;
-            /** Maximum bitpool value */
-            uint8_t maxBitpool;
-        } sbcData;
-        struct LdacData {
-            /**
-             * LDAC bitrate index value:
-             * 0x00 - High
-             * 0x01 - Mid
-             * 0x02 - Low
-             * 0x7F - ABR (Adaptive Bit Rate)
-             */
-            uint8_t bitrateIndex;
-        } ldacData;
-    } codecSpecific;
-};
diff --git a/bluetooth/a2dp/1.0/vts/OWNERS b/bluetooth/a2dp/1.0/vts/OWNERS
deleted file mode 100644
index d3aab51..0000000
--- a/bluetooth/a2dp/1.0/vts/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Bug component: 27441
-include platform/packages/modules/Bluetooth:/OWNERS
-
-cheneyni@google.com
diff --git a/bluetooth/a2dp/1.0/vts/functional/Android.bp b/bluetooth/a2dp/1.0/vts/functional/Android.bp
deleted file mode 100644
index 0d393bc..0000000
--- a/bluetooth/a2dp/1.0/vts/functional/Android.bp
+++ /dev/null
@@ -1,36 +0,0 @@
-//
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "hardware_interfaces_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["hardware_interfaces_license"],
-}
-
-cc_test {
-    name: "VtsHalBluetoothA2dpV1_0TargetTest",
-    defaults: ["VtsHalTargetTestDefaults"],
-    srcs: ["VtsHalBluetoothA2dpV1_0TargetTest.cpp"],
-    static_libs: [
-        "android.hardware.bluetooth@1.0",
-        "android.hardware.bluetooth.a2dp@1.0",
-        "libbluetooth-types",
-    ],
-    test_suites: ["general-tests", "vts"],
-}
diff --git a/bluetooth/a2dp/1.0/vts/functional/VtsHalBluetoothA2dpV1_0TargetTest.cpp b/bluetooth/a2dp/1.0/vts/functional/VtsHalBluetoothA2dpV1_0TargetTest.cpp
deleted file mode 100644
index f7fdf31..0000000
--- a/bluetooth/a2dp/1.0/vts/functional/VtsHalBluetoothA2dpV1_0TargetTest.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2018 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 "bluetooth_a2dp_hidl_hal_test"
-
-#include <android-base/logging.h>
-#include <android/hardware/bluetooth/a2dp/1.0/IBluetoothAudioHost.h>
-#include <android/hardware/bluetooth/a2dp/1.0/IBluetoothAudioOffload.h>
-#include <gtest/gtest.h>
-#include <hardware/bluetooth.h>
-#include <hidl/GtestPrinter.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/ServiceManagement.h>
-#include <utils/Log.h>
-
-#include <VtsHalHidlTargetCallbackBase.h>
-
-using ::android::sp;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::bluetooth::a2dp::V1_0::BitsPerSample;
-using ::android::hardware::bluetooth::a2dp::V1_0::ChannelMode;
-using ::android::hardware::bluetooth::a2dp::V1_0::CodecConfiguration;
-using ::android::hardware::bluetooth::a2dp::V1_0::CodecType;
-using ::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioHost;
-using ::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioOffload;
-using ::android::hardware::bluetooth::a2dp::V1_0::SampleRate;
-using ::android::hardware::bluetooth::a2dp::V1_0::Status;
-
-// The main test class for Bluetooth A2DP HIDL HAL.
-class BluetoothA2dpHidlTest : public ::testing::TestWithParam<std::string> {
- public:
-  virtual void SetUp() override {
-    // currently test passthrough mode only
-    audio_offload = IBluetoothAudioOffload::getService(GetParam());
-    ASSERT_NE(audio_offload, nullptr);
-
-    audio_host = new BluetoothAudioHost(*this);
-    ASSERT_NE(audio_host, nullptr);
-
-    codec.codecType = CodecType::AAC;
-    codec.sampleRate = SampleRate::RATE_44100;
-    codec.bitsPerSample = BitsPerSample::BITS_16;
-    codec.channelMode = ChannelMode::STEREO;
-    codec.encodedAudioBitrate = 320000;
-    codec.peerMtu = 1000;
-  }
-
-  virtual void TearDown() override {}
-
-  // A simple test implementation of IBluetoothAudioHost.
-  class BluetoothAudioHost
-      : public ::testing::VtsHalHidlTargetCallbackBase<BluetoothA2dpHidlTest>,
-        public IBluetoothAudioHost {
-    BluetoothA2dpHidlTest& parent_;
-
-   public:
-    BluetoothAudioHost(BluetoothA2dpHidlTest& parent) : parent_(parent){};
-    virtual ~BluetoothAudioHost() = default;
-
-    Return<void> startStream() override {
-      parent_.audio_offload->streamStarted(Status::SUCCESS);
-      return Void();
-    };
-
-    Return<void> suspendStream() override {
-      parent_.audio_offload->streamSuspended(Status::SUCCESS);
-      return Void();
-    };
-
-    Return<void> stopStream() override { return Void(); };
-  };
-
-  // audio_host is for the Audio HAL to send stream start/suspend/stop commands
-  // to Bluetooth
-  sp<IBluetoothAudioHost> audio_host;
-  // audio_offload is for the Bluetooth HAL to report session started/ended and
-  // handled audio stream started/suspended
-  sp<IBluetoothAudioOffload> audio_offload;
-  // codec is the currently used codec
-  CodecConfiguration codec;
-};
-
-// Empty test: Initialize()/Close() are called in SetUp()/TearDown().
-TEST_P(BluetoothA2dpHidlTest, InitializeAndClose) {}
-
-// Test start and end session
-TEST_P(BluetoothA2dpHidlTest, StartAndEndSession) {
-  EXPECT_EQ(Status::SUCCESS, audio_offload->startSession(audio_host, codec));
-  audio_offload->endSession();
-}
-
-INSTANTIATE_TEST_SUITE_P(
-    PerInstance, BluetoothA2dpHidlTest,
-    testing::ValuesIn(android::hardware::getAllHalInstanceNames(
-        IBluetoothAudioOffload::descriptor)),
-    android::hardware::PrintInstanceNameToString);
-
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BluetoothA2dpHidlTest);
diff --git a/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp b/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp
index aaf436f..fcf1649 100644
--- a/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp
+++ b/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp
@@ -27,7 +27,6 @@
 #include <android/binder_process.h>
 #include <binder/IServiceManager.h>
 
-#include <atomic>
 #include <chrono>
 #include <condition_variable>
 #include <future>
@@ -68,8 +67,8 @@
 using ::bluetooth::hci::ReadLocalVersionInformationBuilder;
 using ::bluetooth::hci::ReadLocalVersionInformationCompleteView;
 
-static constexpr uint8_t kMinLeAdvSetForBt5 = 16;
-static constexpr uint8_t kMinLeAdvSetForBt5FoTv = 10;
+static constexpr uint8_t kMinLeAdvSetForBt5 = 10;
+static constexpr uint8_t kMinLeAdvSetForBt5ForTv = 10;
 static constexpr uint8_t kMinLeResolvingListForBt5 = 8;
 
 static constexpr size_t kNumHciCommandsBandwidth = 100;
@@ -989,7 +988,16 @@
   ASSERT_EQ(status, std::future_status::ready);
 }
 
+// @VsrTest = 5.3.14-001
+// @VsrTest = 5.3.14-002
+// @VsrTest = 5.3.14-004
 TEST_P(BluetoothAidlTest, Vsr_Bluetooth5Requirements) {
+  int api_level = get_vsr_api_level();
+  if (api_level < __ANDROID_API_U__) {
+    GTEST_SKIP() << "API level is lower than 34";
+    return;
+  }
+
   std::vector<uint8_t> version_event;
   send_and_wait_for_cmd_complete(ReadLocalVersionInformationBuilder::Create(),
                                  version_event);
@@ -999,10 +1007,12 @@
   ASSERT_TRUE(version_view.IsValid());
   ASSERT_EQ(::bluetooth::hci::ErrorCode::SUCCESS, version_view.GetStatus());
   auto version = version_view.GetLocalVersionInformation();
+
   if (version.hci_version_ < ::bluetooth::hci::HciVersion::V_5_0) {
-    // This test does not apply to controllers below 5.0
+    GTEST_SKIP() << "Bluetooth version is lower than 5.0";
     return;
-  };
+  }
+
   // When HCI version is 5.0, LMP version must also be at least 5.0
   ASSERT_GE(static_cast<int>(version.lmp_version_),
             static_cast<int>(version.hci_version_));
@@ -1015,6 +1025,16 @@
           std::make_shared<std::vector<uint8_t>>(le_features_event)))));
   ASSERT_TRUE(le_features_view.IsValid());
   ASSERT_EQ(::bluetooth::hci::ErrorCode::SUCCESS, le_features_view.GetStatus());
+
+  // CHIPSETs that set ro.board.api_level to 34 and report 5.0 or higher for
+  // the Bluetooth version through the IBluetoothHci HAL:
+  //
+  // [VSR-5.3.14-001] Must return TRUE for
+  //   - LE 2M PHY
+  //   - LE Coded PHY
+  //   - LE Advertising Extension
+  //   - LE Periodic Advertising
+  //   - LE Link Layer Privacy
   auto le_features = le_features_view.GetLeFeatures();
   ASSERT_TRUE(le_features & static_cast<uint64_t>(LLFeaturesBits::LL_PRIVACY));
   ASSERT_TRUE(le_features & static_cast<uint64_t>(LLFeaturesBits::LE_2M_PHY));
@@ -1022,6 +1042,8 @@
               static_cast<uint64_t>(LLFeaturesBits::LE_CODED_PHY));
   ASSERT_TRUE(le_features &
               static_cast<uint64_t>(LLFeaturesBits::LE_EXTENDED_ADVERTISING));
+  ASSERT_TRUE(le_features &
+              static_cast<uint64_t>(LLFeaturesBits::LE_PERIODIC_ADVERTISING));
 
   std::vector<uint8_t> num_adv_set_event;
   send_and_wait_for_cmd_complete(
@@ -1035,8 +1057,12 @@
   ASSERT_EQ(::bluetooth::hci::ErrorCode::SUCCESS, num_adv_set_view.GetStatus());
   auto num_adv_set = num_adv_set_view.GetNumberSupportedAdvertisingSets();
 
+  // CHIPSETs that set ro.board.api_level to 34 and report 5.0 or higher for
+  // the Bluetooth version through the IBluetoothHci HAL:
+  //
+  // [VSR-5.3.14-002] MUST support at least 10 advertising sets.
   if (isTv() && get_vsr_api_level() == __ANDROID_API_U__) {
-    ASSERT_GE(num_adv_set, kMinLeAdvSetForBt5FoTv);
+    ASSERT_GE(num_adv_set, kMinLeAdvSetForBt5ForTv);
   } else {
     ASSERT_GE(num_adv_set, kMinLeAdvSetForBt5);
   }
@@ -1051,6 +1077,11 @@
   ASSERT_EQ(::bluetooth::hci::ErrorCode::SUCCESS,
             num_resolving_list_view.GetStatus());
   auto num_resolving_list = num_resolving_list_view.GetResolvingListSize();
+
+  // CHIPSETs that set ro.board.api_level to 34 and report 5.0 or higher for
+  // the Bluetooth version through the IBluetoothHci HAL:
+  //
+  // [VSR-5.3.14-004] MUST support a resolving list size of at least 8 entries.
   ASSERT_GE(num_resolving_list, kMinLeResolvingListForBt5);
 }
 
diff --git a/bluetooth/audio/aidl/Android.bp b/bluetooth/audio/aidl/Android.bp
index f273c7a..ae55fa9 100644
--- a/bluetooth/audio/aidl/Android.bp
+++ b/bluetooth/audio/aidl/Android.bp
@@ -85,12 +85,12 @@
         },
 
     ],
-    frozen: true,
+    frozen: false,
 
 }
 
 // Note: This should always be one version ahead of the last frozen version
-latest_android_hardware_bluetooth_audio = "android.hardware.bluetooth.audio-V4"
+latest_android_hardware_bluetooth_audio = "android.hardware.bluetooth.audio-V5"
 
 cc_defaults {
     name: "latest_android_hardware_bluetooth_audio_ndk_shared",
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
index 6783c0f..61c29d3 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
@@ -121,6 +121,40 @@
   return (sessionType == session_type_);
 }
 
+std::string getSettingOutputString(
+    IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting) {
+  std::stringstream ss;
+  std::string name = "";
+  if (!setting.sinkAseConfiguration.has_value() &&
+      !setting.sourceAseConfiguration.has_value())
+    return "";
+  std::vector<
+      std::optional<LeAudioAseConfigurationSetting::AseDirectionConfiguration>>*
+      directionAseConfiguration;
+  if (setting.sinkAseConfiguration.has_value() &&
+      !setting.sinkAseConfiguration.value().empty())
+    directionAseConfiguration = &setting.sinkAseConfiguration.value();
+  else
+    directionAseConfiguration = &setting.sourceAseConfiguration.value();
+  for (auto& aseConfiguration : *directionAseConfiguration) {
+    if (aseConfiguration.has_value() &&
+        aseConfiguration.value().aseConfiguration.metadata.has_value()) {
+      for (auto& meta :
+           aseConfiguration.value().aseConfiguration.metadata.value()) {
+        if (meta.has_value() &&
+            meta.value().getTag() == MetadataLtv::vendorSpecific) {
+          auto k = meta.value().get<MetadataLtv::vendorSpecific>().opaqueValue;
+          name = std::string(k.begin(), k.end());
+          break;
+        }
+      }
+    }
+  }
+
+  ss << "setting name: " << name << ", setting: " << setting.toString();
+  return ss.str();
+}
+
 ndk::ScopedAStatus LeAudioOffloadAudioProvider::startSession(
     const std::shared_ptr<IBluetoothAudioPort>& host_if,
     const AudioConfiguration& audio_config,
@@ -218,15 +252,24 @@
   return false;
 }
 
+int getCountFromBitmask(int bitmask) {
+  return std::bitset<32>(bitmask).count();
+}
+
 bool LeAudioOffloadAudioProvider::isMatchedAudioChannel(
-    CodecSpecificConfigurationLtv::AudioChannelAllocation&
-    /*cfg_channel*/,
+    CodecSpecificConfigurationLtv::AudioChannelAllocation& cfg_channel,
     CodecSpecificCapabilitiesLtv::SupportedAudioChannelCounts&
-    /*capability_channel*/) {
-  // Simply ignore.
-  // Later can use additional capabilities to match requirement.
-  bool isMatched = true;
-  return isMatched;
+        capability_channel) {
+  int count = getCountFromBitmask(cfg_channel.bitmask);
+  if (count == 1 &&
+      !(capability_channel.bitmask &
+        CodecSpecificCapabilitiesLtv::SupportedAudioChannelCounts::ONE))
+    return false;
+  if (count == 2 &&
+      !(capability_channel.bitmask &
+        CodecSpecificCapabilitiesLtv::SupportedAudioChannelCounts::TWO))
+    return false;
+  return true;
 }
 
 bool LeAudioOffloadAudioProvider::isMatchedCodecFramesPerSDU(
@@ -322,12 +365,6 @@
   return true;
 }
 
-bool isMonoConfig(
-    CodecSpecificConfigurationLtv::AudioChannelAllocation allocation) {
-  auto channel_count = std::bitset<32>(allocation.bitmask);
-  return (channel_count.count() <= 1);
-}
-
 bool LeAudioOffloadAudioProvider::filterMatchedAseConfiguration(
     LeAudioAseConfiguration& setting_cfg,
     const LeAudioAseConfiguration& requirement_cfg) {
@@ -337,9 +374,6 @@
     if (!setting_cfg.codecId.has_value()) return false;
     if (!isMatchedValidCodec(setting_cfg.codecId.value(),
                              requirement_cfg.codecId.value())) {
-      LOG(WARNING) << __func__ << ": Doesn't match valid codec, cfg = "
-                   << setting_cfg.codecId.value().toString()
-                   << ", req = " << requirement_cfg.codecId.value().toString();
       return false;
     }
   }
@@ -347,9 +381,6 @@
   if (requirement_cfg.targetLatency !=
           LeAudioAseConfiguration::TargetLatency::UNDEFINED &&
       setting_cfg.targetLatency != requirement_cfg.targetLatency) {
-    LOG(WARNING) << __func__ << ": Doesn't match target latency, cfg = "
-                 << int(setting_cfg.targetLatency)
-                 << ", req = " << int(requirement_cfg.targetLatency);
     return false;
   }
   // Ignore PHY requirement
@@ -365,8 +396,6 @@
     auto cfg = cfg_tag_map.find(requirement_cfg.getTag());
     // Config not found for this requirement, cannot match
     if (cfg == cfg_tag_map.end()) {
-      LOG(WARNING) << __func__ << ": Config not found for the requirement "
-                   << requirement_cfg.toString();
       return false;
     }
 
@@ -377,10 +406,6 @@
       continue;
 
     if (cfg->second != requirement_cfg) {
-      LOG(WARNING) << __func__
-                   << ": Config doesn't match the requirement, cfg = "
-                   << cfg->second.toString()
-                   << ", req = " << requirement_cfg.toString();
       return false;
     }
   }
@@ -437,10 +462,6 @@
   return 0;
 }
 
-int getCountFromBitmask(int bitmask) {
-  return std::bitset<32>(bitmask).count();
-}
-
 std::optional<AseDirectionConfiguration> findValidMonoConfig(
     std::vector<AseDirectionConfiguration>& valid_direction_configurations,
     int bitmask) {
@@ -505,14 +526,13 @@
   return {};
 }
 
+// Check and filter each index to see if it's a match.
 void LeAudioOffloadAudioProvider::filterRequirementAseDirectionConfiguration(
     std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
         direction_configurations,
     const std::vector<std::optional<AseDirectionRequirement>>& requirements,
     std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
-        valid_direction_configurations,
-    bool is_exact) {
-  // For every requirement, find the matched ase configuration
+        valid_direction_configurations) {
   if (!direction_configurations.has_value()) return;
 
   if (!valid_direction_configurations.has_value()) {
@@ -520,38 +540,55 @@
         std::vector<std::optional<AseDirectionConfiguration>>();
   }
 
-  for (auto& requirement : requirements) {
-    if (!requirement.has_value()) continue;
-    auto req_allocation_bitmask = getLeAudioAseConfigurationAllocationBitmask(
-        requirement.value().aseConfiguration);
-    auto req_channel_count = getCountFromBitmask(req_allocation_bitmask);
-
-    auto temp = std::vector<AseDirectionConfiguration>();
-
-    for (auto direction_configuration : direction_configurations.value()) {
-      if (!direction_configuration.has_value()) continue;
-      if (!filterMatchedAseConfiguration(
-              direction_configuration.value().aseConfiguration,
-              requirement.value().aseConfiguration))
-        continue;
-      // Valid if match any requirement.
-      temp.push_back(direction_configuration.value());
-    }
-
-    // Get the best matching config based on channel allocation
-    auto total_cfg_channel_count = 0;
-    auto req_valid_configs = getValidConfigurationsFromAllocation(
-        req_allocation_bitmask, temp, is_exact);
-    // Count and check required channel counts
-    for (auto& cfg : req_valid_configs) {
-      total_cfg_channel_count += getCountFromBitmask(
-          getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration));
-      valid_direction_configurations.value().push_back(cfg);
-    }
-    if (total_cfg_channel_count != req_channel_count) {
+  // Exact matching process
+  // Need to respect the number of device
+  for (int i = 0; i < requirements.size(); ++i) {
+    auto requirement = requirements[i];
+    auto direction_configuration = direction_configurations.value()[i];
+    if (!direction_configuration.has_value()) {
       valid_direction_configurations = std::nullopt;
       return;
     }
+    auto cfg = direction_configuration.value();
+    if (!filterMatchedAseConfiguration(cfg.aseConfiguration,
+                                       requirement.value().aseConfiguration)) {
+      valid_direction_configurations = std::nullopt;
+      return;  // No way to match
+    }
+    // For exact match, we require this direction to have the same allocation.
+    // If stereo, need stereo.
+    // If mono, need mono (modified to the correct required allocation)
+    auto req_allocation_bitmask = getLeAudioAseConfigurationAllocationBitmask(
+        requirement.value().aseConfiguration);
+    int req_channel_count = getCountFromBitmask(req_allocation_bitmask);
+    int cfg_bitmask =
+        getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration);
+    int cfg_channel_count = getCountFromBitmask(cfg_bitmask);
+    if (req_channel_count <= 1) {
+      // MONO case, is a match if also mono, modify to the same allocation
+      if (cfg_channel_count > 1) {
+        valid_direction_configurations = std::nullopt;
+        return;  // Not a match
+      }
+      // Modify the bitmask to be the same as the requirement
+      for (auto& codec_cfg : cfg.aseConfiguration.codecConfiguration) {
+        if (codec_cfg.getTag() ==
+            CodecSpecificConfigurationLtv::Tag::audioChannelAllocation) {
+          codec_cfg
+              .get<CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>()
+              .bitmask = req_allocation_bitmask;
+          break;
+        }
+      }
+    } else {
+      // STEREO case, is a match if same allocation
+      if (req_allocation_bitmask != cfg_bitmask) {
+        valid_direction_configurations = std::nullopt;
+        return;  // Not a match
+      }
+    }
+    // Push to list if valid
+    valid_direction_configurations.value().push_back(cfg);
   }
 }
 
@@ -564,7 +601,6 @@
     const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities,
     uint8_t direction) {
   // Create a new LeAudioAseConfigurationSetting and return
-  // For other direction will contain all settings
   LeAudioAseConfigurationSetting filtered_setting{
       .audioContext = setting.audioContext,
       .sinkAseConfiguration = setting.sinkAseConfiguration,
@@ -612,27 +648,39 @@
 std::optional<LeAudioAseConfigurationSetting>
 LeAudioOffloadAudioProvider::getRequirementMatchedAseConfigurationSettings(
     IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
-    const IBluetoothAudioProvider::LeAudioConfigurationRequirement& requirement,
-    bool is_exact) {
-  // Try to match context in metadata.
-  if ((setting.audioContext.bitmask & requirement.audioContext.bitmask) !=
-      requirement.audioContext.bitmask)
-    return std::nullopt;
-
-  // Further filter setting's context
-  setting.audioContext.bitmask &= requirement.audioContext.bitmask;
-
+    const IBluetoothAudioProvider::LeAudioConfigurationRequirement&
+        requirement) {
   // Create a new LeAudioAseConfigurationSetting to return
+  // Make context the same as the requirement
   LeAudioAseConfigurationSetting filtered_setting{
-      .audioContext = setting.audioContext,
+      .audioContext = requirement.audioContext,
       .packing = setting.packing,
       .flags = setting.flags,
   };
 
+  // The number of AseDirectionRequirement in the requirement
+  // is the number of device.
+
+  // The exact matching process is as follow:
+  // 1. Setting direction has the same number of cfg (ignore when null require)
+  // 2. For each index, it's a 1-1 filter / mapping.
+
+  if (requirement.sinkAseRequirement.has_value() &&
+      requirement.sinkAseRequirement.value().size() !=
+          setting.sinkAseConfiguration.value().size()) {
+    return std::nullopt;
+  }
+
+  if (requirement.sourceAseRequirement.has_value() &&
+      requirement.sourceAseRequirement.value().size() !=
+          setting.sourceAseConfiguration.value().size()) {
+    return std::nullopt;
+  }
+
   if (requirement.sinkAseRequirement.has_value()) {
     filterRequirementAseDirectionConfiguration(
         setting.sinkAseConfiguration, requirement.sinkAseRequirement.value(),
-        filtered_setting.sinkAseConfiguration, is_exact);
+        filtered_setting.sinkAseConfiguration);
     if (!filtered_setting.sinkAseConfiguration.has_value()) {
       return std::nullopt;
     }
@@ -642,7 +690,7 @@
     filterRequirementAseDirectionConfiguration(
         setting.sourceAseConfiguration,
         requirement.sourceAseRequirement.value(),
-        filtered_setting.sourceAseConfiguration, is_exact);
+        filtered_setting.sourceAseConfiguration);
     if (!filtered_setting.sourceAseConfiguration.has_value()) {
       return std::nullopt;
     }
@@ -651,47 +699,44 @@
   return filtered_setting;
 }
 
-std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
+std::optional<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
 LeAudioOffloadAudioProvider::matchWithRequirement(
     std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>&
         matched_ase_configuration_settings,
-    const std::vector<IBluetoothAudioProvider::LeAudioConfigurationRequirement>&
-        in_requirements,
-    bool is_exact) {
-  // Each requirement will match with a valid setting
-  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting> result;
-  for (auto& requirement : in_requirements) {
-    LOG(INFO) << __func__ << ": Trying to match for the requirement "
-              << requirement.toString();
-    bool is_matched = false;
-
-    for (auto& setting : matched_ase_configuration_settings) {
-      auto filtered_ase_configuration_setting =
-          getRequirementMatchedAseConfigurationSettings(setting, requirement,
-                                                        is_exact);
-      if (filtered_ase_configuration_setting.has_value()) {
-        result.push_back(filtered_ase_configuration_setting.value());
-        LOG(INFO) << __func__ << ": Result = "
-                  << filtered_ase_configuration_setting.value().toString();
-        // Found a matched setting, ignore other settings
-        is_matched = true;
-        break;
-      }
+    const IBluetoothAudioProvider::LeAudioConfigurationRequirement& requirement,
+    bool isMatchContext) {
+  LOG(INFO) << __func__ << ": Trying to match for the requirement "
+            << requirement.toString() << ", match context = " << isMatchContext;
+  for (auto& setting : matched_ase_configuration_settings) {
+    // Try to match context in metadata.
+    if (isMatchContext) {
+      if ((setting.audioContext.bitmask & requirement.audioContext.bitmask) !=
+          requirement.audioContext.bitmask)
+        continue;
+      LOG(DEBUG) << __func__ << ": Setting with matched context: "
+                 << getSettingOutputString(setting);
     }
-    if (!is_matched) {
-      // If cannot satisfy this requirement, return an empty result
-      LOG(WARNING) << __func__ << ": Cannot match the requirement "
-                   << requirement.toString();
-      result.clear();
-      break;
+
+    auto filtered_ase_configuration_setting =
+        getRequirementMatchedAseConfigurationSettings(setting, requirement);
+    if (filtered_ase_configuration_setting.has_value()) {
+      LOG(INFO) << __func__ << ": Result found: "
+                << getSettingOutputString(
+                       filtered_ase_configuration_setting.value());
+      // Found a matched setting, ignore other settings
+      return filtered_ase_configuration_setting;
     }
   }
-  return result;
+  // If cannot satisfy this requirement, return nullopt
+  LOG(WARNING) << __func__ << ": Cannot match the requirement "
+               << requirement.toString()
+               << ", match context = " << isMatchContext;
+  return std::nullopt;
 }
 
 // For each requirement, a valid ASE configuration will satify:
-// - matched with any sink capability (if presented)
-// - OR matched with any source capability (if presented)
+// - matched with the sink capability (if presented)
+// - AND matched with the source capability (if presented)
 // - and the setting need to pass the requirement
 ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseConfiguration(
     const std::optional<std::vector<
@@ -714,19 +759,15 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
   }
 
-  // Split out preferred and non-preferred settings based on context
-  // An example: preferred = MEDIA, available: MEDIA | CONVERSATION
-  // -> preferred list will have settings with MEDIA context
-  // -> non-preferred list will have settings with any context
-  // We want to match requirement with preferred context settings first
+  // Matched ASE configuration with ignored audio context
+  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
+      sink_matched_ase_configuration_settings;
   std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
       matched_ase_configuration_settings;
-  // Matched ASE configuration with non-preferred audio context
-  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
-      non_prefer_matched_ase_configuration_settings;
 
-  if (in_remoteSinkAudioCapabilities.has_value())
-    // Matching each setting with any remote capabilities
+  // A setting must match both source and sink.
+  // First filter all setting matched with sink capability
+  if (in_remoteSinkAudioCapabilities.has_value()) {
     for (auto& setting : ase_configuration_settings)
       for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
         if (!capability.has_value()) continue;
@@ -734,81 +775,64 @@
             getCapabilitiesMatchedAseConfigurationSettings(
                 setting, capability.value(), kLeAudioDirectionSink);
         if (filtered_ase_configuration_setting.has_value()) {
-          // Push to non-prefer first for the broadest matching possible
-          non_prefer_matched_ase_configuration_settings.push_back(
+          sink_matched_ase_configuration_settings.push_back(
               filtered_ase_configuration_setting.value());
-          // Try to filter out prefer context to another vector.
-          if (filterCapabilitiesMatchedContext(
-                  filtered_ase_configuration_setting.value().audioContext,
-                  capability.value())) {
-            matched_ase_configuration_settings.push_back(
-                filtered_ase_configuration_setting.value());
-          }
         }
       }
+  } else {
+    sink_matched_ase_configuration_settings = ase_configuration_settings;
+  }
 
   // Combine filter every source capability
-  if (in_remoteSourceAudioCapabilities.has_value())
-    // Matching each setting with any remote capabilities
-    for (auto& setting : ase_configuration_settings)
+  if (in_remoteSourceAudioCapabilities.has_value()) {
+    for (auto& setting : sink_matched_ase_configuration_settings)
       for (auto& capability : in_remoteSourceAudioCapabilities.value()) {
         if (!capability.has_value()) continue;
         auto filtered_ase_configuration_setting =
             getCapabilitiesMatchedAseConfigurationSettings(
                 setting, capability.value(), kLeAudioDirectionSource);
         if (filtered_ase_configuration_setting.has_value()) {
-          // Put into the same list
-          // possibly duplicated, filtered by requirement later
-          // Push to non-prefer first for the broadest matching possible
-          non_prefer_matched_ase_configuration_settings.push_back(
+          matched_ase_configuration_settings.push_back(
               filtered_ase_configuration_setting.value());
-          // Try to filter out prefer context to another vector.
-          if (filterCapabilitiesMatchedContext(
-                  filtered_ase_configuration_setting.value().audioContext,
-                  capability.value())) {
-            matched_ase_configuration_settings.push_back(
-                filtered_ase_configuration_setting.value());
-          }
         }
       }
+  } else {
+    matched_ase_configuration_settings =
+        sink_matched_ase_configuration_settings;
+  }
 
-  // Matching priority list:
-  // Preferred context - exact match with allocation
-  // Any context - exact match with allocation
-  // Preferred context - loose match with allocation
-  // Any context - loose match with allocation
+  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting> result;
+  for (auto& requirement : in_requirements) {
+    // For each requirement, try to match with a setting.
+    // If we cannot match, return an empty result.
 
-  // A loose match will attempt to return 2 settings with the
-  // combined allocation bitmask equal the required allocation.
-  // For example, we can return 2 link (left link and right link) when
-  // the requirement required 1 (left + right) link.
-  auto result = matchWithRequirement(matched_ase_configuration_settings,
-                                     in_requirements, true);
-  if (result.empty()) {
-    LOG(WARNING)
-        << __func__
-        << ": Cannot match with preferred context settings - exact match";
-    result = matchWithRequirement(non_prefer_matched_ase_configuration_settings,
-                                  in_requirements, true);
+    // Matching priority list:
+    // Preferred context - exact match with allocation
+    // Any context - exact match with allocation
+
+    auto matched_setting_with_context = matchWithRequirement(
+        matched_ase_configuration_settings, requirement, true);
+    if (matched_setting_with_context.has_value()) {
+      result.push_back(matched_setting_with_context.value());
+    } else {
+      auto matched_setting = matchWithRequirement(
+          matched_ase_configuration_settings, requirement, false);
+      if (matched_setting.has_value()) {
+        result.push_back(matched_setting.value());
+      } else {
+        // Cannot find a match for this requirement
+        // Immediately return
+        LOG(ERROR)
+            << __func__
+            << ": Cannot find any match for this requirement, exitting...";
+        result.clear();
+        *_aidl_return = result;
+        return ndk::ScopedAStatus::ok();
+      }
+    }
   }
-  if (result.empty()) {
-    LOG(WARNING)
-        << __func__
-        << ": Cannot match with non-preferred context settings - exact match";
-    result = matchWithRequirement(matched_ase_configuration_settings,
-                                  in_requirements, false);
-  }
-  if (result.empty()) {
-    LOG(WARNING) << __func__
-                 << ": Cannot match with preferred context settings - "
-                    "non-exact match";
-    result = matchWithRequirement(non_prefer_matched_ase_configuration_settings,
-                                  in_requirements, false);
-  }
-  if (result.empty())
-    LOG(ERROR) << __func__
-               << ": Cannot match with non preferred context settings - "
-                  "non-exact match";
+
+  LOG(INFO) << __func__ << ": Found matches for all requirements!";
   *_aidl_return = result;
   return ndk::ScopedAStatus::ok();
 };
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
index 043d923..798f183 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
@@ -139,8 +139,7 @@
           direction_configurations,
       const std::vector<std::optional<AseDirectionRequirement>>& requirements,
       std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
-          valid_direction_configurations,
-      bool is_exact);
+          valid_direction_configurations);
   std::optional<LeAudioAseConfigurationSetting>
   getCapabilitiesMatchedAseConfigurationSettings(
       IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
@@ -150,8 +149,7 @@
   getRequirementMatchedAseConfigurationSettings(
       IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
       const IBluetoothAudioProvider::LeAudioConfigurationRequirement&
-          requirement,
-      bool is_exact);
+          requirement);
   bool isMatchedQosRequirement(LeAudioAseQosConfiguration setting_qos,
                                AseQosDirectionRequirement requirement_qos);
   std::optional<LeAudioBroadcastConfigurationSetting>
@@ -169,14 +167,13 @@
       AudioContext requirement_context,
       IBluetoothAudioProvider::BroadcastQuality quality,
       LeAudioBroadcastSubgroupConfiguration configuration);
-  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
+  std::optional<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
   matchWithRequirement(
       std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>&
           matched_ase_configuration_settings,
-      const std::vector<
-          IBluetoothAudioProvider::LeAudioConfigurationRequirement>&
-          in_requirements,
-      bool is_exact);
+      const IBluetoothAudioProvider::LeAudioConfigurationRequirement&
+          requirements,
+      bool isMatchContext);
 };
 
 class LeAudioOffloadOutputAudioProvider : public LeAudioOffloadAudioProvider {
diff --git a/bluetooth/audio/aidl/default/bluetooth_audio.xml b/bluetooth/audio/aidl/default/bluetooth_audio.xml
index 3561dd1..767bf8f 100644
--- a/bluetooth/audio/aidl/default/bluetooth_audio.xml
+++ b/bluetooth/audio/aidl/default/bluetooth_audio.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.bluetooth.audio</name>
-        <version>4</version>
+        <version>5</version>
         <fqname>IBluetoothAudioProviderFactory/default</fqname>
     </hal>
 </manifest>
diff --git a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
index e83cb9e..4481238 100644
--- a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
+++ b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
@@ -142,6 +142,7 @@
   VERSION_AIDL_V2,
   VERSION_AIDL_V3,
   VERSION_AIDL_V4,
+  VERSION_AIDL_V5,
 };
 
 // Some valid configs for HFP PCM configuration (software sessions)
@@ -195,6 +196,17 @@
   }
 }
 
+static std::optional<CodecSpecificConfigurationLtv> GetConfigurationLtv(
+    const std::vector<CodecSpecificConfigurationLtv>& configurationLtvs,
+    CodecSpecificConfigurationLtv::Tag tag) {
+  for (const auto ltv : configurationLtvs) {
+    if (ltv.getTag() == tag) {
+      return ltv;
+    }
+  }
+  return std::nullopt;
+}
+
 class BluetoothAudioPort : public BnBluetoothAudioPort {
  public:
   BluetoothAudioPort() {}
@@ -672,6 +684,8 @@
         return BluetoothAudioHalVersion::VERSION_AIDL_V3;
       case 4:
         return BluetoothAudioHalVersion::VERSION_AIDL_V4;
+      case 5:
+        return BluetoothAudioHalVersion::VERSION_AIDL_V5;
       default:
         return BluetoothAudioHalVersion::VERSION_UNAVAILABLE;
     }
@@ -2393,17 +2407,6 @@
     return capability;
   }
 
-  std::optional<CodecSpecificConfigurationLtv> GetConfigurationLtv(
-      const std::vector<CodecSpecificConfigurationLtv>& configurationLtvs,
-      CodecSpecificConfigurationLtv::Tag tag) {
-    for (const auto ltv : configurationLtvs) {
-      if (ltv.getTag() == tag) {
-        return ltv;
-      }
-    }
-    return std::nullopt;
-  }
-
   bool IsAseRequirementSatisfiedWithUnknownChannelCount(
       const std::vector<std::optional<AseDirectionRequirement>>&
           ase_requirements,
@@ -2560,6 +2563,67 @@
     return (num_of_satisfied_ase_requirements == ase_requirements.size());
   }
 
+  static void VerifyCodecParameters(
+      ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+          LeAudioAseConfigurationSetting::AseDirectionConfiguration config) {
+    ASSERT_NE(config.aseConfiguration.codecConfiguration.size(), 0lu);
+    ASSERT_TRUE(config.qosConfiguration.has_value());
+
+    int32_t frame_blocks = 1;  // by default 1 if not set
+    int8_t frame_duration = 0;
+    int32_t octets_per_frame = 0;
+    std::bitset<32> allocation_bitmask = 0;
+
+    for (auto const& param : config.aseConfiguration.codecConfiguration) {
+      if (param.getTag() ==
+          ::aidl::android::hardware::bluetooth::audio::
+              CodecSpecificConfigurationLtv::Tag::codecFrameBlocksPerSDU) {
+        frame_blocks = param
+                           .get<::aidl::android::hardware::bluetooth::audio::
+                                    CodecSpecificConfigurationLtv::Tag::
+                                        codecFrameBlocksPerSDU>()
+                           .value;
+      } else if (param.getTag() ==
+                 ::aidl::android::hardware::bluetooth::audio::
+                     CodecSpecificConfigurationLtv::Tag::frameDuration) {
+        frame_duration = static_cast<int8_t>(
+            param.get<::aidl::android::hardware::bluetooth::audio::
+                          CodecSpecificConfigurationLtv::Tag::frameDuration>());
+      } else if (param.getTag() ==
+                 ::aidl::android::hardware::bluetooth::audio::
+                     CodecSpecificConfigurationLtv::Tag::octetsPerCodecFrame) {
+        octets_per_frame = static_cast<int32_t>(
+            param
+                .get<::aidl::android::hardware::bluetooth::audio::
+                         CodecSpecificConfigurationLtv::Tag::
+                             octetsPerCodecFrame>()
+                .value);
+      } else if (param.getTag() == ::aidl::android::hardware::bluetooth::audio::
+                                       CodecSpecificConfigurationLtv::Tag::
+                                           audioChannelAllocation) {
+        allocation_bitmask = static_cast<int32_t>(
+            param
+                .get<::aidl::android::hardware::bluetooth::audio::
+                         CodecSpecificConfigurationLtv::Tag::
+                             audioChannelAllocation>()
+                .bitmask);
+      }
+    }
+
+    ASSERT_NE(frame_blocks, 0);
+    ASSERT_NE(frame_duration, 0);
+    ASSERT_NE(octets_per_frame, 0);
+
+    auto const num_channels_per_cis = allocation_bitmask.count();
+    ASSERT_NE(num_channels_per_cis, 0);
+
+    // Verify if QoS takes the codec frame blocks per SDU into the account
+    ASSERT_TRUE(config.qosConfiguration->sduIntervalUs >=
+                frame_blocks * frame_duration);
+    ASSERT_TRUE(config.qosConfiguration->maxSdu >=
+                (frame_blocks * num_channels_per_cis * octets_per_frame));
+  }
+
   void VerifyIfRequirementsSatisfied(
       const std::vector<LeAudioConfigurationRequirement>& requirements,
       const std::vector<LeAudioAseConfigurationSetting>& configurations) {
@@ -2592,32 +2656,52 @@
           continue;
         }
 
+        bool sink_req_satisfied = false;
+        if (req.sinkAseRequirement) {
+          ASSERT_TRUE(conf.sinkAseConfiguration.has_value());
+          sink_req_satisfied = IsAseRequirementSatisfied(
+              *req.sinkAseRequirement, *conf.sinkAseConfiguration);
+
+          ASSERT_NE(conf.sinkAseConfiguration->size(), 0lu);
+          for (auto const& cfg : conf.sinkAseConfiguration.value()) {
+            ASSERT_TRUE(cfg.has_value());
+            VerifyCodecParameters(cfg.value());
+          }
+        }
+
+        bool source_req_satisfied = false;
+        if (req.sourceAseRequirement) {
+          ASSERT_TRUE(conf.sourceAseConfiguration.has_value());
+          source_req_satisfied = IsAseRequirementSatisfied(
+              *req.sourceAseRequirement, *conf.sourceAseConfiguration);
+
+          ASSERT_NE(conf.sourceAseConfiguration->size(), 0lu);
+          for (auto const& cfg : conf.sourceAseConfiguration.value()) {
+            ASSERT_TRUE(cfg.has_value());
+            VerifyCodecParameters(cfg.value());
+          }
+        }
+
         if (req.sinkAseRequirement && req.sourceAseRequirement) {
           if (!conf.sinkAseConfiguration || !conf.sourceAseConfiguration) {
             continue;
           }
 
-          if (!IsAseRequirementSatisfied(*req.sinkAseRequirement,
-                                         *conf.sinkAseConfiguration) ||
-              !IsAseRequirementSatisfied(*req.sourceAseRequirement,
-                                         *conf.sourceAseConfiguration)) {
+          if (!sink_req_satisfied || !source_req_satisfied) {
             continue;
           }
           num_of_satisfied_requirements +=
               std::bitset<32>(req.audioContext.bitmask).count();
-
           break;
         } else if (req.sinkAseRequirement) {
-          if (!IsAseRequirementSatisfied(*req.sinkAseRequirement,
-                                         *conf.sinkAseConfiguration)) {
+          if (!sink_req_satisfied) {
             continue;
           }
           num_of_satisfied_requirements +=
               std::bitset<32>(req.audioContext.bitmask).count();
           break;
         } else if (req.sourceAseRequirement) {
-          if (!IsAseRequirementSatisfied(*req.sourceAseRequirement,
-                                         *conf.sourceAseConfiguration)) {
+          if (!source_req_satisfied) {
             continue;
           }
           num_of_satisfied_requirements +=
@@ -4089,17 +4173,6 @@
     return media_audio_context;
   }
 
-  std::optional<CodecSpecificConfigurationLtv> GetConfigurationLtv(
-      const std::vector<CodecSpecificConfigurationLtv>& configurationLtvs,
-      CodecSpecificConfigurationLtv::Tag tag) {
-    for (const auto ltv : configurationLtvs) {
-      if (ltv.getTag() == tag) {
-        return ltv;
-      }
-    }
-    return std::nullopt;
-  }
-
   std::optional<CodecSpecificConfigurationLtv::SamplingFrequency>
   GetBisSampleFreq(const LeAudioBisConfiguration& bis_conf) {
     auto sample_freq_ltv = GetConfigurationLtv(
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index 1661362..d931c4d 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -81,9 +81,9 @@
     ],
     required: [
         "aidl_audio_set_configurations_bfbs",
-        "aidl_audio_set_configurations_json",
+        "aidl_default_audio_set_configurations_json",
         "aidl_audio_set_scenarios_bfbs",
-        "aidl_audio_set_scenarios_json",
+        "aidl_default_audio_set_scenarios_json",
         "hfp_codec_capabilities_xml",
     ],
 }
@@ -215,9 +215,9 @@
 }
 
 prebuilt_etc {
-    name: "aidl_audio_set_scenarios_json",
+    name: "aidl_default_audio_set_scenarios_json",
     src: "le_audio_configuration_set/audio_set_scenarios.json",
-    filename: "aidl_audio_set_scenarios.json",
+    filename: "aidl_default_audio_set_scenarios.json",
     sub_dir: "aidl/le_audio",
     vendor: true,
 }
@@ -239,9 +239,9 @@
 }
 
 prebuilt_etc {
-    name: "aidl_audio_set_configurations_json",
+    name: "aidl_default_audio_set_configurations_json",
     src: "le_audio_configuration_set/audio_set_configurations.json",
-    filename: "aidl_audio_set_configurations.json",
+    filename: "aidl_default_audio_set_configurations.json",
     sub_dir: "aidl/le_audio",
     vendor: true,
 }
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
index c25b102..db2528e 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
@@ -61,7 +61,7 @@
 
 static const AacCapabilities kDefaultOffloadAacCapability = {
     .objectType = {AacObjectType::MPEG2_LC},
-    .sampleRateHz = {44100},
+    .sampleRateHz = {44100, 48000},
     .channelMode = {ChannelMode::STEREO},
     .variableBitRateSupported = true,
     .bitsPerSample = {16}};
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
index d0f2a26..a458c5b 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
@@ -139,21 +139,36 @@
                   << toString(session_type_);
         return;
       }
+    } else if(session_type_ == SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH) {
+      if (audio_config.getTag() != AudioConfiguration::hfpConfig) {
+        LOG(ERROR) << __func__ << " invalid audio config type for SessionType ="
+                  << toString(session_type_);
+        return;
+      }
     } else {
       LOG(ERROR) << __func__ << " invalid SessionType ="
                  << toString(session_type_);
       return;
     }
   } else {
-    if (session_type_ !=
-            SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
-        session_type_ !=
+    if (session_type_ ==
+            SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+        session_type_ ==
             SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
-      return;
-    }
-    if (audio_config.getTag() != AudioConfiguration::leAudioConfig) {
-      LOG(ERROR) << __func__ << " invalid audio config type for SessionType ="
-                 << toString(session_type_);
+      if (audio_config.getTag() != AudioConfiguration::leAudioConfig) {
+        LOG(ERROR) << __func__ << " invalid audio config type for SessionType ="
+                   << toString(session_type_);
+        return;
+      }
+    } else if(session_type_ == SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH) {
+      if (audio_config.getTag() != AudioConfiguration::hfpConfig) {
+        LOG(ERROR) << __func__ << " invalid audio config type for SessionType ="
+                  << toString(session_type_);
+        return;
+      }
+    } else {
+      LOG(ERROR) << __func__
+                 << " invalid SessionType =" << toString(session_type_);
       return;
     }
   }
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp
index 780154a..37812fa 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp
@@ -240,18 +240,31 @@
      CodecSpecificConfigurationLtv::AudioChannelAllocation::RIGHT_SURROUND},
 };
 
+// Set configuration and scenario files with fallback default
 static const std::vector<
     std::pair<const char* /*schema*/, const char* /*content*/>>
-    kLeAudioSetConfigs = {{"/vendor/etc/aidl/le_audio/"
-                           "aidl_audio_set_configurations.bfbs",
-                           "/vendor/etc/aidl/le_audio/"
-                           "aidl_audio_set_configurations.json"}};
+    kLeAudioSetConfigs = {
+        {"/vendor/etc/aidl/le_audio/"
+         "aidl_audio_set_configurations.bfbs",
+         "/vendor/etc/aidl/le_audio/"
+         "aidl_audio_set_configurations.json"},
+
+        {"/vendor/etc/aidl/le_audio/"
+         "aidl_audio_set_configurations.bfbs",
+         "/vendor/etc/aidl/le_audio/"
+         "aidl_default_audio_set_configurations.json"},
+};
 static const std::vector<
     std::pair<const char* /*schema*/, const char* /*content*/>>
     kLeAudioSetScenarios = {{"/vendor/etc/aidl/le_audio/"
                              "aidl_audio_set_scenarios.bfbs",
                              "/vendor/etc/aidl/le_audio/"
-                             "aidl_audio_set_scenarios.json"}};
+                             "aidl_audio_set_scenarios.json"},
+
+                            {"/vendor/etc/aidl/le_audio/"
+                             "aidl_audio_set_scenarios.bfbs",
+                             "/vendor/etc/aidl/le_audio/"
+                             "aidl_default_audio_set_scenarios.json"}};
 
 /* Implementation */
 
@@ -374,7 +387,7 @@
 }
 
 void AudioSetConfigurationProviderJson::populateAseConfiguration(
-    LeAudioAseConfiguration& ase,
+    const std::string& name, LeAudioAseConfiguration& ase,
     const le_audio::AudioSetSubConfiguration* flat_subconfig,
     const le_audio::QosConfiguration* qos_cfg) {
   // Target latency
@@ -411,20 +424,36 @@
   }
   // Codec configuration data
   populateConfigurationData(ase, flat_subconfig->codec_configuration());
+  // Populate the config name for easier debug
+  auto meta = std::vector<std::optional<MetadataLtv>>();
+  MetadataLtv::VendorSpecific cfg_name;
+  cfg_name.opaqueValue = std::vector<uint8_t>(name.begin(), name.end());
+  meta.push_back(cfg_name);
+  ase.metadata = meta;
 }
 
 void AudioSetConfigurationProviderJson::populateAseQosConfiguration(
     LeAudioAseQosConfiguration& qos, const le_audio::QosConfiguration* qos_cfg,
-    LeAudioAseConfiguration& ase) {
+    LeAudioAseConfiguration& ase, uint8_t ase_channel_cnt) {
   std::optional<CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU>
       frameBlock = std::nullopt;
   std::optional<CodecSpecificConfigurationLtv::FrameDuration> frameDuration =
       std::nullopt;
-  std::optional<CodecSpecificConfigurationLtv::AudioChannelAllocation>
-      allocation = std::nullopt;
   std::optional<CodecSpecificConfigurationLtv::OctetsPerCodecFrame> octet =
       std::nullopt;
 
+  // Hack to put back allocation
+  CodecSpecificConfigurationLtv::AudioChannelAllocation allocation =
+      CodecSpecificConfigurationLtv::AudioChannelAllocation();
+  if (ase_channel_cnt == 1) {
+    allocation.bitmask |=
+        CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_CENTER;
+
+  } else {
+    allocation.bitmask |=
+        CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+        CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+  }
   for (auto& cfg_ltv : ase.codecConfiguration) {
     auto tag = cfg_ltv.getTag();
     if (tag == CodecSpecificConfigurationLtv::codecFrameBlocksPerSDU) {
@@ -433,11 +462,12 @@
     } else if (tag == CodecSpecificConfigurationLtv::frameDuration) {
       frameDuration =
           cfg_ltv.get<CodecSpecificConfigurationLtv::frameDuration>();
-    } else if (tag == CodecSpecificConfigurationLtv::audioChannelAllocation) {
-      allocation =
-          cfg_ltv.get<CodecSpecificConfigurationLtv::audioChannelAllocation>();
     } else if (tag == CodecSpecificConfigurationLtv::octetsPerCodecFrame) {
       octet = cfg_ltv.get<CodecSpecificConfigurationLtv::octetsPerCodecFrame>();
+    } else if (tag == CodecSpecificConfigurationLtv::audioChannelAllocation) {
+      // Change to the old hack allocation
+      cfg_ltv.set<CodecSpecificConfigurationLtv::audioChannelAllocation>(
+          allocation);
     }
   }
 
@@ -445,9 +475,8 @@
   if (frameBlock.has_value()) frameBlockValue = frameBlock.value().value;
 
   // Populate maxSdu
-  if (allocation.has_value() && octet.has_value()) {
-    auto channel_count = std::bitset<32>(allocation.value().bitmask).count();
-    qos.maxSdu = channel_count * octet.value().value * frameBlockValue;
+  if (octet.has_value()) {
+    qos.maxSdu = ase_channel_cnt * octet.value().value * frameBlockValue;
   }
   // Populate sduIntervalUs
   if (frameDuration.has_value()) {
@@ -468,6 +497,7 @@
 // Parse into AseDirectionConfiguration
 AseDirectionConfiguration
 AudioSetConfigurationProviderJson::SetConfigurationFromFlatSubconfig(
+    const std::string& name,
     const le_audio::AudioSetSubConfiguration* flat_subconfig,
     const le_audio::QosConfiguration* qos_cfg, CodecLocation location) {
   AseDirectionConfiguration direction_conf;
@@ -477,10 +507,11 @@
   LeAudioDataPathConfiguration path;
 
   // Translate into LeAudioAseConfiguration
-  populateAseConfiguration(ase, flat_subconfig, qos_cfg);
+  populateAseConfiguration(name, ase, flat_subconfig, qos_cfg);
 
   // Translate into LeAudioAseQosConfiguration
-  populateAseQosConfiguration(qos, qos_cfg, ase);
+  populateAseQosConfiguration(qos, qos_cfg, ase,
+                              flat_subconfig->ase_channel_cnt());
 
   // Translate location to data path id
   switch (location) {
@@ -510,13 +541,18 @@
 // Parse into AseDirectionConfiguration and the ConfigurationFlags
 // and put them in the given list.
 void AudioSetConfigurationProviderJson::processSubconfig(
+    const std::string& name,
     const le_audio::AudioSetSubConfiguration* subconfig,
     const le_audio::QosConfiguration* qos_cfg,
     std::vector<std::optional<AseDirectionConfiguration>>&
         directionAseConfiguration,
     CodecLocation location) {
-  directionAseConfiguration.push_back(
-      SetConfigurationFromFlatSubconfig(subconfig, qos_cfg, location));
+  auto ase_cnt = subconfig->ase_cnt();
+  auto config =
+      SetConfigurationFromFlatSubconfig(name, subconfig, qos_cfg, location);
+  directionAseConfiguration.push_back(config);
+  // Put the same setting again.
+  if (ase_cnt == 2) directionAseConfiguration.push_back(config);
 }
 
 void AudioSetConfigurationProviderJson::PopulateAseConfigurationFromFlat(
@@ -587,11 +623,11 @@
     /* Load subconfigurations */
     for (auto subconfig : *codec_cfg->subconfigurations()) {
       if (subconfig->direction() == kLeAudioDirectionSink) {
-        processSubconfig(subconfig, qos_sink_cfg, sinkAseConfiguration,
-                         location);
+        processSubconfig(flat_cfg->name()->str(), subconfig, qos_sink_cfg,
+                         sinkAseConfiguration, location);
       } else {
-        processSubconfig(subconfig, qos_source_cfg, sourceAseConfiguration,
-                         location);
+        processSubconfig(flat_cfg->name()->str(), subconfig, qos_source_cfg,
+                         sourceAseConfiguration, location);
       }
     }
   } else {
@@ -742,9 +778,6 @@
 
   LOG(DEBUG) << "Updating " << flat_scenarios->size() << " scenarios.";
   for (auto const& scenario : *flat_scenarios) {
-    LOG(DEBUG) << "Scenario " << scenario->name()->c_str()
-               << " configs: " << scenario->configurations()->size();
-
     if (!scenario->configurations()) continue;
     std::string scenario_name = scenario->name()->c_str();
     AudioContext context;
@@ -758,6 +791,9 @@
       context = AudioContext(game_context);
     else if (scenario_name == "VoiceAssistants")
       context = AudioContext(voice_assistants_context);
+    LOG(DEBUG) << "Scenario " << scenario->name()->c_str()
+               << " configs: " << scenario->configurations()->size()
+               << " context: " << context.toString();
 
     for (auto it = scenario->configurations()->begin();
          it != scenario->configurations()->end(); ++it) {
@@ -790,14 +826,22 @@
     std::vector<std::pair<const char* /*schema*/, const char* /*content*/>>
         scenario_files,
     CodecLocation location) {
+  bool is_loaded_config = false;
   for (auto [schema, content] : config_files) {
-    if (!LoadConfigurationsFromFiles(schema, content, location)) return false;
+    if (LoadConfigurationsFromFiles(schema, content, location)) {
+      is_loaded_config = true;
+      break;
+    }
   }
 
+  bool is_loaded_scenario = false;
   for (auto [schema, content] : scenario_files) {
-    if (!LoadScenariosFromFiles(schema, content)) return false;
+    if (LoadScenariosFromFiles(schema, content)) {
+      is_loaded_scenario = true;
+      break;
+    }
   }
-  return true;
+  return is_loaded_config && is_loaded_scenario;
 }
 
 }  // namespace audio
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.h b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.h
index 6639009..fac6152 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.h
@@ -73,19 +73,22 @@
           flat_codec_specific_params);
 
   static void populateAseConfiguration(
-      LeAudioAseConfiguration& ase,
+      const std::string& name, LeAudioAseConfiguration& ase,
       const le_audio::AudioSetSubConfiguration* flat_subconfig,
       const le_audio::QosConfiguration* qos_cfg);
 
   static void populateAseQosConfiguration(
       LeAudioAseQosConfiguration& qos,
-      const le_audio::QosConfiguration* qos_cfg, LeAudioAseConfiguration& ase);
+      const le_audio::QosConfiguration* qos_cfg, LeAudioAseConfiguration& ase,
+      uint8_t ase_channel_cnt);
 
   static AseDirectionConfiguration SetConfigurationFromFlatSubconfig(
+      const std::string& name,
       const le_audio::AudioSetSubConfiguration* flat_subconfig,
       const le_audio::QosConfiguration* qos_cfg, CodecLocation location);
 
   static void processSubconfig(
+      const std::string& name,
       const le_audio::AudioSetSubConfiguration* subconfig,
       const le_audio::QosConfiguration* qos_cfg,
       std::vector<std::optional<AseDirectionConfiguration>>&
diff --git a/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.fbs b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.fbs
index bde467d..ed9ad49 100644
--- a/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.fbs
+++ b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.fbs
@@ -56,10 +56,9 @@
     HIGH_RELIABILITY = 0x03,
 }
 table AudioSetSubConfiguration {
-    device_cnt: ubyte;
+    ase_channel_cnt: ubyte;
     ase_cnt: ubyte;
     direction: AudioSetConfigurationDirection = SINK;
-    configuration_strategy: AudioSetConfigurationStrategy;
     codec_id : CodecId (required);
     codec_configuration: [CodecSpecificConfiguration] (required);
 }
diff --git a/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.json b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.json
index 404a48a..fbfa3f9 100644
--- a/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.json
+++ b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.json
@@ -13,16 +13,11 @@
     "   Codec Configuration parameter types:",
     "     SUPPORTED_SAMPLING_FREQUENCY = 1",
     "     SUPPORTED_FRAME_DURATION = 2",
-    "     SUPPORTED_AUDIO_CHANNEL_ALLOCATION = 3",
     "     SUPPORTED_OCTETS_PER_CODEC_FRAME = 4",
     "     SUPPORTED_CODEC_FRAME_BLOCKS_PER_SDU = 5",
     " Example values which can be used as 'codec_configuration.compound_value'",
     "   Codec Coding formats:",
     "     LC3 = 6",
-    "   ASE Configuration strategies:",
-    "     MONO_ONE_CIS_PER_DEVICE = 0",
-    "     STEREO_TWO_CISES_PER_DEVICE = 1",
-    "     STEREO_ONE_CIS_PER_DEVICE = 2",
     "   Sampling Frequencies: ",
     "     8000Hz = 1",
     "     11025Hz = 2",
@@ -43,1177 +38,1135 @@
   ],
   "configurations": [
     {
-      "name": "DualDev_OneChanStereoSnk_16_1_Low_Latency",
-      "codec_config_name": "DualDev_OneChanStereoSnk_16_1",
+      "name": "Two-OneChan-SnkAse-Lc3_16_1_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_16_1_Balanced_Reliability",
-      "codec_config_name": "DualDev_OneChanStereoSnk_16_1",
+      "name": "Two-OneChan-SnkAse-Lc3_16_1_Balanced_Reliability",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_16_1_1",
-      "codec_config_name": "DualDev_OneChanStereoSnk_16_1",
+      "name": "Two-OneChan-SnkAse-Lc3_16_1_1",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_16_1_1"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_16_1_2",
-      "codec_config_name": "DualDev_OneChanStereoSnk_16_1",
+      "name": "Two-OneChan-SnkAse-Lc3_16_1_2",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_16_1_2"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_16_2_Low_Latency",
-      "codec_config_name": "DualDev_OneChanStereoSnk_16_2",
+      "name": "Two-OneChan-SnkAse-Lc3_16_2_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_16_2_Balanced_Reliability",
-      "codec_config_name": "DualDev_OneChanStereoSnk_16_2",
+      "name": "Two-OneChan-SnkAse-Lc3_16_2_Balanced_Reliability",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_16_2_1",
-      "codec_config_name": "DualDev_OneChanStereoSnk_16_2",
+      "name": "Two-OneChan-SnkAse-Lc3_16_2_1",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_16_2_1"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_16_2_2",
-      "codec_config_name": "DualDev_OneChanStereoSnk_16_2",
+      "name": "Two-OneChan-SnkAse-Lc3_16_2_2",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_16_2_2"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_16_1_Low_Latency",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_16_1",
+      "name": "Two-OneChan-SnkAse-Lc3_16_1_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_16_1_Balanced_Reliability",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_16_1",
+      "name": "Two-OneChan-SnkAse-Lc3_16_1_Balanced_Reliability",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_16_1_1",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_16_1",
+      "name": "Two-OneChan-SnkAse-Lc3_16_1_1",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_16_1_1"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_16_1_2",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_16_1",
+      "name": "Two-OneChan-SnkAse-Lc3_16_1_2",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_16_1_2"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_16_2_Low_Latency",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_16_2",
+      "name": "Two-OneChan-SnkAse-Lc3_16_2_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_16_2_Balanced_Reliability",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_16_2",
+      "name": "Two-OneChan-SnkAse-Lc3_16_2_Balanced_Reliability",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_16_2_1",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_16_2",
+      "name": "Two-OneChan-SnkAse-Lc3_16_2_1",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_16_2_1"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_16_2_2",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_16_2",
+      "name": "Two-OneChan-SnkAse-Lc3_16_2_2",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_16_2_2"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_16_1_Low_Latency",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_16_1",
+      "name": "One-TwoChan-SnkAse-Lc3_16_1_Low_Latency",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_16_1_Balanced_Reliability",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_16_1",
+      "name": "One-TwoChan-SnkAse-Lc3_16_1_Balanced_Reliability",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_16_1_1",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_16_1",
+      "name": "One-TwoChan-SnkAse-Lc3_16_1_1",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_16_1_1"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_16_1_2",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_16_1",
+      "name": "One-TwoChan-SnkAse-Lc3_16_1_2",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_16_1_2"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_16_2_Low_Latency",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_16_2",
+      "name": "One-TwoChan-SnkAse-Lc3_16_2_Low_Latency",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_16_2_Balanced_Reliability",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_16_2",
+      "name": "One-TwoChan-SnkAse-Lc3_16_2_Balanced_Reliability",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_16_2_1",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_16_2",
+      "name": "One-TwoChan-SnkAse-Lc3_16_2_1",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_16_2_1"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_16_2_2",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_16_2",
+      "name": "One-TwoChan-SnkAse-Lc3_16_2_2",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_16_2_2"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_32_1_Balanced_Reliability",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_32_1",
+      "name": "One-OneChan-SnkAse-Lc3_32_1_Balanced_Reliability",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_32_1",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_32_1_1",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_32_1",
+      "name": "One-OneChan-SnkAse-Lc3_32_1_1",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_32_1",
       "qos_config_name": [
         "QoS_Config_32_1_1"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_32_2_Balanced_Reliability",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_32_2",
+      "name": "One-OneChan-SnkAse-Lc3_32_1_2",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_32_1",
+      "qos_config_name": [
+        "QoS_Config_32_1_2"
+      ]
+    },
+    {
+      "name": "One-OneChan-SnkAse-Lc3_32_2_Balanced_Reliability",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_32_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_32_2_1",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_32_2",
+      "name": "One-OneChan-SnkAse-Lc3_32_2_1",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_32_2",
       "qos_config_name": [
         "QoS_Config_32_2_1"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_16_1_Balanced_Reliability",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_16_1",
+      "name": "One-OneChan-SnkAse-Lc3_32_2_2",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_32_2",
+      "qos_config_name": [
+        "QoS_Config_32_2_2"
+      ]
+    },
+    {
+      "name": "One-OneChan-SnkAse-Lc3_16_1_Balanced_Reliability",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_16_1_1",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_16_1",
+      "name": "One-OneChan-SnkAse-Lc3_16_1_1",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_16_1_1"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_16_1_2",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_16_1",
+      "name": "One-OneChan-SnkAse-Lc3_16_1_2",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_16_1_2"
       ]
     },
     {
-      "name": "DualDev_OneChanMonoSnk_16_2_Balanced_Reliability",
-      "codec_config_name": "DualDev_OneChanMonoSnk_16_2",
+      "name": "Two-OneChan-SnkAse-Lc3_16_2_Balanced_Reliability",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_16_2_Balanced_Reliability",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_16_2",
+      "name": "One-OneChan-SnkAse-Lc3_16_2_Balanced_Reliability",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_16_2_1",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_16_2",
+      "name": "One-OneChan-SnkAse-Lc3_16_2_1",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_16_2_1"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_16_2_2",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_16_2",
+      "name": "One-OneChan-SnkAse-Lc3_16_2_2",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_16_2_2"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
-      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1",
+      "name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1_1",
-      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1",
+      "name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_16_1_1"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1_2",
-      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1",
+      "name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_2",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_16_1_2"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_Low_Latency",
-      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2",
+      "name": "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_2",
-      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2",
+      "name": "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_2",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_16_2_2"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_1",
-      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2",
+      "name": "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_1",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_16_2_1"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_Low_Latency",
-      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1",
+      "name": "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_2",
-      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1",
+      "name": "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_2",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_16_1_2"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_1",
-      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1",
+      "name": "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_1",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_16_1_1"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
-      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2",
+      "name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2_1",
-      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2",
+      "name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_16_2_1"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2_2",
-      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2",
+      "name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_2",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_16_2_2"
       ]
     },
     {
-      "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
-      "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1",
+      "name": "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_Low_Latency",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1_1",
-      "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1",
-      "qos_config_name": [
-        "QoS_Config_16_1_1"
-      ]
-    },
-    {
-      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_Low_Latency",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2",
-      "qos_config_name": [
-        "QoS_Config_Low_Latency"
-      ]
-    },
-    {
-      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_1",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2",
+      "name": "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_1",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2",
       "qos_config_name": [
         "QoS_Config_32_2_1"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_Low_Latency",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2",
+      "name": "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_Low_Latency",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_2",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2",
+      "name": "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_2",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_16_2_2"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_1",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2",
+      "name": "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_1",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_16_2_1"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_Low_Latency",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1",
+      "name": "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_Low_Latency",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_2",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1",
+      "name": "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_2",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_16_1_2"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_1",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1",
+      "name": "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_1",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_16_1_1"
       ]
     },
     {
-      "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1_2",
-      "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1",
-      "qos_config_name": [
-        "QoS_Config_16_1_2"
-      ]
-    },
-    {
-      "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
-      "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2",
+      "name": "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2_1",
-      "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2",
-      "qos_config_name": [
-        "QoS_Config_16_2_1"
-      ]
-    },
-    {
-      "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2_2",
-      "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2",
-      "qos_config_name": [
-        "QoS_Config_16_2_2"
-      ]
-    },
-    {
-      "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1",
-      "qos_config_name": [
-        "QoS_Config_Low_Latency"
-      ]
-    },
-    {
-      "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_1",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1",
+      "name": "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_16_1_1"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_2",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1",
+      "name": "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_2",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_16_1_2"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2",
+      "name": "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_1",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2",
+      "name": "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_16_2_1"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_2",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2",
+      "name": "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_2",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_16_2_2"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1",
+      "name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_1",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1",
+      "name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_16_1_1"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_2",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1",
+      "name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_2",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_16_1_2"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2",
+      "name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_1",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2",
+      "name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_16_2_1"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_2",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2",
+      "name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_2",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_16_2_2"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_Low_Latency",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1",
+      "name": "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_1",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1",
+      "name": "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_16_1_1"
       ]
     },
     {
-      "name": "DualDev_OneChanMonoSrc_16_2_Balanced_Reliability",
-      "codec_config_name": "DualDev_OneChanMonoSrc_16_2",
+      "name": "Two-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability",
+      "codec_config_name": "Two-OneChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSrc_16_2_Balanced_Reliability",
-      "codec_config_name": "SingleDev_OneChanStereoSrc_16_2",
+      "name": "Two-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability",
+      "codec_config_name": "Two-OneChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSrc_48_4_Balanced_Reliability",
-      "codec_config_name": "SingleDev_OneChanMonoSrc_48_4",
+      "name": "One-OneChan-SrcAse-Lc3_48_4_Balanced_Reliability",
+      "codec_config_name": "One-OneChan-SrcAse-Lc3_48_4",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSrc_48_3_Balanced_Reliability",
-      "codec_config_name": "SingleDev_OneChanMonoSrc_48_3",
+      "name": "One-OneChan-SrcAse-Lc3_48_3_Balanced_Reliability",
+      "codec_config_name": "One-OneChan-SrcAse-Lc3_48_3",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSrc_48_2_Balanced_Reliability",
-      "codec_config_name": "SingleDev_OneChanMonoSrc_48_2",
+      "name": "One-OneChan-SrcAse-Lc3_48_2_Balanced_Reliability",
+      "codec_config_name": "One-OneChan-SrcAse-Lc3_48_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSrc_48_1_Balanced_Reliability",
-      "codec_config_name": "SingleDev_OneChanMonoSrc_48_1",
+      "name": "One-OneChan-SrcAse-Lc3_48_1_Balanced_Reliability",
+      "codec_config_name": "One-OneChan-SrcAse-Lc3_48_1",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSrc_32_2_Balanced_Reliability",
-      "codec_config_name": "SingleDev_OneChanMonoSrc_32_2",
+      "name": "One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability",
+      "codec_config_name": "One-OneChan-SrcAse-Lc3_32_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSrc_32_1_Balanced_Reliability",
-      "codec_config_name": "SingleDev_OneChanMonoSrc_32_1",
+      "name": "One-OneChan-SrcAse-Lc3_32_1_Balanced_Reliability",
+      "codec_config_name": "One-OneChan-SrcAse-Lc3_32_1",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSrc_24_2_Balanced_Reliability",
-      "codec_config_name": "SingleDev_OneChanMonoSrc_24_2",
+      "name": "One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability",
+      "codec_config_name": "One-OneChan-SrcAse-Lc3_24_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSrc_24_1_Balanced_Reliability",
-      "codec_config_name": "SingleDev_OneChanMonoSrc_24_1",
+      "name": "One-OneChan-SrcAse-Lc3_24_1_Balanced_Reliability",
+      "codec_config_name": "One-OneChan-SrcAse-Lc3_24_1",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSrc_16_2_Balanced_Reliability",
-      "codec_config_name": "SingleDev_OneChanMonoSrc_16_2",
+      "name": "One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability",
+      "codec_config_name": "One-OneChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSrc_16_1_Balanced_Reliability",
-      "codec_config_name": "SingleDev_OneChanMonoSrc_16_1",
+      "name": "One-OneChan-SrcAse-Lc3_16_1_Balanced_Reliability",
+      "codec_config_name": "One-OneChan-SrcAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_2",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1",
+      "name": "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_2",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1",
       "qos_config_name": [
         "QoS_Config_16_1_2"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_Low_Latency",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2",
+      "name": "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_1",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2",
+      "name": "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_16_2_1"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_2",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2",
+      "name": "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_2",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_16_2_2"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_24_1_Low_Latency",
-      "codec_config_name": "DualDev_OneChanStereoSnk_24_1",
+      "name": "Two-OneChan-SnkAse-Lc3_24_1_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_24_1",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_24_1_Low_Latency",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_24_1",
+      "name": "One-TwoChan-SnkAse-Lc3_24_1_Low_Latency",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_24_1",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_24_1_Low_Latency",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_24_2",
+      "name": "Two-OneChan-SnkAse-Lc3_24_2_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_24_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_24_2_Low_Latency",
-      "codec_config_name": "DualDev_OneChanStereoSnk_24_2",
+      "name": "Two-OneChan-SnkAse-Lc3_24_2_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_24_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_24_2_Balanced_Reliability",
-      "codec_config_name": "DualDev_OneChanStereoSnk_24_2",
+      "name": "Two-OneChan-SnkAse-Lc3_24_2_Balanced_Reliability",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_24_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_24_2_2",
-      "codec_config_name": "DualDev_OneChanStereoSnk_24_2",
+      "name": "Two-OneChan-SnkAse-Lc3_24_2_2",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_24_2",
       "qos_config_name": [
         "QoS_Config_24_2_2"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_24_2_Low_Latency",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_24_2",
+      "name": "Two-OneChan-SnkAse-Lc3_24_2_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_24_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_24_2_Balanced_Reliability",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_24_2",
+      "name": "Two-OneChan-SnkAse-Lc3_24_2_Balanced_Reliability",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_24_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_24_2_2",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_24_2",
+      "name": "Two-OneChan-SnkAse-Lc3_24_2_2",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_24_2",
       "qos_config_name": [
         "QoS_Config_24_2_2"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_24_2_Low_Latency",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_24_2",
+      "name": "One-TwoChan-SnkAse-Lc3_24_2_Low_Latency",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_24_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_24_2_Balanced_Reliability",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_24_2",
+      "name": "One-TwoChan-SnkAse-Lc3_24_2_Balanced_Reliability",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_24_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_24_2_2",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_24_2",
+      "name": "One-TwoChan-SnkAse-Lc3_24_2_2",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_24_2",
       "qos_config_name": [
         "QoS_Config_24_2_2"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_24_2_Balanced_Reliability",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_24_2",
+      "name": "One-OneChan-SnkAse-Lc3_24_2_Balanced_Reliability",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_24_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_24_2_2",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_24_2",
+      "name": "One-OneChan-SnkAse-Lc3_24_2_2",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_24_2",
       "qos_config_name": [
         "QoS_Config_24_2_2"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_Low_Latency",
-      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2",
+      "name": "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_1",
-      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2",
+      "name": "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_1",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2",
       "qos_config_name": [
         "QoS_Config_32_2_1"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
-      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2",
+      "name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2_1",
-      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2",
+      "name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2",
       "qos_config_name": [
         "QoS_Config_32_2_1"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_32_2_Low_Latency",
-      "codec_config_name": "DualDev_OneChanStereoSnk_32_2",
+      "name": "Two-OneChan-SnkAse-Lc3_32_2_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_32_1_Low_Latency",
-      "codec_config_name": "DualDev_OneChanStereoSnk_32_1",
+      "name": "Two-OneChan-SnkAse-Lc3_32_1_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_1",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_32_1_Low_Latency",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_32_1",
+      "name": "One-TwoChan-SnkAse-Lc3_32_1_Low_Latency",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_32_1",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_32_2_Low_Latency",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_32_2",
+      "name": "Two-OneChan-SnkAse-Lc3_32_2_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_32_1_Low_Latency",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_32_1",
+      "name": "Two-OneChan-SnkAse-Lc3_32_1_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_1",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
-      "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2",
+      "name": "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2_1",
-      "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2",
+      "name": "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2",
       "qos_config_name": [
         "QoS_Config_32_2_1"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2",
+      "name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_1",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2",
+      "name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2",
       "qos_config_name": [
         "QoS_Config_32_2_1"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2",
+      "name": "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_1",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2",
+      "name": "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2",
       "qos_config_name": [
         "QoS_Config_32_2_1"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_Low_Latency",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2",
+      "name": "One-TwoChan-SnkAse-Lc3_32_2_Low_Latency",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_32_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_1",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2",
-      "qos_config_name": [
-        "QoS_Config_32_2_1"
-      ]
-    },
-    {
-      "name": "SingleDev_TwoChanStereoSnk_32_2_Low_Latency",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_32_2",
-      "qos_config_name": [
-        "QoS_Config_Low_Latency"
-      ]
-    },
-    {
-      "name": "DualDev_OneChanStereoSnk_48_4_High_Reliability",
-      "codec_config_name": "DualDev_OneChanStereoSnk_48_4",
+      "name": "Two-OneChan-SnkAse-Lc3_48_4_High_Reliability",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4",
       "qos_config_name": [
         "QoS_Config_High_Reliability"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_4_1",
-      "codec_config_name": "DualDev_OneChanStereoSnk_48_4",
+      "name": "Two-OneChan-SnkAse-Lc3_48_4_1",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4",
       "qos_config_name": [
         "QoS_Config_48_4_1"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_4_2",
-      "codec_config_name": "DualDev_OneChanStereoSnk_48_4",
+      "name": "Two-OneChan-SnkAse-Lc3_48_4_2",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4",
       "qos_config_name": [
         "QoS_Config_48_4_2"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_3_Low_Latency",
-      "codec_config_name": "DualDev_OneChanStereoSnk_48_3",
+      "name": "Two-OneChan-SnkAse-Lc3_48_3_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_3",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_3_High_Reliability",
-      "codec_config_name": "DualDev_OneChanStereoSnk_48_3",
+      "name": "Two-OneChan-SnkAse-Lc3_48_3_High_Reliability",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_3",
       "qos_config_name": [
         "QoS_Config_High_Reliability"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_3_2",
-      "codec_config_name": "DualDev_OneChanStereoSnk_48_3",
+      "name": "Two-OneChan-SnkAse-Lc3_48_3_2",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_3",
       "qos_config_name": [
         "QoS_Config_48_3_2"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_2_Low_Latency",
-      "codec_config_name": "DualDev_OneChanStereoSnk_48_2",
+      "name": "Two-OneChan-SnkAse-Lc3_48_2_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_2_High_Reliability",
-      "codec_config_name": "DualDev_OneChanStereoSnk_48_2",
+      "name": "Two-OneChan-SnkAse-Lc3_48_2_High_Reliability",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_2",
       "qos_config_name": [
         "QoS_Config_High_Reliability"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_2_2",
-      "codec_config_name": "DualDev_OneChanStereoSnk_48_2",
+      "name": "Two-OneChan-SnkAse-Lc3_48_2_2",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_2",
       "qos_config_name": [
         "QoS_Config_48_2_2"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_1_Low_Latency",
-      "codec_config_name": "DualDev_OneChanStereoSnk_48_1",
+      "name": "Two-OneChan-SnkAse-Lc3_48_1_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_1",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_1_High_Reliability",
-      "codec_config_name": "DualDev_OneChanStereoSnk_48_1",
+      "name": "Two-OneChan-SnkAse-Lc3_48_1_High_Reliability",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_1",
       "qos_config_name": [
         "QoS_Config_High_Reliability"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_1_2",
-      "codec_config_name": "DualDev_OneChanStereoSnk_48_1",
+      "name": "Two-OneChan-SnkAse-Lc3_48_1_2",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_1",
       "qos_config_name": [
         "QoS_Config_48_1_2"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_48_4_High_Reliability",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_48_4",
+      "name": "Two-OneChan-SnkAse-Lc3_48_4_High_Reliability",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4",
       "qos_config_name": [
         "QoS_Config_High_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_48_4_1",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_48_4",
+      "name": "Two-OneChan-SnkAse-Lc3_48_4_1",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4",
       "qos_config_name": [
         "QoS_Config_48_4_1"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_48_4_2",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_48_4",
+      "name": "Two-OneChan-SnkAse-Lc3_48_4_2",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4",
       "qos_config_name": [
         "QoS_Config_48_4_2"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_48_3_Low_Latency",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_48_3",
+      "name": "Two-OneChan-SnkAse-Lc3_48_3_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_3",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_48_3_High_Reliability",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_48_3",
+      "name": "Two-OneChan-SnkAse-Lc3_48_3_High_Reliability",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_3",
       "qos_config_name": [
         "QoS_Config_High_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_48_3_2",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_48_3",
+      "name": "Two-OneChan-SnkAse-Lc3_48_3_2",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_3",
       "qos_config_name": [
         "QoS_Config_48_3_2"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_48_2_Low_Latency",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_48_2",
+      "name": "Two-OneChan-SnkAse-Lc3_48_2_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_48_2_High_Reliability",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_48_2",
+      "name": "Two-OneChan-SnkAse-Lc3_48_2_High_Reliability",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_2",
       "qos_config_name": [
         "QoS_Config_High_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_48_2_2",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_48_2",
+      "name": "Two-OneChan-SnkAse-Lc3_48_2_2",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_2",
       "qos_config_name": [
         "QoS_Config_48_2_2"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_48_1_Low_Latency",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_48_1",
+      "name": "Two-OneChan-SnkAse-Lc3_48_1_Low_Latency",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_1",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_48_1_High_Reliability",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_48_1",
+      "name": "Two-OneChan-SnkAse-Lc3_48_1_High_Reliability",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_1",
       "qos_config_name": [
         "QoS_Config_High_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_48_1_2",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_48_1",
+      "name": "Two-OneChan-SnkAse-Lc3_48_1_2",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_1",
       "qos_config_name": [
         "QoS_Config_48_1_2"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_48_4_High_Reliability",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4",
+      "name": "One-TwoChan-SnkAse-Lc3_48_4_High_Reliability",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4",
       "qos_config_name": [
         "QoS_Config_High_Reliability"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_48_4_1",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4",
+      "name": "One-TwoChan-SnkAse-Lc3_48_4_1",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4",
       "qos_config_name": [
         "QoS_Config_48_4_1"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_48_4_2",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4",
+      "name": "One-TwoChan-SnkAse-Lc3_48_4_2",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4",
       "qos_config_name": [
         "QoS_Config_48_4_2"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_48_3_Low_Latency",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_3",
+      "name": "One-TwoChan-SnkAse-Lc3_48_3_Low_Latency",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_3",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_48_3_High_Reliability",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_3",
+      "name": "One-TwoChan-SnkAse-Lc3_48_3_High_Reliability",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_3",
       "qos_config_name": [
         "QoS_Config_High_Reliability"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_48_3_2",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_3",
+      "name": "One-TwoChan-SnkAse-Lc3_48_3_2",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_3",
       "qos_config_name": [
         "QoS_Config_48_3_2"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_48_2_Low_Latency",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_2",
+      "name": "One-TwoChan-SnkAse-Lc3_48_2_Low_Latency",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_48_2_High_Reliability",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_2",
+      "name": "One-TwoChan-SnkAse-Lc3_48_2_High_Reliability",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_2",
       "qos_config_name": [
         "QoS_Config_High_Reliability"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_48_2_2",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_2",
+      "name": "One-TwoChan-SnkAse-Lc3_48_2_2",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_2",
       "qos_config_name": [
         "QoS_Config_48_2_2"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_48_1_Low_Latency",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_1",
+      "name": "One-TwoChan-SnkAse-Lc3_48_1_Low_Latency",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_1",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_48_1_High_Reliability",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_1",
+      "name": "One-TwoChan-SnkAse-Lc3_48_1_High_Reliability",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_1",
       "qos_config_name": [
         "QoS_Config_High_Reliability"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_48_1_2",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_1",
+      "name": "One-TwoChan-SnkAse-Lc3_48_1_2",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_1",
       "qos_config_name": [
         "QoS_Config_48_1_2"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_48_4_High_Reliability",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_48_4",
+      "name": "One-OneChan-SnkAse-Lc3_48_4_High_Reliability",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_48_4",
       "qos_config_name": [
         "QoS_Config_High_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_48_4_1",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_48_4",
+      "name": "One-OneChan-SnkAse-Lc3_48_4_1",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_48_4",
       "qos_config_name": [
         "QoS_Config_48_4_1"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_48_4_2",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_48_4",
+      "name": "One-OneChan-SnkAse-Lc3_48_4_2",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_48_4",
       "qos_config_name": [
         "QoS_Config_48_4_2"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_48_3_High_Reliability",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_48_3",
+      "name": "One-OneChan-SnkAse-Lc3_48_3_High_Reliability",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_48_3",
       "qos_config_name": [
         "QoS_Config_High_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_48_3_2",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_48_3",
+      "name": "One-OneChan-SnkAse-Lc3_48_3_2",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_48_3",
       "qos_config_name": [
         "QoS_Config_48_3_2"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_48_2_High_Reliability",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_48_2",
+      "name": "One-OneChan-SnkAse-Lc3_48_2_High_Reliability",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_48_2",
       "qos_config_name": [
         "QoS_Config_High_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_48_2_2",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_48_2",
+      "name": "One-OneChan-SnkAse-Lc3_48_2_2",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_48_2",
       "qos_config_name": [
         "QoS_Config_48_2_2"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_48_1_High_Reliability",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_48_1",
+      "name": "One-OneChan-SnkAse-Lc3_48_1_High_Reliability",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_48_1",
       "qos_config_name": [
         "QoS_Config_High_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_48_1_2",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_48_1",
+      "name": "One-OneChan-SnkAse-Lc3_48_1_2",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_48_1",
       "qos_config_name": [
         "QoS_Config_48_1_2"
       ]
@@ -1289,176 +1242,155 @@
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_32_2_Balanced_Reliability",
-      "codec_config_name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_32_2",
+      "name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_32_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_24_2_Balanced_Reliability",
-      "codec_config_name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_24_2",
+      "name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_24_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_16_2_Balanced_Reliability",
-      "codec_config_name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_16_2",
+      "name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_32_2_Balanced_Reliability",
-      "codec_config_name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_32_2",
+      "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_24_2_Balanced_Reliability",
-      "codec_config_name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_24_2",
+      "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_16_2_Balanced_Reliability",
-      "codec_config_name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_16_2",
+      "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_32_2_Balanced_Reliability",
-      "codec_config_name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_32_2",
+      "name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_32_2_Balanced_Reliability",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_32_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_24_2_Balanced_Reliability",
-      "codec_config_name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_24_2",
+      "name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_24_2_Balanced_Reliability",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_24_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_16_2_Balanced_Reliability",
-      "codec_config_name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_16_2",
+      "name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_16_2_Balanced_Reliability",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_32_2_Balanced_Reliability",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_32_2",
+      "name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_24_2_Balanced_Reliability",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_24_2",
+      "name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_16_2_Balanced_Reliability",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_16_2",
+      "name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability",
+      "codec_config_name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_32_2_Balanced_Reliability",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_32_2",
+      "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_48_4_1_OneChanMonoSrc_24_2_Balanced_Reliability",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_24_2",
+      "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_48_4_1_OneChanMonoSrc_16_2_Balanced_Reliability",
-      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_16_2",
+      "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability",
+      "codec_config_name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_48_4_1_OneChanMonoSrc_32_2_Balanced_Reliability",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_32_2",
+      "name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_48_4_1_OneChanMonoSrc_24_2_Balanced_Reliability",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_24_2",
+      "name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_48_4_1_OneChanMonoSrc_16_2_Balanced_Reliability",
-      "codec_config_name": "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_16_2",
+      "name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability",
+      "codec_config_name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_48_4_1_OneChanMonoSrc_32_2_Balanced_Reliability",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_32_2",
-      "qos_config_name": [
-        "QoS_Config_Balanced_Reliability"
-      ]
-    },
-    {
-      "name": "SingleDev_OneChanMonoSnk_48_4_1_OneChanMonoSrc_24_2_1_Balanced_Reliability",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_24_2",
-      "qos_config_name": [
-        "QoS_Config_Balanced_Reliability"
-      ]
-    },
-    {
-      "name": "SingleDev_OneChanMonoSnk_48_4_1_OneChanMonoSrc_16_2_Balanced_Reliability",
-      "codec_config_name": "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_16_2",
-      "qos_config_name": [
-        "QoS_Config_Balanced_Reliability"
-      ]
-    },
-    {
-      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1_Low_Latency",
-      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1",
+      "name": "Two-TwoChan-SnkAse-Lc3_48_1-Two-TwoChan-SrcAse-Lc3_48_1_Low_Latency",
+      "codec_config_name": "Two-TwoChan-SnkAse-Lc3_48_1-Two-TwoChan-SrcAse-Lc3_48_1",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1_Balanced_Reliability",
-      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1",
+      "name": "Two-TwoChan-SnkAse-Lc3_48_1-Two-TwoChan-SrcAse-Lc3_48_1_Balanced_Reliability",
+      "codec_config_name": "Two-TwoChan-SnkAse-Lc3_48_1-Two-TwoChan-SrcAse-Lc3_48_1",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2_Low_Latency",
-      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2",
+      "name": "Two-TwoChan-SnkAse-Lc3_48_2-Two-TwoChan-SrcAse-Lc3_48_2_Low_Latency",
+      "codec_config_name": "Two-TwoChan-SnkAse-Lc3_48_2-Two-TwoChan-SrcAse-Lc3_48_2",
       "qos_config_name": [
         "QoS_Config_Low_Latency"
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2_Balanced_Reliability",
-      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2",
+      "name": "Two-TwoChan-SnkAse-Lc3_48_2-Two-TwoChan-SrcAse-Lc3_48_2_Balanced_Reliability",
+      "codec_config_name": "Two-TwoChan-SnkAse-Lc3_48_2-Two-TwoChan-SrcAse-Lc3_48_2",
       "qos_config_name": [
         "QoS_Config_Balanced_Reliability"
       ]
@@ -1495,13 +1427,11 @@
   ],
   "codec_configurations": [
     {
-      "name": "DualDev_OneChanStereoSnk_16_2",
+      "name": "Two-OneChan-SnkAse-Lc3_16_2",
       "subconfigurations": [
         {
-          "device_cnt": 2,
           "ase_cnt": 2,
           "direction": "SINK",
-          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -1527,18 +1457,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -1557,18 +1475,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_16_1",
+      "name": "Two-OneChan-SnkAse-Lc3_16_1",
       "subconfigurations": [
         {
-          "device_cnt": 2,
           "ase_cnt": 2,
           "direction": "SINK",
-          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -1594,18 +1511,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -1624,152 +1529,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_16_2",
+      "name": "One-TwoChan-SnkAse-Lc3_16_2",
       "subconfigurations": [
         {
-          "device_cnt": 1,
-          "ase_cnt": 2,
-          "direction": "SINK",
-          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  40,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_OneChanStereoSnk_16_1",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 2,
-          "direction": "SINK",
-          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  0
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  30,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_TwoChanStereoSnk_16_2",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -1795,18 +1565,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -1825,18 +1583,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         }
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_16_1",
+      "name": "One-TwoChan-SnkAse-Lc3_16_1",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -1862,18 +1619,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -1892,18 +1637,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         }
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSrc_16_2",
+      "name": "Two-OneChan-SrcAse-Lc3_16_2",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 2,
           "direction": "SOURCE",
-          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -1929,18 +1673,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -1959,15 +1691,15 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSrc_24_2",
+      "name": "One-OneChan-SrcAse-Lc3_24_2",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -1995,13 +1727,109 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
+              "name": "octets_per_codec_frame",
+              "type": 4,
               "compound_value": {
                 "value": [
-                  1,
-                  0,
-                  0,
+                  60,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 1
+        }
+      ]
+    },
+    {
+      "name": "Two-OneChan-SnkAse-Lc3_32_2",
+      "subconfigurations": [
+        {
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 1
+        }
+      ]
+    },
+    {
+      "name": "Two-OneChan-SnkAse-Lc3_32_1",
+      "subconfigurations": [
+        {
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
                   0
                 ]
               }
@@ -2025,18 +1853,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_32_2",
+      "name": "One-OneChan-SnkAse-Lc3_32_2",
       "subconfigurations": [
         {
-          "device_cnt": 2,
-          "ase_cnt": 2,
+          "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -2062,18 +1889,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -2092,18 +1907,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_32_1",
+      "name": "One-OneChan-SnkAse-Lc3_32_1",
       "subconfigurations": [
         {
-          "device_cnt": 2,
-          "ase_cnt": 2,
+          "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -2129,18 +1943,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -2159,18 +1961,537 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_32_2",
+      "name": "One-OneChan-SnkAse-Lc3_16_2",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 1
+        }
+      ]
+    },
+    {
+      "name": "One-OneChan-SnkAse-Lc3_16_1",
+      "subconfigurations": [
+        {
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 1
+        }
+      ]
+    },
+    {
+      "name": "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2",
+      "subconfigurations": [
+        {
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 1
+        },
+        {
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 1
+        }
+      ]
+    },
+    {
+      "name": "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2",
+      "subconfigurations": [
+        {
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 1
+        },
+        {
+          "ase_cnt": 2,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 1
+        }
+      ]
+    },
+    {
+      "name": "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1",
+      "subconfigurations": [
+        {
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 1
+        },
+        {
+          "ase_cnt": 2,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 1
+        }
+      ]
+    },
+    {
+      "name": "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1",
+      "subconfigurations": [
+        {
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 1
+        },
+        {
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 1
+        }
+      ]
+    },
+    {
+      "name": "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2",
+      "subconfigurations": [
+        {
+          "ase_cnt": 1,
+          "direction": "SINK",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -2196,18 +2517,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -2226,344 +2535,10 @@
                 ]
               }
             }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_OneChanMonoSnk_32_1",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SINK",
-          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  6
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  0
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  60,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "DualDev_OneChanMonoSnk_16_2",
-      "subconfigurations": [
-        {
-          "device_cnt": 2,
-          "ase_cnt": 2,
-          "direction": "SINK",
-          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  40,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_OneChanMonoSnk_16_2",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SINK",
-          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  40,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_OneChanMonoSnk_16_1",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SINK",
-          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  0
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  30,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2",
-      "subconfigurations": [
-        {
-          "device_cnt": 2,
-          "ase_cnt": 2,
-          "direction": "SINK",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  40,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
+          ],
+          "ase_channel_cnt": 2
         },
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -2577,710 +2552,6 @@
               "type": 1,
               "compound_value": {
                 "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  40,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2",
-      "subconfigurations": [
-        {
-          "device_cnt": 2,
-          "ase_cnt": 2,
-          "direction": "SINK",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  40,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        },
-        {
-          "device_cnt": 2,
-          "ase_cnt": 2,
-          "direction": "SOURCE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  40,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1",
-      "subconfigurations": [
-        {
-          "device_cnt": 2,
-          "ase_cnt": 2,
-          "direction": "SINK",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  0
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  30,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        },
-        {
-          "device_cnt": 2,
-          "ase_cnt": 2,
-          "direction": "SOURCE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  0
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  30,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1",
-      "subconfigurations": [
-        {
-          "device_cnt": 2,
-          "ase_cnt": 2,
-          "direction": "SINK",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  0
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  30,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        },
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SOURCE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  0
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  30,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2",
-      "subconfigurations": [
-        {
-          "device_cnt": 2,
-          "ase_cnt": 4,
-          "direction": "SINK",
-          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  40,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        },
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SOURCE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  40,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1",
-      "subconfigurations": [
-        {
-          "device_cnt": 2,
-          "ase_cnt": 4,
-          "direction": "SINK",
-          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  0
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  30,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        },
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SOURCE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  0
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  30,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
                   6
                 ]
               }
@@ -3295,18 +2566,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -3325,847 +2584,15 @@
                 ]
               }
             }
-          ]
-        },
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SOURCE",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  6
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  80,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
+          ],
+          "ase_channel_cnt": 2
         }
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2",
+      "name": "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2",
       "subconfigurations": [
         {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  40,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        },
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SOURCE",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  40,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  0
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  30,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        },
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SOURCE",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  0
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  30,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  40,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        },
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SOURCE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  40,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  0
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  30,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        },
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SOURCE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  0
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  30,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 2,
-          "direction": "SINK",
-          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  40,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        },
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SOURCE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  40,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 2,
-          "direction": "SINK",
-          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  0
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  30,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        },
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SOURCE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  0
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  30,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SINK",
           "codec_id": {
@@ -4193,18 +2620,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -4223,10 +2638,10 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         },
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -4254,18 +2669,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -4284,15 +2687,15 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         }
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1",
+      "name": "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SINK",
           "codec_id": {
@@ -4320,18 +2723,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -4350,10 +2741,10 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         },
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -4381,18 +2772,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -4411,16 +2790,65 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         }
       ]
     },
     {
-      "name": "DualDev_OneChanMonoSrc_16_2",
+      "name": "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2",
       "subconfigurations": [
         {
-          "device_cnt": 2,
-          "ase_cnt": 2,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 2
+        },
+        {
+          "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
             "coding_format": 6,
@@ -4447,18 +2875,163 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
+              "name": "octets_per_codec_frame",
+              "type": 4,
               "compound_value": {
                 "value": [
-                  1,
-                  0,
-                  0,
+                  40,
                   0
                 ]
               }
             },
             {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 1
+        }
+      ]
+    },
+    {
+      "name": "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1",
+      "subconfigurations": [
+        {
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 2
+        },
+        {
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 1
+        }
+      ]
+    },
+    {
+      "name": "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2",
+      "subconfigurations": [
+        {
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -4477,15 +3050,167 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
+        },
+        {
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSrc_48_4",
+      "name": "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1",
       "subconfigurations": [
         {
-          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 1
+        },
+        {
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 1
+        }
+      ]
+    },
+    {
+      "name": "One-OneChan-SrcAse-Lc3_48_4",
+      "subconfigurations": [
+        {
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -4513,18 +3238,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -4543,15 +3256,15 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSrc_48_3",
+      "name": "One-OneChan-SrcAse-Lc3_48_3",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -4579,18 +3292,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -4609,15 +3310,15 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSrc_48_2",
+      "name": "One-OneChan-SrcAse-Lc3_48_2",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -4645,18 +3346,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -4675,15 +3364,15 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSrc_48_1",
+      "name": "One-OneChan-SrcAse-Lc3_48_1",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -4711,18 +3400,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -4741,15 +3418,15 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSrc_32_2",
+      "name": "One-OneChan-SrcAse-Lc3_32_2",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -4777,18 +3454,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -4807,15 +3472,15 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSrc_32_1",
+      "name": "One-OneChan-SrcAse-Lc3_32_1",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -4843,18 +3508,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -4873,15 +3526,15 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSrc_24_2",
+      "name": "One-OneChan-SrcAse-Lc3_24_1",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -4904,84 +3557,6 @@
               "type": 2,
               "compound_value": {
                 "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  60,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_OneChanMonoSrc_24_1",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SOURCE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  5
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  0
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
                   0
                 ]
               }
@@ -5005,15 +3580,15 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSrc_16_2",
+      "name": "One-OneChan-SrcAse-Lc3_16_2",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -5041,18 +3616,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -5071,15 +3634,15 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSrc_16_1",
+      "name": "One-OneChan-SrcAse-Lc3_16_1",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -5107,18 +3670,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -5137,18 +3688,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_4",
+      "name": "Two-OneChan-SnkAse-Lc3_48_4",
       "subconfigurations": [
         {
-          "device_cnt": 2,
           "ase_cnt": 2,
           "direction": "SINK",
-          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -5174,18 +3724,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -5204,18 +3742,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_3",
+      "name": "Two-OneChan-SnkAse-Lc3_48_3",
       "subconfigurations": [
         {
-          "device_cnt": 2,
           "ase_cnt": 2,
           "direction": "SINK",
-          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -5241,18 +3778,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -5271,18 +3796,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_2",
+      "name": "Two-OneChan-SnkAse-Lc3_48_2",
       "subconfigurations": [
         {
-          "device_cnt": 2,
           "ase_cnt": 2,
           "direction": "SINK",
-          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -5308,18 +3832,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -5338,18 +3850,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_1",
+      "name": "Two-OneChan-SnkAse-Lc3_48_1",
       "subconfigurations": [
         {
-          "device_cnt": 2,
           "ase_cnt": 2,
           "direction": "SINK",
-          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -5375,18 +3886,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -5405,18 +3904,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_48_4",
+      "name": "One-TwoChan-SnkAse-Lc3_48_4",
       "subconfigurations": [
         {
-          "device_cnt": 1,
-          "ase_cnt": 2,
+          "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -5442,18 +3940,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -5472,18 +3958,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         }
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_48_3",
+      "name": "One-TwoChan-SnkAse-Lc3_48_3",
       "subconfigurations": [
         {
-          "device_cnt": 1,
-          "ase_cnt": 2,
+          "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -5509,18 +3994,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -5539,18 +4012,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         }
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_48_2",
+      "name": "One-TwoChan-SnkAse-Lc3_48_2",
       "subconfigurations": [
         {
-          "device_cnt": 1,
-          "ase_cnt": 2,
+          "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -5576,18 +4048,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -5606,18 +4066,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         }
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_48_1",
+      "name": "One-TwoChan-SnkAse-Lc3_48_1",
       "subconfigurations": [
         {
-          "device_cnt": 1,
-          "ase_cnt": 2,
+          "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -5643,18 +4102,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -5673,18 +4120,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         }
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_48_4",
+      "name": "One-OneChan-SnkAse-Lc3_48_4",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -5710,18 +4156,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -5740,18 +4174,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_48_3",
+      "name": "One-OneChan-SnkAse-Lc3_48_3",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -5777,18 +4210,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -5807,18 +4228,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_48_2",
+      "name": "One-OneChan-SnkAse-Lc3_48_2",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -5844,18 +4264,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -5874,18 +4282,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_48_1",
+      "name": "One-OneChan-SnkAse-Lc3_48_1",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -5911,18 +4318,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -5941,275 +4336,8 @@
                 ]
               }
             }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_OneChanMonoSnk_48_4",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SINK",
-          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  8
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  120,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_OneChanMonoSnk_48_3",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SINK",
-          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  8
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  90,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_OneChanMonoSnk_48_2",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SINK",
-          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  8
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  100,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_OneChanMonoSnk_48_1",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SINK",
-          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  8
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  0
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  75,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
@@ -6217,10 +4345,8 @@
       "name": "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_1",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -6246,18 +4372,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -6276,7 +4390,8 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         }
       ]
     },
@@ -6284,10 +4399,8 @@
       "name": "VND_DualDev_OneChanStereoSnk_48khz_100octs_1",
       "subconfigurations": [
         {
-          "device_cnt": 2,
           "ase_cnt": 2,
           "direction": "SINK",
-          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -6313,18 +4426,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -6343,7 +4444,8 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
@@ -6351,10 +4453,8 @@
       "name": "VND_SingleDev_OneChanStereoSnk_48khz_100octs_1",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 2,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -6380,18 +4480,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -6410,7 +4498,8 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
@@ -6418,10 +4507,8 @@
       "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_1",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -6447,18 +4534,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -6477,15 +4552,15 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         }
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_32_2",
+      "name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_32_2",
       "subconfigurations": [
         {
-          "device_cnt": 2,
           "ase_cnt": 2,
           "direction": "SINK",
           "codec_id": {
@@ -6513,18 +4588,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -6543,10 +4606,10 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         },
         {
-          "device_cnt": 2,
           "ase_cnt": 2,
           "direction": "SOURCE",
           "codec_id": {
@@ -6574,18 +4637,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -6604,15 +4655,15 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_24_2",
+      "name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_24_2",
       "subconfigurations": [
         {
-          "device_cnt": 2,
           "ase_cnt": 2,
           "direction": "SINK",
           "codec_id": {
@@ -6640,18 +4691,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -6670,10 +4709,10 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         },
         {
-          "device_cnt": 2,
           "ase_cnt": 2,
           "direction": "SOURCE",
           "codec_id": {
@@ -6701,23 +4740,11 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
                 "value": [
-                  80,
+                  60,
                   0
                 ]
               }
@@ -6731,15 +4758,15 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_16_2",
+      "name": "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_16_2",
       "subconfigurations": [
         {
-          "device_cnt": 2,
           "ase_cnt": 2,
           "direction": "SINK",
           "codec_id": {
@@ -6767,18 +4794,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -6797,10 +4812,10 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         },
         {
-          "device_cnt": 2,
           "ase_cnt": 2,
           "direction": "SOURCE",
           "codec_id": {
@@ -6828,23 +4843,11 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
                 "value": [
-                  80,
+                  40,
                   0
                 ]
               }
@@ -6858,15 +4861,15 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_32_2",
+      "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2",
       "subconfigurations": [
         {
-          "device_cnt": 2,
           "ase_cnt": 2,
           "direction": "SINK",
           "codec_id": {
@@ -6894,18 +4897,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -6924,10 +4915,10 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         },
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -6955,18 +4946,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -6985,15 +4964,15 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_24_2",
+      "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2",
       "subconfigurations": [
         {
-          "device_cnt": 2,
           "ase_cnt": 2,
           "direction": "SINK",
           "codec_id": {
@@ -7021,18 +5000,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -7051,10 +5018,10 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         },
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -7082,23 +5049,11 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
                 "value": [
-                  80,
+                  60,
                   0
                 ]
               }
@@ -7112,15 +5067,15 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_16_2",
+      "name": "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2",
       "subconfigurations": [
         {
-          "device_cnt": 2,
           "ase_cnt": 2,
           "direction": "SINK",
           "codec_id": {
@@ -7148,18 +5103,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -7178,10 +5121,10 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         },
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -7209,23 +5152,11 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
                 "value": [
-                  80,
+                  40,
                   0
                 ]
               }
@@ -7239,18 +5170,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_32_2",
+      "name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_32_2",
       "subconfigurations": [
         {
-          "device_cnt": 2,
-          "ase_cnt": 4,
+          "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -7276,18 +5206,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -7306,10 +5224,10 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         },
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -7337,18 +5255,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -7367,18 +5273,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         }
       ]
     },
     {
-      "name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_24_2",
+      "name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_24_2",
       "subconfigurations": [
         {
-          "device_cnt": 2,
-          "ase_cnt": 4,
+          "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -7404,18 +5309,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -7434,10 +5327,10 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         },
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -7465,23 +5358,11 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
                 "value": [
-                  80,
+                  60,
                   0
                 ]
               }
@@ -7495,18 +5376,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         }
       ]
     },
     {
-      "name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_16_2",
+      "name": "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_16_2",
       "subconfigurations": [
         {
-          "device_cnt": 2,
-          "ase_cnt": 4,
+          "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -7532,18 +5412,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -7562,10 +5430,10 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         },
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -7593,23 +5461,11 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
                 "value": [
-                  80,
+                  40,
                   0
                 ]
               }
@@ -7623,18 +5479,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         }
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_32_2",
+      "name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -7660,18 +5515,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -7690,397 +5533,10 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         },
         {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SOURCE",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  6
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  80,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_24_2",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  8
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  120,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        },
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SOURCE",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  5
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  80,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_16_2",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  8
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  120,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        },
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SOURCE",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  80,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_32_2",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  8
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  120,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        },
-        {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -8108,18 +5564,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -8138,18 +5582,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_24_2",
+      "name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -8175,18 +5618,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -8205,10 +5636,10 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         },
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -8236,23 +5667,11 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
                 "value": [
-                  80,
+                  60,
                   0
                 ]
               }
@@ -8266,18 +5685,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_16_2",
+      "name": "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -8303,18 +5721,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -8333,10 +5739,10 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         },
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -8364,23 +5770,11 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
                 "value": [
-                  80,
+                  40,
                   0
                 ]
               }
@@ -8394,18 +5788,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_32_2",
+      "name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2",
       "subconfigurations": [
         {
-          "device_cnt": 1,
-          "ase_cnt": 2,
+          "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -8431,18 +5824,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -8461,10 +5842,10 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         },
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -8492,18 +5873,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -8522,18 +5891,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_24_2",
+      "name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2",
       "subconfigurations": [
         {
-          "device_cnt": 1,
-          "ase_cnt": 2,
+          "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -8559,18 +5927,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -8589,10 +5945,10 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         },
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -8620,23 +5976,11 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
                 "value": [
-                  80,
+                  60,
                   0
                 ]
               }
@@ -8650,18 +5994,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_16_2",
+      "name": "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2",
       "subconfigurations": [
         {
-          "device_cnt": 1,
-          "ase_cnt": 2,
+          "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -8687,18 +6030,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -8717,10 +6048,10 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         },
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -8748,23 +6079,11 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
                 "value": [
-                  80,
+                  40,
                   0
                 ]
               }
@@ -8778,399 +6097,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_32_2",
+      "name": "Two-TwoChan-SnkAse-Lc3_48_1-Two-TwoChan-SrcAse-Lc3_48_1",
       "subconfigurations": [
         {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SINK",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  8
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  120,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        },
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SOURCE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  6
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  80,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_24_2",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SINK",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  8
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  120,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        },
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SOURCE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  5
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  80,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_16_2",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SINK",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  8
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  120,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        },
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SOURCE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  3
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  80,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1",
-      "subconfigurations": [
-        {
-          "device_cnt": 2,
           "ase_cnt": 2,
           "direction": "SOURCE",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -9196,18 +6133,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -9226,13 +6151,12 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         },
         {
-          "device_cnt": 2,
           "ase_cnt": 2,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -9258,18 +6182,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -9288,18 +6200,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         }
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2",
+      "name": "Two-TwoChan-SnkAse-Lc3_48_2-Two-TwoChan-SrcAse-Lc3_48_2",
       "subconfigurations": [
         {
-          "device_cnt": 2,
           "ase_cnt": 2,
           "direction": "SOURCE",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -9325,18 +6236,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -9355,13 +6254,12 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         },
         {
-          "device_cnt": 2,
           "ase_cnt": 2,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -9387,18 +6285,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -9417,7 +6303,8 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         }
       ]
     },
@@ -9425,10 +6312,8 @@
       "name": "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_1",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -9454,18 +6339,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -9484,7 +6357,8 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         }
       ]
     },
@@ -9492,10 +6366,8 @@
       "name": "VND_SingleDev_TwoChanStereoSnk_OneChanStereoSrc_32khz_60octs_1",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -9521,18 +6393,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -9551,10 +6411,10 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         },
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
           "codec_id": {
@@ -9582,18 +6442,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -9612,7 +6460,8 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
@@ -9620,10 +6469,8 @@
       "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_TwoChanStereoSrc_16khz_30octs_1",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -9649,18 +6496,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -9679,13 +6514,12 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         },
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SOURCE",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -9711,18 +6545,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -9741,18 +6563,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         }
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_24_2",
+      "name": "Two-OneChan-SnkAse-Lc3_24_2",
       "subconfigurations": [
         {
-          "device_cnt": 2,
           "ase_cnt": 2,
           "direction": "SINK",
-          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -9778,18 +6599,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -9808,18 +6617,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "DualDev_OneChanStereoSnk_24_1",
+      "name": "Two-OneChan-SnkAse-Lc3_24_1",
       "subconfigurations": [
         {
-          "device_cnt": 2,
           "ase_cnt": 2,
           "direction": "SINK",
-          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -9845,18 +6653,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -9875,18 +6671,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 1
         }
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_24_2",
+      "name": "One-TwoChan-SnkAse-Lc3_24_2",
       "subconfigurations": [
         {
-          "device_cnt": 1,
-          "ase_cnt": 2,
+          "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -9912,18 +6707,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -9942,18 +6725,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         }
       ]
     },
     {
-      "name": "SingleDev_OneChanStereoSnk_24_1",
+      "name": "One-TwoChan-SnkAse-Lc3_24_1",
       "subconfigurations": [
         {
-          "device_cnt": 1,
-          "ase_cnt": 2,
+          "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -9979,18 +6761,6 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
               "name": "octets_per_codec_frame",
               "type": 4,
               "compound_value": {
@@ -10009,18 +6779,17 @@
                 ]
               }
             }
-          ]
+          ],
+          "ase_channel_cnt": 2
         }
       ]
     },
     {
-      "name": "SingleDev_TwoChanStereoSnk_24_2",
+      "name": "One-OneChan-SnkAse-Lc3_24_2",
       "subconfigurations": [
         {
-          "device_cnt": 1,
           "ase_cnt": 1,
           "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
           "codec_id": {
             "coding_format": 6,
             "vendor_company_id": 0,
@@ -10046,13 +6815,521 @@
               }
             },
             {
-              "name": "audio_channel_allocation",
-              "type": 3,
+              "name": "octets_per_codec_frame",
+              "type": 4,
               "compound_value": {
                 "value": [
-                  3,
-                  0,
-                  0,
+                  60,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 1
+        }
+      ]
+    },
+    {
+      "name": "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2",
+      "subconfigurations": [
+        {
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 1
+        },
+        {
+          "ase_cnt": 2,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 1
+        }
+      ]
+    },
+    {
+      "name": "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2",
+      "subconfigurations": [
+        {
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 1
+        },
+        {
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 1
+        }
+      ]
+    },
+    {
+      "name": "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2",
+      "subconfigurations": [
+        {
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 2
+        },
+        {
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 1
+        }
+      ]
+    },
+    {
+      "name": "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2",
+      "subconfigurations": [
+        {
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 1
+        },
+        {
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 1
+        }
+      ]
+    },
+    {
+      "name": "One-TwoChan-SnkAse-Lc3_32_2",
+      "subconfigurations": [
+        {
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ],
+          "ase_channel_cnt": 2
+        }
+      ]
+    },
+    {
+      "name": "One-TwoChan-SnkAse-Lc3_32_1",
+      "subconfigurations": [
+        {
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
                   0
                 ]
               }
@@ -10076,1174 +7353,8 @@
                 ]
               }
             }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_TwoChanStereoSnk_24_1",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  5
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  0
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  45,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_OneChanMonoSnk_24_2",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SINK",
-          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  5
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  60,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2",
-      "subconfigurations": [
-        {
-          "device_cnt": 2,
-          "ase_cnt": 2,
-          "direction": "SINK",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  6
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  80,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        },
-        {
-          "device_cnt": 2,
-          "ase_cnt": 2,
-          "direction": "SOURCE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  6
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  80,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2",
-      "subconfigurations": [
-        {
-          "device_cnt": 2,
-          "ase_cnt": 2,
-          "direction": "SINK",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  6
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  80,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        },
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SOURCE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  6
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  80,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2",
-      "subconfigurations": [
-        {
-          "device_cnt": 2,
-          "ase_cnt": 4,
-          "direction": "SINK",
-          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  6
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  80,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        },
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SOURCE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  6
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  80,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  6
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  80,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        },
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SOURCE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  6
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  80,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 2,
-          "direction": "SINK",
-          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  6
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  80,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        },
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SOURCE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  6
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  80,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SINK",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  6
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  80,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        },
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SOURCE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  6
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  80,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_TwoChanStereoSnk_32_2",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  6
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  80,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_TwoChanStereoSnk_32_1",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 1,
-          "direction": "SINK",
-          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  6
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  0
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  3,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  60,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_OneChanStereoSnk_32_2",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 2,
-          "direction": "SINK",
-          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  6
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  80,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "SingleDev_OneChanStereoSnk_32_1",
-      "subconfigurations": [
-        {
-          "device_cnt": 1,
-          "ase_cnt": 2,
-          "direction": "SINK",
-          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
-          "codec_id": {
-            "coding_format": 6,
-            "vendor_company_id": 0,
-            "vendor_codec_id": 0
-          },
-          "codec_configuration": [
-            {
-              "name": "sampling_frequency",
-              "type": 1,
-              "compound_value": {
-                "value": [
-                  6
-                ]
-              }
-            },
-            {
-              "name": "frame_duration",
-              "type": 2,
-              "compound_value": {
-                "value": [
-                  0
-                ]
-              }
-            },
-            {
-              "name": "audio_channel_allocation",
-              "type": 3,
-              "compound_value": {
-                "value": [
-                  1,
-                  0,
-                  0,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "octets_per_codec_frame",
-              "type": 4,
-              "compound_value": {
-                "value": [
-                  60,
-                  0
-                ]
-              }
-            },
-            {
-              "name": "codec_frame_blocks_per_sdu",
-              "type": 5,
-              "compound_value": {
-                "value": [
-                  1
-                ]
-              }
-            }
-          ]
+          ],
+          "ase_channel_cnt": 2
         }
       ]
     }
@@ -11377,6 +7488,5 @@
       "retransmission_number": 0,
       "max_transport_latency": 0
     }
-
   ]
 }
diff --git a/bluetooth/audio/utils/le_audio_configuration_set/audio_set_scenarios.json b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_scenarios.json
index a28c6cd..448adca 100644
--- a/bluetooth/audio/utils/le_audio_configuration_set/audio_set_scenarios.json
+++ b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_scenarios.json
@@ -8,251 +8,206 @@
     {
       "name": "Conversational",
       "configurations": [
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_Low_Latency",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_1",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_Low_Latency",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_1",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_2",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_Low_Latency",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_1",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_2",
-        "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
-        "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2_1",
-        "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
-        "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2_1",
-        "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
-        "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1_1",
-        "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
-        "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2_1",
-        "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
-        "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2_1",
-        "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
-        "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1_1",
-        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_1",
-        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_1",
-        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_2",
-        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_1",
-        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_2",
-        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_1",
-        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_1",
-        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_1",
-        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
-        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_1",
-        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
-        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_1",
-        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
-        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_1",
-        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_Low_Latency",
-        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_1",
-        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_Low_Latency",
-        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_1",
-        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_Low_Latency",
-        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_1",
-        "DualDev_OneChanMonoSrc_16_2_Balanced_Reliability",
-        "SingleDev_OneChanStereoSrc_16_2_Balanced_Reliability",
-        "SingleDev_OneChanMonoSrc_48_4_Balanced_Reliability",
-        "SingleDev_OneChanMonoSrc_48_2_Balanced_Reliability",
-        "SingleDev_OneChanMonoSrc_48_3_Balanced_Reliability",
-        "SingleDev_OneChanMonoSrc_48_1_Balanced_Reliability",
-        "SingleDev_OneChanMonoSrc_32_2_Balanced_Reliability",
-        "SingleDev_OneChanMonoSrc_32_1_Balanced_Reliability",
-        "SingleDev_OneChanMonoSrc_24_2_Balanced_Reliability",
-        "SingleDev_OneChanMonoSrc_24_1_Balanced_Reliability",
-        "SingleDev_OneChanMonoSrc_16_2_Balanced_Reliability",
-        "SingleDev_OneChanMonoSrc_16_1_Balanced_Reliability",
-        "VND_SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32khz_Server_Prefered_1",
-        "VND_SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32khz_60oct_R3_L22_1",
-        "DualDev_OneChanMonoSnk_16_2_Balanced_Reliability",
-        "SingleDev_OneChanStereoSnk_16_2_Balanced_Reliability",
-        "SingleDev_TwoChanStereoSnk_16_2_Balanced_Reliability",
-        "SingleDev_OneChanMonoSnk_16_2_Balanced_Reliability"
+        "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_1",
+        "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_1",
+        "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_2",
+        "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_1",
+        "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_2",
+        "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1",
+        "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1",
+        "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1",
+        "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_1",
+        "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_1",
+        "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_2",
+        "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_1",
+        "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_2",
+        "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1",
+        "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1",
+        "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1",
+        "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency",
+        "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1",
+        "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency",
+        "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1",
+        "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency",
+        "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1",
+        "Two-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability",
+        "One-OneChan-SrcAse-Lc3_48_4_Balanced_Reliability",
+        "One-OneChan-SrcAse-Lc3_48_2_Balanced_Reliability",
+        "One-OneChan-SrcAse-Lc3_48_3_Balanced_Reliability",
+        "One-OneChan-SrcAse-Lc3_48_1_Balanced_Reliability",
+        "One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability",
+        "One-OneChan-SrcAse-Lc3_32_1_Balanced_Reliability",
+        "One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability",
+        "One-OneChan-SrcAse-Lc3_24_1_Balanced_Reliability",
+        "One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability",
+        "One-OneChan-SrcAse-Lc3_16_1_Balanced_Reliability",
+        "VND_SingleDev_TwoChanStereoSnk_OneChanStereoSrc_32khz_60oct_R3_L22_1",
+        "Two-OneChan-SnkAse-Lc3_16_2_Balanced_Reliability",
+        "One-TwoChan-SnkAse-Lc3_16_2_Balanced_Reliability",
+        "One-OneChan-SnkAse-Lc3_16_2_Balanced_Reliability"
       ]
     },
     {
       "name": "Media",
       "configurations": [
-        "DualDev_OneChanStereoSnk_48_4_High_Reliability",
-        "DualDev_OneChanStereoSnk_48_4_2",
-        "DualDev_OneChanStereoSnk_48_2_High_Reliability",
-        "DualDev_OneChanStereoSnk_48_2_2",
-        "DualDev_OneChanStereoSnk_48_3_High_Reliability",
-        "DualDev_OneChanStereoSnk_48_3_2",
-        "DualDev_OneChanStereoSnk_48_1_High_Reliability",
-        "DualDev_OneChanStereoSnk_48_1_2",
-        "DualDev_OneChanStereoSnk_24_2_Balanced_Reliability",
-        "DualDev_OneChanStereoSnk_24_2_2",
-        "DualDev_OneChanStereoSnk_16_2_Balanced_Reliability",
-        "DualDev_OneChanStereoSnk_16_2_2",
-        "DualDev_OneChanStereoSnk_16_1_Balanced_Reliability",
-        "DualDev_OneChanStereoSnk_16_1_2",
-        "SingleDev_OneChanStereoSnk_48_4_High_Reliability",
-        "SingleDev_OneChanStereoSnk_48_4_2",
-        "SingleDev_OneChanStereoSnk_48_2_High_Reliability",
-        "SingleDev_OneChanStereoSnk_48_2_2",
-        "SingleDev_OneChanStereoSnk_48_3_High_Reliability",
-        "SingleDev_OneChanStereoSnk_48_3_2",
-        "SingleDev_OneChanStereoSnk_48_1_High_Reliability",
-        "SingleDev_OneChanStereoSnk_48_1_2",
-        "SingleDev_OneChanStereoSnk_24_2_Balanced_Reliability",
-        "SingleDev_OneChanStereoSnk_24_2_2",
-        "SingleDev_OneChanStereoSnk_16_2_Balanced_Reliability",
-        "SingleDev_OneChanStereoSnk_16_2_2",
-        "SingleDev_OneChanStereoSnk_16_1_Balanced_Reliability",
-        "SingleDev_OneChanStereoSnk_16_1_2",
-        "SingleDev_TwoChanStereoSnk_48_4_High_Reliability",
-        "SingleDev_TwoChanStereoSnk_48_4_2",
-        "SingleDev_TwoChanStereoSnk_48_4_High_Reliability",
-        "SingleDev_TwoChanStereoSnk_48_4_2",
-        "SingleDev_TwoChanStereoSnk_48_2_High_Reliability",
-        "SingleDev_TwoChanStereoSnk_48_2_2",
-        "SingleDev_TwoChanStereoSnk_48_3_High_Reliability",
-        "SingleDev_TwoChanStereoSnk_48_3_2",
-        "SingleDev_TwoChanStereoSnk_48_1_High_Reliability",
-        "SingleDev_TwoChanStereoSnk_48_1_2",
-        "SingleDev_TwoChanStereoSnk_24_2_Balanced_Reliability",
-        "SingleDev_TwoChanStereoSnk_24_2_2",
-        "SingleDev_TwoChanStereoSnk_16_2_Balanced_Reliability",
-        "SingleDev_TwoChanStereoSnk_16_2_2",
-        "SingleDev_TwoChanStereoSnk_16_1_Balanced_Reliability",
-        "SingleDev_TwoChanStereoSnk_16_1_2",
-        "SingleDev_OneChanMonoSnk_48_4_High_Reliability",
-        "SingleDev_OneChanMonoSnk_48_4_2",
-        "SingleDev_OneChanMonoSnk_48_2_High_Reliability",
-        "SingleDev_OneChanMonoSnk_48_2_2",
-        "SingleDev_OneChanMonoSnk_48_3_High_Reliability",
-        "SingleDev_OneChanMonoSnk_48_3_2",
-        "SingleDev_OneChanMonoSnk_48_1_High_Reliability",
-        "SingleDev_OneChanMonoSnk_48_1_2",
-        "SingleDev_OneChanMonoSnk_32_2_Balanced_Reliability",
-        "SingleDev_OneChanMonoSnk_32_2_2",
-        "SingleDev_OneChanMonoSnk_32_1_Balanced_Reliability",
-        "SingleDev_OneChanMonoSnk_32_1_2",
-        "SingleDev_OneChanMonoSnk_24_2_Balanced_Reliability",
-        "SingleDev_OneChanMonoSnk_24_2_2",
-        "SingleDev_OneChanMonoSnk_16_2_Balanced_Reliability",
-        "SingleDev_OneChanMonoSnk_16_2_2",
-        "SingleDev_OneChanMonoSnk_16_1_Balanced_Reliability",
-        "SingleDev_OneChanMonoSnk_16_1_2",
+        "Two-OneChan-SnkAse-Lc3_48_4_High_Reliability",
+        "Two-OneChan-SnkAse-Lc3_48_4_2",
+        "Two-OneChan-SnkAse-Lc3_48_2_High_Reliability",
+        "Two-OneChan-SnkAse-Lc3_48_2_2",
+        "Two-OneChan-SnkAse-Lc3_48_3_High_Reliability",
+        "Two-OneChan-SnkAse-Lc3_48_3_2",
+        "Two-OneChan-SnkAse-Lc3_48_1_High_Reliability",
+        "Two-OneChan-SnkAse-Lc3_48_1_2",
+        "Two-OneChan-SnkAse-Lc3_24_2_Balanced_Reliability",
+        "Two-OneChan-SnkAse-Lc3_24_2_2",
+        "Two-OneChan-SnkAse-Lc3_16_2_Balanced_Reliability",
+        "Two-OneChan-SnkAse-Lc3_16_2_2",
+        "Two-OneChan-SnkAse-Lc3_16_1_Balanced_Reliability",
+        "Two-OneChan-SnkAse-Lc3_16_1_2",
+        "One-TwoChan-SnkAse-Lc3_48_4_High_Reliability",
+        "One-TwoChan-SnkAse-Lc3_48_4_2",
+        "One-TwoChan-SnkAse-Lc3_48_2_High_Reliability",
+        "One-TwoChan-SnkAse-Lc3_48_2_2",
+        "One-TwoChan-SnkAse-Lc3_48_3_High_Reliability",
+        "One-TwoChan-SnkAse-Lc3_48_3_2",
+        "One-TwoChan-SnkAse-Lc3_48_1_High_Reliability",
+        "One-TwoChan-SnkAse-Lc3_48_1_2",
+        "One-TwoChan-SnkAse-Lc3_24_2_Balanced_Reliability",
+        "One-TwoChan-SnkAse-Lc3_24_2_2",
+        "One-TwoChan-SnkAse-Lc3_16_2_Balanced_Reliability",
+        "One-TwoChan-SnkAse-Lc3_16_2_2",
+        "One-TwoChan-SnkAse-Lc3_16_1_Balanced_Reliability",
+        "One-TwoChan-SnkAse-Lc3_16_1_2",
+        "One-OneChan-SnkAse-Lc3_48_4_High_Reliability",
+        "One-OneChan-SnkAse-Lc3_48_4_2",
+        "One-OneChan-SnkAse-Lc3_48_2_High_Reliability",
+        "One-OneChan-SnkAse-Lc3_48_2_2",
+        "One-OneChan-SnkAse-Lc3_48_3_High_Reliability",
+        "One-OneChan-SnkAse-Lc3_48_3_2",
+        "One-OneChan-SnkAse-Lc3_48_1_High_Reliability",
+        "One-OneChan-SnkAse-Lc3_48_1_2",
+        "One-OneChan-SnkAse-Lc3_32_2_Balanced_Reliability",
+        "One-OneChan-SnkAse-Lc3_32_2_2",
+        "One-OneChan-SnkAse-Lc3_32_1_Balanced_Reliability",
+        "One-OneChan-SnkAse-Lc3_32_1_2",
+        "One-OneChan-SnkAse-Lc3_24_2_Balanced_Reliability",
+        "One-OneChan-SnkAse-Lc3_24_2_2",
+        "One-OneChan-SnkAse-Lc3_16_2_Balanced_Reliability",
+        "One-OneChan-SnkAse-Lc3_16_2_2",
+        "One-OneChan-SnkAse-Lc3_16_1_Balanced_Reliability",
+        "One-OneChan-SnkAse-Lc3_16_1_2",
         "VND_DualDev_OneChanStereoSnk_48khz_100octs_High_Reliability_1",
         "VND_DualDev_OneChanStereoSnk_48khz_100octs_R15_L70_1",
         "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_High_Reliability_1",
         "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_R15_L70_1",
         "VND_SingleDev_OneChanStereoSnk_48khz_100octs_High_Reliability_1",
         "VND_SingleDev_OneChanStereoSnk_48khz_100octs_R15_L70_1",
-        "DualDev_OneChanMonoSrc_16_2_Balanced_Reliability",
-        "SingleDev_OneChanStereoSrc_16_2_Balanced_Reliability",
-        "SingleDev_OneChanMonoSrc_16_2_Balanced_Reliability"
+        "Two-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability",
+        "One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability"
       ]
     },
     {
       "name": "Game",
       "configurations": [
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_Low_Latency",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_Low_Latency",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_Low_Latency",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2_Low_Latency",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_1",
+        "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_Low_Latency",
+        "Two-TwoChan-SnkAse-Lc3_48_2-Two-TwoChan-SrcAse-Lc3_48_2_Low_Latency",
+        "Two-TwoChan-SnkAse-Lc3_48_1-Two-TwoChan-SrcAse-Lc3_48_1_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency",
         "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_TwoChanStereoSrc_16khz_30octs_Balanced_Reliability_1",
         "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_R5_L12_TwoChanStereoSrc_16khz_30octs_R3_L12_1",
         "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_High_Reliability_1",
         "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_R5_L12_1",
-        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
-        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
-        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
-        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_Low_Latency",
-        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_Low_Latency",
-        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_Low_Latency",
-        "DualDev_OneChanStereoSnk_48_2_Low_Latency",
-        "DualDev_OneChanStereoSnk_48_3_Low_Latency",
-        "DualDev_OneChanStereoSnk_48_1_Low_Latency",
-        "DualDev_OneChanStereoSnk_32_2_Low_Latency",
-        "DualDev_OneChanStereoSnk_32_1_Low_Latency",
-        "DualDev_OneChanStereoSnk_24_2_Low_Latency",
-        "DualDev_OneChanStereoSnk_24_1_Low_Latency",
-        "DualDev_OneChanStereoSnk_16_2_Low_Latency",
-        "DualDev_OneChanStereoSnk_16_1_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_48_2_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_48_3_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_48_1_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_32_2_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_32_1_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_24_2_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_24_1_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_16_2_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_16_1_Low_Latency",
-        "SingleDev_OneChanStereoSnk_48_2_Low_Latency",
-        "SingleDev_OneChanStereoSnk_48_3_Low_Latency",
-        "SingleDev_OneChanStereoSnk_48_1_Low_Latency",
-        "SingleDev_OneChanStereoSnk_32_2_Low_Latency",
-        "SingleDev_OneChanStereoSnk_32_1_Low_Latency",
-        "SingleDev_OneChanStereoSnk_24_2_Low_Latency",
-        "SingleDev_OneChanStereoSnk_24_1_Low_Latency",
-        "SingleDev_OneChanStereoSnk_16_2_Low_Latency",
-        "SingleDev_OneChanStereoSnk_16_1_Low_Latency"
+        "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1",
+        "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency",
+        "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency",
+        "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency",
+        "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_48_2_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_48_3_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_48_1_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_32_2_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_32_1_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_24_2_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_24_1_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_16_2_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_16_1_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_48_2_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_48_3_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_48_1_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_32_2_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_32_1_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_24_2_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_24_1_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_16_2_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_16_1_Low_Latency"
       ]
     },
     {
       "name": "VoiceAssistants",
       "configurations": [
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_Low_Latency",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_1",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_Low_Latency",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_1",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_Low_Latency",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_1",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2_Balanced_Reliability",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1_Balanced_Reliability",
-        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_1",
-        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_1",
-        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_1",
-        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_1",
-        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_1",
-        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_1",
-        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_Low_Latency",
-        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_1",
-        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_Low_Latency",
-        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_1",
-        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_Low_Latency",
-        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_1",
-        "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_16_2_Balanced_Reliability",
-        "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_24_2_Balanced_Reliability",
-        "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_32_2_Balanced_Reliability",
-        "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_16_2_Balanced_Reliability",
-        "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_24_2_Balanced_Reliability",
-        "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_32_2_Balanced_Reliability",
-        "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_16_2_Balanced_Reliability",
-        "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_24_2_Balanced_Reliability",
-        "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_32_2_Balanced_Reliability",
-        "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_16_2_Balanced_Reliability",
-        "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_24_2_Balanced_Reliability",
-        "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_32_2_Balanced_Reliability",
-        "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_16_2_Balanced_Reliability",
-        "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_24_2_Balanced_Reliability",
-        "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_32_2_Balanced_Reliability",
-        "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_16_2_Balanced_Reliability",
-        "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_24_2_Balanced_Reliability",
-        "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_32_2_Balanced_Reliability",
-        "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_16_2_Balanced_Reliability",
-        "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_24_2_Balanced_Reliability",
-        "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_32_2_Balanced_Reliability"
+        "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_1",
+        "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_1",
+        "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_1",
+        "Two-TwoChan-SnkAse-Lc3_48_2-Two-TwoChan-SrcAse-Lc3_48_2_Balanced_Reliability",
+        "Two-TwoChan-SnkAse-Lc3_48_1-Two-TwoChan-SrcAse-Lc3_48_1_Balanced_Reliability",
+        "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_1",
+        "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_1",
+        "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_1",
+        "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1",
+        "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1",
+        "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1",
+        "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency",
+        "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1",
+        "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency",
+        "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1",
+        "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency",
+        "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1",
+        "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability",
+        "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability",
+        "Two-OneChan-SnkAse-Lc3_48_4-Two-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability",
+        "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability",
+        "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability",
+        "Two-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability",
+        "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_16_2_Balanced_Reliability",
+        "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_24_2_Balanced_Reliability",
+        "One-TwoChan-SnkAse-Lc3_48_4-One-TwoChan-SrcAse-Lc3_32_2_Balanced_Reliability",
+        "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability",
+        "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability",
+        "One-TwoChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability",
+        "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability",
+        "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_24_2_Balanced_Reliability",
+        "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability"
       ]
     },
     {
@@ -260,44 +215,44 @@
       "configurations": [
         "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_Balanced_Reliability_1",
         "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_R11_L40_1",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_Low_Latency",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_1",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_Low_Latency",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_1",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_Low_Latency",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_1",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2_Balanced_Reliability",
-        "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1_Balanced_Reliability",
-        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_1",
-        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_1",
-        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_1",
-        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_1",
-        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_1",
-        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
-        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_1",
-        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
-        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_1",
-        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
-        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_1",
-        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
-        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_1",
-        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_Low_Latency",
-        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_1",
-        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_Low_Latency",
-        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_1",
-        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_Low_Latency",
-        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_1",
-        "SingleDev_OneChanMonoSrc_48_2_Balanced_Reliability",
-        "SingleDev_OneChanMonoSrc_48_1_Balanced_Reliability",
-        "SingleDev_OneChanMonoSrc_32_2_Balanced_Reliability",
-        "SingleDev_OneChanMonoSrc_32_1_Balanced_Reliability",
-        "SingleDev_OneChanMonoSrc_16_2_Balanced_Reliability",
-        "SingleDev_OneChanMonoSrc_16_1_Balanced_Reliability"
+        "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_1",
+        "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_1",
+        "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_16_1-Two-OneChan-SrcAse-Lc3_16_1_1",
+        "Two-TwoChan-SnkAse-Lc3_48_2-Two-TwoChan-SrcAse-Lc3_48_2_Balanced_Reliability",
+        "Two-TwoChan-SnkAse-Lc3_48_1-Two-TwoChan-SrcAse-Lc3_48_1_Balanced_Reliability",
+        "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_32_2-One-TwoChan-SrcAse-Lc3_32_2_1",
+        "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_16_2-One-TwoChan-SrcAse-Lc3_16_2_1",
+        "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_16_1-One-TwoChan-SrcAse-Lc3_16_1_1",
+        "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1",
+        "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1",
+        "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency",
+        "One-TwoChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1",
+        "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1",
+        "Two-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1",
+        "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency",
+        "Two-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1",
+        "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_Low_Latency",
+        "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_1",
+        "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency",
+        "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_1",
+        "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_Low_Latency",
+        "One-OneChan-SnkAse-Lc3_16_1-One-OneChan-SrcAse-Lc3_16_1_1",
+        "One-OneChan-SrcAse-Lc3_48_2_Balanced_Reliability",
+        "One-OneChan-SrcAse-Lc3_48_1_Balanced_Reliability",
+        "One-OneChan-SrcAse-Lc3_32_2_Balanced_Reliability",
+        "One-OneChan-SrcAse-Lc3_32_1_Balanced_Reliability",
+        "One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability",
+        "One-OneChan-SrcAse-Lc3_16_1_Balanced_Reliability"
       ]
     }
   ]
diff --git a/broadcastradio/aidl/vts/Android.bp b/broadcastradio/aidl/vts/Android.bp
index 78c377d..9cfca42 100644
--- a/broadcastradio/aidl/vts/Android.bp
+++ b/broadcastradio/aidl/vts/Android.bp
@@ -44,4 +44,5 @@
         "general-tests",
         "vts",
     ],
+    disable_framework: true,
 }
diff --git a/camera/common/aidl/Android.bp b/camera/common/aidl/Android.bp
index 8f7d19d..b59c92e 100644
--- a/camera/common/aidl/Android.bp
+++ b/camera/common/aidl/Android.bp
@@ -10,6 +10,7 @@
 
 aidl_interface {
     name: "android.hardware.camera.common",
+    host_supported: true,
     vendor_available: true,
     srcs: ["android/hardware/camera/common/*.aidl"],
     frozen: true,
diff --git a/camera/device/aidl/Android.bp b/camera/device/aidl/Android.bp
index 78aefac..125f14c 100644
--- a/camera/device/aidl/Android.bp
+++ b/camera/device/aidl/Android.bp
@@ -10,6 +10,7 @@
 
 aidl_interface {
     name: "android.hardware.camera.device",
+    host_supported: true,
     vendor_available: true,
     srcs: ["android/hardware/camera/device/*.aidl"],
     frozen: true,
@@ -29,6 +30,9 @@
             sdk_version: "module_current",
             enabled: false,
         },
+        rust: {
+            enabled: true,
+        },
     },
     versions_with_info: [
         {
diff --git a/camera/device/aidl/android/hardware/camera/device/ICameraDeviceSession.aidl b/camera/device/aidl/android/hardware/camera/device/ICameraDeviceSession.aidl
index 62a19cf..63ae320 100644
--- a/camera/device/aidl/android/hardware/camera/device/ICameraDeviceSession.aidl
+++ b/camera/device/aidl/android/hardware/camera/device/ICameraDeviceSession.aidl
@@ -575,6 +575,11 @@
      * This can be called at any point after 'processCaptureRequest' in response
      * to camera clients disabling an active repeating request.
      *
+     * Note: The frame number parameter is the latest possible frame number at which the
+     * ongoing repeating request will end. It is possible that the repeating request may end
+     * before the specified frame number due to reasons such as the camera client abandoning
+     * buffers, which is timing dependent.
+     *
      * Performance requirements:
      * The call must not be blocked for extensive periods and should be extremely lightweight. There
      * must be no frame rate degradation or frame jitter introduced.
diff --git a/camera/device/aidl/android/hardware/camera/device/ShutterMsg.aidl b/camera/device/aidl/android/hardware/camera/device/ShutterMsg.aidl
index 24ae1a0..f5489d4 100644
--- a/camera/device/aidl/android/hardware/camera/device/ShutterMsg.aidl
+++ b/camera/device/aidl/android/hardware/camera/device/ShutterMsg.aidl
@@ -40,6 +40,9 @@
      * as timestamp, and for a rolling shutter sensor, the value must be
      * timestamp + exposureTime + t_crop_top where t_crop_top is the exposure time
      * skew of the cropped lines on the top.
+     *
+     * If ANDROID_SENSOR_READOUT_TIMESTAMP is set to NOT_SUPPORTED, this field
+     * will be ignored by the camera framework.
      */
     long readoutTimestamp;
 }
diff --git a/camera/metadata/aidl/Android.bp b/camera/metadata/aidl/Android.bp
index ae8ba14..a9c1a1a 100644
--- a/camera/metadata/aidl/Android.bp
+++ b/camera/metadata/aidl/Android.bp
@@ -10,6 +10,7 @@
 
 aidl_interface {
     name: "android.hardware.camera.metadata",
+    host_supported: true,
     vendor_available: true,
     srcs: ["android/hardware/camera/metadata/*.aidl"],
     frozen: true,
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 82666ae..49c8410 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -52,6 +52,7 @@
 #include <android/hardware/camera/provider/2.7/ICameraProvider.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <binder/MemoryHeapBase.h>
+#include <com_android_graphics_libgui_flags.h>
 #include <cutils/properties.h>
 #include <fmq/MessageQueue.h>
 #include <grallocusage/GrallocUsageConversion.h>
@@ -8714,16 +8715,25 @@
     ASSERT_NE(nullptr, bufferItemConsumer);
     ASSERT_NE(nullptr, bufferHandler);
 
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
+    *bufferItemConsumer = new BufferItemConsumer(
+            GraphicBuffer::USAGE_HW_TEXTURE);  // Use GLConsumer default usage flags
+#else
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
     *bufferItemConsumer = new BufferItemConsumer(consumer,
             GraphicBuffer::USAGE_HW_TEXTURE); //Use GLConsumer default usage flags
+#endif  // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
     ASSERT_NE(nullptr, (*bufferItemConsumer).get());
     *bufferHandler = new BufferItemHander(*bufferItemConsumer);
     ASSERT_NE(nullptr, (*bufferHandler).get());
     (*bufferItemConsumer)->setFrameAvailableListener(*bufferHandler);
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
+    sp<Surface> surface = (*bufferItemConsumer)->getSurface();
+#else
     sp<Surface> surface = new Surface(producer);
+#endif  // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
     sp<PreviewWindowCb> previewCb = new PreviewWindowCb(surface);
 
     auto rc = device->setPreviewWindow(previewCb);
diff --git a/camera/provider/aidl/Android.bp b/camera/provider/aidl/Android.bp
index 38a8936..faad35a 100644
--- a/camera/provider/aidl/Android.bp
+++ b/camera/provider/aidl/Android.bp
@@ -10,6 +10,7 @@
 
 aidl_interface {
     name: "android.hardware.camera.provider",
+    host_supported: true,
     vendor_available: true,
     srcs: [
         "android/hardware/camera/provider/*.aidl",
@@ -27,6 +28,9 @@
         cpp: {
             enabled: false,
         },
+        rust: {
+            enabled: true,
+        },
     },
     versions_with_info: [
         {
diff --git a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
index ad8d4c8..9fa4df2 100644
--- a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
+++ b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
@@ -165,26 +165,21 @@
 
 // Validate the integrity of manual flash strength control metadata
 TEST_P(CameraAidlTest, validateManualFlashStrengthControlKeys) {
-    if (flags::camera_manual_flash_strength_control()) {
-        std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
-        for (const auto& name : cameraDeviceNames) {
-            ALOGI("validateManualFlashStrengthControlKeys: Testing camera device %s", name.c_str());
-            CameraMetadata meta;
-            std::shared_ptr<ICameraDevice> cameraDevice;
-            openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
-                    &cameraDevice /*out*/);
-            ndk::ScopedAStatus ret = cameraDevice->getCameraCharacteristics(&meta);
-            ASSERT_TRUE(ret.isOk());
-            const camera_metadata_t* staticMeta =
-                    reinterpret_cast<const camera_metadata_t*>(meta.metadata.data());
-            verifyManualFlashStrengthControlCharacteristics(staticMeta);
-            ret = mSession->close();
-            mSession = nullptr;
-            ASSERT_TRUE(ret.isOk());
-        }
-    } else {
-        ALOGI("validateManualFlashStrengthControlKeys: Test skipped.\n");
-        GTEST_SKIP();
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    for (const auto& name : cameraDeviceNames) {
+        ALOGI("validateManualFlashStrengthControlKeys: Testing camera device %s", name.c_str());
+        CameraMetadata meta;
+        std::shared_ptr<ICameraDevice> cameraDevice;
+        openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
+                &cameraDevice /*out*/);
+        ndk::ScopedAStatus ret = cameraDevice->getCameraCharacteristics(&meta);
+        ASSERT_TRUE(ret.isOk());
+        const camera_metadata_t* staticMeta =
+                reinterpret_cast<const camera_metadata_t*>(meta.metadata.data());
+        verifyManualFlashStrengthControlCharacteristics(staticMeta);
+        ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
     }
 }
 
@@ -288,77 +283,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 +603,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 1ad5af9..6ecd451 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.cpp
+++ b/camera/provider/aidl/vts/camera_aidl_test.cpp
@@ -456,6 +456,22 @@
     return ret;
 }
 
+bool CameraAidlTest::isReadoutTimestampSupported(const camera_metadata_t* staticMeta) {
+    camera_metadata_ro_entry readoutTimestampEntry;
+    int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_SENSOR_READOUT_TIMESTAMP,
+                                           &readoutTimestampEntry);
+    if (rc != 0) {
+        ALOGI("%s: Failed to find ANDROID_SENSOR_READOUT_TIMESTAMP", __FUNCTION__);
+        return true;
+    }
+    if (readoutTimestampEntry.count == 1 && !readoutTimestampEntry.data.u8[0]) {
+        ALOGI("%s: readout timestamp not supported", __FUNCTION__);
+        return false;
+    }
+    ALOGI("%s: readout timestamp supported", __FUNCTION__);
+    return true;
+}
+
 void CameraAidlTest::verifyLogicalCameraResult(const camera_metadata_t* staticMetadata,
                                                const std::vector<uint8_t>& resultMetadata) {
     camera_metadata_t* metadata = (camera_metadata_t*)resultMetadata.data();
@@ -1904,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());
 
@@ -2383,13 +2393,13 @@
             ASSERT_NE(inflightReq->resultOutputBuffers.size(), 0u);
             ASSERT_EQ(testStream.id, inflightReq->resultOutputBuffers[0].buffer.streamId);
 
-            // shutterReadoutTimestamp must be available, and it must
+            // shutterReadoutTimestamp, if supported, must
             // be >= shutterTimestamp + exposureTime,
             // and < shutterTimestamp + exposureTime + rollingShutterSkew / 2.
-            ASSERT_TRUE(inflightReq->shutterReadoutTimestampValid);
             ASSERT_FALSE(inflightReq->collectedResult.isEmpty());
 
-            if (inflightReq->collectedResult.exists(ANDROID_SENSOR_EXPOSURE_TIME)) {
+            if (mSupportReadoutTimestamp &&
+                inflightReq->collectedResult.exists(ANDROID_SENSOR_EXPOSURE_TIME)) {
                 camera_metadata_entry_t exposureTimeResult =
                         inflightReq->collectedResult.find(ANDROID_SENSOR_EXPOSURE_TIME);
                 nsecs_t exposureToReadout =
@@ -2904,13 +2914,14 @@
             ASSERT_FALSE(inflightReq->errorCodeValid);
             ASSERT_NE(inflightReq->resultOutputBuffers.size(), 0u);
             ASSERT_EQ(testStream.id, inflightReq->resultOutputBuffers[0].buffer.streamId);
-            ASSERT_TRUE(inflightReq->shutterReadoutTimestampValid);
-            nsecs_t readoutTimestamp = inflightReq->shutterReadoutTimestamp;
+            nsecs_t captureTimestamp = mSupportReadoutTimestamp
+                                               ? inflightReq->shutterReadoutTimestamp
+                                               : inflightReq->shutterTimestamp;
 
             if (previewStabilizationOn) {
                 // Here we collect the time difference between the buffer ready
-                // timestamp - notify readout timestamp.
-                // timeLag = buffer ready timestamp - notify readout timestamp.
+                // timestamp - notify timestamp.
+                // timeLag = buffer ready timestamp - notify timestamp.
                 // timeLag(previewStabilization) must be <=
                 //        timeLag(stabilization off) + 1 frame duration.
                 auto it = cameraDeviceToTimeLag.find(name);
@@ -2921,12 +2932,12 @@
                 ASSERT_TRUE(it != cameraDeviceToTimeLag.end());
 
                 nsecs_t previewStabOnLagTime =
-                        inflightReq->resultOutputBuffers[0].timeStamp - readoutTimestamp;
+                        inflightReq->resultOutputBuffers[0].timeStamp - captureTimestamp;
                 ASSERT_TRUE(previewStabOnLagTime <= (it->second + frameDuration));
             } else {
                 // Fill in the buffer ready timestamp - notify timestamp;
                 cameraDeviceToTimeLag[std::string(name)] =
-                        inflightReq->resultOutputBuffers[0].timeStamp - readoutTimestamp;
+                        inflightReq->resultOutputBuffers[0].timeStamp - captureTimestamp;
             }
         }
 
diff --git a/camera/provider/aidl/vts/camera_aidl_test.h b/camera/provider/aidl/vts/camera_aidl_test.h
index 782794b..9edbf41 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.h
+++ b/camera/provider/aidl/vts/camera_aidl_test.h
@@ -346,6 +346,8 @@
 
     static Status isOfflineSessionSupported(const camera_metadata_t* staticMeta);
 
+    static bool isReadoutTimestampSupported(const camera_metadata_t* staticMeta);
+
     static Status getPhysicalCameraIds(const camera_metadata_t* staticMeta,
                                        std::unordered_set<std::string>* physicalIds /*out*/);
 
@@ -456,8 +458,6 @@
     struct InFlightRequest {
         // Set by notify() SHUTTER call.
         nsecs_t shutterTimestamp;
-
-        bool shutterReadoutTimestampValid;
         nsecs_t shutterReadoutTimestamp;
 
         bool errorCodeValid;
@@ -523,7 +523,6 @@
 
         InFlightRequest()
             : shutterTimestamp(0),
-              shutterReadoutTimestampValid(false),
               shutterReadoutTimestamp(0),
               errorCodeValid(false),
               errorCode(ErrorCode::ERROR_BUFFER),
@@ -541,7 +540,6 @@
         InFlightRequest(ssize_t numBuffers, bool hasInput, bool partialResults,
                         int32_t partialCount, std::shared_ptr<ResultMetadataQueue> queue = nullptr)
             : shutterTimestamp(0),
-              shutterReadoutTimestampValid(false),
               shutterReadoutTimestamp(0),
               errorCodeValid(false),
               errorCode(ErrorCode::ERROR_BUFFER),
@@ -561,7 +559,6 @@
                         const std::unordered_set<std::string>& extraPhysicalResult,
                         std::shared_ptr<ResultMetadataQueue> queue = nullptr)
             : shutterTimestamp(0),
-              shutterReadoutTimestampValid(false),
               shutterReadoutTimestamp(0),
               errorCodeValid(false),
               errorCode(ErrorCode::ERROR_BUFFER),
@@ -631,6 +628,8 @@
 
     HandleImporter mHandleImporter;
 
+    bool mSupportReadoutTimestamp;
+
     friend class DeviceCb;
     friend class SimpleDeviceCb;
     friend class TorchProviderCb;
diff --git a/camera/provider/aidl/vts/device_cb.cpp b/camera/provider/aidl/vts/device_cb.cpp
index 8a8b925..bfd1cd1 100644
--- a/camera/provider/aidl/vts/device_cb.cpp
+++ b/camera/provider/aidl/vts/device_cb.cpp
@@ -32,10 +32,11 @@
 
 DeviceCb::DeviceCb(CameraAidlTest* parent, camera_metadata_t* staticMeta) : mParent(parent) {
     mStaticMetadata = staticMeta;
+    parent->mSupportReadoutTimestamp = CameraAidlTest::isReadoutTimestampSupported(staticMeta);
 }
 
 ScopedAStatus DeviceCb::notify(const std::vector<NotifyMsg>& msgs) {
-    std::vector<std::pair<bool, nsecs_t>> readoutTimestamps;
+    std::vector<nsecs_t> readoutTimestamps;
 
     size_t count = msgs.size();
     readoutTimestamps.resize(count);
@@ -44,11 +45,11 @@
         const NotifyMsg& msg = msgs[i];
         switch (msg.getTag()) {
             case NotifyMsg::Tag::error:
-                readoutTimestamps[i] = {false, 0};
+                readoutTimestamps[i] = 0;
                 break;
             case NotifyMsg::Tag::shutter:
                 const auto& shutter = msg.get<NotifyMsg::Tag::shutter>();
-                readoutTimestamps[i] = {true, shutter.readoutTimestamp};
+                readoutTimestamps[i] = shutter.readoutTimestamp;
                 break;
         }
     }
@@ -446,9 +447,8 @@
     return notify;
 }
 
-ScopedAStatus DeviceCb::notifyHelper(
-        const std::vector<NotifyMsg>& msgs,
-        const std::vector<std::pair<bool, nsecs_t>>& readoutTimestamps) {
+ScopedAStatus DeviceCb::notifyHelper(const std::vector<NotifyMsg>& msgs,
+                                     const std::vector<nsecs_t>& readoutTimestamps) {
     std::lock_guard<std::mutex> l(mParent->mLock);
 
     for (size_t i = 0; i < msgs.size(); i++) {
@@ -514,8 +514,7 @@
                 }
                 auto& r = itr->second;
                 r->shutterTimestamp = msg.get<NotifyMsg::Tag::shutter>().timestamp;
-                r->shutterReadoutTimestampValid = readoutTimestamps[i].first;
-                r->shutterReadoutTimestamp = readoutTimestamps[i].second;
+                r->shutterReadoutTimestamp = readoutTimestamps[i];
                 break;
         }
     }
diff --git a/camera/provider/aidl/vts/device_cb.h b/camera/provider/aidl/vts/device_cb.h
index 3ae7d10..d839ab4 100644
--- a/camera/provider/aidl/vts/device_cb.h
+++ b/camera/provider/aidl/vts/device_cb.h
@@ -60,7 +60,7 @@
     bool processCaptureResultLocked(const CaptureResult& results,
                                     std::vector<PhysicalCameraMetadata> physicalCameraMetadata);
     ScopedAStatus notifyHelper(const std::vector<NotifyMsg>& msgs,
-                               const std::vector<std::pair<bool, nsecs_t>>& readoutTimestamps);
+                               const std::vector<nsecs_t>& readoutTimestamps);
 
     CameraAidlTest* mParent;  // Parent object
 
diff --git a/cas/1.2/default/android.hardware.cas@1.2-service-lazy.xml b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.xml
index 9b36406..87c9e02 100644
--- a/cas/1.2/default/android.hardware.cas@1.2-service-lazy.xml
+++ b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.xml
@@ -1,5 +1,5 @@
 <manifest version="1.0" type="device">
-    <hal format="hidl">
+    <hal format="hidl" max-level="7">
         <name>android.hardware.cas</name>
         <transport>hwbinder</transport>
         <version>1.2</version>
diff --git a/cas/1.2/default/android.hardware.cas@1.2-service.xml b/cas/1.2/default/android.hardware.cas@1.2-service.xml
index 9b36406..87c9e02 100644
--- a/cas/1.2/default/android.hardware.cas@1.2-service.xml
+++ b/cas/1.2/default/android.hardware.cas@1.2-service.xml
@@ -1,5 +1,5 @@
 <manifest version="1.0" type="device">
-    <hal format="hidl">
+    <hal format="hidl" max-level="7">
         <name>android.hardware.cas</name>
         <transport>hwbinder</transport>
         <version>1.2</version>
diff --git a/common/aidl/Android.bp b/common/aidl/Android.bp
index 1f5742d..904a3d9 100644
--- a/common/aidl/Android.bp
+++ b/common/aidl/Android.bp
@@ -20,16 +20,18 @@
     backend: {
         java: {
             sdk_version: "module_current",
+            apex_available: [
+                "//apex_available:anyapex",
+                "//apex_available:platform",
+            ],
         },
         cpp: {
             enabled: false,
         },
         ndk: {
             apex_available: [
+                "//apex_available:anyapex",
                 "//apex_available:platform",
-                "com.android.btservices",
-                "com.android.media.swcodec",
-                "com.android.neuralnetworks",
             ],
             min_sdk_version: "29",
         },
diff --git a/common/fmq/aidl/Android.bp b/common/fmq/aidl/Android.bp
index 9c1b45d..4a3658e 100644
--- a/common/fmq/aidl/Android.bp
+++ b/common/fmq/aidl/Android.bp
@@ -35,8 +35,7 @@
         ndk: {
             apex_available: [
                 "//apex_available:platform",
-                "com.android.btservices",
-                "com.android.media.swcodec",
+                "//apex_available:anyapex",
             ],
             min_sdk_version: "29",
         },
diff --git a/common/support/Android.bp b/common/support/Android.bp
index 56700fa..aba5d6b 100644
--- a/common/support/Android.bp
+++ b/common/support/Android.bp
@@ -24,9 +24,8 @@
         "libcutils",
     ],
     apex_available: [
+        "//apex_available:anyapex",
         "//apex_available:platform",
-        "com.android.neuralnetworks",
-        "com.android.media.swcodec",
     ],
     min_sdk_version: "29",
 }
diff --git a/compatibility_matrices/Android.bp b/compatibility_matrices/Android.bp
index ad42015..6a3fa32 100644
--- a/compatibility_matrices/Android.bp
+++ b/compatibility_matrices/Android.bp
@@ -93,6 +93,14 @@
 
 }
 
+// Device framework compatibility matrix (common to all FCM versions)
+// Reference: https://source.android.com/docs/core/architecture/vintf/comp-matrices
+vintf_compatibility_matrix {
+    name: "framework_compatibility_matrix.device.xml",
+    stem: "compatibility_matrix.device.xml",
+    type: "device_fcm",
+}
+
 // Phony target that installs all system compatibility matrix files
 SYSTEM_MATRIX_DEPS = [
     "framework_compatibility_matrix.5.xml",
@@ -114,3 +122,26 @@
         },
     },
 }
+
+// Product Compatibility Matrix
+vintf_compatibility_matrix {
+    name: "product_compatibility_matrix.xml",
+    stem: "compatibility_matrix.xml",
+    product_specific: true,
+    type: "product_fcm",
+}
+
+// Phony target that installs all framework compatibility matrix files (system + product)
+FRAMEWORK_MATRIX_DEPS = SYSTEM_MATRIX_DEPS + ["product_compatibility_matrix.xml"]
+
+phony {
+    name: "framework_compatibility_matrix.xml",
+    required: FRAMEWORK_MATRIX_DEPS,
+    product_variables: {
+        release_aidl_use_unfrozen: {
+            required: [
+                "framework_compatibility_matrix.202504.xml",
+            ],
+        },
+    },
+}
diff --git a/compatibility_matrices/Android.mk b/compatibility_matrices/Android.mk
deleted file mode 100644
index 338c075..0000000
--- a/compatibility_matrices/Android.mk
+++ /dev/null
@@ -1,134 +0,0 @@
-#
-# Copyright (C) 2017 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-BUILD_FRAMEWORK_COMPATIBILITY_MATRIX := $(LOCAL_PATH)/compatibility_matrix.mk
-my_empty_manifest := $(LOCAL_PATH)/manifest.empty.xml
-
-# System Compatibility Matrix (common to all FCM versions)
-
-include $(CLEAR_VARS)
-include $(LOCAL_PATH)/clear_vars.mk
-LOCAL_MODULE := framework_compatibility_matrix.device.xml
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../NOTICE
-LOCAL_MODULE_STEM := compatibility_matrix.device.xml
-# define LOCAL_MODULE_CLASS for local-generated-sources-dir.
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_RELATIVE_PATH := vintf
-
-ifndef DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE
-LOCAL_SRC_FILES := compatibility_matrix.empty.xml
-else
-
-# DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE specifies absolute paths
-LOCAL_GENERATED_SOURCES := $(DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE)
-
-# Enforce that DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE does not specify required HALs
-# by checking it against an empty manifest. But the empty manifest needs to contain
-# BOARD_SEPOLICY_VERS to be compatible with DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE.
-my_gen_check_manifest := $(local-generated-sources-dir)/manifest.check.xml
-$(my_gen_check_manifest): PRIVATE_SRC_FILE := $(my_empty_manifest)
-$(my_gen_check_manifest): $(my_empty_manifest) $(HOST_OUT_EXECUTABLES)/assemble_vintf
-	BOARD_SEPOLICY_VERS=$(BOARD_SEPOLICY_VERS) \
-	VINTF_IGNORE_TARGET_FCM_VERSION=true \
-		$(HOST_OUT_EXECUTABLES)/assemble_vintf -i $(PRIVATE_SRC_FILE) -o $@
-
-LOCAL_GEN_FILE_DEPENDENCIES += $(my_gen_check_manifest)
-LOCAL_ASSEMBLE_VINTF_FLAGS += -c "$(my_gen_check_manifest)"
-
-my_gen_check_manifest :=
-
-endif # DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE
-
-# TODO(b/296875906): use POLICYVERS from Soong
-POLICYVERS ?= 30
-
-LOCAL_ADD_VBMETA_VERSION := true
-LOCAL_ASSEMBLE_VINTF_ENV_VARS := \
-    POLICYVERS \
-    PLATFORM_SEPOLICY_VERSION \
-    PLATFORM_SEPOLICY_COMPAT_VERSIONS
-
-include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
-
-# Product Compatibility Matrix
-
-include $(CLEAR_VARS)
-include $(LOCAL_PATH)/clear_vars.mk
-LOCAL_MODULE := product_compatibility_matrix.xml
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../NOTICE
-
-ifndef DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE
-my_framework_matrix_deps :=
-include $(BUILD_PHONY_PACKAGE)
-else # DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE
-
-LOCAL_MODULE_STEM := compatibility_matrix.xml
-LOCAL_PRODUCT_MODULE := true
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_RELATIVE_PATH := vintf
-
-# DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE specifies absolute paths
-LOCAL_GENERATED_SOURCES := $(DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE)
-
-# Enforce that DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE does not specify required HALs
-# by checking it against an empty manifest.
-LOCAL_GEN_FILE_DEPENDENCIES += $(my_empty_manifest)
-LOCAL_ASSEMBLE_VINTF_FLAGS += -c "$(my_empty_manifest)"
-
-my_framework_matrix_deps := $(LOCAL_MODULE)
-
-include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
-
-endif # DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE
-
-my_system_matrix_deps := \
-    framework_compatibility_matrix.5.xml \
-    framework_compatibility_matrix.6.xml \
-    framework_compatibility_matrix.7.xml \
-    framework_compatibility_matrix.8.xml \
-    framework_compatibility_matrix.202404.xml \
-    framework_compatibility_matrix.device.xml \
-
-# Only allow the use of the unreleased compatibility matrix when we can use unfrozen
-# interfaces (in the `next` release configuration).
-ifeq ($(RELEASE_AIDL_USE_UNFROZEN),true)
-my_system_matrix_deps += \
-    framework_compatibility_matrix.202504.xml \
-
-endif
-
-my_framework_matrix_deps += \
-    $(my_system_matrix_deps)
-
-# Phony target that installs all framework compatibility matrix files (system + product)
-include $(CLEAR_VARS)
-LOCAL_MODULE := framework_compatibility_matrix.xml
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../NOTICE
-LOCAL_REQUIRED_MODULES := $(my_framework_matrix_deps)
-include $(BUILD_PHONY_PACKAGE)
-
-my_system_matrix_deps :=
-my_framework_matrix_deps :=
-my_empty_manifest :=
-BUILD_FRAMEWORK_COMPATIBILITY_MATRIX :=
diff --git a/compatibility_matrices/build/Android.bp b/compatibility_matrices/build/Android.bp
index 79ef36d..6011fcc 100644
--- a/compatibility_matrices/build/Android.bp
+++ b/compatibility_matrices/build/Android.bp
@@ -30,6 +30,7 @@
         "kernel-config-soong-rules",
         "soong",
         "soong-android",
+        "soong-selinux",
     ],
     srcs: [
         "vintf_compatibility_matrix.go",
diff --git a/compatibility_matrices/build/vintf_compatibility_matrix.go b/compatibility_matrices/build/vintf_compatibility_matrix.go
index c72cbde..b8f2a14 100644
--- a/compatibility_matrices/build/vintf_compatibility_matrix.go
+++ b/compatibility_matrices/build/vintf_compatibility_matrix.go
@@ -24,6 +24,7 @@
 
 	"android/soong/android"
 	"android/soong/kernel/configs"
+	"android/soong/selinux"
 )
 
 type dependencyTag struct {
@@ -35,10 +36,10 @@
 	pctx = android.NewPackageContext("android/vintf")
 
 	assembleVintfRule = pctx.AndroidStaticRule("assemble_vintf", blueprint.RuleParams{
-		Command:     `${assembleVintfCmd} -i ${inputs} -o ${out}`,
-		CommandDeps: []string{"${assembleVintfCmd}"},
+		Command:     `${assembleVintfEnv} ${assembleVintfCmd} -i ${inputs} -o ${out} ${extraArgs}`,
+		CommandDeps: []string{"${assembleVintfCmd}", "${AvbToolCmd}"},
 		Description: "assemble_vintf -i ${inputs}",
-	}, "inputs")
+	}, "inputs", "extraArgs", "assembleVintfEnv")
 
 	xmllintXsd = pctx.AndroidStaticRule("xmllint-xsd", blueprint.RuleParams{
 		Command:     `$XmlLintCmd --quiet --schema $xsd $in > /dev/null && touch -a $out`,
@@ -52,7 +53,11 @@
 )
 
 const (
-	relpath = "vintf"
+	relpath                  = "vintf"
+	emptyManifest            = "hardware/interfaces/compatibility_matrices/manifest.empty.xml"
+	compatibilityEmptyMatrix = "hardware/interfaces/compatibility_matrices/compatibility_matrix.empty.xml"
+	deviceFcmType            = "device_fcm"
+	productFcmType           = "product_fcm"
 )
 
 type vintfCompatibilityMatrixProperties struct {
@@ -64,6 +69,9 @@
 
 	// list of kernel_config modules to be combined to final output
 	Kernel_configs []string
+
+	// Type of the FCM type, the allowed type are device_fcm and product_fcm and it should only be used under hardware/interfaces/compatibility_matrices
+	Type *string
 }
 
 type vintfCompatibilityMatrixRule struct {
@@ -72,11 +80,13 @@
 
 	genFile                android.WritablePath
 	additionalDependencies android.WritablePaths
+	phonyOnly              bool
 }
 
 func init() {
 	pctx.HostBinToolVariable("assembleVintfCmd", "assemble_vintf")
 	pctx.HostBinToolVariable("XmlLintCmd", "xmllint")
+	pctx.HostBinToolVariable("AvbToolCmd", "avbtool")
 	android.RegisterModuleType("vintf_compatibility_matrix", vintfCompatibilityMatrixFactory)
 }
 
@@ -131,6 +141,20 @@
 }
 
 func (g *vintfCompatibilityMatrixRule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	// Types attribute only allow `device_fcm` or `product_fcm` if set and only restricted it being used under
+	// `hardware/interfaces/compatibility_matrices` to prevent accidental external usages.
+	matrixType := proptools.String(g.properties.Type)
+	if matrixType != "" {
+		if matrixType != deviceFcmType && matrixType != productFcmType {
+			panic(fmt.Errorf("The attribute 'type' value must be either 'device_fcm' or 'product_fcm' if set!"))
+		}
+		if !strings.HasPrefix(android.PathForModuleSrc(ctx).String(), "hardware/interfaces/compatibility_matrices") {
+			panic(fmt.Errorf("Attribute type can only be set for module under `hardware/interfaces/compatibility_matrices`!"))
+		}
+		if (len(g.properties.Srcs) + len(g.properties.Kernel_configs)) > 0 {
+			panic(fmt.Errorf("Attribute 'type' and 'srcs' or 'kernel_configs' should not set simultaneously! To update inputs for this rule, edit vintf_compatibility_matrix.go directly."))
+		}
+	}
 
 	outputFilename := proptools.String(g.properties.Stem)
 	if outputFilename == "" {
@@ -158,15 +182,72 @@
 		}
 	})
 
+	// For product_compatibility_matrix.xml the source is from the product configuration
+	// DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE.
+	extraArgs := []string{}
+	if matrixType == productFcmType {
+		productMatrixs := android.PathsForSource(ctx, ctx.Config().DeviceProductCompatibilityMatrixFile())
+		if len(productMatrixs) > 0 {
+			inputPaths = append(inputPaths, productMatrixs...)
+			extraArgs = append(extraArgs, "-c", android.PathForSource(ctx, emptyManifest).String())
+		} else {
+			// For product_fcm, if DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE not set, treat it as a phony target without any output generated.
+			g.phonyOnly = true
+			return
+		}
+	}
+
+	// For framework_compatibility_matrix.device.xml the source may come from the product configuration
+	// DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE or use compatibilityEmptyMatrix if not set. We can't
+	// use a phony target because we still need to install framework_compatibility_matrix.device.xml to
+	// include sepolicy versions.
+	frameworkRuleImplicits := []android.Path{}
+
+	if matrixType == deviceFcmType {
+		frameworkMatrixs := android.PathsForSource(ctx, ctx.Config().DeviceFrameworkCompatibilityMatrixFile())
+		if len(frameworkMatrixs) > 0 {
+			inputPaths = append(inputPaths, frameworkMatrixs...)
+
+			// Generate BuildAction for generating the check manifest.
+			emptyManifestPath := android.PathForSource(ctx, emptyManifest)
+			genCheckManifest := android.PathForModuleGen(ctx, "manifest.check.xml")
+			checkManifestInputs := []android.Path{emptyManifestPath}
+			genCheckManifestEnvs := []string{
+				"BOARD_SEPOLICY_VERS=" + ctx.DeviceConfig().BoardSepolicyVers(),
+				"VINTF_IGNORE_TARGET_FCM_VERSION=true",
+			}
+
+			ctx.Build(pctx, android.BuildParams{
+				Rule:        assembleVintfRule,
+				Description: "Framework Check Manifest",
+				Implicits:   checkManifestInputs,
+				Output:      genCheckManifest,
+				Args: map[string]string{
+					"inputs":           android.PathForSource(ctx, emptyManifest).String(),
+					"extraArgs":        "",
+					"assembleVintfEnv": strings.Join(genCheckManifestEnvs, " "),
+				},
+			})
+
+			frameworkRuleImplicits = append(frameworkRuleImplicits, genCheckManifest)
+			extraArgs = append(extraArgs, "-c", genCheckManifest.String())
+		} else {
+			inputPaths = append(inputPaths, android.PathForSource(ctx, compatibilityEmptyMatrix))
+		}
+	}
+
 	g.genFile = android.PathForModuleGen(ctx, outputFilename)
+	frameworkRuleImplicits = append(frameworkRuleImplicits, inputPaths...)
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        assembleVintfRule,
 		Description: "Framework Compatibility Matrix",
-		Implicits:   inputPaths,
+		Implicits:   frameworkRuleImplicits,
 		Output:      g.genFile,
 		Args: map[string]string{
-			"inputs": strings.Join(inputPaths.Strings(), ":"),
+			"inputs":           strings.Join(inputPaths.Strings(), ":"),
+			"extraArgs":        strings.Join(extraArgs, " "),
+			"assembleVintfEnv": g.getAssembleVintfEnv(ctx),
 		},
 	})
 	g.generateValidateBuildAction(ctx, g.genFile, schema.Path())
@@ -174,7 +255,39 @@
 	ctx.InstallFile(android.PathForModuleInstall(ctx, "etc", relpath), outputFilename, g.genFile)
 }
 
+func (g *vintfCompatibilityMatrixRule) getAssembleVintfEnv(ctx android.ModuleContext) string {
+	if proptools.String(g.properties.Type) == deviceFcmType {
+		assembleVintfEnvs := []string{
+			// POLICYVERS defined in system/sepolicy/build/soong/policy.go
+			fmt.Sprintf("POLICYVERS=%d", selinux.PolicyVers),
+			fmt.Sprintf("PLATFORM_SEPOLICY_VERSION=%s", ctx.DeviceConfig().PlatformSepolicyVersion()),
+			fmt.Sprintf("PLATFORM_SEPOLICY_COMPAT_VERSIONS=\"%s\"", strings.Join(ctx.DeviceConfig().PlatformSepolicyCompatVersions(), " ")),
+		}
+
+		if ctx.Config().BoardAvbEnable() {
+			assembleVintfEnvs = append(assembleVintfEnvs, fmt.Sprintf("FRAMEWORK_VBMETA_VERSION=\"$$(${AvbToolCmd} add_hashtree_footer --print_required_libavb_version %s)\"", strings.Join(ctx.Config().BoardAvbSystemAddHashtreeFooterArgs(), " ")))
+		} else {
+			assembleVintfEnvs = append(assembleVintfEnvs, "FRAMEWORK_VBMETA_VERSION=\"0.0\"")
+		}
+
+		return strings.Join(assembleVintfEnvs, " ")
+	}
+
+	return ""
+}
+
 func (g *vintfCompatibilityMatrixRule) AndroidMk() android.AndroidMkData {
+	if g.phonyOnly {
+		return android.AndroidMkData{
+			Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
+				fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)", " # vintf.vintf_compatibility_matrix")
+				fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
+				fmt.Fprintln(w, "LOCAL_MODULE :=", name)
+				fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
+			},
+		}
+	}
+
 	return android.AndroidMkData{
 		Class:      "ETC",
 		OutputFile: android.OptionalPathForPath(g.genFile),
diff --git a/compatibility_matrices/bump.py b/compatibility_matrices/bump.py
index a5a453b..4e3ceaa 100755
--- a/compatibility_matrices/bump.py
+++ b/compatibility_matrices/bump.py
@@ -21,7 +21,7 @@
 import argparse
 import os
 import pathlib
-import shutil
+import re
 import subprocess
 import textwrap
 
@@ -44,6 +44,7 @@
 
         self.current_level = cmdline_args.current_level
         self.current_letter = cmdline_args.current_letter
+        self.current_version = cmdline_args.platform_version
         self.current_module_name = f"framework_compatibility_matrix.{self.current_level}.xml"
         self.current_xml = self.interfaces_dir / f"compatibility_matrices/compatibility_matrix.{self.current_level}.xml"
         self.device_module_name = "framework_compatibility_matrix.device.xml"
@@ -58,12 +59,13 @@
         self.copy_matrix()
         self.edit_android_bp()
         self.edit_android_mk()
+        self.bump_libvintf()
 
     def bump_kernel_configs(self):
         check_call([
             self.top / "kernel/configs/tools/bump.py",
-            self.current_letter,
-            self.next_letter,
+            self.current_letter.lower(),
+            self.next_letter.lower(),
         ])
 
     def copy_matrix(self):
@@ -87,7 +89,7 @@
         next_kernel_configs = check_output(
             """grep -rh name: | sed -E 's/^.*"(.*)".*/\\1/g'""",
             cwd=self.top / "kernel/configs" /
-            self.next_letter,
+            self.next_letter.lower(),
             text=True,
             shell=True,
         ).splitlines()
@@ -109,6 +111,25 @@
             "kernel_configs", "-a", " ".join(next_kernel_configs), android_bp
         ])
 
+        # update the SYSTEM_MATRIX_DEPS variable and the phony module's
+        # product_variables entry.
+        lines = []
+        with open(android_bp) as f:
+            for line in f:
+              if f"    \"{self.device_module_name}\",\n" in line:
+                  lines.append(f"    \"{self.current_module_name}\",\n")
+
+              if f"                \"{self.current_module_name}\",\n" in line:
+                  lines.append(f"                \"{self.next_module_name}\",\n")
+              else:
+                  lines.append(line)
+
+        with open(android_bp, "w") as f:
+            f.write("".join(lines))
+
+
+    # This Android.mk file may be deprecated soon and the functionality is
+    # replaced by the soong phony module system_compatibility_matrix.xml.
     def edit_android_mk(self):
         android_mk = self.interfaces_dir / "compatibility_matrices/Android.mk"
         lines = []
@@ -128,21 +149,69 @@
         with open(android_mk, "w") as f:
             f.write("".join(lines))
 
+    def bump_libvintf(self):
+        if not self.current_version:
+            print("Skip libvintf update...")
+            return
+        try:
+            check_call(["grep", "-h",
+                        f"{self.current_letter.upper()} = {self.current_level}",
+                        "system/libvintf/include/vintf/Level.h"])
+        except subprocess.CalledProcessError:
+            print("Adding new API level to libvintf")
+            add_lines_above("system/libvintf/analyze_matrix/analyze_matrix.cpp",
+                            "        case Level::UNSPECIFIED:",
+                            textwrap.indent(textwrap.dedent(f"""\
+                                    case Level::{self.current_letter.upper()}:
+                                        return "Android {self.current_version} ({self.current_letter.upper()})";"""),
+                            "    "*2))
+            add_lines_above("system/libvintf/include/vintf/Level.h",
+                            "    // To add new values:",
+                            f"    {self.current_letter.upper()} = {self.current_level},")
+            add_lines_above("system/libvintf/include/vintf/Level.h",
+                            "        Level::UNSPECIFIED,",
+                            f"        Level::{self.current_letter.upper()},")
+            add_lines_above("system/libvintf/RuntimeInfo.cpp",
+                            "            // Add more levels above this line.",
+                            textwrap.indent(textwrap.dedent(f"""\
+                                        case {self.current_version}: {{
+                                            ret = Level::{self.current_letter.upper()};
+                                        }} break;"""),
+                            "    "*3))
+
+
+def add_lines_above(file, pattern, lines):
+    with open(file, 'r+') as f:
+        text = f.read()
+        split_text = re.split(rf"\n{pattern}\n", text)
+        if len(split_text) != 2:
+            # Only one pattern must be found, otherwise the source must be
+            # changed unexpectedly.
+            raise Exception(
+                f'Pattern "{pattern}" not found or multiple patterns found in {file}')
+        f.seek(0)
+        f.write(f"\n{lines}\n{pattern}\n".join(split_text))
+        f.truncate()
+
 
 def main():
     parser = argparse.ArgumentParser(description=__doc__)
     parser.add_argument("current_level",
                         type=str,
-                        help="VINTF level of the current version (e.g. 9)")
+                        help="VINTF level of the current version (e.g. 202404)")
     parser.add_argument("next_level",
                         type=str,
-                        help="VINTF level of the next version (e.g. 10)")
+                        help="VINTF level of the next version (e.g. 202504)")
     parser.add_argument("current_letter",
                         type=str,
                         help="Letter of the API level of the current version (e.g. v)")
     parser.add_argument("next_letter",
                         type=str,
                         help="Letter of the API level of the next version (e.g. w)")
+    parser.add_argument("platform_version",
+                        type=str,
+                        nargs="?",
+                        help="Android release version number number (e.g. 15)")
     cmdline_args = parser.parse_args()
 
     Bump(cmdline_args).run()
diff --git a/compatibility_matrices/clear_vars.mk b/compatibility_matrices/clear_vars.mk
index 0e53885..3c62377 100644
--- a/compatibility_matrices/clear_vars.mk
+++ b/compatibility_matrices/clear_vars.mk
@@ -16,10 +16,6 @@
 
 # Clear input variables to BUILD_FRAMEWORK_COMPATIBILITY_MATRIX
 LOCAL_ADD_VBMETA_VERSION :=
-LOCAL_ADD_VBMETA_VERSION_OVERRIDE :=
 LOCAL_ASSEMBLE_VINTF_ENV_VARS :=
-LOCAL_ASSEMBLE_VINTF_ENV_VARS_OVERRIDE :=
-LOCAL_ASSEMBLE_VINTF_ERROR_MESSAGE :=
 LOCAL_ASSEMBLE_VINTF_FLAGS :=
-LOCAL_KERNEL_CONFIG_DATA_PATHS :=
 LOCAL_GEN_FILE_DEPENDENCIES :=
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 0e714a4..22746e3 100644
--- a/compatibility_matrices/compatibility_matrix.202504.xml
+++ b/compatibility_matrices/compatibility_matrix.202504.xml
@@ -1,7 +1,7 @@
 <compatibility-matrix version="1.0" type="framework" level="202504">
     <hal format="aidl">
         <name>android.hardware.audio.core</name>
-        <version>1-2</version>
+        <version>1-3</version>
         <interface>
             <name>IModule</name>
             <instance>default</instance>
@@ -20,20 +20,12 @@
     </hal>
     <hal format="aidl">
         <name>android.hardware.audio.effect</name>
-        <version>1-2</version>
+        <version>1-3</version>
         <interface>
             <name>IFactory</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl">
-        <name>android.hardware.audio.sounddose</name>
-        <version>1-2</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>
@@ -44,7 +36,7 @@
     </hal>
     <hal format="aidl">
         <name>android.hardware.automotive.audiocontrol</name>
-        <version>2-4</version>
+        <version>2-5</version>
         <interface>
             <name>IAudioControl</name>
             <instance>default</instance>
@@ -132,7 +124,7 @@
     </hal>
     <hal format="aidl">
         <name>android.hardware.bluetooth.audio</name>
-        <version>3-4</version>
+        <version>3-5</version>
         <interface>
             <name>IBluetoothAudioProviderFactory</name>
             <instance>default</instance>
@@ -249,7 +241,7 @@
     </hal>
     <hal format="aidl">
         <name>android.hardware.graphics.composer3</name>
-        <version>3</version>
+        <version>4</version>
         <interface>
             <name>IComposer</name>
             <instance>default</instance>
@@ -372,6 +364,7 @@
     </hal>
     <hal format="aidl" updatable-via-apex="true">
         <name>android.hardware.nfc</name>
+        <version>1-2</version>
         <interface>
             <name>INfc</name>
             <instance>default</instance>
@@ -542,7 +535,7 @@
     </hal>
     <hal format="aidl">
          <name>android.hardware.soundtrigger3</name>
-         <version>1-2</version>
+         <version>1-3</version>
          <interface>
              <name>ISoundTriggerHw</name>
              <instance>default</instance>
@@ -629,7 +622,7 @@
     </hal>
     <hal format="aidl">
         <name>android.hardware.vibrator</name>
-        <version>1-2</version>
+        <version>1-3</version>
         <interface>
             <name>IVibrator</name>
             <instance>default</instance>
@@ -637,7 +630,7 @@
     </hal>
     <hal format="aidl">
         <name>android.hardware.vibrator</name>
-        <version>1-2</version>
+        <version>1-3</version>
         <interface>
             <name>IVibratorManager</name>
             <instance>default</instance>
@@ -669,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>
@@ -677,7 +670,7 @@
     </hal>
     <hal format="aidl">
         <name>android.hardware.wifi.supplicant</name>
-        <version>2-3</version>
+        <version>3-4</version>
         <interface>
             <name>ISupplicant</name>
             <instance>default</instance>
diff --git a/compatibility_matrices/compatibility_matrix.mk b/compatibility_matrices/compatibility_matrix.mk
deleted file mode 100644
index d22e510..0000000
--- a/compatibility_matrices/compatibility_matrix.mk
+++ /dev/null
@@ -1,128 +0,0 @@
-#
-# Copyright (C) 2018 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.
-#
-
-##### Input Variables:
-# LOCAL_MODULE: required. Module name for the build system.
-# LOCAL_MODULE_CLASS: optional. Default is ETC.
-# LOCAL_MODULE_PATH / LOCAL_MODULE_RELATIVE_PATH: required. (Relative) path of output file.
-#       If not defined, LOCAL_MODULE_RELATIVE_PATH will be "vintf".
-# LOCAL_MODULE_STEM: optional. Name of output file. Default is $(LOCAL_MODULE).
-# LOCAL_SRC_FILES: required. Local source files provided to assemble_vintf
-#       (command line argument -i).
-# LOCAL_GENERATED_SOURCES: optional. Global source files provided to assemble_vintf
-#       (command line argument -i).
-#
-# LOCAL_ADD_VBMETA_VERSION: Use AVBTOOL to add avb version to the output matrix
-#       (corresponds to <avb><vbmeta-version> tag)
-# LOCAL_ASSEMBLE_VINTF_ENV_VARS: Add a list of environment variable names from global variables in
-#       the build system that is lazily evaluated (e.g. PRODUCT_ENFORCE_VINTF_MANIFEST).
-# LOCAL_ASSEMBLE_VINTF_ENV_VARS_OVERRIDE: Add a list of environment variables that is local to
-#       assemble_vintf invocation. Format is "VINTF_ENFORCE_NO_UNUSED_HALS=true".
-# LOCAL_ASSEMBLE_VINTF_FLAGS: Add additional command line arguments to assemble_vintf invocation.
-# LOCAL_KERNEL_CONFIG_DATA_PATHS: Paths to search for kernel config requirements. Format for each is
-#       <kernel version x.y.z>:<path that contains android-base*.config>.
-# LOCAL_GEN_FILE_DEPENDENCIES: A list of additional dependencies for the generated file.
-
-ifndef LOCAL_MODULE
-$(error LOCAL_MODULE must be defined.)
-endif
-
-ifndef LOCAL_MODULE_STEM
-LOCAL_MODULE_STEM := $(LOCAL_MODULE)
-endif
-
-ifndef LOCAL_MODULE_CLASS
-LOCAL_MODULE_CLASS := ETC
-endif
-
-ifndef LOCAL_MODULE_PATH
-ifndef LOCAL_MODULE_RELATIVE_PATH
-$(error Either LOCAL_MODULE_PATH or LOCAL_MODULE_RELATIVE_PATH must be defined.)
-endif
-endif
-
-GEN := $(local-generated-sources-dir)/$(LOCAL_MODULE_STEM)
-
-$(GEN): PRIVATE_ENV_VARS := $(LOCAL_ASSEMBLE_VINTF_ENV_VARS)
-$(GEN): PRIVATE_FLAGS := $(LOCAL_ASSEMBLE_VINTF_FLAGS)
-
-$(GEN): $(LOCAL_GEN_FILE_DEPENDENCIES)
-
-ifeq (true,$(strip $(LOCAL_ADD_VBMETA_VERSION)))
-ifeq (true,$(BOARD_AVB_ENABLE))
-$(GEN): $(AVBTOOL)
-# INTERNAL_AVB_SYSTEM_SIGNING_ARGS consists of BOARD_AVB_SYSTEM_KEY_PATH and
-# BOARD_AVB_SYSTEM_ALGORITHM. We should add the dependency of key path, which
-# is a file, here.
-$(GEN): $(BOARD_AVB_SYSTEM_KEY_PATH)
-# Use deferred assignment (=) instead of immediate assignment (:=).
-# Otherwise, cannot get INTERNAL_AVB_SYSTEM_SIGNING_ARGS.
-$(GEN): FRAMEWORK_VBMETA_VERSION = $$("$(AVBTOOL)" add_hashtree_footer \
-                           --print_required_libavb_version \
-                           $(INTERNAL_AVB_SYSTEM_SIGNING_ARGS) \
-                           $(BOARD_AVB_SYSTEM_ADD_HASHTREE_FOOTER_ARGS))
-else
-$(GEN): FRAMEWORK_VBMETA_VERSION := 0.0
-endif # BOARD_AVB_ENABLE
-$(GEN): PRIVATE_ENV_VARS += FRAMEWORK_VBMETA_VERSION
-endif # LOCAL_ADD_VBMETA_VERSION
-
-ifeq (true,$(strip $(LOCAL_ADD_VBMETA_VERSION_OVERRIDE)))
-ifneq ($(BOARD_OTA_FRAMEWORK_VBMETA_VERSION_OVERRIDE),)
-$(GEN): FRAMEWORK_VBMETA_VERSION_OVERRIDE := $(BOARD_OTA_FRAMEWORK_VBMETA_VERSION_OVERRIDE)
-$(GEN): PRIVATE_ENV_VARS += FRAMEWORK_VBMETA_VERSION_OVERRIDE
-endif
-endif
-
-ifneq (,$(strip $(LOCAL_KERNEL_CONFIG_DATA_PATHS)))
-$(GEN): PRIVATE_KERNEL_CONFIG_DATA_PATHS := $(LOCAL_KERNEL_CONFIG_DATA_PATHS)
-$(GEN): $(foreach pair,$(LOCAL_KERNEL_CONFIG_DATA_PATHS),\
-    $(wildcard $(call word-colon,2,$(pair))/android-base*.config))
-$(GEN): PRIVATE_FLAGS += $(foreach pair,$(PRIVATE_KERNEL_CONFIG_DATA_PATHS),\
-	--kernel=$(call word-colon,1,$(pair)):$(call normalize-path-list,\
-		$(wildcard $(call word-colon,2,$(pair))/android-base*.config)))
-endif
-
-my_matrix_src_files := \
-	$(addprefix $(LOCAL_PATH)/,$(LOCAL_SRC_FILES)) \
-	$(LOCAL_GENERATED_SOURCES)
-
-$(GEN): PRIVATE_ADDITIONAL_ENV_VARS := $(LOCAL_ASSEMBLE_VINTF_ENV_VARS_OVERRIDE)
-
-ifneq (,$(strip $(LOCAL_ASSEMBLE_VINTF_ERROR_MESSAGE)))
-$(GEN): PRIVATE_COMMAND_TAIL := || (echo $(strip $(LOCAL_ASSEMBLE_VINTF_ERROR_MESSAGE)) && false)
-endif
-
-$(GEN): PRIVATE_SRC_FILES := $(my_matrix_src_files)
-$(GEN): $(my_matrix_src_files) $(HOST_OUT_EXECUTABLES)/assemble_vintf
-	$(foreach varname,$(PRIVATE_ENV_VARS),\
-		$(if $(findstring $(varname),$(PRIVATE_ADDITIONAL_ENV_VARS)),\
-			$(error $(varname) should not be overridden by LOCAL_ASSEMBLE_VINTF_ENV_VARS_OVERRIDE.)))
-	$(foreach varname,$(PRIVATE_ENV_VARS),$(varname)="$($(varname))") \
-		$(PRIVATE_ADDITIONAL_ENV_VARS) \
-		$(HOST_OUT_EXECUTABLES)/assemble_vintf \
-		-i $(call normalize-path-list,$(PRIVATE_SRC_FILES)) \
-		-o $@ \
-		$(PRIVATE_FLAGS) $(PRIVATE_COMMAND_TAIL)
-
-LOCAL_PREBUILT_MODULE_FILE := $(GEN)
-LOCAL_SRC_FILES :=
-LOCAL_GENERATED_SOURCES :=
-
-include $(LOCAL_PATH)/clear_vars.mk
-my_matrix_src_files :=
-
-include $(BUILD_PREBUILT)
diff --git a/compatibility_matrices/exclude/fcm_exclude.cpp b/compatibility_matrices/exclude/fcm_exclude.cpp
index 08ef49b..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.",
@@ -164,8 +165,10 @@
             // AIDL
             "android.hardware.audio.core.sounddose@1",
             "android.hardware.audio.core.sounddose@2",
+            "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/gnss/aidl/android/hardware/gnss/IGnss.aidl b/gnss/aidl/android/hardware/gnss/IGnss.aidl
index 8a22d6e..aaafe7f 100644
--- a/gnss/aidl/android/hardware/gnss/IGnss.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnss.aidl
@@ -217,10 +217,6 @@
      * Starts a location output stream using the IGnssCallback gnssLocationCb(), following the
      * settings from the most recent call to setPositionMode().
      *
-     * When a location output stream is in progress, calling setPositionMode() does not change the
-     * settings of the current location output stream. stop() and start() must be called to make the
-     * new settings effective.
-     *
      * This output must operate independently of any GNSS location batching operations,
      * see the IGnssBatching for details.
      */
@@ -310,10 +306,6 @@
     /**
      * Sets the GnssPositionMode parameter, its associated recurrence value, the time between fixes,
      * requested fix accuracy, time to first fix.
-     *
-     * If a location output stream is in progress, calling this method does not affect the settings
-     * of current location output stream. stop() and start() must be called to make the new settings
-     * effective.
      */
     void setPositionMode(in PositionModeOptions options);
 
diff --git a/gnss/aidl/vts/gnss_hal_test.cpp b/gnss/aidl/vts/gnss_hal_test.cpp
index 5e2cbe3..0dd8b32 100644
--- a/gnss/aidl/vts/gnss_hal_test.cpp
+++ b/gnss/aidl/vts/gnss_hal_test.cpp
@@ -276,29 +276,35 @@
 }
 
 /*
- * FindStrongFrequentNonGpsSource:
+ * FindStrongFrequentBlockableSource:
  *
- * Search through a GnssSvStatus list for the strongest non-GPS satellite observed enough times
+ * Search through a GnssSvStatus list for the strongest blockable satellite observed enough times
  *
  * returns the strongest source,
  *         or a source with constellation == UNKNOWN if none are found sufficient times
  */
-BlocklistedSource GnssHalTest::FindStrongFrequentNonGpsSource(
+BlocklistedSource GnssHalTest::FindStrongFrequentBlockableSource(
         const std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_list,
         const int min_observations) {
-    return FindStrongFrequentNonGpsSource(convertToAidl(sv_info_list), min_observations);
+    return FindStrongFrequentBlockableSource(convertToAidl(sv_info_list), min_observations);
 }
 
-BlocklistedSource GnssHalTest::FindStrongFrequentNonGpsSource(
+BlocklistedSource GnssHalTest::FindStrongFrequentBlockableSource(
         const std::list<std::vector<IGnssCallback::GnssSvInfo>> sv_info_list,
         const int min_observations) {
     std::map<ComparableBlocklistedSource, SignalCounts> mapSignals;
 
+    bool isCnBuild = Utils::isCnBuild();
+    ALOGD("isCnBuild: %s", isCnBuild ? "true" : "false");
     for (const auto& sv_info_vec : sv_info_list) {
         for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
             const auto& gnss_sv = sv_info_vec[iSv];
             if ((gnss_sv.svFlag & (int)IGnssCallback::GnssSvFlags::USED_IN_FIX) &&
                 (gnss_sv.constellation != GnssConstellationType::GPS)) {
+                if (isCnBuild && (gnss_sv.constellation == GnssConstellationType::BEIDOU)) {
+                    // Do not blocklist BDS on CN builds
+                    continue;
+                }
                 ComparableBlocklistedSource source;
                 source.id.svid = gnss_sv.svid;
                 source.id.constellation = gnss_sv.constellation;
@@ -343,7 +349,7 @@
     return source_to_blocklist.id;
 }
 
-GnssConstellationType GnssHalTest::startLocationAndGetNonGpsConstellation(
+GnssConstellationType GnssHalTest::startLocationAndGetBlockableConstellation(
         const int locations_to_await, const int gnss_sv_info_list_timeout) {
     if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
         return static_cast<GnssConstellationType>(
@@ -360,7 +366,9 @@
     ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)",
           sv_info_list_cbq_size, locations_to_await, location_called_count);
 
-    // Find first non-GPS constellation to blocklist
+    bool isCnBuild = Utils::isCnBuild();
+    ALOGD("isCnBuild: %s", isCnBuild ? "true" : "false");
+    // Find first blockable constellation to blocklist
     GnssConstellationType constellation_to_blocklist = GnssConstellationType::UNKNOWN;
     for (int i = 0; i < sv_info_list_cbq_size; ++i) {
         std::vector<IGnssCallback::GnssSvInfo> sv_info_vec;
@@ -370,7 +378,11 @@
             if ((gnss_sv.svFlag & (uint32_t)IGnssCallback::GnssSvFlags::USED_IN_FIX) &&
                 (gnss_sv.constellation != GnssConstellationType::UNKNOWN) &&
                 (gnss_sv.constellation != GnssConstellationType::GPS)) {
-                // found a non-GPS constellation
+                if (isCnBuild && (gnss_sv.constellation == GnssConstellationType::BEIDOU)) {
+                    // Do not blocklist BDS on CN builds
+                    continue;
+                }
+                // found a blockable constellation
                 constellation_to_blocklist = gnss_sv.constellation;
                 break;
             }
@@ -381,11 +393,11 @@
     }
 
     if (constellation_to_blocklist == GnssConstellationType::UNKNOWN) {
-        ALOGI("No non-GPS constellations found, constellation blocklist test less effective.");
+        ALOGI("No blockable constellations found, constellation blocklist test less effective.");
         // Proceed functionally to blocklist something.
         constellation_to_blocklist = GnssConstellationType::GLONASS;
     }
-
+    ALOGD("Constellation to blocklist: %d", constellation_to_blocklist);
     return constellation_to_blocklist;
 }
 
@@ -462,6 +474,10 @@
         GnssData lastGnssData;
         ASSERT_TRUE(callback->gnss_data_cbq_.retrieve(lastGnssData, timeoutSeconds));
         EXPECT_EQ(callback->gnss_data_cbq_.calledCount(), i + 1);
+        if (i <= 2 && lastGnssData.measurements.size() == 0) {
+            // Allow 3 seconds tolerance for empty measurement
+            continue;
+        }
         ASSERT_TRUE(lastGnssData.measurements.size() > 0);
 
         // Validity check GnssData fields
@@ -507,6 +523,10 @@
         GnssData lastGnssData;
         ASSERT_TRUE(callback->gnss_data_cbq_.retrieve(lastGnssData, timeoutSeconds));
         EXPECT_EQ(callback->gnss_data_cbq_.calledCount(), i + 1);
+        if (i <= 2 && lastGnssData.measurements.size() == 0) {
+            // Allow 3 seconds tolerance to report empty measurement
+            continue;
+        }
         ASSERT_TRUE(lastGnssData.measurements.size() > 0);
 
         // Validity check GnssData fields
diff --git a/gnss/aidl/vts/gnss_hal_test.h b/gnss/aidl/vts/gnss_hal_test.h
index 88d01c1..dec5856 100644
--- a/gnss/aidl/vts/gnss_hal_test.h
+++ b/gnss/aidl/vts/gnss_hal_test.h
@@ -76,16 +76,16 @@
     void StartAndCheckLocations(const int count);
     void StartAndCheckLocations(const int count, const bool start_sv_status, const bool start_nmea);
 
-    android::hardware::gnss::GnssConstellationType startLocationAndGetNonGpsConstellation(
+    android::hardware::gnss::GnssConstellationType startLocationAndGetBlockableConstellation(
             const int locations_to_await, const int gnss_sv_info_list_timeout);
     std::list<std::vector<android::hardware::gnss::IGnssCallback::GnssSvInfo>> convertToAidl(
             const std::list<hidl_vec<android::hardware::gnss::V2_1::IGnssCallback::GnssSvInfo>>&
                     sv_info_list);
-    android::hardware::gnss::BlocklistedSource FindStrongFrequentNonGpsSource(
+    android::hardware::gnss::BlocklistedSource FindStrongFrequentBlockableSource(
             const std::list<hidl_vec<android::hardware::gnss::V2_1::IGnssCallback::GnssSvInfo>>
                     sv_info_list,
             const int min_observations);
-    android::hardware::gnss::BlocklistedSource FindStrongFrequentNonGpsSource(
+    android::hardware::gnss::BlocklistedSource FindStrongFrequentBlockableSource(
             const std::list<std::vector<android::hardware::gnss::IGnssCallback::GnssSvInfo>>
                     sv_info_list,
             const int min_observations);
diff --git a/gnss/aidl/vts/gnss_hal_test_cases.cpp b/gnss/aidl/vts/gnss_hal_test_cases.cpp
index f7408d8..e4890a7 100644
--- a/gnss/aidl/vts/gnss_hal_test_cases.cpp
+++ b/gnss/aidl/vts/gnss_hal_test_cases.cpp
@@ -419,6 +419,10 @@
         ASSERT_TRUE(callback->gnss_data_cbq_.retrieve(lastMeasurement,
                                                       kFirstGnssMeasurementTimeoutSeconds));
         EXPECT_EQ(callback->gnss_data_cbq_.calledCount(), i + 1);
+        if (i <= 2 && lastMeasurement.measurements.size() == 0) {
+            // Allow 3 seconds tolerance for empty measurement
+            continue;
+        }
         ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
 
         // Validity check GnssData fields
@@ -479,6 +483,10 @@
         ASSERT_TRUE(callback->gnss_data_cbq_.retrieve(lastMeasurement,
                                                       kFirstGnssMeasurementTimeoutSeconds));
         EXPECT_EQ(callback->gnss_data_cbq_.calledCount(), i + 1);
+        if (i <= 2 && lastMeasurement.measurements.size() == 0) {
+            // Allow 3 seconds tolerance for empty measurement
+            continue;
+        }
         ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
 
         // Validity check GnssData fields
@@ -657,19 +665,19 @@
                                                          kGnssSvInfoListTimeout);
         ASSERT_EQ(count, sv_info_list_cbq_size);
         source_to_blocklist =
-                FindStrongFrequentNonGpsSource(sv_info_vec_list, kLocationsToAwait - 1);
+                FindStrongFrequentBlockableSource(sv_info_vec_list, kLocationsToAwait - 1);
     } else {
         std::list<std::vector<IGnssCallback::GnssSvInfo>> sv_info_vec_list;
         int count = aidl_gnss_cb_->sv_info_list_cbq_.retrieve(
                 sv_info_vec_list, sv_info_list_cbq_size, kGnssSvInfoListTimeout);
         ASSERT_EQ(count, sv_info_list_cbq_size);
         source_to_blocklist =
-                FindStrongFrequentNonGpsSource(sv_info_vec_list, kLocationsToAwait - 1);
+                FindStrongFrequentBlockableSource(sv_info_vec_list, kLocationsToAwait - 1);
     }
 
     if (source_to_blocklist.constellation == GnssConstellationType::UNKNOWN) {
-        // Cannot find a non-GPS satellite. Let the test pass.
-        ALOGD("Cannot find a non-GPS satellite. Letting the test pass.");
+        // Cannot find a blockable satellite. Let the test pass.
+        ALOGD("Cannot find a blockable satellite. Letting the test pass.");
         return;
     }
 
@@ -816,8 +824,8 @@
  * BlocklistConstellationLocationOff:
  *
  * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
- * GnssStatus for any non-GPS constellations.
- * 2a & b) Turns off location, and blocklist first non-GPS constellations.
+ * GnssStatus for any blockable constellations.
+ * 2a & b) Turns off location, and blocklist first blockable constellations.
  * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
  * GnssStatus does not use any constellation but GPS.
  * 4a & b) Clean up by turning off location, and send in empty blocklist.
@@ -833,9 +841,9 @@
     const int kLocationsToAwait = 3;
     const int kGnssSvInfoListTimeout = 2;
 
-    // Find first non-GPS constellation to blocklist
+    // Find first blockable constellation to blocklist
     GnssConstellationType constellation_to_blocklist = static_cast<GnssConstellationType>(
-            startLocationAndGetNonGpsConstellation(kLocationsToAwait, kGnssSvInfoListTimeout));
+            startLocationAndGetBlockableConstellation(kLocationsToAwait, kGnssSvInfoListTimeout));
 
     // Turns off location
     StopAndClearLocations();
@@ -919,8 +927,8 @@
  * BlocklistConstellationLocationOn:
  *
  * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
- * GnssStatus for any non-GPS constellations.
- * 2a & b) Blocklist first non-GPS constellation, and turn off location.
+ * GnssStatus for any blockable constellations.
+ * 2a & b) Blocklist first blockable constellation, and turn off location.
  * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
  * GnssStatus does not use any constellation but GPS.
  * 4a & b) Clean up by turning off location, and send in empty blocklist.
@@ -936,9 +944,9 @@
     const int kLocationsToAwait = 3;
     const int kGnssSvInfoListTimeout = 2;
 
-    // Find first non-GPS constellation to blocklist
+    // Find first blockable constellation to blocklist
     GnssConstellationType constellation_to_blocklist = static_cast<GnssConstellationType>(
-            startLocationAndGetNonGpsConstellation(kLocationsToAwait, kGnssSvInfoListTimeout));
+            startLocationAndGetBlockableConstellation(kLocationsToAwait, kGnssSvInfoListTimeout));
 
     BlocklistedSource source_to_blocklist_1;
     source_to_blocklist_1.constellation = constellation_to_blocklist;
@@ -1335,7 +1343,10 @@
         ASSERT_TRUE(callback->gnss_data_cbq_.retrieve(lastMeasurement,
                                                       kFirstGnssMeasurementTimeoutSeconds));
         EXPECT_EQ(callback->gnss_data_cbq_.calledCount(), i + 1);
-        ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
+        if (i > 2) {
+            // Allow 3 seconds tolerance for empty measurement
+            ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
+        }
 
         // Validity check GnssData fields
         checkGnssMeasurementClockFields(lastMeasurement);
@@ -1790,6 +1801,10 @@
         GnssData lastGnssData;
         ASSERT_TRUE(callback->gnss_data_cbq_.retrieve(lastGnssData, 10));
         EXPECT_EQ(callback->gnss_data_cbq_.calledCount(), i + 1);
+        if (i <= 2 && lastGnssData.measurements.size() == 0) {
+            // Allow 3 seconds tolerance to report empty measurement
+            continue;
+        }
         ASSERT_TRUE(lastGnssData.measurements.size() > 0);
 
         // Validity check GnssData fields
diff --git a/gnss/common/utils/vts/Utils.cpp b/gnss/common/utils/vts/Utils.cpp
index e3ff0f3..38afaf3 100644
--- a/gnss/common/utils/vts/Utils.cpp
+++ b/gnss/common/utils/vts/Utils.cpp
@@ -319,6 +319,24 @@
     return d * 1000;  // meters
 }
 
+// Returns true iff the device has the specified feature.
+bool Utils::deviceSupportsFeature(const char* feature) {
+    bool device_supports_feature = false;
+    FILE* p = popen("/system/bin/pm list features", "re");
+    if (p) {
+        char* line = NULL;
+        size_t len = 0;
+        while (getline(&line, &len, p) > 0) {
+            if (strstr(line, feature)) {
+                device_supports_feature = true;
+                break;
+            }
+        }
+        pclose(p);
+    }
+    return device_supports_feature;
+}
+
 }  // namespace common
 }  // namespace gnss
 }  // namespace hardware
diff --git a/gnss/common/utils/vts/include/Utils.h b/gnss/common/utils/vts/include/Utils.h
index 62d409a..09b99c4 100644
--- a/gnss/common/utils/vts/include/Utils.h
+++ b/gnss/common/utils/vts/include/Utils.h
@@ -60,6 +60,11 @@
     static bool isAutomotiveDevice();
     static double distanceMeters(double lat1, double lon1, double lat2, double lon2);
 
+    // Returns true iff the device has the specified feature.
+    static bool deviceSupportsFeature(const char* feature);
+
+    static bool isCnBuild() { return deviceSupportsFeature("cn.google.services"); }
+
   private:
     template <class T>
     static int64_t getLocationTimestampMillis(const T&);
diff --git a/graphics/Android.bp b/graphics/Android.bp
index cae5292..c33f7ff 100644
--- a/graphics/Android.bp
+++ b/graphics/Android.bp
@@ -53,13 +53,15 @@
 cc_defaults {
     name: "android.hardware.graphics.composer3-ndk_static",
     static_libs: [
-        "android.hardware.graphics.composer3-V3-ndk",
+        "android.hardware.drm.common-V1-ndk",
+        "android.hardware.graphics.composer3-V4-ndk",
     ],
 }
 
 cc_defaults {
     name: "android.hardware.graphics.composer3-ndk_shared",
     shared_libs: [
-        "android.hardware.graphics.composer3-V3-ndk",
+        "android.hardware.drm.common-V1-ndk",
+        "android.hardware.graphics.composer3-V4-ndk",
     ],
 }
diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp
index 4f5c3d9..c28da4c 100644
--- a/graphics/common/aidl/Android.bp
+++ b/graphics/common/aidl/Android.bp
@@ -24,15 +24,18 @@
         java: {
             enabled: true,
             platform_apis: true,
+            apex_available: [
+                "//apex_available:anyapex",
+                "//apex_available:platform",
+            ],
         },
         cpp: {
             enabled: false,
         },
         ndk: {
             apex_available: [
+                "//apex_available:anyapex",
                 "//apex_available:platform",
-                "com.android.media.swcodec",
-                "com.android.neuralnetworks",
             ],
             min_sdk_version: "29",
         },
diff --git a/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
index 6a45987..9ce6eed 100644
--- a/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
+++ b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
@@ -21,8 +21,7 @@
 #warn "ComposerCommandBuffer.h included without LOG_TAG"
 #endif
 
-#undef LOG_NDEBUG
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 
 #include <algorithm>
 #include <limits>
diff --git a/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h b/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h
index 00f427a..cd47374 100644
--- a/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h
+++ b/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h
@@ -20,8 +20,7 @@
 #warn "ComposerCommandBuffer.h included without LOG_TAG"
 #endif
 
-#undef LOG_NDEBUG
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 
 #include <algorithm>
 #include <limits>
diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp
index 7157862..3b0a597 100644
--- a/graphics/composer/2.2/utils/vts/Android.bp
+++ b/graphics/composer/2.2/utils/vts/Android.bp
@@ -39,6 +39,7 @@
     shared_libs: [
         "libui",
         "server_configurable_flags",
+        "libtracing_perfetto",
     ],
     static_libs: [
         "android.hardware.graphics.composer@2.1-vts",
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index bda4198..431b1b6 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -55,6 +55,7 @@
         "libui",
         "android.hardware.common-V2-ndk",
         "server_configurable_flags",
+        "libtracing_perfetto",
     ],
     static_libs: [
         "android.hardware.graphics.common@1.1",
diff --git a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
index 5e9a287..1a9276c 100644
--- a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
+++ b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
@@ -20,8 +20,7 @@
 #warn "ComposerCommandBuffer.h included without LOG_TAG"
 #endif
 
-#undef LOG_NDEBUG
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 
 #include <android/hardware/graphics/composer/2.3/IComposer.h>
 #include <android/hardware/graphics/composer/2.3/IComposerClient.h>
diff --git a/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h
index eb35e5c..e981da6 100644
--- a/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h
+++ b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h
@@ -20,8 +20,7 @@
 #warn "ComposerCommandBuffer.h included without LOG_TAG"
 #endif
 
-#undef LOG_NDEBUG
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 
 #include <android/hardware/graphics/composer/2.4/IComposer.h>
 #include <android/hardware/graphics/composer/2.4/IComposerClient.h>
diff --git a/graphics/composer/aidl/Android.bp b/graphics/composer/aidl/Android.bp
index c4e6878..1728f78 100644
--- a/graphics/composer/aidl/Android.bp
+++ b/graphics/composer/aidl/Android.bp
@@ -29,7 +29,7 @@
     host_supported: true,
     vendor_available: true,
     double_loadable: true,
-    frozen: true,
+    frozen: false,
     srcs: [
         "android/hardware/graphics/composer3/*.aidl",
     ],
@@ -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/CommandResultPayload.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/CommandResultPayload.aidl
index 6892f06..0fff523 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/CommandResultPayload.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/CommandResultPayload.aidl
@@ -41,4 +41,5 @@
   android.hardware.graphics.composer3.ReleaseFences releaseFences;
   android.hardware.graphics.composer3.PresentOrValidate presentOrValidateResult;
   android.hardware.graphics.composer3.ClientTargetPropertyWithBrightness clientTargetProperty;
+  android.hardware.graphics.composer3.DisplayLuts displayLuts;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/NextEnrollment.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayLuts.aidl
similarity index 84%
rename from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/NextEnrollment.aidl
rename to graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayLuts.aidl
index 75ed070..327e84c 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/NextEnrollment.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayLuts.aidl
@@ -5,7 +5,7 @@
  * 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
+ *     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,
@@ -31,11 +31,13 @@
 // 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.graphics.composer3;
 @VintfStability
-parcelable NextEnrollment {
-  int id;
-  android.hardware.biometrics.fingerprint.EnrollmentProgressStep[] progressSteps;
-  boolean result = true;
+parcelable DisplayLuts {
+  long display;
+  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/LayerCommand.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl
index 87c8c18..8b2b13c 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl
@@ -57,4 +57,5 @@
   @nullable int[] bufferSlotsToClear;
   android.hardware.graphics.composer3.LayerLifecycleBatchCommandType layerLifecycleBatchCommandType;
   int newBufferSlotCount;
+  @nullable android.hardware.graphics.composer3.Lut[] luts;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Lut.aidl
similarity index 85%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Lut.aidl
index 173ac17..5fae35b 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Lut.aidl
@@ -5,7 +5,7 @@
  * 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
+ *     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,
@@ -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.graphics.composer3;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable Lut {
+  @nullable ParcelFileDescriptor pfd;
+  android.hardware.graphics.composer3.LutProperties lutProperties;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/NextEnrollment.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LutProperties.aidl
similarity index 79%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/NextEnrollment.aidl
copy to graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LutProperties.aidl
index 75ed070..5edceb5 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/NextEnrollment.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LutProperties.aidl
@@ -5,7 +5,7 @@
  * 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
+ *     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,
@@ -31,11 +31,20 @@
 // 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.graphics.composer3;
 @VintfStability
-parcelable NextEnrollment {
-  int id;
-  android.hardware.biometrics.fingerprint.EnrollmentProgressStep[] progressSteps;
-  boolean result = true;
+parcelable LutProperties {
+  android.hardware.graphics.composer3.LutProperties.Dimension dimension;
+  long size;
+  android.hardware.graphics.composer3.LutProperties.SamplingKey[] samplingKeys;
+  @VintfStability
+  enum Dimension {
+    ONE_D = 1,
+    THREE_D = 3,
+  }
+  @VintfStability
+  enum SamplingKey {
+    RGB,
+    MAX_RGB,
+  }
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/OverlayProperties.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/OverlayProperties.aidl
index 7d31ea3..dae78fd 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/OverlayProperties.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/OverlayProperties.aidl
@@ -36,6 +36,7 @@
 parcelable OverlayProperties {
   android.hardware.graphics.composer3.OverlayProperties.SupportedBufferCombinations[] combinations;
   boolean supportMixedColorSpaces;
+  @nullable android.hardware.graphics.composer3.LutProperties[] lutProperties;
   parcelable SupportedBufferCombinations {
     android.hardware.graphics.common.PixelFormat[] pixelFormats;
     android.hardware.graphics.common.Dataspace[] standards;
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/CommandResultPayload.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/CommandResultPayload.aidl
index 99c91aa..94fc3d0 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/CommandResultPayload.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/CommandResultPayload.aidl
@@ -19,6 +19,7 @@
 import android.hardware.graphics.composer3.ChangedCompositionTypes;
 import android.hardware.graphics.composer3.ClientTargetPropertyWithBrightness;
 import android.hardware.graphics.composer3.CommandError;
+import android.hardware.graphics.composer3.DisplayLuts;
 import android.hardware.graphics.composer3.DisplayRequest;
 import android.hardware.graphics.composer3.PresentFence;
 import android.hardware.graphics.composer3.PresentOrValidate;
@@ -96,4 +97,13 @@
      * the SDR buffers when an HDR layer is simultaneously device-composited.
      */
     ClientTargetPropertyWithBrightness clientTargetProperty;
+
+    /**
+     * Sets the Lut(s) for the layers.
+     *
+     * HWC should only request Lut(s) if SurfaceFlinger does not send the Lut(s) to the HWC.
+     * The main use-case is like HDR10+ or Dolby Vision where there is no Lut to send from
+     * SurfaceFlinger.
+     */
+    DisplayLuts displayLuts;
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayLuts.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayLuts.aidl
new file mode 100644
index 0000000..ac0a606
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayLuts.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+import android.hardware.graphics.composer3.Lut;
+
+/**
+ * LUT (Look-Up Table) Interface for Color Transformation.
+ *
+ * This interface allows the HWC (Hardware Composer) to define and communicate Luts
+ * to SurfaceFlinger.
+ */
+@VintfStability
+parcelable DisplayLuts {
+    /**
+     * The display which the layerLuts list is for.
+     */
+    long display;
+
+    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/LayerCommand.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl
index e961c48..bf4f504 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl
@@ -24,6 +24,7 @@
 import android.hardware.graphics.composer3.Color;
 import android.hardware.graphics.composer3.LayerBrightness;
 import android.hardware.graphics.composer3.LayerLifecycleBatchCommandType;
+import android.hardware.graphics.composer3.Lut;
 import android.hardware.graphics.composer3.ParcelableBlendMode;
 import android.hardware.graphics.composer3.ParcelableComposition;
 import android.hardware.graphics.composer3.ParcelableDataspace;
@@ -279,4 +280,9 @@
      * Specifies the number of buffer slot to be reserved.
      */
     int newBufferSlotCount;
+
+    /**
+     * Sets the lut(s) for the layer.
+     */
+    @nullable Lut[] luts;
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/Lut.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/Lut.aidl
new file mode 100644
index 0000000..abfeb14
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/Lut.aidl
@@ -0,0 +1,56 @@
+/*
+ * 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.graphics.composer3;
+
+import android.hardware.graphics.composer3.LutProperties;
+
+/**
+ * LUT (Look-Up Table) Interface for Color Transformation.
+ *
+ * This interface allows the HWC (Hardware Composer) to define and communicate LUTs
+ * with SurfaceFlinger.
+ */
+
+@VintfStability
+parcelable Lut {
+    /**
+     * A handle to a memory region.
+     * If the file descriptor is not set, this means that the HWC doesn't specify a Lut.
+     *
+     * When specifying a Lut, the HWC is required to follow the instructions as below:
+     * 1. use `memfd_create` to create a shared memory segment
+     *    with the size specified in lutProperties.
+     * 2. use `mmap` to map the shared memory segment into its own virtual address space.
+     *    PROT_READ/PROT_WRITE recommended for prot argument.
+     *
+     * For data precision, 32-bit float is used to specify a Lut by both the HWC and
+     * the platform.
+     *
+     * For unflattening/flattening 3D Lut(s), the algorithm below should be observed
+     * by both the HWC and the platform.
+     * Assuming that we have a 3D array `ORIGINAL[WIDTH, HEIGHT, DEPTH]`, we would turn it into
+     * `FLAT[WIDTH * HEIGHT * DEPTH]` by
+     *
+     * `FLAT[z + DEPTH * (y + HEIGHT * x)] = ORIGINAL[x, y, z]`
+     */
+    @nullable ParcelFileDescriptor pfd;
+
+    /**
+     * The properties of the Lut.
+     */
+    LutProperties lutProperties;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/LutProperties.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/LutProperties.aidl
new file mode 100644
index 0000000..47ec390
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/LutProperties.aidl
@@ -0,0 +1,48 @@
+/*
+ * 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.graphics.composer3;
+
+/**
+ * The properties of the LUT (Look-Up Table).
+ */
+@VintfStability
+parcelable LutProperties {
+    /**
+     * The dimension of the Lut.
+     * Either 1d or 3d.
+     */
+    @VintfStability enum Dimension { ONE_D = 1, THREE_D = 3 }
+    Dimension dimension;
+
+    /**
+     * The size of the Lut.
+     * This refers to the length of a 1D Lut, or the grid size of a 3D one.
+     */
+    long size;
+
+    /**
+     * SamplingKey is about how a Lut can be sampled.
+     * A Lut can be sampled in more than one way,
+     * but only one sampling method is used at one time.
+     *
+     * The implementations should use a sampling strategy
+     * at least as good as linear sampling.
+     */
+    // TODO(b/358422255): add sampling ways
+    @VintfStability enum SamplingKey { RGB, MAX_RGB }
+    SamplingKey[] samplingKeys;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/OverlayProperties.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/OverlayProperties.aidl
index c25eea4..b97cdcc 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/OverlayProperties.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/OverlayProperties.aidl
@@ -16,6 +16,8 @@
 
 package android.hardware.graphics.composer3;
 
+import android.hardware.graphics.composer3.LutProperties;
+
 @VintfStability
 parcelable OverlayProperties {
     parcelable SupportedBufferCombinations {
@@ -42,4 +44,8 @@
     // True if the DPU is able to color manage at least two overlays
     // with different input colorspaces, false otherwise.
     boolean supportMixedColorSpaces;
+
+    // Array of lut properties in order that the HWC supports.
+    // The list accepts 1D lut(s) and 3D lut(s).
+    @nullable LutProperties[] lutProperties;
 }
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 76ba24b..331d717 100644
--- a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h
+++ b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h
@@ -27,9 +27,8 @@
 #include <string.h>
 
 #include <aidl/android/hardware/graphics/composer3/ClientTargetProperty.h>
-#include <aidl/android/hardware/graphics/composer3/Composition.h>
 #include <aidl/android/hardware/graphics/composer3/CommandResultPayload.h>
-
+#include <aidl/android/hardware/graphics/composer3/Composition.h>
 
 #include <log/log.h>
 #include <sync/sync.h>
@@ -84,6 +83,10 @@
                     parseSetClientTargetProperty(std::move(
                             result.get<CommandResultPayload::Tag::clientTargetProperty>()));
                     break;
+                case CommandResultPayload::Tag::displayLuts:
+                    parseSetDisplayLuts(
+                            std::move(result.get<CommandResultPayload::Tag::displayLuts>()));
+                    break;
             }
         }
     }
@@ -182,6 +185,20 @@
         return std::move(data.clientTargetProperty);
     }
 
+    // Get the lut(s) requested by hardware composer.
+    std::vector<DisplayLuts::LayerLut> takeDisplayLuts(int64_t display) {
+        LOG_ALWAYS_FATAL_IF(mDisplay && display != *mDisplay);
+        auto found = mReturnData.find(display);
+
+        // If not found, return the empty vector
+        if (found == mReturnData.end()) {
+            return {};
+        }
+
+        ReturnData& data = found->second;
+        return std::move(data.layerLuts);
+    }
+
   private:
     void resetData() {
         mErrors.clear();
@@ -227,6 +244,18 @@
         data.clientTargetProperty = std::move(clientTargetProperty);
     }
 
+    void parseSetDisplayLuts(DisplayLuts&& displayLuts) {
+        LOG_ALWAYS_FATAL_IF(mDisplay && displayLuts.display != *mDisplay);
+        auto& data = mReturnData[displayLuts.display];
+        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}});
+            }
+        }
+    }
+
     struct ReturnData {
         DisplayRequest displayRequests;
         std::vector<ChangedCompositionLayer> changedLayers;
@@ -238,6 +267,7 @@
                 .clientTargetProperty = {common::PixelFormat::RGBA_8888, Dataspace::UNKNOWN},
                 .brightness = 1.f,
         };
+        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 3464fe9..894ca52 100644
--- a/graphics/composer/aidl/vts/Android.bp
+++ b/graphics/composer/aidl/vts/Android.bp
@@ -57,6 +57,7 @@
         "libprocessgroup",
         "libvndksupport",
         "server_configurable_flags",
+        "libtracing_perfetto",
     ],
     header_libs: [
         "android.hardware.graphics.composer3-command-buffer",
@@ -65,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/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
index ba15421..eaf23b5 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
@@ -1845,7 +1845,7 @@
         writer.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 0.5f, -1.f);
         execute();
         const auto errors = mReader.takeErrors();
-        EXPECT_EQ(1, errors.size());
+        ASSERT_EQ(1, errors.size());
         EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, errors[0].errorCode);
         GTEST_SUCCEED() << "SetDisplayBrightness is not supported";
         return;
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index bae362f..f398c53 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -719,6 +719,38 @@
 }
 
 /**
+ * Test IMapper::lock and IMapper::unlock with no CPU usage requested.
+ */
+TEST_P(GraphicsMapperHidlTest, LockUnlockNoCPUUsage) {
+    const auto& info = mDummyDescriptorInfo;
+
+    const native_handle_t* bufferHandle;
+    uint32_t stride;
+    ASSERT_NO_FATAL_FAILURE(
+            bufferHandle = mGralloc->allocate(info, true, Tolerance::kToleranceStrict, &stride));
+
+    // lock buffer with 0 usage
+    const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+                               static_cast<int32_t>(info.height)};
+
+    hidl_handle acquireFenceHandle;
+
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+    mGralloc->getMapper()->lock(buffer, 0, region, acquireFenceHandle,
+                                [&](const auto& tmpError, const auto& /*tmpData*/) {
+                                    EXPECT_EQ(Error::BAD_VALUE, tmpError)
+                                            << "Locking with 0 access succeeded";
+                                });
+
+    mGralloc->getMapper()->unlock(buffer, [&](const auto& tmpError, const auto&) {
+        EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+                << "Unlocking not locked buffer succeeded";
+    });
+
+    mGralloc->freeBuffer(bufferHandle);
+}
+
+/**
  *  Test multiple operations associated with different color formats
  */
 TEST_P(GraphicsMapperHidlTest, Lock_YCRCB_420_SP) {
diff --git a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
index 1e0c427..bdbe4d0 100644
--- a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
+++ b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
@@ -750,6 +750,42 @@
 }
 
 /**
+ * Test IMapper::lock and IMapper::unlock with no CPU usage requested.
+ */
+TEST_P(GraphicsMapperStableCTests, LockUnlockNoCPUUsage) {
+    constexpr auto usage = BufferUsage::CPU_READ_NEVER | BufferUsage::CPU_WRITE_NEVER;
+    auto buffer = allocate({
+            .name = {"VTS_TEMP"},
+            .width = 64,
+            .height = 64,
+            .layerCount = 1,
+            .format = PixelFormat::RGBA_8888,
+            .usage = usage,
+            .reservedSize = 0,
+    });
+    ASSERT_NE(nullptr, buffer.get());
+
+    // lock buffer for writing
+    const auto& info = buffer->info();
+    const ARect region{0, 0, info.width, info.height};
+    auto handle = buffer->import();
+    uint8_t* data = nullptr;
+
+    EXPECT_EQ(AIMAPPER_ERROR_BAD_VALUE,
+              mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+                                region, -1,(void**)&data))
+              << "Locking with 0 access succeeded";
+
+    int releaseFence = -1;
+    EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER,
+              mapper()->v5.unlock(*handle, &releaseFence))
+              << "Unlocking not locked buffer succeeded";
+    if (releaseFence != -1) {
+        close(releaseFence);
+    }
+}
+
+/**
  *  Test multiple operations associated with different color formats
  */
 TEST_P(GraphicsMapperStableCTests, Lock_YCRCB_420_SP) {
diff --git a/health/2.1/default/Android.bp b/health/2.1/default/Android.bp
index b7bcea5..00d89e2 100644
--- a/health/2.1/default/Android.bp
+++ b/health/2.1/default/Android.bp
@@ -81,7 +81,7 @@
     ],
 
     vintf_fragments: [
-        "android.hardware.health@2.1.xml"
+        "android.hardware.health@2.1.xml",
     ],
 
     overrides: [
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/Android.bp b/health/utils/libhealthloop/Android.bp
index 7aaf905..4ebc575 100644
--- a/health/utils/libhealthloop/Android.bp
+++ b/health/utils/libhealthloop/Android.bp
@@ -21,6 +21,17 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
+bpf {
+    name: "filterPowerSupplyEvents.o",
+    srcs: ["filterPowerSupplyEvents.c"],
+    // "vendor: true" because all binaries that use this BPF filter are vendor
+    // binaries.
+    vendor: true,
+}
+
+// Since "required" sections are ignored in static library definitions,
+// filterPowerSupplyEvents.o has been added in
+// build/make/target/product/base_vendor.mk.
 cc_library_static {
     name: "libhealthloop",
     vendor_available: true,
@@ -30,10 +41,11 @@
         "utils.cpp",
     ],
     shared_libs: [
-        "libcutils",
         "libbase",
+        "libcutils",
     ],
     header_libs: [
+        "bpf_headers",
         "libbatteryservice_headers",
         "libhealthd_headers",
         "libutils_headers",
@@ -42,3 +54,30 @@
         "include",
     ],
 }
+
+genrule {
+    name: "filterPowerSupplyEvents.h",
+    out: ["filterPowerSupplyEvents.h"],
+    srcs: [":filterPowerSupplyEvents.o"],
+    cmd: "cat $(in) | od -v -tx1 | cut -c9- | grep -v '^$$' | sed 's/^/0x/;s/ /, 0x/g;s/^, //;s/$$/,/' > $(out)",
+}
+
+cc_test_host {
+    name: "filterPowerSupplyEventsTest",
+    team: "trendy_team_pixel_system_sw_storage",
+    srcs: [
+        "filterPowerSupplyEventsTest.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbpf",
+    ],
+    static_libs: [
+        "libgmock",
+    ],
+    generated_headers: [
+        "filterPowerSupplyEvents.h",
+        "libbpf_headers",
+    ],
+    compile_multilib: "64",
+}
diff --git a/health/utils/libhealthloop/HealthLoop.cpp b/health/utils/libhealthloop/HealthLoop.cpp
index 4190769..c5ad5a8 100644
--- a/health/utils/libhealthloop/HealthLoop.cpp
+++ b/health/utils/libhealthloop/HealthLoop.cpp
@@ -20,23 +20,22 @@
 #include <health/HealthLoop.h>
 
 #include <errno.h>
-#include <libgen.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/epoll.h>
+#include <sys/epoll.h>  // epoll_create1(), epoll_ctl(), epoll_wait()
 #include <sys/timerfd.h>
-#include <unistd.h>
+#include <unistd.h>  // read()
 
 #include <android-base/logging.h>
 #include <batteryservice/BatteryService.h>
-#include <cutils/klog.h>
+#include <cutils/klog.h>  // KLOG_*()
 #include <cutils/uevent.h>
 #include <healthd/healthd.h>
-#include <utils/Errors.h>
 
+#include <BpfSyscallWrappers.h>
 #include <health/utils.h>
 
+using android::base::ErrnoError;
+using android::base::Result;
+using android::base::unique_fd;
 using namespace android;
 using namespace std::chrono_literals;
 
@@ -44,6 +43,8 @@
 namespace hardware {
 namespace health {
 
+static constexpr uint32_t kUeventMsgLen = 2048;
+
 HealthLoop::HealthLoop() {
     InitHealthdConfig(&healthd_config_);
     awake_poll_interval_ = -1;
@@ -57,19 +58,18 @@
 int HealthLoop::RegisterEvent(int fd, BoundFunction func, EventWakeup wakeup) {
     CHECK(!reject_event_register_);
 
-    auto* event_handler =
-            event_handlers_
-                    .emplace_back(std::make_unique<EventHandler>(EventHandler{this, fd, func}))
-                    .get();
+    auto* event_handler = event_handlers_
+                                  .emplace_back(std::make_unique<EventHandler>(
+                                          EventHandler{this, fd, std::move(func)}))
+                                  .get();
 
-    struct epoll_event ev;
-
-    ev.events = EPOLLIN;
+    struct epoll_event ev = {
+        .events = EPOLLIN | EPOLLERR,
+        .data.ptr = reinterpret_cast<void*>(event_handler),
+    };
 
     if (wakeup == EVENT_WAKEUP_FD) ev.events |= EPOLLWAKEUP;
 
-    ev.data.ptr = reinterpret_cast<void*>(event_handler);
-
     if (epoll_ctl(epollfd_, EPOLL_CTL_ADD, fd, &ev) == -1) {
         KLOG_ERROR(LOG_TAG, "epoll_ctl failed; errno=%d\n", errno);
         return -1;
@@ -122,38 +122,65 @@
     ScheduleBatteryUpdate();
 }
 
-// TODO(b/140330870): Use BPF instead.
-#define UEVENT_MSG_LEN 2048
-void HealthLoop::UeventEvent(uint32_t /*epevents*/) {
-    // No need to lock because uevent_fd_ is guaranteed to be initialized.
-
-    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();
+    }
+}
+
+// Attach a BPF filter to the @uevent_fd file descriptor. This fails in recovery mode because BPF is
+// not supported in recovery mode. This fails for kernel versions 5.4 and before because the BPF
+// program is rejected by the BPF verifier of older kernels.
+Result<void> HealthLoop::AttachFilter(int uevent_fd) {
+    static const char prg[] =
+            "/sys/fs/bpf/vendor/prog_filterPowerSupplyEvents_skfilter_power_supply";
+    int filter_fd(bpf::retrieveProgram(prg));
+    if (filter_fd < 0) {
+        return ErrnoError() << "failed to load BPF program " << prg;
+    }
+    if (setsockopt(uevent_fd, SOL_SOCKET, SO_ATTACH_BPF, &filter_fd, sizeof(filter_fd)) < 0) {
+        close(filter_fd);
+        return ErrnoError() << "failed to attach BPF program";
+    }
+    close(filter_fd);
+    return {};
+}
+
 void HealthLoop::UeventInit(void) {
-    uevent_fd_.reset(uevent_open_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");
@@ -161,8 +188,25 @@
     }
 
     fcntl(uevent_fd_, F_SETFL, O_NONBLOCK);
+
+    Result<void> attach_result = AttachFilter(uevent_fd_);
+    if (!attach_result.ok()) {
+        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\n", error_msg.c_str());
+    } else {
+        KLOG_INFO(LOG_TAG, "Successfully attached the BPF filter to the uevent socket\n");
+    }
+
     if (RegisterEvent(uevent_fd_, &HealthLoop::UeventEvent, EVENT_WAKEUP_FD))
         KLOG_ERROR(LOG_TAG, "register for uevent events failed\n");
+
+    if (uevent_bind(uevent_fd_.get()) < 0) {
+        uevent_fd_.reset();
+        KLOG_ERROR(LOG_TAG, "uevent_init: binding socket failed\n");
+        return;
+    }
 }
 
 void HealthLoop::WakeAlarmEvent(uint32_t /*epevents*/) {
diff --git a/health/utils/libhealthloop/filterPowerSupplyEvents.c b/health/utils/libhealthloop/filterPowerSupplyEvents.c
new file mode 100644
index 0000000..5296993
--- /dev/null
+++ b/health/utils/libhealthloop/filterPowerSupplyEvents.c
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+#include <bpf_helpers.h>    // load_word()
+#include <linux/bpf.h>      // struct __sk_buff
+#include <linux/netlink.h>  // struct nlmsghdr
+#include <stdint.h>         // uint32_t
+
+// M4: match 4 bytes. Returns 0 if all bytes match.
+static inline uint32_t M4(struct __sk_buff* skb, unsigned int offset, uint8_t c0, uint8_t c1,
+                          uint8_t c2, uint8_t c3) {
+    return load_word(skb, offset) ^ ((c0 << 24) | (c1 << 16) | (c2 << 8) | c3);
+}
+
+// M2: match 2 bytes. Returns 0 if all bytes match.
+static inline uint16_t M2(struct __sk_buff* skb, unsigned int offset, uint8_t c0, uint8_t c1) {
+    return load_half(skb, offset) ^ ((c0 << 8) | c1);
+}
+
+// M1: match 1 byte. Returns 0 in case of a match.
+static inline uint8_t M1(struct __sk_buff* skb, unsigned int offset, uint8_t c0) {
+    return load_byte(skb, offset) ^ c0;
+}
+
+// Match "\0SUBSYSTEM=". Returns 0 in case of a match.
+#define MATCH_SUBSYSTEM_LENGTH 11
+static inline uint32_t match_subsystem(struct __sk_buff* skb, unsigned int offset) {
+    return M4(skb, offset + 0, '\0', 'S', 'U', 'B') | M4(skb, offset + 4, 'S', 'Y', 'S', 'T') |
+           M2(skb, offset + 8, 'E', 'M') | M1(skb, offset + 10, '=');
+}
+
+// Match "power_supply\0". Returns 0 in case of a match.
+#define MATCH_POWER_SUPPLY_LENGTH 13
+static inline uint32_t match_power_supply(struct __sk_buff* skb, unsigned int offset) {
+    return M4(skb, offset + 0, 'p', 'o', 'w', 'e') | M4(skb, offset + 4, 'r', '_', 's', 'u') |
+           M4(skb, offset + 8, 'p', 'p', 'l', 'y') | M1(skb, offset + 12, '\0');
+}
+
+// The Linux kernel 5.4 BPF verifier rejects this program, probably because of its size. Hence the
+// restriction that the kernel version must be at least 5.10.
+DEFINE_BPF_PROG_KVER("skfilter/power_supply", AID_ROOT, AID_SYSTEM, filterPowerSupplyEvents,
+                     KVER(5, 10, 0))
+(struct __sk_buff* skb) {
+    uint32_t i;
+
+    // The first character matched by match_subsystem() is a '\0'. Starting
+    // right past the netlink message header is fine since the SUBSYSTEM= text
+    // never occurs at the start. See also the kobject_uevent_env() implementation:
+    // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/lib/kobject_uevent.c?#n473
+    // The upper bound of this loop has been chosen not to exceed the maximum
+    // number of instructions in a BPF program (BPF loops are unrolled).
+    for (i = sizeof(struct nlmsghdr); i < 256; ++i) {
+        if (i + MATCH_SUBSYSTEM_LENGTH > skb->len) {
+            break;
+        }
+        if (match_subsystem(skb, i) == 0) {
+            goto found_subsystem;
+        }
+    }
+
+    // The SUBSYSTEM= text has not been found in the bytes that have been
+    // examined: let the user space software perform filtering.
+    return skb->len;
+
+found_subsystem:
+    i += MATCH_SUBSYSTEM_LENGTH;
+    if (i + MATCH_POWER_SUPPLY_LENGTH <= skb->len && match_power_supply(skb, i) == 0) {
+        return skb->len;
+    }
+    return 0;
+}
+
+LICENSE("Apache 2.0");
+CRITICAL("healthd");
diff --git a/health/utils/libhealthloop/filterPowerSupplyEventsTest.cpp b/health/utils/libhealthloop/filterPowerSupplyEventsTest.cpp
new file mode 100644
index 0000000..04b8bcd
--- /dev/null
+++ b/health/utils/libhealthloop/filterPowerSupplyEventsTest.cpp
@@ -0,0 +1,212 @@
+/*
+ * 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.
+ */
+
+#include <android-base/unique_fd.h>
+#include <bpf/libbpf.h>
+#include <gtest/gtest.h>
+#include <linux/bpf.h>  // SO_ATTACH_BPF
+#include <linux/netlink.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <string>
+#include <string_view>
+
+#define ASSERT_UNIX_OK(e) ASSERT_GE(e, 0) << strerror(errno)
+
+// TODO(bvanassche): remove the code below. See also b/357099095.
+#ifndef SO_ATTACH_BPF
+#define SO_ATTACH_BPF 50  // From <asm-generic/socket.h>.
+#endif
+
+using ::android::base::unique_fd;
+using ::testing::ScopedTrace;
+
+struct test_data {
+    bool discarded;
+    std::string_view str;
+};
+
+static const uint8_t binary_bpf_prog[] = {
+#include "filterPowerSupplyEvents.h"
+};
+
+static std::vector<std::unique_ptr<ScopedTrace>>* msg_vec;
+
+std::ostream& operator<<(std::ostream& os, const test_data& td) {
+    os << "{.discarded=" << td.discarded << ", .str=";
+    for (auto c : td.str) {
+        if (isprint(c)) {
+            os << c;
+        } else {
+            os << ".";
+        }
+    }
+    return os << '}';
+}
+
+#define RECORD_ERR_MSG(fmt, ...)                                          \
+    do {                                                                  \
+        char* str;                                                        \
+        if (asprintf(&str, fmt, ##__VA_ARGS__) < 0) break;                \
+        auto st = std::make_unique<ScopedTrace>(__FILE__, __LINE__, str); \
+        msg_vec->emplace_back(std::move(st));                             \
+        free(str);                                                        \
+    } while (0)
+
+int libbpf_print_fn(enum libbpf_print_level, const char* fmt, va_list args) {
+    char* str;
+    if (vasprintf(&str, fmt, args) < 0) {
+        return 0;
+    }
+    msg_vec->emplace_back(std::make_unique<ScopedTrace>(__FILE__, -1, str));
+    free(str);
+    return 0;
+}
+
+static void record_libbpf_output() {
+    libbpf_set_print(libbpf_print_fn);
+}
+
+class filterPseTest : public testing::TestWithParam<test_data> {};
+
+struct ConnectedSockets {
+    unique_fd write_fd;
+    unique_fd read_fd;
+};
+
+// socketpair() only supports AF_UNIX sockets. AF_UNIX sockets do not
+// support BPF filters. Hence connect two TCP sockets with each other.
+static ConnectedSockets ConnectSockets(int domain, int type, int protocol) {
+    int _server_fd = socket(domain, type, protocol);
+    if (_server_fd < 0) {
+        return {};
+    }
+    unique_fd server_fd(_server_fd);
+
+    int _write_fd = socket(domain, type, protocol);
+    if (_write_fd < 0) {
+        RECORD_ERR_MSG("socket: %s", strerror(errno));
+        return {};
+    }
+    unique_fd write_fd(_write_fd);
+
+    struct sockaddr_in sa = {.sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY};
+    if (bind(_server_fd, (const struct sockaddr*)&sa, sizeof(sa)) < 0) {
+        RECORD_ERR_MSG("bind: %s", strerror(errno));
+        return {};
+    }
+    if (listen(_server_fd, 1) < 0) {
+        RECORD_ERR_MSG("listen: %s", strerror(errno));
+        return {};
+    }
+    socklen_t addr_len = sizeof(sa);
+    if (getsockname(_server_fd, (struct sockaddr*)&sa, &addr_len) < 0) {
+        RECORD_ERR_MSG("getsockname: %s", strerror(errno));
+        return {};
+    }
+    errno = 0;
+    if (connect(_write_fd, (const struct sockaddr*)&sa, sizeof(sa)) < 0 && errno != EINPROGRESS) {
+        RECORD_ERR_MSG("connect: %s", strerror(errno));
+        return {};
+    }
+    int _read_fd = accept(_server_fd, NULL, NULL);
+    if (_read_fd < 0) {
+        RECORD_ERR_MSG("accept: %s", strerror(errno));
+        return {};
+    }
+    unique_fd read_fd(_read_fd);
+
+    return {.write_fd = std::move(write_fd), .read_fd = std::move(read_fd)};
+}
+
+TEST_P(filterPseTest, filterPse) {
+    if (getuid() != 0) {
+        GTEST_SKIP() << "Must be run as root.";
+        return;
+    }
+    if (!msg_vec) {
+        msg_vec = new typeof(*msg_vec);
+    }
+    std::unique_ptr<int, void (*)(int*)> clear_msg_vec_at_end_of_scope(new int, [](int* p) {
+        msg_vec->clear();
+        delete p;
+    });
+    record_libbpf_output();
+
+    auto connected_sockets = ConnectSockets(AF_INET, SOCK_STREAM, 0);
+    unique_fd write_fd = std::move(connected_sockets.write_fd);
+    unique_fd read_fd = std::move(connected_sockets.read_fd);
+
+    ASSERT_UNIX_OK(fcntl(read_fd, F_SETFL, O_NONBLOCK));
+
+    bpf_object* obj = bpf_object__open_mem(binary_bpf_prog, sizeof(binary_bpf_prog), NULL);
+    ASSERT_TRUE(obj) << "bpf_object__open() failed" << strerror(errno);
+
+    // Find the BPF program within the object.
+    bpf_program* prog = bpf_object__find_program_by_name(obj, "filterPowerSupplyEvents");
+    ASSERT_TRUE(prog);
+
+    ASSERT_UNIX_OK(bpf_program__set_type(prog, BPF_PROG_TYPE_SOCKET_FILTER));
+
+    ASSERT_UNIX_OK(bpf_object__load(obj));
+
+    int filter_fd = bpf_program__fd(prog);
+    ASSERT_UNIX_OK(filter_fd);
+
+    int setsockopt_result =
+            setsockopt(read_fd, SOL_SOCKET, SO_ATTACH_BPF, &filter_fd, sizeof(filter_fd));
+    ASSERT_UNIX_OK(setsockopt_result);
+
+    const test_data param = GetParam();
+    const std::string header(sizeof(struct nlmsghdr), '\0');
+    ASSERT_EQ(header.length(), sizeof(struct nlmsghdr));
+    const std::string data = header + std::string(param.str);
+    const size_t len = data.length();
+    std::cerr.write(data.data(), data.length());
+    std::cerr << ")\n";
+    ASSERT_EQ(write(write_fd, data.data(), len), len);
+    std::array<uint8_t, 512> read_buf;
+    int bytes_read = read(read_fd, read_buf.data(), read_buf.size());
+    if (bytes_read < 0) {
+        ASSERT_EQ(errno, EAGAIN);
+        bytes_read = 0;
+    } else {
+        ASSERT_LT(bytes_read, read_buf.size());
+    }
+    EXPECT_EQ(bytes_read, param.discarded ? 0 : len);
+
+    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, 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 fc3066e..43c38dc 100644
--- a/health/utils/libhealthloop/include/health/HealthLoop.h
+++ b/health/utils/libhealthloop/include/health/HealthLoop.h
@@ -20,6 +20,7 @@
 #include <mutex>
 #include <vector>
 
+#include <android-base/result.h>
 #include <android-base/unique_fd.h>
 #include <healthd/healthd.h>
 
@@ -87,10 +88,12 @@
     };
 
     int InitInternal();
+    static android::base::Result<void> AttachFilter(int uevent_fd);
     void MainLoop();
     void WakeAlarmInit();
     void WakeAlarmEvent(uint32_t);
     void UeventInit();
+    bool RecvUevents();
     void UeventEvent(uint32_t);
     void WakeAlarmSetInterval(int interval);
     void PeriodicChores();
diff --git a/keymaster/3.0/default/Android.bp b/keymaster/3.0/default/Android.bp
new file mode 100644
index 0000000..4018cc0
--- /dev/null
+++ b/keymaster/3.0/default/Android.bp
@@ -0,0 +1,57 @@
+// 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 {
+    // See: http://go/android-license-faq
+    default_applicable_licenses: [
+        "hardware_interfaces_license",
+    ],
+}
+
+cc_library_shared {
+    name: "android.hardware.keymaster@3.0-impl",
+    proprietary: true,
+    relative_install_path: "hw",
+    srcs: ["KeymasterDevice.cpp"],
+    shared_libs: [
+        "android.hardware.keymaster@3.0",
+        "libcrypto",
+        "libhardware",
+        "libhidlbase",
+        "libkeymaster_portable",
+        "libkeymaster3device",
+        "liblog",
+        "libpuresoftkeymasterdevice",
+        "libsoftkeymasterdevice",
+        "libutils",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.keymaster@3.0-service",
+    relative_install_path: "hw",
+    proprietary: true,
+    init_rc: ["android.hardware.keymaster@3.0-service.rc"],
+    srcs: ["service.cpp"],
+    shared_libs: [
+        "android.hardware.keymaster@3.0",
+        "libbase",
+        "libcutils",
+        "libdl",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+    ],
+}
diff --git a/keymaster/3.0/default/Android.mk b/keymaster/3.0/default/Android.mk
deleted file mode 100644
index 053ad67..0000000
--- a/keymaster/3.0/default/Android.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.keymaster@3.0-impl
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../NOTICE
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_SRC_FILES := \
-    KeymasterDevice.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-    liblog \
-    libsoftkeymasterdevice \
-    libcrypto \
-    libkeymaster_portable \
-    libpuresoftkeymasterdevice \
-    libkeymaster3device \
-    libhidlbase \
-    libutils \
-    libhardware \
-    android.hardware.keymaster@3.0
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_MODULE := android.hardware.keymaster@3.0-service
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../NOTICE
-LOCAL_INIT_RC := android.hardware.keymaster@3.0-service.rc
-LOCAL_SRC_FILES := \
-    service.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    liblog \
-    libcutils \
-    libdl \
-    libbase \
-    libutils \
-    libhardware \
-    libhidlbase \
-    android.hardware.keymaster@3.0
-
-include $(BUILD_EXECUTABLE)
diff --git a/keymaster/aidl/Android.bp b/keymaster/aidl/Android.bp
index 0f2debd..c101f56 100644
--- a/keymaster/aidl/Android.bp
+++ b/keymaster/aidl/Android.bp
@@ -18,6 +18,16 @@
         java: {
             platform_apis: true,
         },
+        ndk: {
+            apex_available: [
+                "com.android.hardware.biometrics.face.virtual",
+                "com.android.hardware.biometrics.fingerprint.virtual",
+                "//apex_available:platform",
+            ],
+        },
+        rust: {
+            enabled: true,
+        },
     },
     versions_with_info: [
         {
diff --git a/media/bufferpool/aidl/default/Accessor.cpp b/media/bufferpool/aidl/default/Accessor.cpp
index 423fd84..81e8eac 100644
--- a/media/bufferpool/aidl/default/Accessor.cpp
+++ b/media/bufferpool/aidl/default/Accessor.cpp
@@ -444,7 +444,7 @@
         std::map<const std::weak_ptr<Accessor>, nsecs_t, std::owner_less<>> &accessors,
         std::mutex &mutex,
         std::condition_variable &cv) {
-    std::list<const std::weak_ptr<Accessor>> evictList;
+    std::list<std::weak_ptr<Accessor>> evictList;
     while (true) {
         int expired = 0;
         int evicted = 0;
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/memtrack/OWNERS b/memtrack/OWNERS
index a182ed9..8017da6 100644
--- a/memtrack/OWNERS
+++ b/memtrack/OWNERS
@@ -1,2 +1,3 @@
-# Bug component: 30545
-connoro@google.com
+# Bug component: 356484
+kaleshsingh@google.com
+surenb@google.com
diff --git a/neuralnetworks/1.2/utils/test/DeviceTest.cpp b/neuralnetworks/1.2/utils/test/DeviceTest.cpp
index 0d8c141..0e855c4 100644
--- a/neuralnetworks/1.2/utils/test/DeviceTest.cpp
+++ b/neuralnetworks/1.2/utils/test/DeviceTest.cpp
@@ -54,6 +54,10 @@
         .execTime = std::numeric_limits<float>::max(),
         .powerUsage = std::numeric_limits<float>::max()};
 
+// FIXME: This function causes Clang to hang indefinitely when building with
+// -O1. Turn off optimization as a temporary workaround.
+// http://b/296850773
+#pragma clang optimize off
 template <typename... Args>
 auto makeCallbackReturn(Args&&... args) {
     return [argPack = std::make_tuple(std::forward<Args>(args)...)](const auto& cb) {
@@ -61,6 +65,7 @@
         return Void();
     };
 }
+#pragma clang optimize on
 
 sp<MockDevice> createMockDevice() {
     const auto mockDevice = MockDevice::create();
diff --git a/nfc/1.0/vts/functional/VtsHalNfcV1_0TargetTest.cpp b/nfc/1.0/vts/functional/VtsHalNfcV1_0TargetTest.cpp
index 2fc9e65..6d4936b 100644
--- a/nfc/1.0/vts/functional/VtsHalNfcV1_0TargetTest.cpp
+++ b/nfc/1.0/vts/functional/VtsHalNfcV1_0TargetTest.cpp
@@ -108,7 +108,7 @@
     EXPECT_EQ(NfcStatus::OK, nfc_->open(nfc_cb_));
     // Wait for OPEN_CPLT event
     auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
-    EXPECT_TRUE(res.no_timeout);
+    ASSERT_TRUE(res.no_timeout);
     EXPECT_EQ(NfcEvent::OPEN_CPLT, res.args->last_event_);
     EXPECT_EQ(NfcStatus::OK, res.args->last_status_);
 
@@ -118,7 +118,7 @@
     EXPECT_EQ(data.size(), nfc_->write(data));
     // Wait for CORE_RESET_RSP
     res = nfc_cb_->WaitForCallback(kCallbackNameSendData);
-    EXPECT_TRUE(res.no_timeout);
+    ASSERT_TRUE(res.no_timeout);
     EXPECT_GE(6ul, res.args->last_data_.size());
     EXPECT_EQ((int)NfcStatus::OK, res.args->last_data_[3]);
     if (res.args->last_data_.size() == 6) {
@@ -127,7 +127,7 @@
         EXPECT_EQ(4ul, res.args->last_data_.size());
         nci_version = NCI_VERSION_2;
         res = nfc_cb_->WaitForCallback(kCallbackNameSendData);
-        EXPECT_TRUE(res.no_timeout);
+        ASSERT_TRUE(res.no_timeout);
     }
 
     /*
@@ -137,14 +137,14 @@
     EXPECT_EQ(NfcStatus::OK, nfc_->close());
     // Wait for CLOSE_CPLT event
     res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
-    EXPECT_TRUE(res.no_timeout);
+    ASSERT_TRUE(res.no_timeout);
     EXPECT_EQ(NfcEvent::CLOSE_CPLT, res.args->last_event_);
     EXPECT_EQ(NfcStatus::OK, res.args->last_status_);
 
     EXPECT_EQ(NfcStatus::OK, nfc_->open(nfc_cb_));
     // Wait for OPEN_CPLT event
     res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
-    EXPECT_TRUE(res.no_timeout);
+    ASSERT_TRUE(res.no_timeout);
     EXPECT_EQ(NfcEvent::OPEN_CPLT, res.args->last_event_);
     EXPECT_EQ(NfcStatus::OK, res.args->last_status_);
   }
@@ -153,7 +153,7 @@
     EXPECT_EQ(NfcStatus::OK, nfc_->close());
     // Wait for CLOSE_CPLT event
     auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
-    EXPECT_TRUE(res.no_timeout);
+    ASSERT_TRUE(res.no_timeout);
     EXPECT_EQ(NfcEvent::CLOSE_CPLT, res.args->last_event_);
     EXPECT_EQ(NfcStatus::OK, res.args->last_status_);
   }
@@ -186,7 +186,7 @@
   EXPECT_EQ(data.size(), nfc_->write(data));
   // Wait for CORE_RESET_RSP
   auto res = nfc_cb_->WaitForCallback(kCallbackNameSendData);
-  EXPECT_TRUE(res.no_timeout);
+  ASSERT_TRUE(res.no_timeout);
 
   /* The response/notification format for CORE_RESET_CMD differs
    * with NCI 1.0 and 2.0. */
@@ -200,7 +200,7 @@
       EXPECT_EQ((int)NfcStatus::OK, res.args->last_data_[3]);
       // Wait for CORE_RESET_NTF
       res = nfc_cb_->WaitForCallback(kCallbackNameSendData);
-      EXPECT_TRUE(res.no_timeout);
+      ASSERT_TRUE(res.no_timeout);
       // Check if reset trigger was due to CORE_RESET_CMD
       EXPECT_LE(8ul, res.args->last_data_.size());
       EXPECT_EQ(2ul, res.args->last_data_[3]);
@@ -221,7 +221,7 @@
   EXPECT_EQ(data.size(), nfc_->write(data));
   // Wait for CORE_RESET_RSP
   auto res = nfc_cb_->WaitForCallback(kCallbackNameSendData);
-  EXPECT_TRUE(res.no_timeout);
+  ASSERT_TRUE(res.no_timeout);
 
   /* The response/notification format for CORE_RESET_CMD differs
    * with NCI 1.0 and 2.0. */
@@ -235,7 +235,7 @@
       EXPECT_EQ((int)NfcStatus::OK, res.args->last_data_[3]);
       // Wait for CORE_RESET_NTF
       res = nfc_cb_->WaitForCallback(kCallbackNameSendData);
-      EXPECT_TRUE(res.no_timeout);
+      ASSERT_TRUE(res.no_timeout);
       // Check if reset trigger was due to CORE_RESET_CMD
       EXPECT_LE(8ul, res.args->last_data_.size());
       EXPECT_EQ(2ul, res.args->last_data_[3]);
@@ -257,7 +257,7 @@
   EXPECT_EQ(data.size(), nfc_->write(data));
   // Wait for RSP
   auto res = nfc_cb_->WaitForCallback(kCallbackNameSendData);
-  EXPECT_TRUE(res.no_timeout);
+  ASSERT_TRUE(res.no_timeout);
   EXPECT_EQ(4ul, res.args->last_data_.size());
   EXPECT_EQ(SYNTAX_ERROR, res.args->last_data_[3]);
 }
@@ -277,14 +277,14 @@
     EXPECT_EQ(data.size(), nfc_->write(data));
     // Wait for CORE_RESET_RSP
     auto res = nfc_cb_->WaitForCallback(kCallbackNameSendData);
-    EXPECT_TRUE(res.no_timeout);
+    ASSERT_TRUE(res.no_timeout);
     EXPECT_EQ((int)NfcStatus::OK, res.args->last_data_[3]);
 
     /* NCI 2.0 sends CORE_RESET_NTF everytime. */
     if (nci_version == NCI_VERSION_2) {
         // Wait for CORE_RESET_NTF
         res = nfc_cb_->WaitForCallback(kCallbackNameSendData);
-        EXPECT_TRUE(res.no_timeout);
+        ASSERT_TRUE(res.no_timeout);
         cmd = CORE_INIT_CMD_NCI20;
     } else {
         cmd = CORE_INIT_CMD;
@@ -294,7 +294,7 @@
     EXPECT_EQ(data.size(), nfc_->write(data));
     // Wait for CORE_INIT_RSP
     res = nfc_cb_->WaitForCallback(kCallbackNameSendData);
-    EXPECT_TRUE(res.no_timeout);
+    ASSERT_TRUE(res.no_timeout);
     EXPECT_EQ((int)NfcStatus::OK, res.args->last_data_[3]);
     // Send an Error Data Packet
     cmd = INVALID_COMMAND;
@@ -307,7 +307,7 @@
         EXPECT_EQ(data.size(), nfc_->write(data));
         // Wait for response with SYNTAX_ERROR
         res = nfc_cb_->WaitForCallback(kCallbackNameSendData);
-        EXPECT_TRUE(res.no_timeout);
+        ASSERT_TRUE(res.no_timeout);
         EXPECT_EQ(4ul, res.args->last_data_.size());
         EXPECT_EQ(SYNTAX_ERROR, res.args->last_data_[3]);
   }
@@ -317,7 +317,7 @@
   EXPECT_EQ(data.size(), nfc_->write(data));
   // Wait for CORE_CONN_CREATE_RSP
   res = nfc_cb_->WaitForCallback(kCallbackNameSendData);
-  EXPECT_TRUE(res.no_timeout);
+  ASSERT_TRUE(res.no_timeout);
   EXPECT_EQ(7ul, res.args->last_data_.size());
   EXPECT_EQ((int)NfcStatus::OK, res.args->last_data_[3]);
 }
@@ -335,14 +335,14 @@
     EXPECT_EQ(data.size(), nfc_->write(data));
     // Wait for CORE_RESET_RSP
     auto res = nfc_cb_->WaitForCallback(kCallbackNameSendData);
-    EXPECT_TRUE(res.no_timeout);
+    ASSERT_TRUE(res.no_timeout);
     EXPECT_EQ((int)NfcStatus::OK, res.args->last_data_[3]);
 
     /* NCI 2.0 sends CORE_RESET_NTF everytime. */
     if (nci_version == NCI_VERSION_2) {
         // Wait for CORE_RESET_NTF
         res = nfc_cb_->WaitForCallback(kCallbackNameSendData);
-        EXPECT_TRUE(res.no_timeout);
+        ASSERT_TRUE(res.no_timeout);
         cmd = CORE_INIT_CMD_NCI20;
     } else {
         cmd = CORE_INIT_CMD;
@@ -352,15 +352,15 @@
     EXPECT_EQ(data.size(), nfc_->write(data));
     // Wait for CORE_INIT_RSP
     res = nfc_cb_->WaitForCallback(kCallbackNameSendData);
-    EXPECT_TRUE(res.no_timeout);
+    ASSERT_TRUE(res.no_timeout);
     EXPECT_EQ((int)NfcStatus::OK, res.args->last_data_[3]);
     cmd = CORE_CONN_CREATE_CMD;
     data = cmd;
     EXPECT_EQ(data.size(), nfc_->write(data));
     // Wait for CORE_CONN_CREATE_RSP
     res = nfc_cb_->WaitForCallback(kCallbackNameSendData);
-    EXPECT_TRUE(res.no_timeout);
-    EXPECT_TRUE(res.no_timeout);
+    ASSERT_TRUE(res.no_timeout);
+    ASSERT_TRUE(res.no_timeout);
     EXPECT_EQ(7ul, res.args->last_data_.size());
     EXPECT_EQ((int)NfcStatus::OK, res.args->last_data_[3]);
     uint8_t conn_id = res.args->last_data_[6];
@@ -414,7 +414,7 @@
   EXPECT_EQ(NfcStatus::OK, nfc_->powerCycle());
   // Wait for NfcEvent.OPEN_CPLT
   auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
-  EXPECT_TRUE(res.no_timeout);
+  ASSERT_TRUE(res.no_timeout);
   EXPECT_EQ(NfcEvent::OPEN_CPLT, res.args->last_event_);
   EXPECT_EQ(NfcStatus::OK, res.args->last_status_);
 }
@@ -428,7 +428,7 @@
   EXPECT_EQ(NfcStatus::OK, nfc_->close());
   // Wait for CLOSE_CPLT event
   auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
-  EXPECT_TRUE(res.no_timeout);
+  ASSERT_TRUE(res.no_timeout);
   EXPECT_EQ(NfcEvent::CLOSE_CPLT, res.args->last_event_);
   EXPECT_EQ(NfcStatus::OK, res.args->last_status_);
 
@@ -437,7 +437,7 @@
   EXPECT_EQ(NfcStatus::OK, nfc_->open(nfc_cb_));
   // Wait for OPEN_CPLT event
   res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
-  EXPECT_TRUE(res.no_timeout);
+  ASSERT_TRUE(res.no_timeout);
   EXPECT_EQ(NfcEvent::OPEN_CPLT, res.args->last_event_);
   EXPECT_EQ(NfcStatus::OK, res.args->last_status_);
 }
@@ -464,7 +464,7 @@
       EXPECT_EQ(NfcStatus::OK, status);
       // Wait for NfcEvent.POST_INIT_CPLT
       auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
-      EXPECT_TRUE(res.no_timeout);
+      ASSERT_TRUE(res.no_timeout);
       EXPECT_EQ(NfcEvent::POST_INIT_CPLT, res.args->last_event_);
   }
 }
@@ -487,7 +487,7 @@
   EXPECT_EQ(NfcStatus::OK, nfc_->close());
   // Wait for CLOSE_CPLT event
   auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
-  EXPECT_TRUE(res.no_timeout);
+  ASSERT_TRUE(res.no_timeout);
   EXPECT_EQ(NfcEvent::CLOSE_CPLT, res.args->last_event_);
   EXPECT_EQ(NfcStatus::OK, res.args->last_status_);
 
@@ -496,7 +496,7 @@
   EXPECT_EQ(NfcStatus::OK, nfc_->open(nfc_cb_));
   // Wait for OPEN_CPLT event
   res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
-  EXPECT_TRUE(res.no_timeout);
+  ASSERT_TRUE(res.no_timeout);
   EXPECT_EQ(NfcEvent::OPEN_CPLT, res.args->last_event_);
   EXPECT_EQ(NfcStatus::OK, res.args->last_status_);
 }
@@ -518,7 +518,7 @@
   EXPECT_EQ(NfcStatus::OK, nfc_->close());
   // Wait for CLOSE_CPLT event
   auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
-  EXPECT_TRUE(res.no_timeout);
+  ASSERT_TRUE(res.no_timeout);
   EXPECT_EQ(NfcEvent::CLOSE_CPLT, res.args->last_event_);
   EXPECT_EQ(NfcStatus::OK, res.args->last_status_);
 
@@ -527,7 +527,7 @@
   EXPECT_EQ(NfcStatus::OK, nfc_->open(nfc_cb_));
   // Wait for OPEN_CPLT event
   res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
-  EXPECT_TRUE(res.no_timeout);
+  ASSERT_TRUE(res.no_timeout);
   EXPECT_EQ(NfcEvent::OPEN_CPLT, res.args->last_event_);
   EXPECT_EQ(NfcStatus::OK, res.args->last_status_);
 }
@@ -541,7 +541,7 @@
   EXPECT_EQ(NfcStatus::OK, nfc_->close());
   // Wait for CLOSE_CPLT event
   auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
-  EXPECT_TRUE(res.no_timeout);
+  ASSERT_TRUE(res.no_timeout);
   EXPECT_EQ(NfcEvent::CLOSE_CPLT, res.args->last_event_);
   EXPECT_EQ(NfcStatus::OK, res.args->last_status_);
 
@@ -550,7 +550,7 @@
   EXPECT_EQ(NfcStatus::OK, nfc_->open(nfc_cb_));
   // Wait for OPEN_CPLT event
   res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
-  EXPECT_TRUE(res.no_timeout);
+  ASSERT_TRUE(res.no_timeout);
   EXPECT_EQ(NfcEvent::OPEN_CPLT, res.args->last_event_);
   EXPECT_EQ(NfcStatus::OK, res.args->last_status_);
 }
@@ -564,14 +564,14 @@
   EXPECT_EQ(NfcStatus::OK, nfc_->open(nfc_cb_));
   // Wait for OPEN_CPLT event
   auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
-  EXPECT_TRUE(res.no_timeout);
+  ASSERT_TRUE(res.no_timeout);
   EXPECT_EQ(NfcEvent::OPEN_CPLT, res.args->last_event_);
   EXPECT_EQ(NfcStatus::OK, res.args->last_status_);
 
   EXPECT_EQ(NfcStatus::OK, nfc_->open(nfc_cb_));
   // Wait for OPEN_CPLT event
   res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
-  EXPECT_TRUE(res.no_timeout);
+  ASSERT_TRUE(res.no_timeout);
   EXPECT_EQ(NfcEvent::OPEN_CPLT, res.args->last_event_);
   EXPECT_EQ(NfcStatus::OK, res.args->last_status_);
 }
diff --git a/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/INfc.aidl b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/INfc.aidl
index 7a0ae54..220912e 100644
--- a/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/INfc.aidl
+++ b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/INfc.aidl
@@ -44,4 +44,5 @@
   int write(in byte[] data);
   void setEnableVerboseLogging(in boolean enable);
   boolean isVerboseLoggingEnabled();
+  android.hardware.nfc.NfcStatus controlGranted();
 }
diff --git a/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcConfig.aidl b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcConfig.aidl
index 92e0a9a..0261a0a 100644
--- a/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcConfig.aidl
+++ b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcConfig.aidl
@@ -49,4 +49,5 @@
   byte[] offHostRouteUicc;
   byte[] offHostRouteEse;
   byte defaultIsoDepRoute;
+  byte[] offHostSimPipeIds = {};
 }
diff --git a/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcEvent.aidl b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcEvent.aidl
index dda258e..aebe836 100644
--- a/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcEvent.aidl
+++ b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcEvent.aidl
@@ -40,4 +40,6 @@
   PRE_DISCOVER_CPLT = 3,
   HCI_NETWORK_RESET = 4,
   ERROR = 5,
+  REQUEST_CONTROL = 6,
+  RELEASE_CONTROL = 7,
 }
diff --git a/nfc/aidl/android/hardware/nfc/INfc.aidl b/nfc/aidl/android/hardware/nfc/INfc.aidl
index 662f8d4..1d18b9e 100644
--- a/nfc/aidl/android/hardware/nfc/INfc.aidl
+++ b/nfc/aidl/android/hardware/nfc/INfc.aidl
@@ -140,4 +140,13 @@
      * @return true if verbose logging flag value is enabled, false if disabled.
      */
     boolean isVerboseLoggingEnabled();
+
+    /**
+     * Requests control of NFCC to libnfc-nci.
+     * If an API request is sent when the framework has no control of NFCC, the request will be
+     * queued until the control is released from HAL.
+     * The control will be taken out of the framework for at most 2 seconds.
+     * @return NfcStatus::OK on success and NfcStatus::FAILED on error.
+     */
+    NfcStatus controlGranted();
 }
diff --git a/nfc/aidl/android/hardware/nfc/NfcConfig.aidl b/nfc/aidl/android/hardware/nfc/NfcConfig.aidl
index 1b4fcfb..870cdbd 100644
--- a/nfc/aidl/android/hardware/nfc/NfcConfig.aidl
+++ b/nfc/aidl/android/hardware/nfc/NfcConfig.aidl
@@ -86,4 +86,8 @@
      * Default IsoDep route. 0x00 if there aren't any. Refer to NCI spec.
      */
     byte defaultIsoDepRoute;
+    /**
+     * Pipe IDs for UICC. Empty if not available
+     */
+    byte[] offHostSimPipeIds = {};
 }
diff --git a/nfc/aidl/android/hardware/nfc/NfcEvent.aidl b/nfc/aidl/android/hardware/nfc/NfcEvent.aidl
index a78b1cd..7e0231a 100644
--- a/nfc/aidl/android/hardware/nfc/NfcEvent.aidl
+++ b/nfc/aidl/android/hardware/nfc/NfcEvent.aidl
@@ -50,4 +50,14 @@
      * Error event to notify upper layer when there's an unknown error.
      */
     ERROR = 5,
+    /**
+     * Request control event to notify upper layer when HAL
+     * request control of NFCC to libnfc-nci
+     */
+    REQUEST_CONTROL = 6,
+    /**
+     * Release control event to notify upper layer when HAL
+     * release control of NFCC to libnfc-nci.
+     */
+    RELEASE_CONTROL = 7,
 }
diff --git a/nfc/aidl/vts/functional/Android.bp b/nfc/aidl/vts/functional/Android.bp
index d0b684b..f97405e 100644
--- a/nfc/aidl/vts/functional/Android.bp
+++ b/nfc/aidl/vts/functional/Android.bp
@@ -38,7 +38,7 @@
         "libbinder_ndk",
     ],
     static_libs: [
-        "android.hardware.nfc-V1-ndk",
+        "android.hardware.nfc-V2-ndk",
     ],
     test_suites: [
         "general-tests",
@@ -49,6 +49,7 @@
 cc_test {
     name: "VtsNfcBehaviorChangesTest",
     defaults: [
+        "aconfig_lib_cc_shared_link.defaults",
         "VtsHalTargetTestDefaults",
         "use_libaidlvintf_gtest_helper_static",
     ],
@@ -65,13 +66,14 @@
         "system/nfc/utils/include",
     ],
     shared_libs: [
+        "liblog",
         "libbinder",
         "libbinder_ndk",
         "libnativehelper",
         "libstatssocket",
     ],
     static_libs: [
-        "android.hardware.nfc-V1-ndk",
+        "android.hardware.nfc-V2-ndk",
         "android.hardware.nfc@1.0",
         "android.hardware.nfc@1.1",
         "android.hardware.nfc@1.2",
diff --git a/nfc/aidl/vts/functional/VtsAidlHalNfcTargetTest.cpp b/nfc/aidl/vts/functional/VtsAidlHalNfcTargetTest.cpp
index 977b25c..6e6ca3e 100644
--- a/nfc/aidl/vts/functional/VtsAidlHalNfcTargetTest.cpp
+++ b/nfc/aidl/vts/functional/VtsAidlHalNfcTargetTest.cpp
@@ -423,6 +423,11 @@
         EXPECT_GE((uint8_t)configValue.defaultIsoDepRoute, MIN_OFFHOST_ROUTE_ID);
         EXPECT_LE((uint8_t)configValue.defaultIsoDepRoute, MAX_OFFHOST_ROUTE_ID);
     }
+    for (auto simPipeId : configValue.offHostSimPipeIds) {
+        LOG(INFO) << StringPrintf("offHostSimPipeId= %x", simPipeId);
+        EXPECT_GE(simPipeId, MIN_OFFHOST_ROUTE_ID);
+        EXPECT_LE(simPipeId, MAX_OFFHOST_ROUTE_ID);
+    }
 }
 
 /*
@@ -440,6 +445,16 @@
     EXPECT_TRUE(!enabled);
 }
 
+TEST_P(NfcAidl, CheckControlGrantedStatus) {
+    int interface_version;
+    EXPECT_TRUE(infc_->getInterfaceVersion(&interface_version).isOk());
+    if (interface_version > 1) {
+        NfcStatus status;
+        EXPECT_TRUE(infc_->controlGranted(&status).isOk());
+        EXPECT_EQ(status, NfcStatus::OK);
+    }
+}
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(NfcAidl);
 INSTANTIATE_TEST_SUITE_P(Nfc, NfcAidl,
                          testing::ValuesIn(::android::getAidlHalInstanceNames(INfc::descriptor)),
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/compat/libradiocompat/sim/structs.cpp b/radio/aidl/compat/libradiocompat/sim/structs.cpp
index 00db2b8..27aca60 100644
--- a/radio/aidl/compat/libradiocompat/sim/structs.cpp
+++ b/radio/aidl/compat/libradiocompat/sim/structs.cpp
@@ -70,26 +70,60 @@
     };
 }
 
-aidl::CarrierRestrictions toAidl(const V1_0::CarrierRestrictions& cr) {
+static aidl::CarrierInfo toCarrierInfo(const aidl::Carrier& carrier) {
     return {
-            .allowedCarriers = toAidl(cr.allowedCarriers),
-            .excludedCarriers = toAidl(cr.excludedCarriers),
+            .mcc = carrier.mcc,
+            .mnc = carrier.mnc,
+    };
+}
+
+static std::vector<aidl::CarrierInfo> toCarrierInfos(const std::vector<aidl::Carrier>& carriers) {
+    std::vector<aidl::CarrierInfo> infos(carriers.size());
+    for (size_t i = 0; i < carriers.size(); i++) {
+        infos[i] = toCarrierInfo(carriers[i]);
+    }
+    return infos;
+}
+
+V1_0::Carrier toHidl(const aidl::CarrierInfo& carrierInfo) {
+    return {
+            .mcc = carrierInfo.mcc,
+            .mnc = carrierInfo.mnc,
+    };
+}
+
+aidl::CarrierRestrictions toAidl(const V1_0::CarrierRestrictions& cr) {
+    auto allowedCarriers = toAidl(cr.allowedCarriers);
+    auto excludedCarriers = toAidl(cr.excludedCarriers);
+    return {
+            .allowedCarriers = allowedCarriers,
+            .excludedCarriers = excludedCarriers,
             .allowedCarriersPrioritized = true,
+            .allowedCarrierInfoList = toCarrierInfos(allowedCarriers),
+            .excludedCarrierInfoList = toCarrierInfos(excludedCarriers),
     };
 }
 
 aidl::CarrierRestrictions toAidl(const V1_4::CarrierRestrictionsWithPriority& cr) {
+    auto allowedCarriers = toAidl(cr.allowedCarriers);
+    auto excludedCarriers = toAidl(cr.excludedCarriers);
     return {
-            .allowedCarriers = toAidl(cr.allowedCarriers),
-            .excludedCarriers = toAidl(cr.excludedCarriers),
+            .allowedCarriers = allowedCarriers,
+            .excludedCarriers = excludedCarriers,
             .allowedCarriersPrioritized = cr.allowedCarriersPrioritized,
+            .allowedCarrierInfoList = toCarrierInfos(allowedCarriers),
+            .excludedCarrierInfoList = toCarrierInfos(excludedCarriers),
     };
 }
 
 V1_4::CarrierRestrictionsWithPriority toHidl(const aidl::CarrierRestrictions& cr) {
     return {
-            .allowedCarriers = toHidl(cr.allowedCarriers),
-            .excludedCarriers = toHidl(cr.excludedCarriers),
+            .allowedCarriers = (cr.allowedCarriers.size() > cr.allowedCarrierInfoList.size())
+                                       ? toHidl(cr.allowedCarriers)
+                                       : toHidl(cr.allowedCarrierInfoList),
+            .excludedCarriers = (cr.excludedCarriers.size() > cr.excludedCarrierInfoList.size())
+                                        ? toHidl(cr.excludedCarriers)
+                                        : toHidl(cr.excludedCarrierInfoList),
             .allowedCarriersPrioritized = cr.allowedCarriersPrioritized,
     };
 }
diff --git a/radio/aidl/compat/libradiocompat/sim/structs.h b/radio/aidl/compat/libradiocompat/sim/structs.h
index 54099b7..7774bee 100644
--- a/radio/aidl/compat/libradiocompat/sim/structs.h
+++ b/radio/aidl/compat/libradiocompat/sim/structs.h
@@ -37,6 +37,7 @@
 
 ::aidl::android::hardware::radio::sim::Carrier toAidl(const V1_0::Carrier& carrier);
 V1_0::Carrier toHidl(const ::aidl::android::hardware::radio::sim::Carrier& carrier);
+V1_0::Carrier toHidl(const ::aidl::android::hardware::radio::sim::CarrierInfo& carrierInfo);
 
 ::aidl::android::hardware::radio::sim::CarrierRestrictions  //
 toAidl(const V1_0::CarrierRestrictions& cr);
diff --git a/radio/aidl/vts/Android.bp b/radio/aidl/vts/Android.bp
index e83a7c1..9521068 100644
--- a/radio/aidl/vts/Android.bp
+++ b/radio/aidl/vts/Android.bp
@@ -25,6 +25,7 @@
 cc_test {
     name: "VtsHalRadioTargetTest",
     defaults: [
+        "aconfig_lib_cc_shared_link.defaults",
         "VtsHalTargetTestDefaults",
         "use_libaidlvintf_gtest_helper_static",
     ],
diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
index b214401..914cad0 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -2171,6 +2171,14 @@
     // exit emergency mode for other tests
     serial = GetRandomSerialNumber();
     radio_network->exitEmergencyMode(serial);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+                                 {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED,
+                                  RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
 }
 
 /*
@@ -2494,24 +2502,27 @@
                                  {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
                                   RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
 
-    // Assert the value has changed
-    serial = GetRandomSerialNumber();
-    ndk::ScopedAStatus res = radio_network->isCellularIdentifierTransparencyEnabled(serial);
+    if (radioRsp_network->rspInfo.error == RadioError::NONE) {
+        // Assert the value has changed
+        serial = GetRandomSerialNumber();
+        ndk::ScopedAStatus res = radio_network->isCellularIdentifierTransparencyEnabled(serial);
 
-    ASSERT_OK(res);
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
-    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
-                                 {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
-                                  RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
-    EXPECT_EQ(valueToSet, radioRsp_network->isCellularIdentifierTransparencyEnabled);
+        ASSERT_OK(res);
+        EXPECT_EQ(std::cv_status::no_timeout, wait());
+        EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+        EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+                                     {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+                                      RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
+        EXPECT_EQ(valueToSet, radioRsp_network->isCellularIdentifierTransparencyEnabled);
 
-    // Reset original state
-    radio_network->setCellularIdentifierTransparencyEnabled(serial, originalTransparencySetting);
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+        // Reset original state
+        radio_network->setCellularIdentifierTransparencyEnabled(serial,
+                                                                originalTransparencySetting);
+        EXPECT_EQ(std::cv_status::no_timeout, wait());
+        EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+        EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+    }
 }
 
 /*
@@ -2547,24 +2558,26 @@
                                  {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
                                   RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
 
-    // Assert the value has changed
-    serial = GetRandomSerialNumber();
-    ndk::ScopedAStatus res = radio_network->isSecurityAlgorithmsUpdatedEnabled(serial);
+    if (radioRsp_network->rspInfo.error == RadioError::NONE) {
+        // Assert the value has changed
+        serial = GetRandomSerialNumber();
+        ndk::ScopedAStatus res = radio_network->isSecurityAlgorithmsUpdatedEnabled(serial);
 
-    ASSERT_OK(res);
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
-    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
-                                 {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
-                                  RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
-    EXPECT_EQ(valueToSet, radioRsp_network->isSecurityAlgorithmsUpdatedEnabled);
+        ASSERT_OK(res);
+        EXPECT_EQ(std::cv_status::no_timeout, wait());
+        EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+        EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+                                     {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+                                      RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
+        EXPECT_EQ(valueToSet, radioRsp_network->isSecurityAlgorithmsUpdatedEnabled);
 
-    // Reset original state
-    radio_network->setSecurityAlgorithmsUpdatedEnabled(serial, originalSecuritySetting);
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+        // Reset original state
+        radio_network->setSecurityAlgorithmsUpdatedEnabled(serial, originalSecuritySetting);
+        EXPECT_EQ(std::cv_status::no_timeout, wait());
+        EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+        EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+    }
 }
 
 /**
diff --git a/radio/aidl/vts/radio_sim_test.cpp b/radio/aidl/vts/radio_sim_test.cpp
index 06654c2..2823977 100644
--- a/radio/aidl/vts/radio_sim_test.cpp
+++ b/radio/aidl/vts/radio_sim_test.cpp
@@ -118,7 +118,14 @@
         EXPECT_EQ(CardStatus::STATE_PRESENT, slotStatus.cardState);
         if (CardStatus::STATE_PRESENT == slotStatus.cardState) {
             ASSERT_TRUE(slotStatus.portInfo[0].portActive);
-            EXPECT_EQ(0, cardStatus.slotMap.portId);
+            if (cardStatus.supportedMepMode == aidl::android::hardware::radio::config::
+                                                       MultipleEnabledProfilesMode::MEP_A1 ||
+                cardStatus.supportedMepMode == aidl::android::hardware::radio::config::
+                                                       MultipleEnabledProfilesMode::MEP_A2) {
+                EXPECT_EQ(1, cardStatus.slotMap.portId);
+            } else {
+                EXPECT_EQ(0, cardStatus.slotMap.portId);
+            }
         }
     }
 }
@@ -453,14 +460,43 @@
     serial = GetRandomSerialNumber();
     CarrierRestrictions carrierRestrictions;
     memset(&carrierRestrictions, 0, sizeof(carrierRestrictions));
-    carrierRestrictions.allowedCarriers.resize(1);
-    carrierRestrictions.excludedCarriers.resize(0);
-    carrierRestrictions.allowedCarriers[0].mcc = std::string("123");
-    carrierRestrictions.allowedCarriers[0].mnc = std::string("456");
-    carrierRestrictions.allowedCarriers[0].matchType = Carrier::MATCH_TYPE_ALL;
-    carrierRestrictions.allowedCarriers[0].matchData = std::string();
-    carrierRestrictions.allowedCarriersPrioritized = true;
+    int32_t aidl_version;
+    ndk::ScopedAStatus aidl_status = radio_sim->getInterfaceVersion(&aidl_version);
+    ASSERT_OK(aidl_status);
+
+    // Changes start
+
     SimLockMultiSimPolicy multisimPolicy = SimLockMultiSimPolicy::NO_MULTISIM_POLICY;
+    ALOGI("VTSAllowedCarriers Current AIDL version is %d ", aidl_version);
+    if (aidl_version <= 2) {
+        ALOGI("VTSAllowedCarriers If aidl_version is below 3 then , it will consider old AIDLs");
+        carrierRestrictions.allowedCarrierInfoList.resize(1);
+        if ((carrierRestrictions.allowedCarrierInfoList.size() > 0)) {
+            ALOGI("VTSAllowedCarriers If size of allowedCarrierInfoList is greater than 0");
+        }
+        carrierRestrictions.allowedCarriers.resize(1);
+        carrierRestrictions.excludedCarriers.resize(0);
+        carrierRestrictions.allowedCarriers[0].mcc = std::string("123");
+        carrierRestrictions.allowedCarriers[0].mnc = std::string("456");
+        carrierRestrictions.allowedCarriers[0].matchType = Carrier::MATCH_TYPE_ALL;
+        carrierRestrictions.allowedCarriers[0].matchData = std::string();
+        carrierRestrictions.allowedCarriersPrioritized = true;
+        multisimPolicy = SimLockMultiSimPolicy::NO_MULTISIM_POLICY;
+    } else {
+        carrierRestrictions.allowedCarrierInfoList.resize(1);
+        carrierRestrictions.excludedCarrierInfoList.resize(0);
+        // TODO(b/365568518): change mcc/mnc to something else once CF fully supports
+        // setAllowedCarriers
+        carrierRestrictions.allowedCarrierInfoList[0].mcc = std::string("123");
+        carrierRestrictions.allowedCarrierInfoList[0].mnc = std::string("456");
+        carrierRestrictions.allowedCarrierInfoList[0].spn = std::string("TestNetwork");
+        carrierRestrictions.allowedCarrierInfoList[0].gid1 = std::string("BAE000000000000");
+        carrierRestrictions.allowedCarrierInfoList[0].gid2 = std::string("AE0000000000000");
+        carrierRestrictions.allowedCarrierInfoList[0].imsiPrefix = std::string("9987");
+        carrierRestrictions.allowedCarriersPrioritized = true;
+        carrierRestrictions.status = CarrierRestrictions::CarrierRestrictionStatus::RESTRICTED;
+        multisimPolicy = SimLockMultiSimPolicy::NO_MULTISIM_POLICY;
+    }
 
     radio_sim->setAllowedCarriers(serial, carrierRestrictions, multisimPolicy);
     EXPECT_EQ(std::cv_status::no_timeout, wait());
@@ -483,7 +519,7 @@
                 sleep(2);
                 updateSimCardStatus();
             }
-            // TODO: uncomment once CF fully supports setAllowedCarriers
+            // TODO(b/365568518): uncomment once CF fully supports setAllowedCarriers
             // EXPECT_EQ(CardStatus::STATE_RESTRICTED, cardStatus.cardState);
         }
 
@@ -496,17 +532,38 @@
         EXPECT_EQ(serial, radioRsp_sim->rspInfo.serial);
         EXPECT_EQ(RadioError::NONE, radioRsp_sim->rspInfo.error);
 
-        EXPECT_EQ(1, radioRsp_sim->carrierRestrictionsResp.allowedCarriers.size());
-        EXPECT_EQ(0, radioRsp_sim->carrierRestrictionsResp.excludedCarriers.size());
-        ASSERT_TRUE(std::string("123") ==
-                    radioRsp_sim->carrierRestrictionsResp.allowedCarriers[0].mcc);
-        ASSERT_TRUE(std::string("456") ==
-                    radioRsp_sim->carrierRestrictionsResp.allowedCarriers[0].mnc);
-        EXPECT_EQ(Carrier::MATCH_TYPE_ALL,
-                  radioRsp_sim->carrierRestrictionsResp.allowedCarriers[0].matchType);
-        ASSERT_TRUE(radioRsp_sim->carrierRestrictionsResp.allowedCarriersPrioritized);
-        EXPECT_EQ(SimLockMultiSimPolicy::NO_MULTISIM_POLICY, radioRsp_sim->multiSimPolicyResp);
+        if (aidl_version <= 2) {
+            ASSERT_EQ(1, radioRsp_sim->carrierRestrictionsResp.allowedCarriers.size());
+            EXPECT_EQ(0, radioRsp_sim->carrierRestrictionsResp.excludedCarriers.size());
 
+            ASSERT_TRUE(std::string("123") ==
+                        radioRsp_sim->carrierRestrictionsResp.allowedCarriers[0].mcc);
+            ASSERT_TRUE(std::string("456") ==
+                        radioRsp_sim->carrierRestrictionsResp.allowedCarriers[0].mnc);
+            EXPECT_EQ(Carrier::MATCH_TYPE_ALL,
+                      radioRsp_sim->carrierRestrictionsResp.allowedCarriers[0].matchType);
+            ASSERT_TRUE(radioRsp_sim->carrierRestrictionsResp.allowedCarriersPrioritized);
+            EXPECT_EQ(SimLockMultiSimPolicy::NO_MULTISIM_POLICY, radioRsp_sim->multiSimPolicyResp);
+        } else {
+            ASSERT_EQ(1, radioRsp_sim->carrierRestrictionsResp.allowedCarrierInfoList.size());
+            EXPECT_EQ(0, radioRsp_sim->carrierRestrictionsResp.excludedCarrierInfoList.size());
+            ASSERT_EQ(std::string("123"),
+                      radioRsp_sim->carrierRestrictionsResp.allowedCarrierInfoList[0].mcc);
+            ASSERT_EQ(std::string("456"),
+                      radioRsp_sim->carrierRestrictionsResp.allowedCarrierInfoList[0].mnc);
+#if 0  // TODO(b/365568518): enable once CF fully supports setAllowedCarriers
+            ASSERT_EQ(std::string("BAE000000000000"),
+                        radioRsp_sim->carrierRestrictionsResp.allowedCarrierInfoList[0].gid1);
+            ASSERT_EQ(std::string("AE0000000000000"),
+                        radioRsp_sim->carrierRestrictionsResp.allowedCarrierInfoList[0].gid2);
+            ASSERT_EQ(std::string("9987"),
+                        radioRsp_sim->carrierRestrictionsResp.allowedCarrierInfoList[0].imsiPrefix);
+            EXPECT_EQ(CarrierRestrictions::CarrierRestrictionStatus::RESTRICTED,
+                      radioRsp_sim->carrierRestrictionsResp.status);
+#endif
+            ASSERT_TRUE(radioRsp_sim->carrierRestrictionsResp.allowedCarriersPrioritized);
+            EXPECT_EQ(SimLockMultiSimPolicy::NO_MULTISIM_POLICY, radioRsp_sim->multiSimPolicyResp);
+        }
         sleep(10);
 
         /**
@@ -515,9 +572,15 @@
          * status for cardStatus.
          */
         memset(&carrierRestrictions, 0, sizeof(carrierRestrictions));
-        carrierRestrictions.allowedCarriers.resize(0);
-        carrierRestrictions.excludedCarriers.resize(0);
-        carrierRestrictions.allowedCarriersPrioritized = false;
+        if (aidl_version <= 2) {
+            carrierRestrictions.allowedCarriers.resize(0);
+            carrierRestrictions.excludedCarriers.resize(0);
+            carrierRestrictions.allowedCarriersPrioritized = false;
+        } else {
+            carrierRestrictions.allowedCarrierInfoList.resize(0);
+            carrierRestrictions.excludedCarrierInfoList.resize(0);
+            carrierRestrictions.allowedCarriersPrioritized = false;
+        }
 
         serial = GetRandomSerialNumber();
         radio_sim->setAllowedCarriers(serial, carrierRestrictions, multisimPolicy);
diff --git a/secure_element/aidl/default/Android.bp b/secure_element/aidl/default/Android.bp
index b382822..6f5e5f7 100644
--- a/secure_element/aidl/default/Android.bp
+++ b/secure_element/aidl/default/Android.bp
@@ -55,6 +55,7 @@
     prebuilts: [
         "secure_element.rc",
         "secure_element.xml",
-        "android.hardware.se.omapi.ese.prebuilt.xml", // <feature>
+        // TODO (b/289193458): Add this back when access control is implemented for cuttlefish.
+        // "android.hardware.se.omapi.ese.prebuilt.xml", // <feature>
     ],
 }
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/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
index 5106561..464883e 100644
--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -39,7 +39,9 @@
 class AttestKeyTest : public KeyMintAidlTestBase {
   public:
     void SetUp() override {
-        skipAttestKeyTestIfNeeded();
+        if (shouldSkipAttestKeyTest()) {
+            GTEST_SKIP() << "Test using ATTEST_KEY is not applicable on waivered device";
+        }
         KeyMintAidlTestBase::SetUp();
     }
 };
@@ -251,7 +253,11 @@
                                             .SetDefaultValidity(),
                                     {} /* attestation signing key */, &attest_key.keyBlob,
                                     &attest_key_characteristics, &attest_key_cert_chain);
-    if (isRkpOnly() && result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) {
+    std::optional<bool> rkpOnly = isRkpOnly();
+    if (!rkpOnly.has_value()) {
+        GTEST_SKIP() << "Test not applicable because RKP-only status cannot be determined";
+    }
+    if (rkpOnly.value() && result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) {
         GTEST_SKIP() << "RKP-only devices do not have a factory key";
     }
     ASSERT_EQ(ErrorCode::OK, result);
@@ -355,7 +361,8 @@
                         .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
                         .SetDefaultValidity();
         // In RKP-only systems, the first key cannot be attested due to lack of batch key
-        if (!isRkpOnly() || i > 0) {
+        bool confirmedNotRkpOnly = !isRkpOnly().value_or(true);
+        if (confirmedNotRkpOnly || i > 0) {
             auth_set_builder.AttestationChallenge("foo");
         }
         auto result = GenerateAttestKey(auth_set_builder, attest_key_opt, &key_blob_list[i],
@@ -363,7 +370,7 @@
         ASSERT_EQ(ErrorCode::OK, result);
         deleters.push_back(KeyBlobDeleter(keymint_, key_blob_list[i]));
 
-        if (!isRkpOnly() || i > 0) {
+        if (confirmedNotRkpOnly || i > 0) {
             AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
             AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
             ASSERT_GT(cert_chain_list[i].size(), 0);
@@ -386,7 +393,7 @@
         }
 
         EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_list[i]));
-        EXPECT_GT(cert_chain_list[i].size(), i + (isRkpOnly() ? 0 : 1));
+        EXPECT_GT(cert_chain_list[i].size(), i + (confirmedNotRkpOnly ? 1 : 0));
         verify_subject_and_serial(cert_chain_list[i][0], serial_int, subject, false);
     }
 }
@@ -432,7 +439,8 @@
                         .Authorization(TAG_NO_AUTH_REQUIRED)
                         .SetDefaultValidity();
         // In RKP-only systems, the first key cannot be attested due to lack of batch key
-        if (!isRkpOnly() || i > 0) {
+        bool confirmedNotRkpOnly = !isRkpOnly().value_or(true);
+        if (confirmedNotRkpOnly || i > 0) {
             auth_set_builder.AttestationChallenge("foo");
         }
         auto result = GenerateAttestKey(auth_set_builder, attest_key_opt, &key_blob_list[i],
@@ -440,7 +448,7 @@
         ASSERT_EQ(ErrorCode::OK, result);
         deleters.push_back(KeyBlobDeleter(keymint_, key_blob_list[i]));
 
-        if (!isRkpOnly() || i > 0) {
+        if (confirmedNotRkpOnly || i > 0) {
             AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
             AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
             ASSERT_GT(cert_chain_list[i].size(), 0);
@@ -459,7 +467,7 @@
         }
 
         EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_list[i]));
-        EXPECT_GT(cert_chain_list[i].size(), i + (isRkpOnly() ? 0 : 1));
+        EXPECT_GT(cert_chain_list[i].size(), i + (confirmedNotRkpOnly ? 1 : 0));
         verify_subject_and_serial(cert_chain_list[i][0], serial_int, subject, false);
     }
 }
@@ -530,7 +538,8 @@
                         .Authorization(TAG_NO_AUTH_REQUIRED)
                         .SetDefaultValidity();
         // In RKP-only systems, the first key cannot be attested due to lack of batch key
-        if (!isRkpOnly() || i > 0) {
+        bool confirmedNotRkpOnly = !isRkpOnly().value_or(true);
+        if (confirmedNotRkpOnly || i > 0) {
             auth_set_builder.AttestationChallenge("foo");
         }
         if ((i & 0x1) == 1) {
@@ -543,7 +552,7 @@
         ASSERT_EQ(ErrorCode::OK, result);
         deleters.push_back(KeyBlobDeleter(keymint_, key_blob_list[i]));
 
-        if (!isRkpOnly() || i > 0) {
+        if (confirmedNotRkpOnly || i > 0) {
             AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
             AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
             ASSERT_GT(cert_chain_list[i].size(), 0);
@@ -566,7 +575,7 @@
         }
 
         EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_list[i]));
-        EXPECT_GT(cert_chain_list[i].size(), i + (isRkpOnly() ? 0 : 1));
+        EXPECT_GT(cert_chain_list[i].size(), i + (confirmedNotRkpOnly ? 1 : 0));
         verify_subject_and_serial(cert_chain_list[i][0], serial_int, subject, false);
     }
 }
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index cef8120..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__;
 }
 
 /**
@@ -250,7 +250,13 @@
     return AidlVersion() >= 3 && property_get_int32("ro.vendor.api_level", 0) > __ANDROID_API_T__;
 }
 
-bool KeyMintAidlTestBase::isRkpOnly() {
+std::optional<bool> KeyMintAidlTestBase::isRkpOnly() {
+    // GSI replaces the values for remote_prov_prop properties (since they’re system_internal_prop
+    // properties), so on GSI the properties are not reliable indicators of whether StrongBox/TEE is
+    // RKP-only or not.
+    if (is_gsi_image()) {
+        return std::nullopt;
+    }
     if (SecLevel() == SecurityLevel::STRONGBOX) {
         return property_get_bool("remote_provisioning.strongbox.rkp_only", false);
     }
@@ -318,8 +324,11 @@
     vector<Certificate> attest_cert_chain;
     // If an attestation is requested, but the system is RKP-only, we need to supply an explicit
     // attestation key. Else the result is a key without an attestation.
-    if (isRkpOnly() && key_desc.Contains(TAG_ATTESTATION_CHALLENGE)) {
-        skipAttestKeyTestIfNeeded();
+    // If the RKP-only value is undeterminable (i.e., when running on GSI), generate and use the
+    // attest key anyways. In the case that using an attest key is not supported
+    // (shouldSkipAttestKeyTest), assume the device has factory keys (so not RKP-only).
+    if (isRkpOnly().value_or(true) && key_desc.Contains(TAG_ATTESTATION_CHALLENGE) &&
+        !shouldSkipAttestKeyTest()) {
         AuthorizationSet attest_key_desc =
                 AuthorizationSetBuilder().EcdsaKey(EcCurve::P_256).AttestKey().SetDefaultValidity();
         attest_key.emplace();
@@ -1677,14 +1686,6 @@
             is_attest_key_feature_disabled());
 }
 
-// Skip a test that involves use of the ATTEST_KEY feature in specific configurations
-// where ATTEST_KEY is not supported (for either StrongBox or TEE).
-void KeyMintAidlTestBase::skipAttestKeyTestIfNeeded() const {
-    if (shouldSkipAttestKeyTest()) {
-        GTEST_SKIP() << "Test using ATTEST_KEY is not applicable on waivered device";
-    }
-}
-
 void verify_serial(X509* cert, const uint64_t expected_serial) {
     BIGNUM_Ptr ser(BN_new());
     EXPECT_TRUE(ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), ser.get()));
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index 1bf2d9d..0368bba 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -104,7 +104,7 @@
     uint32_t boot_patch_level();
     bool isDeviceIdAttestationRequired();
     bool isSecondImeiIdAttestationRequired();
-    bool isRkpOnly();
+    std::optional<bool> isRkpOnly();
 
     bool Curve25519Supported();
 
@@ -356,7 +356,6 @@
     bool is_strongbox_enabled(void) const;
     bool is_chipset_allowed_km4_strongbox(void) const;
     bool shouldSkipAttestKeyTest(void) const;
-    void skipAttestKeyTestIfNeeded() const;
 
     void assert_mgf_digests_present_or_not_in_key_characteristics(
             const vector<KeyCharacteristics>& key_characteristics,
diff --git a/security/keymint/support/fuzzer/Android.bp b/security/keymint/support/fuzzer/Android.bp
index 1b1a580..a3ceb91 100644
--- a/security/keymint/support/fuzzer/Android.bp
+++ b/security/keymint/support/fuzzer/Android.bp
@@ -46,6 +46,35 @@
         "hardware/interfaces/security/keymint/support/include",
         "frameworks/native/libs/binder/ndk/include_platform",
     ],
+    fuzz_config: {
+        cc: [
+            "android-hardware-security@google.com",
+        ],
+        componentid: 1084733,
+        hotlists: [
+            "4593311",
+            "4271696",
+        ],
+        description: "The fuzzer targets the APIs of libkeymint_support",
+        vector: "local_no_privileges_required",
+        service_privilege: "privileged",
+        users: "multi_user",
+        fuzzed_code_usage: "shipped",
+    },
+}
+
+cc_defaults {
+    name: "keymint_remote_fuzzer_defaults",
+    static_libs: [
+        "libkeymint_remote_prov_support",
+        "android.hardware.security.rkp-V3-ndk",
+    ],
+    shared_libs: [
+        "libcppbor",
+        "libcppcose_rkp",
+        "libjsoncpp",
+        "libkeymaster_portable",
+    ],
 }
 
 cc_fuzz {
@@ -67,3 +96,25 @@
         "keymint_fuzzer_defaults",
     ],
 }
+
+cc_fuzz {
+    name: "keymint_remote_prov_fuzzer",
+    srcs: [
+        "keymint_remote_prov_fuzzer.cpp",
+    ],
+    defaults: [
+        "keymint_fuzzer_defaults",
+        "keymint_remote_fuzzer_defaults",
+    ],
+}
+
+cc_fuzz {
+    name: "keymint_rkpsupport_fuzzer",
+    srcs: [
+        "keymint_rkpsupport_fuzzer.cpp",
+    ],
+    defaults: [
+        "keymint_fuzzer_defaults",
+        "keymint_remote_fuzzer_defaults",
+    ],
+}
diff --git a/security/keymint/support/fuzzer/README.md b/security/keymint/support/fuzzer/README.md
index d41af08..4cf6927 100644
--- a/security/keymint/support/fuzzer/README.md
+++ b/security/keymint/support/fuzzer/README.md
@@ -12,6 +12,8 @@
 ## Table of contents
 + [keymint_attestation_fuzzer](#KeyMintAttestation)
 + [keymint_authSet_fuzzer](#KeyMintAuthSet)
++ [keymint_remote_prov_fuzzer](#KeyMintRemoteProv)
++ [keymint_rkpsupport_fuzzer](#KeyMintRemoteKeyProvSupport)
 
 # <a name="KeyMintAttestation"></a> Fuzzer for KeyMintAttestation
 KeyMintAttestation supports the following parameters:
@@ -77,3 +79,53 @@
 $ adb sync data
 $ adb shell /data/fuzz/arm64/keymint_authSet_fuzzer/keymint_authSet_fuzzer
 ```
+
+# <a name="KeyMintRemoteProv"></a> Fuzzer for KeyMintRemoteProv
+KeyMintRemoteProv supports the following parameters:
+1. ChallengeSize(parameter name: "challengeSize")
+2. Challenge(parameter name: "challenge")
+3. NumKeys(parameter name: "numKeys")
+
+| Parameter| Valid Values| Configured Value|
+|------------- |--------------| -------------------- |
+|`challengeSize`| `uint8_t` |Value obtained from FuzzedDataProvider|
+|`challenge`| `std::vector<uint8_t>` |Value obtained from FuzzedDataProvider|
+|`numKeys`| `uint8_t` |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+$ mm -j$(nproc) keymint_remote_prov_fuzzer
+```
+2. Run on device
+```
+$ adb sync data
+$ adb shell /data/fuzz/arm64/keymint_remote_prov_fuzzer/keymint_remote_prov_fuzzer
+```
+
+# <a name="KeyMintRemoteKeyProvSupport"></a> Fuzzer for KeyMintRemoteKeyProvSupport
+KeyMintRemoteKeyProvSupport supports the following parameters:
+1. SupportedEekCurve(parameter name: "supportedEekCurve")
+2. Length(parameter name: "length")
+3. SerialNumberProp(parameter name: "serialNoProp")
+4. InstanceName(parameter name: "instanceName")
+5. Value(parameter name: "value")
+
+| Parameter| Valid Values| Configured Value|
+|------------- |--------------| -------------------- |
+|`supportedEekCurve`| `uint8_t` |Value obtained from FuzzedDataProvider|
+|`length`| `uint8_t` |Value obtained from FuzzedDataProvider|
+|`serialNoProp`| `string` |Value obtained from FuzzedDataProvider|
+|`instanceName`| `string` |Value obtained from FuzzedDataProvider|
+|`value`| `uint8_t` |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+$ mm -j$(nproc) keymint_rkpsupport_fuzzer
+```
+2. Run on device
+```
+$ adb sync data
+$ adb shell /data/fuzz/arm64/keymint_rkpsupport_fuzzer/keymint_rkpsupport_fuzzer
+```
diff --git a/security/keymint/support/fuzzer/keymint_attestation_fuzzer.cpp b/security/keymint/support/fuzzer/keymint_attestation_fuzzer.cpp
index bd781ac..1757997 100644
--- a/security/keymint/support/fuzzer/keymint_attestation_fuzzer.cpp
+++ b/security/keymint/support/fuzzer/keymint_attestation_fuzzer.cpp
@@ -151,7 +151,7 @@
 
 extern "C" int LLVMFuzzerInitialize(int /* *argc */, char /* ***argv */) {
     ::ndk::SpAIBinder binder(AServiceManager_waitForService(kServiceName.c_str()));
-    gKeyMint = std::move(IKeyMintDevice::fromBinder(binder));
+    gKeyMint = IKeyMintDevice::fromBinder(binder);
     LOG_ALWAYS_FATAL_IF(!gKeyMint, "Failed to get IKeyMintDevice instance.");
     return 0;
 }
diff --git a/security/keymint/support/fuzzer/keymint_remote_prov_fuzzer.cpp b/security/keymint/support/fuzzer/keymint_remote_prov_fuzzer.cpp
new file mode 100644
index 0000000..6bd986c
--- /dev/null
+++ b/security/keymint/support/fuzzer/keymint_remote_prov_fuzzer.cpp
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ *
+ */
+#include <android/binder_manager.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <remote_prov/remote_prov_utils.h>
+#include <utils/Log.h>
+
+namespace android::hardware::security::keymint_support::fuzzer {
+
+using namespace cppcose;
+using namespace aidl::android::hardware::security::keymint;
+using namespace aidl::android::hardware::security::keymint::remote_prov;
+
+constexpr size_t kMinSize = 0;
+constexpr size_t kSupportedNumKeys = 4;
+constexpr size_t kChallengeSize = 64;
+constexpr size_t kMaxBytes = 128;
+const std::string kServiceName =
+        "android.hardware.security.keymint.IRemotelyProvisionedComponent/default";
+
+std::shared_ptr<IRemotelyProvisionedComponent> gRPC = nullptr;
+
+class KeyMintRemoteProv {
+  public:
+    KeyMintRemoteProv(const uint8_t* data, size_t size) : mFdp(data, size){};
+    void process();
+
+  private:
+    std::vector<uint8_t> ExtractPayloadValue(const MacedPublicKey& macedPubKey);
+    FuzzedDataProvider mFdp;
+};
+
+std::vector<uint8_t> KeyMintRemoteProv::ExtractPayloadValue(const MacedPublicKey& macedPubKey) {
+    std::vector<uint8_t> payloadValue;
+
+    auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
+    if (coseMac0) {
+        // The payload is a bstr holding an encoded COSE_Key
+        auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
+        if (payload != nullptr) {
+            payloadValue = payload->value();
+        }
+    }
+    return payloadValue;
+}
+
+void KeyMintRemoteProv::process() {
+    std::vector<MacedPublicKey> keysToSign = std::vector<MacedPublicKey>(
+            mFdp.ConsumeIntegralInRange<uint8_t>(kMinSize, kSupportedNumKeys));
+    cppbor::Array cborKeysToSign;
+    for (auto& key : keysToSign) {
+        // TODO: b/350649166 - Randomize keysToSign
+        std::vector<uint8_t> privateKeyBlob;
+        gRPC->generateEcdsaP256KeyPair(false /* testMode */, &key, &privateKeyBlob);
+
+        std::vector<uint8_t> payloadValue = ExtractPayloadValue(key);
+        cborKeysToSign.add(cppbor::EncodedItem(payloadValue));
+    }
+
+    uint8_t challengeSize = mFdp.ConsumeIntegralInRange<uint8_t>(kMinSize, kChallengeSize);
+    std::vector<uint8_t> challenge = mFdp.ConsumeBytes<uint8_t>(challengeSize);
+
+    std::vector<uint8_t> csr;
+    gRPC->generateCertificateRequestV2(keysToSign, challenge, &csr);
+
+    while (mFdp.remaining_bytes()) {
+        auto invokeProvAPI = mFdp.PickValueInArray<const std::function<void()>>({
+                [&]() { verifyFactoryCsr(cborKeysToSign, csr, gRPC.get(), challenge); },
+                [&]() { verifyProductionCsr(cborKeysToSign, csr, gRPC.get(), challenge); },
+                [&]() { isCsrWithProperDiceChain(csr); },
+        });
+        invokeProvAPI();
+    }
+}
+
+extern "C" int LLVMFuzzerInitialize(int /* *argc */, char /* ***argv */) {
+    ::ndk::SpAIBinder binder(AServiceManager_waitForService(kServiceName.c_str()));
+    gRPC = IRemotelyProvisionedComponent::fromBinder(binder);
+    LOG_ALWAYS_FATAL_IF(!gRPC, "Failed to get IRemotelyProvisionedComponent instance.");
+    return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    KeyMintRemoteProv kmRemoteProv(data, size);
+    kmRemoteProv.process();
+    return 0;
+}
+
+}  // namespace android::hardware::security::keymint_support::fuzzer
diff --git a/security/keymint/support/fuzzer/keymint_rkpsupport_fuzzer.cpp b/security/keymint/support/fuzzer/keymint_rkpsupport_fuzzer.cpp
new file mode 100644
index 0000000..778d48f
--- /dev/null
+++ b/security/keymint/support/fuzzer/keymint_rkpsupport_fuzzer.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ *
+ */
+#include <fuzzer/FuzzedDataProvider.h>
+#include <remote_prov/remote_prov_utils.h>
+
+namespace android::hardware::security::keymint_support::fuzzer {
+
+using namespace aidl::android::hardware::security::keymint::remote_prov;
+
+constexpr size_t kMaxBytes = 128;
+
+class KeyMintRemoteKeyProvSupport {
+  public:
+    KeyMintRemoteKeyProvSupport(const uint8_t* data, size_t size) : mFdp(data, size) {}
+    void process();
+
+  private:
+    FuzzedDataProvider mFdp;
+};
+
+void KeyMintRemoteKeyProvSupport::process() {
+    while (mFdp.remaining_bytes()) {
+        auto invokeProvAPI = mFdp.PickValueInArray<const std::function<void()>>({
+                [&]() {
+                    std::vector<uint8_t> eekId;
+                    if (mFdp.ConsumeBool()) {
+                        eekId = mFdp.ConsumeBytes<uint8_t>(kMaxBytes);
+                    }
+                    generateEekChain(mFdp.ConsumeIntegral<uint8_t>() /* supportedEekCurve */,
+                                     mFdp.ConsumeIntegral<uint8_t>() /* length */, eekId);
+                },
+                [&]() { getProdEekChain(mFdp.ConsumeIntegral<uint8_t>() /* supportedEekCurve */); },
+                [&]() {
+                    std::string serialNoProp = mFdp.ConsumeRandomLengthString(kMaxBytes);
+                    std::string instanceName = mFdp.ConsumeRandomLengthString(kMaxBytes);
+                    cppbor::Array array;
+                    array.add(mFdp.ConsumeIntegral<uint8_t>() /* value */);
+                    jsonEncodeCsrWithBuild(instanceName, array, serialNoProp);
+                },
+        });
+        invokeProvAPI();
+    }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    KeyMintRemoteKeyProvSupport keymintRKPSupport(data, size);
+    keymintRKPSupport.process();
+    return 0;
+}
+
+}  // namespace android::hardware::security::keymint_support::fuzzer
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..141f243 100644
--- a/security/keymint/support/include/remote_prov/remote_prov_utils.h
+++ b/security/keymint/support/include/remote_prov/remote_prov_utils.h
@@ -21,6 +21,7 @@
 #include <vector>
 #include "aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h"
 
+#include <hwtrust/hwtrust.h>
 #include <keymaster/cppcose/cppcose.h>
 
 namespace aidl::android::hardware::security::keymint::remote_prov {
@@ -167,7 +168,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
@@ -175,15 +177,22 @@
  */
 ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyFactoryCsr(
         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 allowDegenerate = true);
 /**
  * Verify the CSR as if the device is a final production sample.
  */
 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);
 
+/** Verify the DICE chain. */
+ErrMsgOr<std::vector<BccEntryData>> validateBcc(const cppbor::Array* bcc,
+                                                hwtrust::DiceChain::Kind kind, bool allowAnyMode,
+                                                bool allowDegenerate);
+
 }  // namespace aidl::android::hardware::security::keymint::remote_prov
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
index b74fd59..a679340 100644
--- a/security/keymint/support/remote_prov_utils.cpp
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -26,7 +26,6 @@
 #include <android-base/macros.h>
 #include <android-base/properties.h>
 #include <cppbor.h>
-#include <hwtrust/hwtrust.h>
 #include <json/json.h>
 #include <keymaster/km_openssl/ec_key.h>
 #include <keymaster/km_openssl/ecdsa_operation.h>
@@ -65,9 +64,9 @@
     return privKey;
 }
 
-ErrMsgOr<bytevec> ecKeyGetPublicKey(const EC_KEY* ecKey) {
+ErrMsgOr<bytevec> ecKeyGetPublicKey(const EC_KEY* ecKey, const int nid) {
     // Extract public key.
-    auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+    auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(nid));
     if (group.get() == nullptr) {
         return "Error creating EC group by curve name";
     }
@@ -123,11 +122,12 @@
     int keyType = EVP_PKEY_base_id(pubKey.get());
     switch (keyType) {
         case EVP_PKEY_EC: {
+            int nid = EVP_PKEY_bits(pubKey.get()) == 384 ? NID_secp384r1 : NID_X9_62_prime256v1;
             auto ecKey = EC_KEY_Ptr(EVP_PKEY_get1_EC_KEY(pubKey.get()));
             if (ecKey.get() == nullptr) {
                 return "Failed to get ec key";
-            }
-            return ecKeyGetPublicKey(ecKey.get());
+          }
+          return ecKeyGetPublicKey(ecKey.get(), nid);
         }
         case EVP_PKEY_ED25519: {
             bytevec rawPubKey;
@@ -165,7 +165,7 @@
     auto privKey = ecKeyGetPrivateKey(ec_key.get());
     if (!privKey) return privKey.moveMessage();
 
-    auto pubKey = ecKeyGetPublicKey(ec_key.get());
+    auto pubKey = ecKeyGetPublicKey(ec_key.get(), NID_X9_62_prime256v1);
     if (!pubKey) return pubKey.moveMessage();
 
     return std::make_tuple(pubKey.moveValue(), privKey.moveValue());
@@ -324,10 +324,23 @@
 }
 
 ErrMsgOr<std::vector<BccEntryData>> validateBcc(const cppbor::Array* bcc,
-                                                hwtrust::DiceChain::Kind kind) {
+                                                hwtrust::DiceChain::Kind kind, bool allowAnyMode,
+                                                bool allowDegenerate) {
     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();
+
+    if (!allowDegenerate && !chain->IsProper()) {
+        return "DICE chain is degenerate";
+    }
+
     auto keys = chain->CosePublicKeys();
     if (!keys.ok()) return keys.error().message();
     std::vector<BccEntryData> result;
@@ -637,7 +650,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;
@@ -693,7 +706,8 @@
     }
 
     // BCC is [ pubkey, + BccEntry]
-    auto bccContents = validateBcc(bcc->asArray(), hwtrust::DiceChain::Kind::kVsr13);
+    auto bccContents = validateBcc(bcc->asArray(), hwtrust::DiceChain::Kind::kVsr13, allowAnyMode,
+                                   /*allowDegenerate=*/true);
     if (!bccContents) {
         return bccContents.message() + "\n" + prettyPrint(bcc.get());
     }
@@ -746,10 +760,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) {
@@ -824,7 +839,7 @@
         }
         if (i == chain.size() - 1) {
             auto key = getRawPublicKey(pubKey);
-            if (!key) key.moveMessage();
+            if (!key) return key.moveMessage();
             rawPubKey = key.moveValue();
         }
     }
@@ -973,20 +988,23 @@
 
 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,
+                                                       bool allowDegenerate = true) {
     auto [parsedRequest, _, csrErrMsg] = cppbor::parse(request);
     if (!parsedRequest) {
         return csrErrMsg;
@@ -1024,19 +1042,20 @@
         return diceChainKind.message();
     }
 
-    auto diceContents = validateBcc(diceCertChain, *diceChainKind);
+    auto diceContents = validateBcc(diceCertChain, *diceChainKind, allowAnyMode, allowDegenerate);
     if (!diceContents) {
         return diceContents.message() + "\n" + prettyPrint(diceCertChain);
     }
 
-    auto& udsPub = diceContents->back().pubKey;
+    auto udsPub = diceCertChain->get(0)->asMap()->encode();
+    auto& kmDiceKey = diceContents->back().pubKey;
 
     auto error = validateUdsCerts(*udsCerts, udsPub);
     if (!error.empty()) {
         return error;
     }
 
-    auto signedPayload = verifyAndParseCoseSign1(signedData, udsPub, {} /* aad */);
+    auto signedPayload = verifyAndParseCoseSign1(signedData, kmDiceKey, {} /* aad */);
     if (!signedPayload) {
         return signedPayload.message();
     }
@@ -1053,7 +1072,8 @@
                                                    const std::vector<uint8_t>& csr,
                                                    IRemotelyProvisionedComponent* provisionable,
                                                    const std::vector<uint8_t>& challenge,
-                                                   bool isFactory) {
+                                                   bool isFactory, bool allowAnyMode = false,
+                                                   bool allowDegenerate = true) {
     RpcHardwareInfo info;
     provisionable->getHardwareInfo(&info);
     if (info.versionNumber != 3) {
@@ -1061,7 +1081,8 @@
                ") does not match expected version (3).";
     }
 
-    auto csrPayload = parseAndValidateAuthenticatedRequest(csr, challenge);
+    auto csrPayload =
+            parseAndValidateAuthenticatedRequest(csr, challenge, allowAnyMode, allowDegenerate);
     if (!csrPayload) {
         return csrPayload.message();
     }
@@ -1071,14 +1092,17 @@
 
 ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyFactoryCsr(
         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=*/true);
+        IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge,
+        bool allowDegenerate) {
+    return verifyCsr(keysToSign, csr, provisionable, challenge, /*isFactory=*/true,
+                     /*allowAnyMode=*/false, allowDegenerate);
 }
 
 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) {
@@ -1112,7 +1136,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/keymint/support/remote_prov_utils_test.cpp b/security/keymint/support/remote_prov_utils_test.cpp
index 89469f1..82121cb 100644
--- a/security/keymint/support/remote_prov_utils_test.cpp
+++ b/security/keymint/support/remote_prov_utils_test.cpp
@@ -41,6 +41,41 @@
 using ::testing::ElementsAreArray;
 using byte_view = std::span<const uint8_t>;
 
+inline const std::vector<uint8_t> kDegenerateBcc{
+        0x82, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0xf5,
+        0x5a, 0xfb, 0x28, 0x06, 0x48, 0x68, 0xea, 0x49, 0x3e, 0x47, 0x80, 0x1d, 0xfe, 0x1f, 0xfc,
+        0xa8, 0x84, 0xb3, 0x4d, 0xdb, 0x99, 0xc7, 0xbf, 0x23, 0x53, 0xe5, 0x71, 0x92, 0x41, 0x9b,
+        0x46, 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01, 0x75, 0xa9, 0x01, 0x78, 0x28, 0x31,
+        0x64, 0x34, 0x35, 0x65, 0x33, 0x35, 0x63, 0x34, 0x35, 0x37, 0x33, 0x31, 0x61, 0x32, 0x62,
+        0x34, 0x35, 0x36, 0x37, 0x63, 0x33, 0x63, 0x65, 0x35, 0x31, 0x36, 0x66, 0x35, 0x63, 0x31,
+        0x66, 0x34, 0x33, 0x61, 0x62, 0x64, 0x36, 0x30, 0x62, 0x02, 0x78, 0x28, 0x31, 0x64, 0x34,
+        0x35, 0x65, 0x33, 0x35, 0x63, 0x34, 0x35, 0x37, 0x33, 0x31, 0x61, 0x32, 0x62, 0x34, 0x35,
+        0x36, 0x37, 0x63, 0x33, 0x63, 0x65, 0x35, 0x31, 0x36, 0x66, 0x35, 0x63, 0x31, 0x66, 0x34,
+        0x33, 0x61, 0x62, 0x64, 0x36, 0x30, 0x62, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x40, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x41, 0xa0, 0x3a, 0x00, 0x47, 0x44, 0x52,
+        0x58, 0x40, 0x71, 0xd7, 0x47, 0x9e, 0x61, 0xb5, 0x30, 0xa3, 0xda, 0xe6, 0xac, 0xb2, 0x91,
+        0xa4, 0xf9, 0xcf, 0x7f, 0xba, 0x6b, 0x5f, 0xf9, 0xa3, 0x7f, 0xba, 0xab, 0xac, 0x69, 0xdd,
+        0x0b, 0x04, 0xd6, 0x34, 0xd2, 0x3f, 0x8f, 0x84, 0x96, 0xd7, 0x58, 0x51, 0x1d, 0x68, 0x25,
+        0xea, 0xbe, 0x11, 0x11, 0x1e, 0xd8, 0xdf, 0x4b, 0x62, 0x78, 0x5c, 0xa8, 0xfa, 0xb7, 0x66,
+        0x4e, 0x8d, 0xac, 0x3b, 0x00, 0x4c, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x40, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x00, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58,
+        0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0xf5,
+        0x5a, 0xfb, 0x28, 0x06, 0x48, 0x68, 0xea, 0x49, 0x3e, 0x47, 0x80, 0x1d, 0xfe, 0x1f, 0xfc,
+        0xa8, 0x84, 0xb3, 0x4d, 0xdb, 0x99, 0xc7, 0xbf, 0x23, 0x53, 0xe5, 0x71, 0x92, 0x41, 0x9b,
+        0x46, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40, 0x31, 0x5c, 0x43, 0x87, 0xf9,
+        0xbb, 0xb9, 0x45, 0x09, 0xa8, 0xe8, 0x08, 0x70, 0xc4, 0xd9, 0xdc, 0x4e, 0x5a, 0x19, 0x10,
+        0x4f, 0xa3, 0x21, 0x20, 0x34, 0x05, 0x5b, 0x2e, 0x78, 0x91, 0xd1, 0xe2, 0x39, 0x43, 0x8b,
+        0x50, 0x12, 0x82, 0x37, 0xfe, 0xa4, 0x07, 0xc3, 0xd5, 0xc3, 0x78, 0xcc, 0xf9, 0xef, 0xe1,
+        0x95, 0x38, 0x9f, 0xb0, 0x79, 0x16, 0x4c, 0x4a, 0x23, 0xc4, 0xdc, 0x35, 0x4e, 0x0f};
+
 inline bool equal_byte_views(const byte_view& view1, const byte_view& view2) {
     return std::equal(view1.begin(), view1.end(), view2.begin(), view2.end());
 }
@@ -258,5 +293,14 @@
     EXPECT_THAT(eekPubY, ElementsAreArray(geek->getBstrValue(CoseKey::PUBKEY_Y).value_or(empty)));
 }
 
+TEST(RemoteProvUtilsTest, validateBccDegenerate) {
+    auto [bcc, _, errMsg] = cppbor::parse(kDegenerateBcc);
+    ASSERT_TRUE(bcc) << "Error: " << errMsg;
+
+    EXPECT_TRUE(validateBcc(bcc->asArray(), hwtrust::DiceChain::Kind::kVsr16,
+                            /*allowAnyMode=*/false, /*allowDegenerate=*/true));
+    EXPECT_FALSE(validateBcc(bcc->asArray(), hwtrust::DiceChain::Kind::kVsr16,
+                             /*allowAnyMode=*/false, /*allowDegenerate=*/false));
+}
 }  // namespace
 }  // namespace aidl::android::hardware::security::keymint::remote_prov
diff --git a/security/rkp/OWNERS b/security/rkp/OWNERS
index d25977f..8f854b4 100644
--- a/security/rkp/OWNERS
+++ b/security/rkp/OWNERS
@@ -2,4 +2,3 @@
 
 jbires@google.com
 sethmo@google.com
-trong@google.com
diff --git a/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequestV2.cddl b/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequestV2.cddl
index 3c43238..7a02ff5 100644
--- a/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequestV2.cddl
+++ b/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequestV2.cddl
@@ -62,9 +62,13 @@
 SignerName = tstr
 
 UdsCertChain = [
-    2* X509Certificate      ; Root -> ... -> Leaf. "Root" is the vendor self-signed
-                            ; cert, "Leaf" contains UDS_Public. There may also be
-                            ; intermediate certificates between Root and Leaf.
+    + X509Certificate       ; Root -> ... -> Leaf. "Root" is the vendor self-signed
+                            ; cert, "Leaf" contains UDS_Pub. It's recommended to
+                            ; have at least 3 certificates in the chain.
+                            ; The Root certificate is recommended to be generated in an air-gapped,
+                            ; HSM-based secure environment. The intermediate signing keys may be
+                            ; online, and should be rotated regularly (e.g. annually). Additionally,
+                            ; the intermediate certificates may contain product family identifiers.
 ]
 
 ; A bstr containing a DER-encoded X.509 certificate (RSA, NIST P-curve, or EdDSA)
@@ -73,7 +77,7 @@
 ; The DICE Chain contains measurements about the device firmware.
 ; The first entry in the DICE Chain is the UDS_Pub, encoded as a COSE_key. All entries
 ; after the first describe a link in the boot chain (e.g. bootloaders: BL1, BL2, ... BLN)
-; Note that there is no DiceChainEntry for UDS_pub, only a "bare" COSE_key.
+; Note that there is no DiceChainEntry for UDS_Pub, only a "bare" COSE_key.
 DiceCertChain = [
     PubKeyEd25519 / PubKeyECDSA256 / PubKeyECDSA384,  ; UDS_Pub
     + DiceChainEntry,               ; First CDI_Certificate -> Last CDI_Certificate
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/sensors/aidl/android/hardware/sensors/SensorType.aidl b/sensors/aidl/android/hardware/sensors/SensorType.aidl
index 9098894..4904c3f 100644
--- a/sensors/aidl/android/hardware/sensors/SensorType.aidl
+++ b/sensors/aidl/android/hardware/sensors/SensorType.aidl
@@ -718,8 +718,8 @@
     HEADING = 42,
 
     /**
-     * Base for device manufacturers private sensor types.
-     * These sensor types can't be exposed in the SDK.
+     * Base of the range reserved for device manufacturers' private sensor
+     * types. These sensor types aren't documented in the SDK.
      */
     DEVICE_PRIVATE_BASE = 0x10000,
 }
diff --git a/sensors/aidl/default/include/sensors-impl/Sensors.h b/sensors/aidl/default/include/sensors-impl/Sensors.h
index 2adbc9d..c90db69 100644
--- a/sensors/aidl/default/include/sensors-impl/Sensors.h
+++ b/sensors/aidl/default/include/sensors-impl/Sensors.h
@@ -97,9 +97,13 @@
             return;
         }
         if (mEventQueue->write(&events.front(), events.size())) {
+            if (mEventQueueFlag == nullptr) {
+                // Don't take the wake lock if we can't wake the receiver to avoid holding it
+                // indefinitely.
+                return;
+            }
             mEventQueueFlag->wake(
                     static_cast<uint32_t>(BnSensors::EVENT_QUEUE_FLAG_BITS_READ_AND_PROCESS));
-
             if (wakeup) {
                 // Keep track of the number of outstanding WAKE_UP events in order to properly hold
                 // a wake lock until the framework has secured a wake lock
diff --git a/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp b/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
index 0b15d12..b1590f9 100644
--- a/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
+++ b/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
@@ -714,11 +714,14 @@
         return;  // Exit early if setting up the new environment failed
     }
 
+    size_t numNonOneShotAndNonSpecialSensors = getNonOneShotAndNonSpecialSensors().size();
     activateAllSensors(true);
     // Verify that the old environment does not receive any events
     EXPECT_EQ(getEnvironment()->collectEvents(kCollectionTimeoutUs, kNumEvents).size(), 0);
-    // Verify that the new event queue receives sensor events
-    EXPECT_GE(newEnv.get()->collectEvents(kCollectionTimeoutUs, kNumEvents).size(), kNumEvents);
+    if (numNonOneShotAndNonSpecialSensors > 0) {
+        // Verify that the new event queue receives sensor events
+        EXPECT_GE(newEnv.get()->collectEvents(kCollectionTimeoutUs, kNumEvents).size(), kNumEvents);
+    }
     activateAllSensors(false);
 
     // Cleanup the test environment
@@ -733,7 +736,9 @@
 
     // Ensure that the original environment is receiving events
     activateAllSensors(true);
-    EXPECT_GE(getEnvironment()->collectEvents(kCollectionTimeoutUs, kNumEvents).size(), kNumEvents);
+    if (numNonOneShotAndNonSpecialSensors > 0) {
+        EXPECT_GE(getEnvironment()->collectEvents(kCollectionTimeoutUs, kNumEvents).size(), kNumEvents);
+    }
     activateAllSensors(false);
 }
 
@@ -743,7 +748,11 @@
     // Verify that events are received
     constexpr useconds_t kCollectionTimeoutUs = 1000 * 1000;  // 1s
     constexpr int32_t kNumEvents = 1;
-    ASSERT_GE(getEnvironment()->collectEvents(kCollectionTimeoutUs, kNumEvents).size(), kNumEvents);
+
+    size_t numNonOneShotAndNonSpecialSensors = getNonOneShotAndNonSpecialSensors().size();
+    if (numNonOneShotAndNonSpecialSensors > 0) {
+        ASSERT_GE(getEnvironment()->collectEvents(kCollectionTimeoutUs, kNumEvents).size(), kNumEvents);
+    }
 
     // Clear the active sensor handles so they are not disabled during TearDown
     auto handles = mSensorHandles;
@@ -757,7 +766,9 @@
     // Verify no events are received until sensors are re-activated
     ASSERT_EQ(getEnvironment()->collectEvents(kCollectionTimeoutUs, kNumEvents).size(), 0);
     activateAllSensors(true);
-    ASSERT_GE(getEnvironment()->collectEvents(kCollectionTimeoutUs, kNumEvents).size(), kNumEvents);
+    if (numNonOneShotAndNonSpecialSensors > 0) {
+        ASSERT_GE(getEnvironment()->collectEvents(kCollectionTimeoutUs, kNumEvents).size(), kNumEvents);
+    }
 
     // Disable sensors
     activateAllSensors(false);
diff --git a/soundtrigger/aidl/Android.bp b/soundtrigger/aidl/Android.bp
index af9a5fc..b8b6915 100644
--- a/soundtrigger/aidl/Android.bp
+++ b/soundtrigger/aidl/Android.bp
@@ -35,7 +35,7 @@
             sdk_version: "module_current",
         },
     },
-    frozen: true,
+    frozen: false,
     versions_with_info: [
         {
             version: "1",
@@ -52,7 +52,7 @@
 }
 
 // Note: This should always be one version ahead of the last frozen version
-latest_android_hardware_soundtrigger3 = "android.hardware.soundtrigger3-V2"
+latest_android_hardware_soundtrigger3 = "android.hardware.soundtrigger3-V3"
 
 // Modules that depend on android.hardware.soundtrigger3 directly can include
 // the following java_defaults to avoid explicitly managing dependency versions
diff --git a/staging/security/see/hwcrypto/aidl/Android.bp b/staging/security/see/hwcrypto/aidl/Android.bp
index 3e7ee9e..0a7e8be 100644
--- a/staging/security/see/hwcrypto/aidl/Android.bp
+++ b/staging/security/see/hwcrypto/aidl/Android.bp
@@ -10,6 +10,8 @@
 aidl_interface {
     name: "android.hardware.security.see",
     unstable: false,
+    // TODO Remove this owner field when this interface is moved out of /staging
+    owner: "google_while_staging",
     host_supported: true,
     srcs: [
         "android/hardware/security/see/hwcrypto/*.aidl",
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl b/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
index 7efcdd6..3763f0a 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
+++ b/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
@@ -36,6 +36,8 @@
   android.hardware.security.see.hwcrypto.IHwCryptoKey.DiceCurrentBoundKeyResult deriveCurrentDicePolicyBoundKey(in android.hardware.security.see.hwcrypto.IHwCryptoKey.DiceBoundDerivationKey derivationKey);
   android.hardware.security.see.hwcrypto.IHwCryptoKey.DiceBoundKeyResult deriveDicePolicyBoundKey(in android.hardware.security.see.hwcrypto.IHwCryptoKey.DiceBoundDerivationKey derivationKey, in byte[] dicePolicyForKeyVersion);
   android.hardware.security.see.hwcrypto.IHwCryptoKey.DerivedKey deriveKey(in android.hardware.security.see.hwcrypto.IHwCryptoKey.DerivedKeyParameters parameters);
+  android.hardware.security.see.hwcrypto.IHwCryptoOperations getHwCryptoOperations();
+  android.hardware.security.see.hwcrypto.IOpaqueKey importClearKey(in android.hardware.security.see.hwcrypto.types.ExplicitKeyMaterial keyMaterial, in android.hardware.security.see.hwcrypto.KeyPolicy newKeyPolicy);
   enum DeviceKeyId {
     DEVICE_BOUND_KEY,
     BATCH_KEY,
@@ -56,8 +58,8 @@
     int keySizeBytes;
   }
   union DerivedKeyPolicy {
-    android.hardware.security.see.hwcrypto.KeyPolicy opaqueKey;
     android.hardware.security.see.hwcrypto.IHwCryptoKey.ClearKeyPolicy clearKey;
+    byte[] opaqueKey;
   }
   parcelable DerivedKeyParameters {
     android.hardware.security.see.hwcrypto.IOpaqueKey derivationKey;
diff --git a/drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevel.aidl b/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/AesKey.aidl
similarity index 84%
copy from drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevel.aidl
copy to staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/AesKey.aidl
index 5704fb0..f4bf786 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevel.aidl
+++ b/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/AesKey.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -31,15 +31,8 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.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,
+package android.hardware.security.see.hwcrypto.types;
+union AesKey {
+  byte[16] aes128 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  byte[32] aes256;
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevel.aidl b/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ExplicitKeyMaterial.aidl
similarity index 84%
copy from drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevel.aidl
copy to staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ExplicitKeyMaterial.aidl
index 5704fb0..933fb67 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevel.aidl
+++ b/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ExplicitKeyMaterial.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -31,15 +31,7 @@
 // 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,
+package android.hardware.security.see.hwcrypto.types;
+union ExplicitKeyMaterial {
+  android.hardware.security.see.hwcrypto.types.AesKey aes;
 }
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/MemoryBufferReference.aidl b/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/MemoryBufferReference.aidl
index eaa8dd7..59c8757 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/MemoryBufferReference.aidl
+++ b/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/MemoryBufferReference.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto.types;
+@RustDerive(Clone=true, Copy=true)
 parcelable MemoryBufferReference {
   int startOffset;
   int sizeBytes;
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl b/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
index 939014a..b5e7e9d 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
+++ b/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
@@ -15,8 +15,10 @@
  */
 package android.hardware.security.see.hwcrypto;
 
+import android.hardware.security.see.hwcrypto.IHwCryptoOperations;
 import android.hardware.security.see.hwcrypto.IOpaqueKey;
 import android.hardware.security.see.hwcrypto.KeyPolicy;
+import android.hardware.security.see.hwcrypto.types.ExplicitKeyMaterial;
 
 /*
  * Higher level interface to access and generate keys.
@@ -88,15 +90,15 @@
 
     union DerivedKeyPolicy {
         /*
-         * Policy for the newly derived opaque key. Defines how the key can be used and its type.
-         */
-        KeyPolicy opaqueKey;
-
-        /*
          * If used we will derive a clear key and pass it back as an array of bytes on
          * <code>HwCryptoKeyMaterial::explicitKey</code>.
          */
         ClearKeyPolicy clearKey;
+
+        /*
+         * Policy for the newly derived opaque key. Defines how the key can be used and its type.
+         */
+        byte[] opaqueKey;
     }
 
     parcelable DerivedKeyParameters {
@@ -183,4 +185,36 @@
      *      <code>HalErrorCode</code> otherwise.
      */
     DerivedKey deriveKey(in DerivedKeyParameters parameters);
+
+    /*
+     * getHwCryptoOperations() - Returns an interface used to work on opaque keys. This interface
+     *                           can also be used to operate on any opaque key generated by
+     *                           hwkeyDeriveVersioned, even if this key has been generated after
+     *                           retrieving a IHwCryptoOperations binder object, as long as the
+     *                           parent IHwCryptoDeviceKeyAccess is not dropped between retrieving
+     *                           the IHwCryptoOperations binder object and deriving the key.
+     *                           IHwCryptoOperations can also be used to create opaque keys that
+     *                           are not bound to the device.
+     *
+     * Return:
+     *      IHwCryptoOperations on success
+     */
+    IHwCryptoOperations getHwCryptoOperations();
+
+    /*
+     * importClearKey() - Imports a SW clear key into the secure environment.
+     *
+     * @keyMaterial:
+     *     key to be imported.
+     * @newKeyPolicy:
+     *      Policy of the new key. Defines how the newly created key can be used. Because any
+     *      clear key imported into the system is considered to have a
+     *      <code>KeyLifetime::PORTABLE</code> lifetime, a call to this function will return an
+     *      error if <code>newKeyPolicy.newKeyPolicy</code> is not set to portable.
+     *
+     * Return:
+     *      IOpaqueKey on success, service specific error based on <code>HalErrorCode</code>
+     *      otherwise.
+     */
+    IOpaqueKey importClearKey(in ExplicitKeyMaterial keyMaterial, in KeyPolicy newKeyPolicy);
 }
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/KeyPolicy.cddl b/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/KeyPolicy.cddl
new file mode 100644
index 0000000..77b632b
--- /dev/null
+++ b/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/KeyPolicy.cddl
@@ -0,0 +1,66 @@
+;
+; 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.
+;
+
+KeyPolicy = [
+    -65701: KeyUse,           ;usage
+    -65702: KeyLifetime       ;keyLifetime
+    -65703: KeyPermissions    ;keyPermissions
+    -65704: KeyType           ;keyType
+    -65705: bool              ;keyManagementKey
+]
+
+KeyUse = &(
+    ENCRYPT: 1,
+    DECRYPT: 2,
+    ENCRYPT_DECRYPT: ENCRYPT | DECRYPT,
+    SIGN: 4,
+    DERIVE: 8,
+    WRAP: 16,
+)
+
+KeyLifetime = &(
+    EPHEMERAL: 0,
+    HARDWARE: 1,
+    PORTABLE: 2,
+)
+
+KeyPermissions = &(
+    ALLOW_EPHEMERAL_KEY_WRAPPING: 0,
+    ALLOW_HARDWARE_KEY_WRAPPING: 1,
+    ALLOW_PORTABLE_KEY_WRAPPING: 2,
+)
+
+enum KeyType = &(
+    AES_128_CBC_NO_PADDING: 0,
+    AES_128_CBC_PKCS7_PADDING: 1,
+    AES_128_CTR: 2,
+    AES_128_GCM: 3,
+    AES_128_CMAC: 4,
+    AES_256_CBC_NO_PADDING: 5,
+    AES_256_CBC_PKCS7_PADDING: 6,
+    AES_256_CTR: 7,
+    AES_256_GCM: 8,
+    AES_256_CMAC: 9,
+    HMAC_SHA256: 10,
+    HMAC_SHA512: 11,
+    RSA2048_PSS_SHA256: 12,
+    RSA2048_PKCS1_5_SHA256: 13,
+    ECC_NIST_P256_SIGN_NO_PADDING: 14,
+    ECC_NIST_P256_SIGN_SHA256: 15,
+    ECC_NIST_P521_SIGN_NO_PADDING: 16,
+    ECC_NIST_P521_SIGN_SHA512: 17,
+    ECC_ED25519_SIGN:18,
+)
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/FileAvailability.aidl b/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/AesKey.aidl
similarity index 65%
copy from staging/security/see/storage/aidl/android/hardware/security/see/storage/FileAvailability.aidl
copy to staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/AesKey.aidl
index d339170..cf9082d 100644
--- a/staging/security/see/storage/aidl/android/hardware/security/see/storage/FileAvailability.aidl
+++ b/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/AesKey.aidl
@@ -13,13 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.hardware.security.see.storage;
+package android.hardware.security.see.hwcrypto.types;
 
-/** Determines how early during the boot process file is able to be accessed. */
-enum FileAvailability {
-    /** Available before userdata is mounted, but after android has booted. */
-    BEFORE_USERDATA,
+/*
+ * Type that represents an AES key.
+ */
+union AesKey {
+    /*
+     * Raw AES 128 bit key material.
+     */
+    byte[16] aes128 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 
-    /** Available after userdata is mounted. */
-    AFTER_USERDATA,
+    /*
+     * Raw AES 256 bit key material.
+     */
+    byte[32] aes256;
 }
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/FileAvailability.aidl b/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/ExplicitKeyMaterial.aidl
similarity index 65%
copy from staging/security/see/storage/aidl/android/hardware/security/see/storage/FileAvailability.aidl
copy to staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/ExplicitKeyMaterial.aidl
index d339170..4298ba9 100644
--- a/staging/security/see/storage/aidl/android/hardware/security/see/storage/FileAvailability.aidl
+++ b/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/ExplicitKeyMaterial.aidl
@@ -13,13 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.hardware.security.see.storage;
+package android.hardware.security.see.hwcrypto.types;
 
-/** Determines how early during the boot process file is able to be accessed. */
-enum FileAvailability {
-    /** Available before userdata is mounted, but after android has booted. */
-    BEFORE_USERDATA,
+import android.hardware.security.see.hwcrypto.types.AesKey;
 
-    /** Available after userdata is mounted. */
-    AFTER_USERDATA,
+/*
+ * Type encapsulating a clear key.
+ */
+union ExplicitKeyMaterial {
+    AesKey aes;
 }
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/MemoryBufferReference.aidl b/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/MemoryBufferReference.aidl
index 5b90d9c..1175dc5 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/MemoryBufferReference.aidl
+++ b/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/MemoryBufferReference.aidl
@@ -18,6 +18,7 @@
 /*
  * Structure representing a section of a memory buffer.
  */
+@RustDerive(Copy=true, Clone=true)
 parcelable MemoryBufferReference {
     /*
      * Start of the memory buffer section measured from the start of the memory buffer set for this
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/FileAvailability.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/Availability.aidl
similarity index 97%
rename from staging/security/see/storage/aidl/android/hardware/security/see/storage/FileAvailability.aidl
rename to staging/security/see/storage/aidl/android/hardware/security/see/storage/Availability.aidl
index d339170..21a275c 100644
--- a/staging/security/see/storage/aidl/android/hardware/security/see/storage/FileAvailability.aidl
+++ b/staging/security/see/storage/aidl/android/hardware/security/see/storage/Availability.aidl
@@ -16,7 +16,7 @@
 package android.hardware.security.see.storage;
 
 /** Determines how early during the boot process file is able to be accessed. */
-enum FileAvailability {
+enum Availability {
     /** Available before userdata is mounted, but after android has booted. */
     BEFORE_USERDATA,
 
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/DeleteOptions.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/DeleteOptions.aidl
deleted file mode 100644
index 1a94eb2..0000000
--- a/staging/security/see/storage/aidl/android/hardware/security/see/storage/DeleteOptions.aidl
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 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.security.see.storage;
-
-import android.hardware.security.see.storage.ReadIntegrity;
-
-parcelable DeleteOptions {
-    /**
-     * Set to acknowledge possible files tampering.
-     *
-     * If unacknowledged tampering is detected, the operation will fail with an ERR_FS_*
-     * service-specific code.
-     */
-    ReadIntegrity readIntegrity = ReadIntegrity.NO_TAMPER;
-
-    /**
-     * Allow writes to succeed while the filesystem is in the middle of an A/B update.
-     *
-     * If the A/B update fails, the operation will be rolled back. This rollback will not
-     * cause subsequent operations fail with any ERR_FS_* code nor will need to be
-     * acknowledged by setting the `readIntegrity`.
-     */
-    boolean allowWritesDuringAbUpdate = false;
-}
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/FileProperties.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/FileProperties.aidl
deleted file mode 100644
index 733b5b0..0000000
--- a/staging/security/see/storage/aidl/android/hardware/security/see/storage/FileProperties.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 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.security.see.storage;
-
-import android.hardware.security.see.storage.FileAvailability;
-import android.hardware.security.see.storage.FileIntegrity;
-
-parcelable FileProperties {
-    FileIntegrity integrity = FileIntegrity.TAMPER_PROOF_AT_REST;
-    FileAvailability availability = FileAvailability.BEFORE_USERDATA;
-
-    /** Whether the file is reset when user data is wiped. */
-    boolean persistent;
-}
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/Filesystem.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/Filesystem.aidl
new file mode 100644
index 0000000..ea8db53
--- /dev/null
+++ b/staging/security/see/storage/aidl/android/hardware/security/see/storage/Filesystem.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright 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.security.see.storage;
+
+import android.hardware.security.see.storage.Availability;
+import android.hardware.security.see.storage.Integrity;
+
+/**
+ * Specifies minimum security requirements for a Secure Storage filesystem.
+ */
+parcelable Filesystem {
+    Integrity integrity = Integrity.TAMPER_PROOF_AT_REST;
+    Availability availability = Availability.BEFORE_USERDATA;
+
+    /**
+     * Whether the file is reset on factory resets. Factory resets will not be reported as
+     * tampering.
+     */
+    boolean persistent;
+}
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/IDir.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/IDir.aidl
index a0a9f3d..5d9a761 100644
--- a/staging/security/see/storage/aidl/android/hardware/security/see/storage/IDir.aidl
+++ b/staging/security/see/storage/aidl/android/hardware/security/see/storage/IDir.aidl
@@ -26,15 +26,15 @@
      *
      * @maxCount:
      *     the maximum number of filenames to return. A @maxCount of 0 signifies no limit on the
-     * number of filenames returned.
+     *     number of filenames returned.
      *
      * Returns:
      *     An ordered list of filenames. If @maxCount > 0, the length of the returned list will be
-     * less than or equal to @maxCount.
+     *     less than or equal to @maxCount.
      *
      * May return service-specific errors:
-     *   - ERR_FS_* if the filesystem has been tampered with in a way that the `readIntegrity` the
-     *       dir was opened with does not acknowledge
+     *   - ERR_FS_* if the filesystem has been tampered with in a way that the session did not
+     *       acknowledge
      */
     @utf8InCpp String[] readNextFilenames(int maxCount);
 }
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/IFile.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/IFile.aidl
index ff26aa4..fd2032e 100644
--- a/staging/security/see/storage/aidl/android/hardware/security/see/storage/IFile.aidl
+++ b/staging/security/see/storage/aidl/android/hardware/security/see/storage/IFile.aidl
@@ -32,8 +32,8 @@
      *     the sequence of bytes at [offset, offset + size) in the file
      *
      * May return service-specific errors:
-     *   - ERR_FS_* if the filesystem has been tampered with in a way that the `readIntegrity` the
-     *       file was opened with does not acknowledge
+     *   - ERR_FS_* if the filesystem has been tampered with in a way that the session did not
+     *       acknowledge
      */
     byte[] read(long size, long offset);
 
@@ -47,8 +47,8 @@
      *     the number of bytes written successfully
      *
      * May return service-specific errors:
-     *   - ERR_FS_* if the filesystem has been tampered with in a way that the `readIntegrity` the
-     *       file was opened with does not acknowledge
+     *   - ERR_FS_* if the filesystem has been tampered with in a way that the session did not
+     *       acknowledge
      */
     long write(long offset, in byte[] buffer);
 
@@ -56,8 +56,8 @@
      * Reads this file's size.
      *
      * May return service-specific errors:
-     *   - ERR_FS_* if the filesystem has been tampered with in a way that the `readIntegrity` the
-     *       file was opened with does not acknowledge
+     *   - ERR_FS_* if the filesystem has been tampered with in a way that the session did not
+     *       acknowledge
      */
     long getSize();
 
@@ -71,8 +71,8 @@
      *     the file's new size
      *
      * May return service-specific errors:
-     *   - ERR_FS_* if the filesystem has been tampered with in a way that the `readIntegrity` the
-     *       file was opened with does not acknowledge
+     *   - ERR_FS_* if the filesystem has been tampered with in a way that the session did not
+     *       acknowledge
      */
     void setSize(long newSize);
 
@@ -88,8 +88,8 @@
      *   - ERR_NOT_FOUND if no file exists at @destPath and @destCreateMode is `NO_CREATE`
      *   - ERR_ALREADY_EXISTS if a file already exists at @destPath and @destCreateMode is
      *       `CREATE_EXCLUSIVE`
-     *   - ERR_FS_* if the filesystem has been tampered with in a way that the `readIntegrity` the
-     *       file was opened with does not acknowledge
+     *   - ERR_FS_* if the filesystem has been tampered with in a way that the session did not
+     *       acknowledge
      */
     void rename(in @utf8InCpp String destPath, in CreationMode destCreateMode);
 }
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/ISecureStorage.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/ISecureStorage.aidl
index be3c045..022de9a 100644
--- a/staging/security/see/storage/aidl/android/hardware/security/see/storage/ISecureStorage.aidl
+++ b/staging/security/see/storage/aidl/android/hardware/security/see/storage/ISecureStorage.aidl
@@ -15,7 +15,7 @@
  */
 package android.hardware.security.see.storage;
 
-import android.hardware.security.see.storage.FileProperties;
+import android.hardware.security.see.storage.Filesystem;
 import android.hardware.security.see.storage.IStorageSession;
 
 /**
@@ -28,20 +28,18 @@
     const int ERR_NOT_FOUND = 2;
     const int ERR_ALREADY_EXISTS = 3;
     const int ERR_BAD_TRANSACTION = 4;
-
-    const int ERR_FS_RESET = 5;
-    const int ERR_FS_ROLLED_BACK = 6;
-    const int ERR_FS_TAMPERED = 7;
+    const int ERR_AB_UPDATE_IN_PROGRESS = 5;
+    const int ERR_FS_TAMPERED = 6;
 
     /**
      * Starts a storage session for a filesystem.
      *
-     * @properties:
-     *     the minimum filesystem properties requested for the session.
+     * @filesystem:
+     *     The minimum filesystem properties requested.
      *
      * May return service-specific errors:
      *   - ERR_UNSUPPORTED_PROPERTIES if no filesystems exist which meet the minimum requested
-     * requirements
+     *       requirements
      */
-    IStorageSession startSession(in FileProperties properties);
+    IStorageSession startSession(in Filesystem filesystem);
 }
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/IStorageSession.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/IStorageSession.aidl
index cd126b8..1b70a0e 100644
--- a/staging/security/see/storage/aidl/android/hardware/security/see/storage/IStorageSession.aidl
+++ b/staging/security/see/storage/aidl/android/hardware/security/see/storage/IStorageSession.aidl
@@ -15,12 +15,10 @@
  */
 package android.hardware.security.see.storage;
 
-import android.hardware.security.see.storage.DeleteOptions;
+import android.hardware.security.see.storage.CreationMode;
 import android.hardware.security.see.storage.IDir;
 import android.hardware.security.see.storage.IFile;
 import android.hardware.security.see.storage.OpenOptions;
-import android.hardware.security.see.storage.ReadIntegrity;
-import android.hardware.security.see.storage.RenameOptions;
 
 /**
  * Interface for a Secure Storage session
@@ -66,8 +64,8 @@
      * May return service-specific errors:
      *   - ERR_NOT_FOUND
      *   - ERR_ALREADY_EXISTS
-     *   - ERR_FS_* if the filesystem has been tampered with in a way that @options.readIntegrity
-     *       does not acknowledge
+     *   - ERR_FS_* if the filesystem has been tampered with in a way that the session did not
+     *       acknowledge
      */
     IFile openFile(in @utf8InCpp String filePath, in OpenOptions options);
 
@@ -81,10 +79,10 @@
      *
      * May return service-specific errors:
      *   - ERR_NOT_FOUND
-     *   - ERR_FS_* if the filesystem has been tampered with in a way that @options.readIntegrity
-     *       does not acknowledge
+     *   - ERR_FS_* if the filesystem has been tampered with in a way that the session did not
+     *       acknowledge
      */
-    void deleteFile(in @utf8InCpp String filePath, in DeleteOptions options);
+    void deleteFile(in @utf8InCpp String filePath);
 
     /**
      * Renames an existing file.
@@ -95,19 +93,19 @@
      *     path to the file, relative to filesystem root
      * @destPath:
      *     the file's new path, relative to filesystem root
-     * @options:
-     *     options controlling rename behavior
+     * @destCreateMode:
+     *     creation behavior for the dest file
      *
      * May return service-specific errors:
-     *   - ERR_NOT_FOUND if no file exists at @currentPath, or if @options.destCreateMode is
-     *       `NO_CREATE` and no file exists at @destPath
-     *   - ERR_ALREADY_EXISTS if @options.destCreateMode is `CREATE_EXCLUSIVE` and a file exists at
+     *   - ERR_NOT_FOUND if no file exists at @currentPath, or if @destCreateMode is `NO_CREATE` and
+     *       no file exists at @destPath
+     *   - ERR_ALREADY_EXISTS if @destCreateMode is `CREATE_EXCLUSIVE` and a file exists at
      *       @destPath
-     *   - ERR_FS_* if the filesystem has been tampered with in a way that @options.readIntegrity
-     *       does not acknowledge
+     *   - ERR_FS_* if the filesystem has been tampered with in a way that the session did not
+     *       acknowledge
      */
     void renameFile(in @utf8InCpp String currentPath, in @utf8InCpp String destPath,
-            in RenameOptions options);
+            in CreationMode destCreateMode);
 
     /**
      * Opens a directory from a filesystem with the given properties.
@@ -116,14 +114,11 @@
      *
      * @path:
      *     path to the directory, relative to filesystem root
-     * @readIntegrity:
-     *     allow opening (and subsequent read/write operations) despite possible tampering for the
-     * directory
      *
      * May return service-specific errors:
      *   - ERR_NOT_FOUND
-     *   - ERR_FS_* if the filesystem has been tampered with in a way that @readIntegrity does not
+     *   - ERR_FS_* if the filesystem has been tampered with in a way that the session did not
      *       acknowledge
      */
-    IDir openDir(in @utf8InCpp String path, in ReadIntegrity readIntegrity);
+    IDir openDir(in @utf8InCpp String path);
 }
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/FileIntegrity.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/Integrity.aidl
similarity index 83%
rename from staging/security/see/storage/aidl/android/hardware/security/see/storage/FileIntegrity.aidl
rename to staging/security/see/storage/aidl/android/hardware/security/see/storage/Integrity.aidl
index 1879b16..2f7f7ab 100644
--- a/staging/security/see/storage/aidl/android/hardware/security/see/storage/FileIntegrity.aidl
+++ b/staging/security/see/storage/aidl/android/hardware/security/see/storage/Integrity.aidl
@@ -15,7 +15,7 @@
  */
 package android.hardware.security.see.storage;
 
-enum FileIntegrity {
+enum Integrity {
     /** REE may prevent operations, but cannot alter data once written. */
     TAMPER_PROOF_AT_REST,
 
@@ -24,10 +24,4 @@
      * an error on read.
      */
     TAMPER_DETECT,
-
-    /**
-     * REE may alter written data. Changes other than full filesystem resets will be detected and
-     * reported.
-     */
-    TAMPER_DETECT_IGNORE_RESET,
 }
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/OpenOptions.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/OpenOptions.aidl
index 997ca62..9fdf9e5 100644
--- a/staging/security/see/storage/aidl/android/hardware/security/see/storage/OpenOptions.aidl
+++ b/staging/security/see/storage/aidl/android/hardware/security/see/storage/OpenOptions.aidl
@@ -17,7 +17,6 @@
 
 import android.hardware.security.see.storage.CreationMode;
 import android.hardware.security.see.storage.FileMode;
-import android.hardware.security.see.storage.ReadIntegrity;
 
 parcelable OpenOptions {
     /** Controls creation behavior of the to-be-opened file. See `CreationMode` docs for details. */
@@ -27,25 +26,8 @@
     FileMode accessMode = FileMode.READ_WRITE;
 
     /**
-     * Set to acknowledge possible files tampering.
-     *
-     * If unacknowledged tampering is detected, the operation will fail with an ERR_FS_*
-     * service-specific code.
-     */
-    ReadIntegrity readIntegrity = ReadIntegrity.NO_TAMPER;
-
-    /**
      * If this file already exists, discard existing content and open
      * it as a new file. No semantic change if the file does not exist.
      */
     boolean truncateOnOpen;
-
-    /**
-     * Allow writes to succeed while the filesystem is in the middle of an A/B update.
-     *
-     * If the A/B update fails, the operation will be rolled back. This rollback will not
-     * cause subsequent operations fail with any ERR_FS_* code nor will need to be
-     * acknowledged by setting the `readIntegrity`.
-     */
-    boolean allowWritesDuringAbUpdate = false;
 }
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/ReadIntegrity.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/ReadIntegrity.aidl
deleted file mode 100644
index cc0e4f9..0000000
--- a/staging/security/see/storage/aidl/android/hardware/security/see/storage/ReadIntegrity.aidl
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 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.security.see.storage;
-
-enum ReadIntegrity {
-    /**
-     * Return an error on reads if any REE alteration of the written data
-     * has been detected.
-     */
-    NO_TAMPER,
-
-    /**
-     * Return an error on reads if any REE alteration other than a reset
-     * has been detected.
-     */
-    IGNORE_RESET,
-
-    /**
-     * Return an error if any REE alteration other than a rollback to a
-     * valid checkpoint has been detected. (What makes a checkpoint valid is
-     * implementation defined; an implementation might take a checkpoint on its
-     * first post-factory boot. A reset is a rollback to the initial state.)
-     */
-    IGNORE_ROLLBACK,
-
-    // There's no `IGNORE_ALL` because if REE has done any alteration other
-    // than a rollback, the file contents will be known-bad data.
-}
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/RenameOptions.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/RenameOptions.aidl
deleted file mode 100644
index f55ea7f..0000000
--- a/staging/security/see/storage/aidl/android/hardware/security/see/storage/RenameOptions.aidl
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 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.security.see.storage;
-
-import android.hardware.security.see.storage.CreationMode;
-import android.hardware.security.see.storage.ReadIntegrity;
-
-parcelable RenameOptions {
-    /** Controls creation behavior of the dest file. See `CreationMode` docs for details. */
-    CreationMode destCreateMode = CreationMode.CREATE_EXCLUSIVE;
-
-    /**
-     * Set to acknowledge possible files tampering.
-     *
-     * If unacknowledged tampering is detected, the operation will fail with an ERR_FS_*
-     * service-specific code.
-     */
-    ReadIntegrity readIntegrity = ReadIntegrity.NO_TAMPER;
-
-    /**
-     * Allow writes to succeed while the filesystem is in the middle of an A/B update.
-     *
-     * If the A/B update fails, the operation will be rolled back. This rollback will not
-     * cause subsequent operations fail with any ERR_FS_* code nor will need to be
-     * acknowledged by setting the `readIntegrity`.
-     */
-    boolean allowWritesDuringAbUpdate = false;
-}
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/Tamper.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/Tamper.aidl
deleted file mode 100644
index 0a39fdd..0000000
--- a/staging/security/see/storage/aidl/android/hardware/security/see/storage/Tamper.aidl
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 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.security.see.storage;
-
-/** Specifies types of REE tampering the filesystem may detect */
-enum Tamper {
-    /** REE has reset this file or the containing file system. */
-    RESET,
-
-    /** REE has rolled back this file or the containing file system to a previous state. */
-    ROLLBACK,
-
-    /** REE has made some other modification to the file. */
-    OTHER,
-}
diff --git a/tests/extension/vibrator/aidl/Android.bp b/tests/extension/vibrator/aidl/Android.bp
index 0306dca..3ef8749 100644
--- a/tests/extension/vibrator/aidl/Android.bp
+++ b/tests/extension/vibrator/aidl/Android.bp
@@ -37,6 +37,15 @@
         java: {
             enabled: false,
         },
+        ndk: {
+            enabled: true,
+        },
+        cpp: {
+            enabled: false,
+        },
+        rust: {
+            enabled: false,
+        },
     },
     frozen: true,
     versions_with_info: [
diff --git a/tests/extension/vibrator/aidl/client/Android.bp b/tests/extension/vibrator/aidl/client/Android.bp
index 284ac74..00510b7 100644
--- a/tests/extension/vibrator/aidl/client/Android.bp
+++ b/tests/extension/vibrator/aidl/client/Android.bp
@@ -16,16 +16,10 @@
     srcs: [
         // system code has the option to use the unstable C++ libbinder API
         // or the NDK one. For maximum code portability, using the ndk client
-        // makes the most sense, but both are provided here as an example.
-        "test-cpp-client.cpp",
+        // makes the most sense.
         "test-ndk-client.cpp",
     ],
     shared_libs: [
-        "libbinder",
-        "libutils",
-        "android.hardware.vibrator-V2-cpp",
-        "android.hardware.tests.extension.vibrator-V1-cpp",
-
         "libbinder_ndk",
         "android.hardware.vibrator-V2-ndk",
         "android.hardware.tests.extension.vibrator-V1-ndk",
diff --git a/tests/extension/vibrator/aidl/client/test-cpp-client.cpp b/tests/extension/vibrator/aidl/client/test-cpp-client.cpp
deleted file mode 100644
index 015a345..0000000
--- a/tests/extension/vibrator/aidl/client/test-cpp-client.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android/hardware/tests/extension/vibrator/ICustomVibrator.h>
-#include <android/hardware/vibrator/IVibrator.h>
-#include <binder/IInterface.h>
-#include <binder/IServiceManager.h>
-#include <gtest/gtest.h>
-
-using android::checked_interface_cast;
-using android::IBinder;
-using android::IInterface;
-using android::OK;
-using android::sp;
-using android::waitForVintfService;
-using android::hardware::tests::extension::vibrator::Directionality;
-using android::hardware::tests::extension::vibrator::ICustomVibrator;
-using android::hardware::vibrator::IVibrator;
-
-TEST(Cpp, CallRootMethod) {
-    sp<IVibrator> vib = waitForVintfService<IVibrator>();
-    ASSERT_NE(nullptr, vib.get());
-    ASSERT_TRUE(vib->off().isOk());
-}
-
-TEST(Cpp, CallExtMethod) {
-    // normally you would want to cache this
-    sp<IVibrator> vib = waitForVintfService<IVibrator>();
-    ASSERT_NE(nullptr, vib.get());
-
-    // getting the extension
-    sp<IBinder> ext;
-    ASSERT_EQ(OK, IInterface::asBinder(vib)->getExtension(&ext));
-    sp<ICustomVibrator> cvib = checked_interface_cast<ICustomVibrator>(ext);
-    ASSERT_NE(nullptr, cvib.get());
-
-    // calling extension method
-    ASSERT_TRUE(cvib->setDirectionality(Directionality::TRANSVERSE).isOk());
-}
diff --git a/tests/extension/vibrator/aidl/client/test-ndk-client.cpp b/tests/extension/vibrator/aidl/client/test-ndk-client.cpp
index c846495..4dd86e8 100644
--- a/tests/extension/vibrator/aidl/client/test-ndk-client.cpp
+++ b/tests/extension/vibrator/aidl/client/test-ndk-client.cpp
@@ -28,7 +28,7 @@
 static const std::string kInstance = std::string() + IVibrator::descriptor + "/default";
 
 TEST(Ndk, CallRootMethod) {
-    SpAIBinder vibBinder = SpAIBinder(AServiceManager_getService(kInstance.c_str()));
+    SpAIBinder vibBinder = SpAIBinder(AServiceManager_waitForService(kInstance.c_str()));
     ASSERT_NE(nullptr, vibBinder.get());
     std::shared_ptr<IVibrator> vib = IVibrator::fromBinder(vibBinder);
     ASSERT_NE(nullptr, vib.get());
@@ -38,7 +38,7 @@
 TEST(Ndk, CallExtMethod) {
     // normally you would want to cache this
     //
-    SpAIBinder vibBinder = SpAIBinder(AServiceManager_getService(kInstance.c_str()));
+    SpAIBinder vibBinder = SpAIBinder(AServiceManager_waitForService(kInstance.c_str()));
     ASSERT_NE(nullptr, vibBinder.get());
     std::shared_ptr<IVibrator> vib = IVibrator::fromBinder(vibBinder);
     ASSERT_NE(nullptr, vib.get());
diff --git a/tests/extension/vibrator/aidl/default/Android.bp b/tests/extension/vibrator/aidl/default/Android.bp
index 5e156af..479b4fd 100644
--- a/tests/extension/vibrator/aidl/default/Android.bp
+++ b/tests/extension/vibrator/aidl/default/Android.bp
@@ -10,11 +10,6 @@
 cc_binary {
     name: "android.hardware.tests.extension.vibrator-service.example",
     relative_install_path: "hw",
-    // normally you implement a service directly, but we are using an implementation
-    // from a library to attach our extension to.
-    static_libs: [
-        "libvibratorexampleimpl",
-    ],
 
     // need to add this in the manifest and to init as well to use, see
     // android.hardware.vibrator-service.example. This binary is being tested
@@ -23,6 +18,7 @@
     vendor: true,
     srcs: [
         "service.cpp",
+        "Vibrator.cpp",
         "CustomVibrator.cpp",
     ],
     shared_libs: [
diff --git a/tests/extension/vibrator/aidl/default/CustomVibrator.cpp b/tests/extension/vibrator/aidl/default/CustomVibrator.cpp
index 7a7c58b..9c306b5 100644
--- a/tests/extension/vibrator/aidl/default/CustomVibrator.cpp
+++ b/tests/extension/vibrator/aidl/default/CustomVibrator.cpp
@@ -60,7 +60,7 @@
 ndk::SpAIBinder CustomVibrator::createBinder() {
     auto binder = BnCustomVibrator::createBinder();
     // e.g. AIBinder_setInheritRt(binder.get(), true);
-    // e.g. AIBinder_setMinSchedulerPolicy(binder.get(), SCHED_NORMAL, 20);
+    // e.g. AIBinder_setMinSchedulerPolicy(binder.get(), SCHED_NORMAL, -2);
     // e.g. AIBinder_setRequestingSid(binder.get(), true);
     return binder;
 }
diff --git a/tests/extension/vibrator/aidl/default/Vibrator.cpp b/tests/extension/vibrator/aidl/default/Vibrator.cpp
new file mode 100644
index 0000000..5084096
--- /dev/null
+++ b/tests/extension/vibrator/aidl/default/Vibrator.cpp
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+
+#include "Vibrator.h"
+
+#include <android-base/logging.h>
+
+namespace aidl::android::hardware::vibrator {
+
+ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) {
+    // basic example with only amplitude control capability
+    *_aidl_return = IVibrator::CAP_AMPLITUDE_CONTROL;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::off() {
+    LOG(INFO) << "Vibrator off";
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs, const std::shared_ptr<IVibratorCallback>&) {
+    LOG(INFO) << "Vibrator on for timeoutMs: " << timeoutMs;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) {
+    LOG(INFO) << "Vibrator set amplitude: " << amplitude;
+    if (amplitude <= 0.0f || amplitude > 1.0f) {
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::perform(Effect, EffectStrength,
+                                     const std::shared_ptr<IVibratorCallback>&, int32_t*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector<Effect>* _aidl_return) {
+    *_aidl_return = {};
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::setExternalControl(bool) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getCompositionDelayMax(int32_t*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getSupportedPrimitives(std::vector<CompositePrimitive>*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive, int32_t*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect>&,
+                                     const std::shared_ptr<IVibratorCallback>&) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector<Effect>*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t, Effect, EffectStrength) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getResonantFrequency(float*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getQFactor(float*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getFrequencyResolution(float*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getFrequencyMinimum(float*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getBandwidthAmplitudeMap(std::vector<float>*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getPwlePrimitiveDurationMax(int32_t*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getPwleCompositionSizeMax(int32_t*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getSupportedBraking(std::vector<Braking>*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle>&,
+                                         const std::shared_ptr<IVibratorCallback>&) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+}  // namespace aidl::android::hardware::vibrator
diff --git a/tests/extension/vibrator/aidl/default/Vibrator.h b/tests/extension/vibrator/aidl/default/Vibrator.h
new file mode 100644
index 0000000..80916ae
--- /dev/null
+++ b/tests/extension/vibrator/aidl/default/Vibrator.h
@@ -0,0 +1,56 @@
+/*
+ * 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/vibrator/BnVibrator.h>
+
+namespace aidl::android::hardware::vibrator {
+
+class Vibrator : public BnVibrator {
+    ndk::ScopedAStatus getCapabilities(int32_t* _aidl_return) override;
+    ndk::ScopedAStatus off() override;
+    ndk::ScopedAStatus on(int32_t timeoutMs,
+                          const std::shared_ptr<IVibratorCallback>& callback) override;
+    ndk::ScopedAStatus perform(Effect effect, EffectStrength strength,
+                               const std::shared_ptr<IVibratorCallback>& callback,
+                               int32_t* _aidl_return) override;
+    ndk::ScopedAStatus getSupportedEffects(std::vector<Effect>* _aidl_return) override;
+    ndk::ScopedAStatus setAmplitude(float amplitude) override;
+    ndk::ScopedAStatus setExternalControl(bool enabled) override;
+    ndk::ScopedAStatus getCompositionDelayMax(int32_t* maxDelayMs);
+    ndk::ScopedAStatus getCompositionSizeMax(int32_t* maxSize);
+    ndk::ScopedAStatus getSupportedPrimitives(std::vector<CompositePrimitive>* supported) override;
+    ndk::ScopedAStatus getPrimitiveDuration(CompositePrimitive primitive,
+                                            int32_t* durationMs) override;
+    ndk::ScopedAStatus compose(const std::vector<CompositeEffect>& composite,
+                               const std::shared_ptr<IVibratorCallback>& callback) override;
+    ndk::ScopedAStatus getSupportedAlwaysOnEffects(std::vector<Effect>* _aidl_return) override;
+    ndk::ScopedAStatus alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) override;
+    ndk::ScopedAStatus alwaysOnDisable(int32_t id) override;
+    ndk::ScopedAStatus getResonantFrequency(float* resonantFreqHz) override;
+    ndk::ScopedAStatus getQFactor(float* qFactor) override;
+    ndk::ScopedAStatus getFrequencyResolution(float* freqResolutionHz) override;
+    ndk::ScopedAStatus getFrequencyMinimum(float* freqMinimumHz) override;
+    ndk::ScopedAStatus getBandwidthAmplitudeMap(std::vector<float>* _aidl_return) override;
+    ndk::ScopedAStatus getPwlePrimitiveDurationMax(int32_t* durationMs) override;
+    ndk::ScopedAStatus getPwleCompositionSizeMax(int32_t* maxSize) override;
+    ndk::ScopedAStatus getSupportedBraking(std::vector<Braking>* supported) override;
+    ndk::ScopedAStatus composePwle(const std::vector<PrimitivePwle>& composite,
+                                   const std::shared_ptr<IVibratorCallback>& callback) override;
+};
+
+}  // namespace aidl::android::hardware::vibrator
diff --git a/tests/extension/vibrator/aidl/default/service.cpp b/tests/extension/vibrator/aidl/default/service.cpp
index 16290df..5917d0f 100644
--- a/tests/extension/vibrator/aidl/default/service.cpp
+++ b/tests/extension/vibrator/aidl/default/service.cpp
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#include <vibrator-impl/Vibrator.h>
 #include "CustomVibrator.h"
+#include "Vibrator.h"
 
 #include <android-base/logging.h>
 #include <android/binder_manager.h>
diff --git a/tests/msgq/1.0/ITestMsgQ.hal b/tests/msgq/1.0/ITestMsgQ.hal
index 0cf9c7c..62bef0a 100644
--- a/tests/msgq/1.0/ITestMsgQ.hal
+++ b/tests/msgq/1.0/ITestMsgQ.hal
@@ -18,8 +18,8 @@
 
 interface ITestMsgQ {
     enum EventFlagBits : uint32_t {
-        FMQ_NOT_EMPTY = 1 << 0,
-        FMQ_NOT_FULL  = 1 << 1,
+        FMQ_NOT_FULL = 1 << 0,
+        FMQ_NOT_EMPTY  = 1 << 1,
     };
 
     /**
diff --git a/tests/msgq/TEST_MAPPING b/tests/msgq/TEST_MAPPING
new file mode 100644
index 0000000..51c6c97
--- /dev/null
+++ b/tests/msgq/TEST_MAPPING
@@ -0,0 +1,18 @@
+{
+  "presubmit": [
+    {
+      "name": "fmq_unit_tests"
+    },
+    {
+      "name": "fmq_test"
+    }
+  ],
+  "hwasan-presubmit": [
+    {
+      "name": "fmq_unit_tests"
+    },
+    {
+      "name": "fmq_test"
+    }
+  ]
+}
diff --git a/threadnetwork/aidl/default/Android.bp b/threadnetwork/aidl/default/Android.bp
index 82a76e0..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",
 
@@ -90,10 +103,20 @@
     installable: false,
 }
 
+filegroup {
+    name: "com.android.hardware.threadnetwork_manifest",
+    srcs: ["manifest.json"],
+}
+
+filegroup {
+    name: "com.android.hardware.threadnetwork_file_contexts",
+    srcs: ["file_contexts"],
+}
+
 apex {
     name: "com.android.hardware.threadnetwork",
-    manifest: "manifest.json",
-    file_contexts: "file_contexts",
+    manifest: ":com.android.hardware.threadnetwork_manifest",
+    file_contexts: ":com.android.hardware.threadnetwork_file_contexts",
     key: "com.android.hardware.key",
     certificate: ":com.android.hardware.certificate",
     updatable: false,
@@ -110,3 +133,21 @@
         "android.hardware.thread_network.prebuilt.xml", // permission
     ],
 }
+
+prebuilt_etc {
+    name: "threadnetwork-service-simulation-rcp.rc",
+    src: "threadnetwork-service-simulation-rcp.rc",
+    installable: false,
+}
+
+// Thread HAL service which uses a simulation RCP (i.e. ot-rcp),
+// typically used in emulator devices.
+override_apex {
+    name: "com.android.hardware.threadnetwork-simulation-rcp",
+    base: "com.android.hardware.threadnetwork",
+    prebuilts: [
+        "threadnetwork-service-simulation-rcp.rc",
+        "threadnetwork-default.xml",
+        "android.hardware.thread_network.prebuilt.xml",
+    ],
+}
diff --git a/threadnetwork/aidl/default/socket_interface.cpp b/threadnetwork/aidl/default/socket_interface.cpp
index 0544502..a5aa2b4 100644
--- a/threadnetwork/aidl/default/socket_interface.cpp
+++ b/threadnetwork/aidl/default/socket_interface.cpp
@@ -33,6 +33,7 @@
 #include <unistd.h>
 
 #include <string>
+#include <vector>
 
 #include "common/code_utils.hpp"
 #include "openthread/openthread-system.h"
@@ -49,10 +50,8 @@
     : mReceiveFrameCallback(nullptr),
       mReceiveFrameContext(nullptr),
       mReceiveFrameBuffer(nullptr),
-      mSockFd(-1),
       mRadioUrl(aRadioUrl) {
-    memset(&mInterfaceMetrics, 0, sizeof(mInterfaceMetrics));
-    mInterfaceMetrics.mRcpInterfaceType = kSpinelInterfaceTypeVendor;
+    ResetStates();
 }
 
 otError SocketInterface::Init(ReceiveFrameCallback aCallback, void* aCallbackContext,
@@ -95,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;
@@ -120,13 +119,50 @@
     } else if (rval == 0) {
         ExitNow(error = OT_ERROR_RESPONSE_TIMEOUT);
     } else {
-        DieNowWithMessage("wait response", OT_EXIT_FAILURE);
+        DieNowWithMessage("Wait response", OT_EXIT_FAILURE);
     }
 
 exit:
     return error;
 }
 
+otError SocketInterface::WaitForHardwareResetCompletion(uint32_t aTimeoutMs) {
+    otError error = OT_ERROR_NONE;
+    int retries = 0;
+    int rval;
+
+    while (mIsHardwareResetting && retries++ < kMaxRetriesForSocketCloseCheck) {
+        struct timeval timeout;
+        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;
+
+        FD_ZERO(&readFds);
+        FD_SET(mSockFd, &readFds);
+
+        rval = TEMP_FAILURE_RETRY(select(mSockFd + 1, &readFds, nullptr, nullptr, &timeout));
+
+        if (rval > 0) {
+            Read();
+        } else if (rval < 0) {
+            DieNowWithMessage("Wait response", OT_EXIT_ERROR_ERRNO);
+        } else {
+            LogInfo("Waiting for hardware reset, retry attempt: %d, max attempt: %d", retries,
+                    kMaxRetriesForSocketCloseCheck);
+        }
+    }
+
+    VerifyOrExit(!mIsHardwareResetting, error = OT_ERROR_FAILED);
+
+    WaitForSocketFileCreated(mRadioUrl.GetPath());
+    mSockFd = OpenFile(mRadioUrl);
+    VerifyOrExit(mSockFd != -1, error = OT_ERROR_FAILED);
+
+exit:
+    return error;
+}
+
 void SocketInterface::UpdateFdSet(void* aMainloopContext) {
     otSysMainloopContext* context = reinterpret_cast<otSysMainloopContext*>(aMainloopContext);
 
@@ -150,6 +186,16 @@
     }
 }
 
+otError SocketInterface::HardwareReset(void) {
+    otError error = OT_ERROR_NONE;
+    std::vector<uint8_t> resetCommand = {SPINEL_HEADER_FLAG, SPINEL_CMD_RESET, 0x04};
+
+    mIsHardwareResetting = true;
+    SendFrame(resetCommand.data(), resetCommand.size());
+
+    return WaitForHardwareResetCompletion(kMaxSelectTimeMs);
+}
+
 void SocketInterface::Read(void) {
     uint8_t buffer[kMaxFrameSize];
 
@@ -160,8 +206,13 @@
     } else if (rval < 0) {
         DieNow(OT_EXIT_ERROR_ERRNO);
     } else {
-        LogCrit("Socket connection is closed by remote.");
-        exit(OT_EXIT_FAILURE);
+        if (mIsHardwareResetting) {
+            LogInfo("Socket connection is closed due to hardware reset.");
+            ResetStates();
+        } else {
+            LogCrit("Socket connection is closed by remote.");
+            exit(OT_EXIT_FAILURE);
+        }
     }
 }
 
@@ -263,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);
@@ -298,6 +349,13 @@
     return stat(aPath, &st) == 0 && S_ISSOCK(st.st_mode);
 }
 
+void SocketInterface::ResetStates() {
+    mSockFd = -1;
+    mIsHardwareResetting = false;
+    memset(&mInterfaceMetrics, 0, sizeof(mInterfaceMetrics));
+    mInterfaceMetrics.mRcpInterfaceType = kSpinelInterfaceTypeVendor;
+}
+
 }  // namespace threadnetwork
 }  // namespace hardware
 }  // namespace android
diff --git a/threadnetwork/aidl/default/socket_interface.hpp b/threadnetwork/aidl/default/socket_interface.hpp
index 6f3be7f..494d76a 100644
--- a/threadnetwork/aidl/default/socket_interface.hpp
+++ b/threadnetwork/aidl/default/socket_interface.hpp
@@ -136,10 +136,10 @@
      * Hardware resets the RCP.
      *
      * @retval OT_ERROR_NONE            Successfully reset the RCP.
-     * @retval OT_ERROR_NOT_IMPLEMENT   The hardware reset is not implemented.
+     * @retval OT_ERROR_FAILED          Hardware reset is failed.
      *
      */
-    otError HardwareReset(void) { return OT_ERROR_NOT_IMPLEMENTED; }
+    otError HardwareReset(void);
 
     /**
      * Returns the RCP interface metrics.
@@ -237,9 +237,26 @@
      */
     void WaitForSocketFileCreated(const char* aPath);
 
+    /**
+     * Wait for the hardware reset completion signal.
+     *
+     * @retval OT_ERROR_NONE       Hardware reset is successfully.
+     * @retval OT_ERROR_FAILED     Hardware reset is failed.
+     *
+     */
+    otError WaitForHardwareResetCompletion(uint32_t aTimeoutMs);
+
+    /**
+     * Reset socket interface to intitial state.
+     *
+     */
+    void ResetStates(void);
+
     enum {
-        kMaxSelectTimeMs = 2000,  ///< Maximum wait time in Milliseconds for file
-                                  ///< descriptor to become available.
+        kMaxSelectTimeMs = 2000,             ///< Maximum wait time in Milliseconds for file
+                                             ///< descriptor to become available.
+        kMaxRetriesForSocketCloseCheck = 3,  ///< Maximum retry times for checking
+                                             ///< if socket is closed.
     };
 
     ReceiveFrameCallback mReceiveFrameCallback;
@@ -249,6 +266,8 @@
     int mSockFd;
     const ot::Url::Url& mRadioUrl;
 
+    bool mIsHardwareResetting;
+
     otRcpInterfaceMetrics mInterfaceMetrics;
 
     // Non-copyable, intentionally not implemented.
diff --git a/threadnetwork/aidl/default/threadnetwork-service-simulation-rcp.rc b/threadnetwork/aidl/default/threadnetwork-service-simulation-rcp.rc
new file mode 100644
index 0000000..3b889eb
--- /dev/null
+++ b/threadnetwork/aidl/default/threadnetwork-service-simulation-rcp.rc
@@ -0,0 +1,3 @@
+service vendor.threadnetwork_hal /apex/com.android.hardware.threadnetwork/bin/hw/android.hardware.threadnetwork-service spinel+hdlc+forkpty:///apex/com.android.hardware.threadnetwork/bin/ot-rcp?forkpty-arg=1
+    class hal
+    user thread_network
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/input/aidl/vts/functional/VtsHalTvInputTargetTest.cpp b/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.cpp
index 7e095f1..41a78eb 100644
--- a/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.cpp
+++ b/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.cpp
@@ -137,13 +137,15 @@
 }
 
 bool TvInputAidlTest::isValidHandle(NativeHandle& handle) {
-    if (handle.fds.empty()) {
+    if (handle.fds.empty() && handle.ints.empty()) {
         return false;
     }
-    for (size_t i = 0; i < handle.fds.size(); i++) {
-        int fd = handle.fds[i].get();
-        if (fcntl(fd, F_GETFL) < 0) {
-            return false;
+    if (!(handle.fds.empty())) {
+        for (size_t i = 0; i < handle.fds.size(); i++) {
+            int fd = handle.fds[i].get();
+            if (fcntl(fd, F_GETFL) < 0) {
+                return false;
+            }
         }
     }
     return true;
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/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
index 6cabb3d..be9b996 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
@@ -32,9 +32,10 @@
 bool initConfiguration() {
     std::array<char, PROPERTY_VALUE_MAX> variant;
     property_get("ro.vendor.vts_tuner_configuration_variant", variant.data(), "");
+    string variantString = variant.data();
     string configFilePath = "/vendor/etc/tuner_vts_config_aidl_V1";
-    if (variant.size() != 0) {
-        configFilePath = configFilePath + "."  + variant.data();
+    if (variantString.length() != 0) {
+        configFilePath = configFilePath + "." + variantString;
     }
     configFilePath = configFilePath + ".xml";
     TunerTestingConfigAidlReader1_0::setConfigFilePath(configFilePath);
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
index 58919d1..09cdc26 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -35,6 +35,7 @@
 @Backing(type="int") @VintfStability
 enum UwbVendorCapabilityTlvTypes {
   SUPPORTED_POWER_STATS_QUERY = 0xC0,
+  SUPPORTED_ANTENNA_MODES = 0xC1,
   CCC_SUPPORTED_CHAPS_PER_SLOT = 0xA0,
   CCC_SUPPORTED_SYNC_CODES = 0xA1,
   CCC_SUPPORTED_HOPPING_CONFIG_MODES_AND_SEQUENCES = 0xA2,
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvValues.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvValues.aidl
index 702e561..d9b7220 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvValues.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvValues.aidl
@@ -34,6 +34,8 @@
 package android.hardware.uwb.fira_android;
 @Backing(type="long") @VintfStability
 enum UwbVendorCapabilityTlvValues {
+  ANTENNA_MODE_OMNI = 1,
+  ANTENNA_MODE_DIRECTIONAL = (1 << 1) /* 2 */,
   UWB_CONFIG_0 = 0,
   UWB_CONFIG_1 = 1,
   PULSE_SHAPE_SYMMETRICAL_ROOT_RAISED_COSINE = 0,
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
index 4df45b6..28e44ef 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -41,6 +41,13 @@
      */
     SUPPORTED_POWER_STATS_QUERY = 0xC0,
 
+    /**
+     * 1 byte bitmask to indicate which antennas modes are supported.
+     * 0x01 = "Omni mode",
+     * 0x02 = "Directional mode",
+     */
+    SUPPORTED_ANTENNA_MODES = 0xC1,
+
     /*********************************************
      * CCC specific
      ********************************************/
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvValues.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvValues.aidl
index 6ef52fe..e5165dc 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvValues.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvValues.aidl
@@ -25,6 +25,12 @@
 @Backing(type="long")
 enum UwbVendorCapabilityTlvValues {
     /*********************************************
+     * Protocol agnostic
+     ********************************************/
+    ANTENNA_MODE_OMNI = 1,
+    ANTENNA_MODE_DIRECTIONAL = 1 << 1,
+
+    /*********************************************
      * CCC specific
      ********************************************/
     UWB_CONFIG_0 = 0,
diff --git a/uwb/aidl/default/Android.bp b/uwb/aidl/default/Android.bp
index eba18cf..037eac3 100644
--- a/uwb/aidl/default/Android.bp
+++ b/uwb/aidl/default/Android.bp
@@ -16,17 +16,13 @@
     prefer_rlib: true,
     rustlibs: [
         "android.hardware.uwb-V1-rust",
-        "liblibc",
         "liblogger",
         "liblog_rust",
         "libbinder_rs",
         "libbinder_tokio_rs",
         "libtokio",
-        "libtokio_util",
         "libnix",
         "libanyhow",
-        "libpdl_runtime",
-        "libuwb_uci_packets",
     ],
     proc_macros: [
         "libasync_trait",
diff --git a/uwb/aidl/default/src/service.rs b/uwb/aidl/default/src/service.rs
index e97b291..80fa8af 100644
--- a/uwb/aidl/default/src/service.rs
+++ b/uwb/aidl/default/src/service.rs
@@ -1,8 +1,6 @@
 use android_hardware_uwb::aidl::android::hardware::uwb::IUwb::{self, IUwb as _};
 use android_hardware_uwb::binder;
 
-use tokio::runtime::Runtime;
-
 use std::env;
 use std::panic;
 
@@ -25,13 +23,12 @@
 
     log::info!("UWB HAL starting up");
 
-    // Create the tokio runtime
-    let rt = Runtime::new()?;
+    let rt = tokio::runtime::Runtime::new()?;
 
     let chips = env::args()
         .skip(1) // Skip binary name
         .enumerate()
-        .map(|(i, arg)| uwb_chip::UwbChip::new(i.to_string(), arg));
+        .map(|(i, arg)| rt.block_on(uwb_chip::UwbChip::new(i.to_string(), arg)));
 
     binder::add_service(
         &format!("{}/default", IUwb::BpUwb::get_descriptor()),
diff --git a/uwb/aidl/default/src/uwb_chip.rs b/uwb/aidl/default/src/uwb_chip.rs
index 956cf6c..0ed05d8 100644
--- a/uwb/aidl/default/src/uwb_chip.rs
+++ b/uwb/aidl/default/src/uwb_chip.rs
@@ -7,126 +7,113 @@
 use binder::{DeathRecipient, IBinder, Result, Strong};
 
 use std::sync::Arc;
-use tokio::io::unix::AsyncFd;
-use tokio::select;
+use tokio::fs;
+use tokio::io::{AsyncReadExt, AsyncWriteExt};
 use tokio::sync::Mutex;
-use tokio_util::sync::CancellationToken;
 
-use std::fs::{File, OpenOptions};
-use std::io::{self, Read, Write};
-use std::os::unix::fs::OpenOptionsExt;
-
-use pdl_runtime::Packet;
-use uwb_uci_packets::{DeviceResetCmdBuilder, ResetConfig, UciControlPacket, UciControlPacketHal};
-
-enum State {
+enum ClientState {
     Closed,
     Opened {
         callbacks: Strong<dyn IUwbClientCallback>,
-        handle: tokio::task::JoinHandle<()>,
-        serial: File,
-        death_recipient: DeathRecipient,
-        token: CancellationToken,
+        _death_recipient: DeathRecipient,
     },
 }
 
+struct ServiceState {
+    client_state: ClientState,
+    writer: fs::File,
+}
+
 pub struct UwbChip {
     name: String,
-    path: String,
-    state: Arc<Mutex<State>>,
+    _handle: tokio::task::JoinHandle<()>,
+    service_state: Arc<Mutex<ServiceState>>,
 }
 
-impl UwbChip {
-    pub fn new(name: String, path: String) -> Self {
-        Self {
-            name,
-            path,
-            state: Arc::new(Mutex::new(State::Closed)),
-        }
-    }
-}
-
-impl State {
-    /// Terminate the reader task.
-    async fn close(&mut self) -> Result<()> {
-        if let State::Opened {
-            ref mut token,
-            ref callbacks,
-            ref mut death_recipient,
-            ref mut handle,
-            ref mut serial,
-        } = *self
-        {
-            log::info!("waiting for task cancellation");
-            callbacks.as_binder().unlink_to_death(death_recipient)?;
-            token.cancel();
-            handle.await.unwrap();
-            let packet: UciControlPacket = DeviceResetCmdBuilder {
-                reset_config: ResetConfig::UwbsReset,
-            }
-            .build()
-            .into();
-            // DeviceResetCmd need to be send to reset the device to stop all running
-            // activities on UWBS.
-            let packet_vec: Vec<UciControlPacketHal> = packet.into();
-            for hal_packet in packet_vec.into_iter() {
-                serial
-                    .write(&hal_packet.encode_to_vec().unwrap())
-                    .map(|written| written as i32)
-                    .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
-            }
-            consume_device_reset_rsp_and_ntf(
-                &mut serial
-                    .try_clone()
-                    .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?,
-            );
-            log::info!("task successfully cancelled");
-            callbacks.onHalEvent(UwbEvent::CLOSE_CPLT, UwbStatus::OK)?;
-            *self = State::Closed;
-        }
-        Ok(())
-    }
-}
-
-fn consume_device_reset_rsp_and_ntf(reader: &mut File) {
-    // Poll the DeviceResetRsp and DeviceStatusNtf before hal is closed to prevent
-    // the host from getting response and notifications from a 'powered down' UWBS.
-    // Do nothing when these packets are received.
-    const DEVICE_RESET_RSP: [u8; 5] = [64, 0, 0, 1, 0];
-    const DEVICE_STATUS_NTF: [u8; 5] = [96, 1, 0, 1, 1];
-    let mut buffer = vec![0; DEVICE_RESET_RSP.len() + DEVICE_STATUS_NTF.len()];
-    read_exact(reader, &mut buffer).unwrap();
-
-    // Make sure received packets are the expected ones.
-    assert_eq!(&buffer[0..DEVICE_RESET_RSP.len()], &DEVICE_RESET_RSP);
-    assert_eq!(&buffer[DEVICE_RESET_RSP.len()..], &DEVICE_STATUS_NTF);
-}
-
-pub fn makeraw(file: File) -> io::Result<File> {
-    // Configure the file descriptor as raw fd.
+/// Configure a file descriptor as raw fd.
+pub fn makeraw(file: fs::File) -> std::io::Result<fs::File> {
     use nix::sys::termios::*;
     let mut attrs = tcgetattr(&file)?;
     cfmakeraw(&mut attrs);
     tcsetattr(&file, SetArg::TCSANOW, &attrs)?;
-
     Ok(file)
 }
 
-/// Wrapper around Read::read to handle EWOULDBLOCK.
-/// /!\ will actively wait for more data, make sure to call
-/// this method only when data is immediately expected.
-fn read_exact(file: &mut File, mut buf: &mut [u8]) -> io::Result<()> {
-    while buf.len() > 0 {
-        match file.read(buf) {
-            Ok(0) => panic!("unexpectedly reached end of file"),
-            Ok(read_len) => buf = &mut buf[read_len..],
-            Err(err) if err.kind() == io::ErrorKind::WouldBlock => continue,
-            Err(err) => return Err(err),
+impl UwbChip {
+    pub async fn new(name: String, path: String) -> Self {
+        // Open the serial file and configure it as raw file
+        // descriptor.
+        let mut reader = fs::OpenOptions::new()
+            .read(true)
+            .write(true)
+            .create(false)
+            .open(&path)
+            .await
+            .and_then(makeraw)
+            .expect("failed to open the serial device");
+        let writer = reader
+            .try_clone()
+            .await
+            .expect("failed to clone serial for writing");
+
+        // Create the chip
+        let service_state = Arc::new(Mutex::new(ServiceState {
+            writer,
+            client_state: ClientState::Closed,
+        }));
+
+        // Spawn the task that will run the polling loop.
+        let handle = {
+            let service_state = service_state.clone();
+
+            tokio::task::spawn(async move {
+                log::info!("UCI reader task started");
+
+                const MESSAGE_TYPE_MASK: u8 = 0b11100000;
+                const DATA_MESSAGE_TYPE: u8 = 0b000;
+                const UCI_HEADER_SIZE: usize = 4;
+                const UCI_BUFFER_SIZE: usize = 1024;
+
+                let mut buffer = [0; UCI_BUFFER_SIZE];
+
+                loop {
+                    reader
+                        .read_exact(&mut buffer[0..UCI_HEADER_SIZE])
+                        .await
+                        .expect("failed to read uci header bytes");
+                    let common_header = buffer[0];
+                    let mt = (common_header & MESSAGE_TYPE_MASK) >> 5;
+                    let payload_length = if mt == DATA_MESSAGE_TYPE {
+                        u16::from_le_bytes([buffer[2], buffer[3]]) as usize
+                    } else {
+                        buffer[3] as usize
+                    };
+
+                    let total_packet_length = payload_length + UCI_HEADER_SIZE;
+                    reader
+                        .read_exact(&mut buffer[UCI_HEADER_SIZE..total_packet_length])
+                        .await
+                        .expect("failed to read uci payload bytes");
+
+                    log::debug!(" <-- {:?}", &buffer[0..total_packet_length]);
+
+                    let service_state = service_state.lock().await;
+                    if let ClientState::Opened { ref callbacks, .. } = service_state.client_state {
+                        callbacks
+                            .onUciMessage(&buffer[0..total_packet_length])
+                            .unwrap();
+                    }
+                }
+            })
+        };
+
+        Self {
+            name,
+            _handle: handle,
+            service_state,
         }
     }
-    Ok(())
 }
-
 impl binder::Interface for UwbChip {}
 
 #[async_trait]
@@ -136,124 +123,30 @@
     }
 
     async fn open(&self, callbacks: &Strong<dyn IUwbClientCallback>) -> Result<()> {
-        log::debug!("open: {:?}", &self.path);
+        log::debug!("open");
 
-        let mut state = self.state.lock().await;
+        let mut service_state = self.service_state.lock().await;
 
-        if matches!(*state, State::Opened { .. }) {
+        if matches!(service_state.client_state, ClientState::Opened { .. }) {
             log::error!("the state is already opened");
             return Err(binder::ExceptionCode::ILLEGAL_STATE.into());
         }
 
-        let serial = OpenOptions::new()
-            .read(true)
-            .write(true)
-            .create(false)
-            .custom_flags(libc::O_NONBLOCK)
-            .open(&self.path)
-            .and_then(makeraw)
-            .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
-
-        let state_death_recipient = self.state.clone();
-        let mut death_recipient = DeathRecipient::new(move || {
-            let mut state = state_death_recipient.blocking_lock();
-            log::info!("Uwb service has died");
-            if let State::Opened { ref mut token, .. } = *state {
-                token.cancel();
-                *state = State::Closed;
-            }
-        });
+        let mut death_recipient = {
+            let service_state = self.service_state.clone();
+            DeathRecipient::new(move || {
+                log::info!("Uwb service has died");
+                let mut service_state = service_state.blocking_lock();
+                service_state.client_state = ClientState::Closed;
+            })
+        };
 
         callbacks.as_binder().link_to_death(&mut death_recipient)?;
-
-        let token = CancellationToken::new();
-        let cloned_token = token.clone();
-
-        let client_callbacks = callbacks.clone();
-
-        let reader = serial
-            .try_clone()
-            .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
-
-        let join_handle = tokio::task::spawn(async move {
-            log::info!("UCI reader task started");
-            let mut reader = AsyncFd::new(reader).unwrap();
-
-            loop {
-                const MESSAGE_TYPE_MASK: u8 = 0b11100000;
-                const DATA_MESSAGE_TYPE: u8 = 0b000;
-                const UWB_HEADER_SIZE: usize = 4;
-                let mut buffer = vec![0; UWB_HEADER_SIZE];
-
-                // The only time where the task can be safely
-                // cancelled is when no packet bytes have been read.
-                //
-                // - read_exact() cannot be used here since it is not
-                //   cancellation safe.
-                // - read() cannot be used because it cannot be cancelled:
-                //   the syscall is executed blocking on the threadpool
-                //   and completes after termination of the task when
-                //   the pipe receives more data.
-                let read_len = loop {
-                    // On some platforms, the readiness detecting mechanism
-                    // relies on edge-triggered notifications. This means that
-                    // the OS will only notify Tokio when the file descriptor
-                    // transitions from not-ready to ready. For this to work
-                    // you should first try to read or write and only poll for
-                    // readiness if that fails with an error of
-                    // std::io::ErrorKind::WouldBlock.
-                    match reader.get_mut().read(&mut buffer) {
-                        Ok(0) => {
-                            log::error!("file unexpectedly closed");
-                            return;
-                        }
-                        Ok(read_len) => break read_len,
-                        Err(err) if err.kind() == io::ErrorKind::WouldBlock => (),
-                        Err(_) => panic!("unexpected read failure"),
-                    }
-
-                    let mut guard = select! {
-                        _ = cloned_token.cancelled() => {
-                            log::info!("task is cancelled!");
-                            return;
-                        },
-                        result = reader.readable() => result.unwrap()
-                    };
-
-                    guard.clear_ready();
-                };
-
-                // Read the remaining header bytes, if truncated.
-                read_exact(reader.get_mut(), &mut buffer[read_len..]).unwrap();
-
-                let common_header = buffer[0];
-                let mt = (common_header & MESSAGE_TYPE_MASK) >> 5;
-                let payload_length = if mt == DATA_MESSAGE_TYPE {
-                    let payload_length_fields: [u8; 2] = buffer[2..=3].try_into().unwrap();
-                    u16::from_le_bytes(payload_length_fields) as usize
-                } else {
-                    buffer[3] as usize
-                };
-
-                let length = payload_length + UWB_HEADER_SIZE;
-                buffer.resize(length, 0);
-
-                // Read the payload bytes.
-                read_exact(reader.get_mut(), &mut buffer[UWB_HEADER_SIZE..]).unwrap();
-
-                log::debug!(" <-- {:?}", buffer);
-                client_callbacks.onUciMessage(&buffer).unwrap();
-            }
-        });
-
         callbacks.onHalEvent(UwbEvent::OPEN_CPLT, UwbStatus::OK)?;
 
-        *state = State::Opened {
+        service_state.client_state = ClientState::Opened {
             callbacks: callbacks.clone(),
-            handle: join_handle,
-            serial,
-            death_recipient,
-            token,
+            _death_recipient: death_recipient,
         };
 
         Ok(())
@@ -262,19 +155,42 @@
     async fn close(&self) -> Result<()> {
         log::debug!("close");
 
-        let mut state = self.state.lock().await;
+        let mut service_state = self.service_state.lock().await;
 
-        if let State::Opened { .. } = *state {
-            state.close().await
-        } else {
-            Err(binder::ExceptionCode::ILLEGAL_STATE.into())
+        if matches!(service_state.client_state, ClientState::Closed) {
+            log::error!("the state is already closed");
+            return Err(binder::ExceptionCode::ILLEGAL_STATE.into());
         }
+
+        // Send the command Device Reset to stop all running activities
+        // on the UWBS emulator. This is necessary because the emulator
+        // is otherwise not notified of the power down (the serial stays
+        // open).
+        //
+        // The response to the command will be dropped by the polling loop,
+        // as the callbacks will have been removed then.
+        let uci_core_device_reset_cmd = [0x20, 0x00, 0x00, 0x01, 0x00];
+
+        service_state
+            .writer
+            .write_all(&uci_core_device_reset_cmd)
+            .await
+            .expect("failed to write UCI Device Reset command");
+
+        if let ClientState::Opened { ref callbacks, .. } = service_state.client_state {
+            callbacks.onHalEvent(UwbEvent::CLOSE_CPLT, UwbStatus::OK)?;
+        }
+
+        service_state.client_state = ClientState::Closed;
+        Ok(())
     }
 
     async fn coreInit(&self) -> Result<()> {
         log::debug!("coreInit");
 
-        if let State::Opened { ref callbacks, .. } = *self.state.lock().await {
+        let service_state = self.service_state.lock().await;
+
+        if let ClientState::Opened { ref callbacks, .. } = service_state.client_state {
             callbacks.onHalEvent(UwbEvent::POST_INIT_CPLT, UwbStatus::OK)?;
             Ok(())
         } else {
@@ -289,22 +205,27 @@
     }
 
     async fn getSupportedAndroidUciVersion(&self) -> Result<i32> {
+        log::debug!("getSupportedAndroidUciVersion");
+
         Ok(1)
     }
 
     async fn sendUciMessage(&self, data: &[u8]) -> Result<i32> {
         log::debug!("sendUciMessage");
 
-        if let State::Opened { ref mut serial, .. } = &mut *self.state.lock().await {
-            log::debug!(" --> {:?}", data);
-            let result = serial
-                .write_all(data)
-                .map(|_| data.len() as i32)
-                .map_err(|_| binder::StatusCode::UNKNOWN_ERROR.into());
-            log::debug!(" status: {:?}", result);
-            result
-        } else {
-            Err(binder::ExceptionCode::ILLEGAL_STATE.into())
+        let mut service_state = self.service_state.lock().await;
+
+        if matches!(service_state.client_state, ClientState::Closed) {
+            log::error!("the state is not opened");
+            return Err(binder::ExceptionCode::ILLEGAL_STATE.into());
         }
+
+        log::debug!(" --> {:?}", data);
+        service_state
+            .writer
+            .write_all(data)
+            .await
+            .map(|_| data.len() as i32)
+            .map_err(|_| binder::StatusCode::UNKNOWN_ERROR.into())
     }
 }
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/Android.bp b/vibrator/aidl/Android.bp
index b5199e2..b2d98f5 100644
--- a/vibrator/aidl/Android.bp
+++ b/vibrator/aidl/Android.bp
@@ -15,14 +15,33 @@
     srcs: [
         "android/hardware/vibrator/*.aidl",
     ],
+    headers: [
+        "PersistableBundle_aidl",
+    ],
     stability: "vintf",
     backend: {
         java: {
             sdk_version: "system_current",
         },
+        ndk: {
+            enabled: true,
+        },
+        cpp: {
+            enabled: false,
+        },
+        rust: {
+            enabled: false,
+        },
     },
-    versions: [
-        "1",
-        "2",
+    versions_with_info: [
+        {
+            version: "1",
+            imports: [],
+        },
+        {
+            version: "2",
+            imports: [],
+        },
     ],
+    frozen: false,
 }
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 b7afb66..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
@@ -58,15 +58,23 @@
   int getPwleCompositionSizeMax();
   android.hardware.vibrator.Braking[] getSupportedBraking();
   void composePwle(in android.hardware.vibrator.PrimitivePwle[] composite, in android.hardware.vibrator.IVibratorCallback callback);
-  const int CAP_ON_CALLBACK = 1;
-  const int CAP_PERFORM_CALLBACK = 2;
-  const int CAP_AMPLITUDE_CONTROL = 4;
-  const int CAP_EXTERNAL_CONTROL = 8;
-  const int CAP_EXTERNAL_AMPLITUDE_CONTROL = 16;
-  const int CAP_COMPOSE_EFFECTS = 32;
-  const int CAP_ALWAYS_ON_CONTROL = 64;
-  const int CAP_GET_RESONANT_FREQUENCY = 128;
-  const int CAP_GET_Q_FACTOR = 256;
-  const int CAP_FREQUENCY_CONTROL = 512;
-  const int CAP_COMPOSE_PWLE_EFFECTS = 1024;
+  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 */;
+  const int CAP_EXTERNAL_CONTROL = (1 << 3) /* 8 */;
+  const int CAP_EXTERNAL_AMPLITUDE_CONTROL = (1 << 4) /* 16 */;
+  const int CAP_COMPOSE_EFFECTS = (1 << 5) /* 32 */;
+  const int CAP_ALWAYS_ON_CONTROL = (1 << 6) /* 64 */;
+  const int CAP_GET_RESONANT_FREQUENCY = (1 << 7) /* 128 */;
+  const int CAP_GET_Q_FACTOR = (1 << 8) /* 256 */;
+  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/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorManager.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorManager.aidl
index 290c68d..ef5794c 100644
--- a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorManager.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorManager.aidl
@@ -40,12 +40,12 @@
   void prepareSynced(in int[] vibratorIds);
   void triggerSynced(in android.hardware.vibrator.IVibratorCallback callback);
   void cancelSynced();
-  const int CAP_SYNC = 1;
-  const int CAP_PREPARE_ON = 2;
-  const int CAP_PREPARE_PERFORM = 4;
-  const int CAP_PREPARE_COMPOSE = 8;
-  const int CAP_MIXED_TRIGGER_ON = 16;
-  const int CAP_MIXED_TRIGGER_PERFORM = 32;
-  const int CAP_MIXED_TRIGGER_COMPOSE = 64;
-  const int CAP_TRIGGER_CALLBACK = 128;
+  const int CAP_SYNC = (1 << 0) /* 1 */;
+  const int CAP_PREPARE_ON = (1 << 1) /* 2 */;
+  const int CAP_PREPARE_PERFORM = (1 << 2) /* 4 */;
+  const int CAP_PREPARE_COMPOSE = (1 << 3) /* 8 */;
+  const int CAP_MIXED_TRIGGER_ON = (1 << 4) /* 16 */;
+  const int CAP_MIXED_TRIGGER_PERFORM = (1 << 5) /* 32 */;
+  const int CAP_MIXED_TRIGGER_COMPOSE = (1 << 6) /* 64 */;
+  const int CAP_TRIGGER_CALLBACK = (1 << 7) /* 128 */;
 }
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/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/VendorEffect.aidl
similarity index 86%
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/VendorEffect.aidl
index 173ac17..62a7380 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/VendorEffect.aidl
@@ -31,10 +31,11 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
+package android.hardware.vibrator;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable VendorEffect {
+  android.os.PersistableBundle vendorData;
+  android.hardware.vibrator.EffectStrength strength = android.hardware.vibrator.EffectStrength.MEDIUM;
+  float scale;
+  float vendorScale;
 }
diff --git a/vibrator/aidl/android/hardware/vibrator/Braking.aidl b/vibrator/aidl/android/hardware/vibrator/Braking.aidl
index 2bc51db..f934ff2 100644
--- a/vibrator/aidl/android/hardware/vibrator/Braking.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/Braking.aidl
@@ -23,12 +23,12 @@
      * No braking mechanism used.
      * This is the default if the hardware does not support any braking mechanism.
      */
-    NONE,
+    NONE = 0,
     /**
      * Closed-loop active braking.
      *
      * This effect should produce a sharp, crisp end to the waveform
      * Support is optional.
      */
-    CLAB,
+    CLAB = 1,
 }
diff --git a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
index 5314898..5f8ee8d 100644
--- a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
@@ -24,13 +24,13 @@
      *
      * Support is required.
      */
-    NOOP,
+    NOOP = 0,
     /**
      * This effect should produce a sharp, crisp click sensation.
      *
      * Support is required.
      */
-    CLICK,
+    CLICK = 1,
     /**
      * A haptic effect that simulates downwards movement with gravity. Often
      * followed by extra energy of hitting and reverberation to augment
@@ -38,43 +38,43 @@
      *
      * Support is optional.
      */
-    THUD,
+    THUD = 2,
     /**
      * A haptic effect that simulates spinning momentum.
      *
      * Support is optional.
      */
-    SPIN,
+    SPIN = 3,
     /**
      * A haptic effect that simulates quick upward movement against gravity.
      *
      * Support is required.
      */
-    QUICK_RISE,
+    QUICK_RISE = 4,
     /**
      * A haptic effect that simulates slow upward movement against gravity.
      *
      * Support is required.
      */
-    SLOW_RISE,
+    SLOW_RISE = 5,
     /**
      * A haptic effect that simulates quick downwards movement with gravity.
      *
      * Support is required.
      */
-    QUICK_FALL,
+    QUICK_FALL = 6,
     /**
      * This very short effect should produce a light crisp sensation intended
      * to be used repetitively for dynamic feedback.
      *
      * Support is required.
      */
-    LIGHT_TICK,
+    LIGHT_TICK = 7,
     /**
      * This very short low frequency effect should produce a light crisp sensation intended
      * to be used repetitively for dynamic feedback.
      *
      * Support is required.
      */
-    LOW_TICK,
+    LOW_TICK = 8,
 }
diff --git a/vibrator/aidl/android/hardware/vibrator/Effect.aidl b/vibrator/aidl/android/hardware/vibrator/Effect.aidl
index c60bfe9..f5cf9e3 100644
--- a/vibrator/aidl/android/hardware/vibrator/Effect.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/Effect.aidl
@@ -24,57 +24,57 @@
      *
      * This effect should produce a sharp, crisp click sensation.
      */
-    CLICK,
+    CLICK = 0,
     /**
      * A double click effect.
      *
      * This effect should produce two sequential sharp, crisp click sensations with a minimal
      * amount of time between them.
      */
-    DOUBLE_CLICK,
+    DOUBLE_CLICK = 1,
     /**
      * A tick effect.
      *
      * This effect should produce a soft, short sensation, like the tick of a clock.
      */
-    TICK,
+    TICK = 2,
     /**
      * A thud effect.
      *
      * This effect should solid feeling bump, like the depression of a heavy mechanical button.
      */
-    THUD,
+    THUD = 3,
     /**
      * A pop effect.
      *
      * A short, quick burst effect.
      */
-    POP,
+    POP = 4,
     /**
      * A heavy click effect.
      *
      * This should produce a sharp striking sensation, like a click but stronger.
      */
-    HEAVY_CLICK,
+    HEAVY_CLICK = 5,
     /**
      * Ringtone patterns. They may correspond with the device's ringtone audio, or may just be a
      * pattern that can be played as a ringtone with any audio, depending on the device.
      */
-    RINGTONE_1,
-    RINGTONE_2,
-    RINGTONE_3,
-    RINGTONE_4,
-    RINGTONE_5,
-    RINGTONE_6,
-    RINGTONE_7,
-    RINGTONE_8,
-    RINGTONE_9,
-    RINGTONE_10,
-    RINGTONE_11,
-    RINGTONE_12,
-    RINGTONE_13,
-    RINGTONE_14,
-    RINGTONE_15,
+    RINGTONE_1 = 6,
+    RINGTONE_2 = 7,
+    RINGTONE_3 = 8,
+    RINGTONE_4 = 9,
+    RINGTONE_5 = 10,
+    RINGTONE_6 = 11,
+    RINGTONE_7 = 12,
+    RINGTONE_8 = 13,
+    RINGTONE_9 = 14,
+    RINGTONE_10 = 15,
+    RINGTONE_11 = 16,
+    RINGTONE_12 = 17,
+    RINGTONE_13 = 18,
+    RINGTONE_14 = 19,
+    RINGTONE_15 = 20,
     /**
      * A soft tick effect meant to be played as a texture.
      *
@@ -82,5 +82,5 @@
      * are expected to be played multiple times in quick succession, replicating a specific
      * texture to the user as a form of haptic feedback.
      */
-    TEXTURE_TICK,
+    TEXTURE_TICK = 21,
 }
diff --git a/vibrator/aidl/android/hardware/vibrator/EffectStrength.aidl b/vibrator/aidl/android/hardware/vibrator/EffectStrength.aidl
index 66f70e5..c6a78d4 100644
--- a/vibrator/aidl/android/hardware/vibrator/EffectStrength.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/EffectStrength.aidl
@@ -19,7 +19,7 @@
 @VintfStability
 @Backing(type="byte")
 enum EffectStrength {
-    LIGHT,
-    MEDIUM,
-    STRONG,
+    LIGHT = 0,
+    MEDIUM = 1,
+    STRONG = 2,
 }
diff --git a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
index b4e7e44..11f36ba 100644
--- a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
@@ -16,13 +16,16 @@
 
 package android.hardware.vibrator;
 
-import android.hardware.vibrator.IVibratorCallback;
 import android.hardware.vibrator.Braking;
-import android.hardware.vibrator.Effect;
-import android.hardware.vibrator.EffectStrength;
 import android.hardware.vibrator.CompositeEffect;
 import android.hardware.vibrator.CompositePrimitive;
+import android.hardware.vibrator.Effect;
+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
 interface IVibrator {
@@ -70,6 +73,14 @@
      * Whether composePwle is supported.
      */
     const int CAP_COMPOSE_PWLE_EFFECTS = 1 << 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)
@@ -359,4 +370,103 @@
      * @param composite Array of PWLEs.
      */
     void composePwle(in PrimitivePwle[] composite, in IVibratorCallback callback);
+
+    /**
+     * Fire off a vendor-defined haptic event.
+     *
+     * This may not be supported and this support is reflected in
+     * getCapabilities (CAP_PERFORM_VENDOR_EFFECTS).
+     *
+     * The duration of the effect is unknown and can be undefined for looping effects.
+     * IVibratorCallback.onComplete() support is required for this API.
+     *
+     * Doing this operation while the vibrator is already on is undefined behavior. Clients should
+     * explicitly call off.
+     *
+     * @param effect The vendor data representing the effect to be performed.
+     * @param callback A callback used to inform Frameworks of state change.
+     * @throws :
+     *         - EX_UNSUPPORTED_OPERATION if unsupported, as reflected by getCapabilities.
+     *         - EX_ILLEGAL_ARGUMENT for bad framework parameters, e.g. scale or effect strength.
+     *         - 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/android/hardware/vibrator/VendorEffect.aidl b/vibrator/aidl/android/hardware/vibrator/VendorEffect.aidl
new file mode 100644
index 0000000..6b1af53
--- /dev/null
+++ b/vibrator/aidl/android/hardware/vibrator/VendorEffect.aidl
@@ -0,0 +1,70 @@
+/*
+ * 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;
+
+import android.hardware.vibrator.EffectStrength;
+import android.os.PersistableBundle;
+
+@VintfStability
+parcelable VendorEffect {
+    /**
+     * Vendor data describing the haptic effect. Expected fields should be defined by the vendor.
+     *
+     * Vendors can use this as a platform extension point for experimental hardware capabilities,
+     * but they are strongly discouraged from using it as an alternative to the AOSP support for
+     * stable vibrator APIs. Implemenitng vendor-specific custom effects outside the platform APIs
+     * will hinder portability for the code and overall user experience.
+     *
+     * Vendors are encouraged to upstream new capabilities to the IVibrator surface once it has
+     * matured into a stable interface.
+     */
+    PersistableBundle vendorData;
+
+    /**
+     * The intensity of the haptic effect.
+     *
+     * This value is defined by discrete scale levels that represents the intensity of this haptic
+     * effect. This is a discrete representation of the scale parameter below.
+     */
+    EffectStrength strength = EffectStrength.MEDIUM;
+
+    /**
+     * The intensity of the haptic effect.
+     *
+     * This value is defined by continuous scale that represents the intensity of this haptic
+     * effect. The vendor implementation can follow the platform scaling function or customize the
+     * implementation to their needs. This is a continuous representation of the strength parameter
+     * above.
+     *
+     * Values in [0,1) should scale down. Values > 1 should scale up within hardware bounds.
+     */
+    float scale;
+
+    /**
+     * The dynamic scale parameter provided by the vendor vibrator controller.
+     *
+     * This value is the same provided by the vendor to the platform IVibratorControlService and
+     * should be applied on top of the effect intensity provided by the strength/scale fields.
+     * The vendor can use this to dynamically adapt the haptic effect intensity to the device state.
+     *
+     * See frameworks/hardware/interfaces/vibrator for more documentation on vendor vibrator
+     * controller, and ScaleParam for more about this scale parameter.
+     *
+     * Values in [0,1) should scale down. Values > 1 should scale up within hardware bounds.
+     */
+    float vendorScale;
+}
diff --git a/vibrator/aidl/default/Android.bp b/vibrator/aidl/default/Android.bp
index 0f342db..4b26640 100644
--- a/vibrator/aidl/default/Android.bp
+++ b/vibrator/aidl/default/Android.bp
@@ -15,7 +15,7 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.vibrator-V2-ndk",
+        "android.hardware.vibrator-V3-ndk",
     ],
     export_include_dirs: ["include"],
     srcs: [
@@ -49,7 +49,7 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.vibrator-V2-ndk",
+        "android.hardware.vibrator-V3-ndk",
     ],
     static_libs: [
         "libvibratorexampleimpl",
@@ -62,7 +62,7 @@
     host_supported: true,
     defaults: ["service_fuzzer_defaults"],
     static_libs: [
-        "android.hardware.vibrator-V2-ndk",
+        "android.hardware.vibrator-V3-ndk",
         "liblog",
         "libvibratorexampleimpl",
     ],
diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp
index 01602ab..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;
@@ -39,14 +42,30 @@
 static constexpr float PWLE_BW_MAP_SIZE =
         1 + ((PWLE_FREQUENCY_MAX_HZ - PWLE_FREQUENCY_MIN_HZ) / PWLE_FREQUENCY_RESOLUTION_HZ);
 
+// Service specific error code used for vendor vibration effects.
+static constexpr int32_t ERROR_CODE_INVALID_DURATION = 1;
+
 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;
+    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();
 }
 
@@ -102,6 +121,47 @@
     return ndk::ScopedAStatus::ok();
 }
 
+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) {
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
+    }
+    float scale = effect.scale;
+    if (scale <= 0) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    float vendorScale = effect.vendorScale;
+    if (vendorScale <= 0) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+
+    int32_t durationMs = 0;
+    if (!effect.vendorData.getInt("DURATION_MS", &durationMs) || durationMs <= 0) {
+        return ndk::ScopedAStatus::fromServiceSpecificError(ERROR_CODE_INVALID_DURATION);
+    }
+
+    if (callback != nullptr) {
+        std::thread([callback, durationMs] {
+            LOG(VERBOSE) << "Starting perform on another thread for durationMs:" << durationMs;
+            usleep(durationMs * 1000);
+            LOG(VERBOSE) << "Notifying perform vendor effect complete";
+            callback->onComplete();
+        }).detach();
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector<Effect>* _aidl_return) {
     *_aidl_return = {Effect::CLICK, Effect::TICK};
     return ndk::ScopedAStatus::ok();
@@ -412,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/android.hardware.vibrator.xml b/vibrator/aidl/default/android.hardware.vibrator.xml
index b5bd3dd..b730046 100644
--- a/vibrator/aidl/default/android.hardware.vibrator.xml
+++ b/vibrator/aidl/default/android.hardware.vibrator.xml
@@ -1,12 +1,12 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.vibrator</name>
-        <version>2</version>
+        <version>3</version>
         <fqname>IVibrator/default</fqname>
     </hal>
     <hal format="aidl">
         <name>android.hardware.vibrator</name>
-        <version>2</version>
+        <version>3</version>
         <fqname>IVibratorManager/default</fqname>
     </hal>
 </manifest>
diff --git a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
index 4203bf2..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 {
@@ -31,6 +32,9 @@
     ndk::ScopedAStatus perform(Effect effect, EffectStrength strength,
                                const std::shared_ptr<IVibratorCallback>& callback,
                                int32_t* _aidl_return) override;
+    ndk::ScopedAStatus performVendorEffect(
+            const VendorEffect& effect,
+            const std::shared_ptr<IVibratorCallback>& callback) override;
     ndk::ScopedAStatus getSupportedEffects(std::vector<Effect>* _aidl_return) override;
     ndk::ScopedAStatus setAmplitude(float amplitude) override;
     ndk::ScopedAStatus setExternalControl(bool enabled) override;
@@ -54,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/Android.bp b/vibrator/aidl/vts/Android.bp
index b6d2fb2..a48bb2e 100644
--- a/vibrator/aidl/vts/Android.bp
+++ b/vibrator/aidl/vts/Android.bp
@@ -17,10 +17,10 @@
     tidy_timeout_srcs: ["VtsHalVibratorTargetTest.cpp"],
     srcs: ["VtsHalVibratorTargetTest.cpp"],
     shared_libs: [
-        "libbinder",
+        "libbinder_ndk",
     ],
     static_libs: [
-        "android.hardware.vibrator-V2-cpp",
+        "android.hardware.vibrator-V3-ndk",
     ],
     test_suites: [
         "general-tests",
@@ -36,10 +36,10 @@
     ],
     srcs: ["VtsHalVibratorManagerTargetTest.cpp"],
     shared_libs: [
-        "libbinder",
+        "libbinder_ndk",
     ],
     static_libs: [
-        "android.hardware.vibrator-V2-cpp",
+        "android.hardware.vibrator-V3-ndk",
     ],
     test_suites: [
         "general-tests",
diff --git a/vibrator/aidl/vts/VtsHalVibratorManagerTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorManagerTargetTest.cpp
index e8ed26a..3c2a360 100644
--- a/vibrator/aidl/vts/VtsHalVibratorManagerTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorManagerTargetTest.cpp
@@ -15,42 +15,40 @@
  */
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
+#include <aidl/android/hardware/vibrator/BnVibratorCallback.h>
+#include <aidl/android/hardware/vibrator/IVibrator.h>
+#include <aidl/android/hardware/vibrator/IVibratorManager.h>
 
-#include <android/hardware/vibrator/BnVibratorCallback.h>
-#include <android/hardware/vibrator/IVibrator.h>
-#include <android/hardware/vibrator/IVibratorManager.h>
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
 
 #include <cmath>
 #include <future>
 
-using android::ProcessState;
-using android::sp;
-using android::String16;
-using android::binder::Status;
-using android::hardware::vibrator::BnVibratorCallback;
-using android::hardware::vibrator::CompositeEffect;
-using android::hardware::vibrator::CompositePrimitive;
-using android::hardware::vibrator::Effect;
-using android::hardware::vibrator::EffectStrength;
-using android::hardware::vibrator::IVibrator;
-using android::hardware::vibrator::IVibratorManager;
+#include "test_utils.h"
+
+using aidl::android::hardware::vibrator::BnVibratorCallback;
+using aidl::android::hardware::vibrator::CompositeEffect;
+using aidl::android::hardware::vibrator::CompositePrimitive;
+using aidl::android::hardware::vibrator::Effect;
+using aidl::android::hardware::vibrator::EffectStrength;
+using aidl::android::hardware::vibrator::IVibrator;
+using aidl::android::hardware::vibrator::IVibratorManager;
 using std::chrono::high_resolution_clock;
 
-const std::vector<Effect> kEffects{android::enum_range<Effect>().begin(),
-                                   android::enum_range<Effect>().end()};
-const std::vector<EffectStrength> kEffectStrengths{android::enum_range<EffectStrength>().begin(),
-                                                   android::enum_range<EffectStrength>().end()};
-const std::vector<CompositePrimitive> kPrimitives{android::enum_range<CompositePrimitive>().begin(),
-                                                  android::enum_range<CompositePrimitive>().end()};
+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(),
+                                                   ndk::enum_range<EffectStrength>().end()};
+const std::vector<CompositePrimitive> kPrimitives{ndk::enum_range<CompositePrimitive>().begin(),
+                                                  ndk::enum_range<CompositePrimitive>().end()};
 
 class CompletionCallback : public BnVibratorCallback {
   public:
     CompletionCallback(const std::function<void()>& callback) : mCallback(callback) {}
-    Status onComplete() override {
+    ndk::ScopedAStatus onComplete() override {
         mCallback();
-        return Status::ok();
+        return ndk::ScopedAStatus::ok();
     }
 
   private:
@@ -60,55 +58,50 @@
 class VibratorAidl : public testing::TestWithParam<std::string> {
   public:
     virtual void SetUp() override {
-        manager = android::waitForDeclaredService<IVibratorManager>(String16(GetParam().c_str()));
+        auto serviceName = GetParam().c_str();
+        manager = IVibratorManager::fromBinder(
+                ndk::SpAIBinder(AServiceManager_waitForService(serviceName)));
         ASSERT_NE(manager, nullptr);
-        ASSERT_TRUE(manager->getCapabilities(&capabilities).isOk());
-        EXPECT_TRUE(manager->getVibratorIds(&vibratorIds).isOk());
+        EXPECT_OK(manager->getCapabilities(&capabilities));
+        EXPECT_OK(manager->getVibratorIds(&vibratorIds));
     }
 
-    sp<IVibratorManager> manager;
+    std::shared_ptr<IVibratorManager> manager;
     int32_t capabilities;
     std::vector<int32_t> vibratorIds;
 };
 
-inline bool isUnknownOrUnsupported(Status status) {
-    return status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
-           status.transactionError() == android::UNKNOWN_TRANSACTION;
-}
-
 TEST_P(VibratorAidl, ValidateExistingVibrators) {
-    sp<IVibrator> vibrator;
-    for (auto& id : vibratorIds) {
-        EXPECT_TRUE(manager->getVibrator(id, &vibrator).isOk());
+    std::shared_ptr<IVibrator> vibrator;
+    for (int32_t id : vibratorIds) {
+        EXPECT_OK(manager->getVibrator(id, &vibrator));
         ASSERT_NE(vibrator, nullptr);
     }
 }
 
 TEST_P(VibratorAidl, GetVibratorWithInvalidId) {
     int32_t invalidId = *max_element(vibratorIds.begin(), vibratorIds.end()) + 1;
-    sp<IVibrator> vibrator;
-    EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-              manager->getVibrator(invalidId, &vibrator).exceptionCode());
+    std::shared_ptr<IVibrator> vibrator;
+    EXPECT_ILLEGAL_ARGUMENT(manager->getVibrator(invalidId, &vibrator));
     ASSERT_EQ(vibrator, nullptr);
 }
 
 TEST_P(VibratorAidl, ValidatePrepareSyncedExistingVibrators) {
     if (!(capabilities & IVibratorManager::CAP_SYNC)) return;
     if (vibratorIds.empty()) return;
-    EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
-    EXPECT_TRUE(manager->cancelSynced().isOk());
+    EXPECT_OK(manager->prepareSynced(vibratorIds));
+    EXPECT_OK(manager->cancelSynced());
 }
 
 TEST_P(VibratorAidl, PrepareSyncedEmptySetIsInvalid) {
     if (!(capabilities & IVibratorManager::CAP_SYNC)) return;
     std::vector<int32_t> emptyIds;
-    EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, manager->prepareSynced(emptyIds).exceptionCode());
+    EXPECT_ILLEGAL_ARGUMENT(manager->prepareSynced(emptyIds));
 }
 
 TEST_P(VibratorAidl, PrepareSyncedNotSupported) {
     if (!(capabilities & IVibratorManager::CAP_SYNC)) {
-        Status status = manager->prepareSynced(vibratorIds);
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(manager->prepareSynced(vibratorIds));
     }
 }
 
@@ -117,15 +110,14 @@
     if (!(capabilities & IVibratorManager::CAP_SYNC)) return;
     if (!(capabilities & IVibratorManager::CAP_PREPARE_ON)) {
         uint32_t durationMs = 250;
-        EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
-        sp<IVibrator> vibrator;
-        for (auto& id : vibratorIds) {
-            EXPECT_TRUE(manager->getVibrator(id, &vibrator).isOk());
+        EXPECT_OK(manager->prepareSynced(vibratorIds));
+        std::shared_ptr<IVibrator> vibrator;
+        for (int32_t id : vibratorIds) {
+            EXPECT_OK(manager->getVibrator(id, &vibrator));
             ASSERT_NE(vibrator, nullptr);
-            Status status = vibrator->on(durationMs, nullptr);
-            EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+            EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->on(durationMs, nullptr));
         }
-        EXPECT_TRUE(manager->cancelSynced().isOk());
+        EXPECT_OK(manager->cancelSynced());
     }
 }
 
@@ -133,16 +125,16 @@
     if (vibratorIds.empty()) return;
     if (!(capabilities & IVibratorManager::CAP_SYNC)) return;
     if (!(capabilities & IVibratorManager::CAP_PREPARE_ON)) {
-        EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
-        sp<IVibrator> vibrator;
-        for (auto& id : vibratorIds) {
-            EXPECT_TRUE(manager->getVibrator(id, &vibrator).isOk());
+        EXPECT_OK(manager->prepareSynced(vibratorIds));
+        std::shared_ptr<IVibrator> vibrator;
+        for (int32_t id : vibratorIds) {
+            EXPECT_OK(manager->getVibrator(id, &vibrator));
             ASSERT_NE(vibrator, nullptr);
             int32_t lengthMs = 0;
-            Status status = vibrator->perform(kEffects[0], kEffectStrengths[0], nullptr, &lengthMs);
-            EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+            EXPECT_UNKNOWN_OR_UNSUPPORTED(
+                    vibrator->perform(kEffects[0], kEffectStrengths[0], nullptr, &lengthMs));
         }
-        EXPECT_TRUE(manager->cancelSynced().isOk());
+        EXPECT_OK(manager->cancelSynced());
     }
 }
 
@@ -157,15 +149,14 @@
         effect.scale = 1.0f;
         composite.emplace_back(effect);
 
-        EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
-        sp<IVibrator> vibrator;
-        for (auto& id : vibratorIds) {
-            EXPECT_TRUE(manager->getVibrator(id, &vibrator).isOk());
+        EXPECT_OK(manager->prepareSynced(vibratorIds));
+        std::shared_ptr<IVibrator> vibrator;
+        for (int32_t id : vibratorIds) {
+            EXPECT_OK(manager->getVibrator(id, &vibrator));
             ASSERT_NE(vibrator, nullptr);
-            Status status = vibrator->compose(composite, nullptr);
-            EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+            EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->compose(composite, nullptr));
         }
-        EXPECT_TRUE(manager->cancelSynced().isOk());
+        EXPECT_OK(manager->cancelSynced());
     }
 }
 
@@ -177,51 +168,58 @@
 
     std::promise<void> completionPromise;
     std::future<void> completionFuture{completionPromise.get_future()};
-    sp<CompletionCallback> callback =
-            new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+    auto callback = ndk::SharedRefBase::make<CompletionCallback>(
+            [&completionPromise] { completionPromise.set_value(); });
     uint32_t durationMs = 250;
     std::chrono::milliseconds timeout{durationMs * 2};
 
-    EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
-    sp<IVibrator> vibrator;
-    for (auto& id : vibratorIds) {
-        EXPECT_TRUE(manager->getVibrator(id, &vibrator).isOk());
+    EXPECT_OK(manager->prepareSynced(vibratorIds));
+    std::shared_ptr<IVibrator> vibrator;
+    for (int32_t id : vibratorIds) {
+        EXPECT_OK(manager->getVibrator(id, &vibrator));
         ASSERT_NE(vibrator, nullptr);
-        EXPECT_TRUE(vibrator->on(durationMs, nullptr).isOk());
+        EXPECT_OK(vibrator->on(durationMs, nullptr));
     }
 
-    EXPECT_TRUE(manager->triggerSynced(callback).isOk());
+    EXPECT_OK(manager->triggerSynced(callback));
     EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
-    EXPECT_TRUE(manager->cancelSynced().isOk());
+    EXPECT_OK(manager->cancelSynced());
 }
 
 TEST_P(VibratorAidl, TriggerSyncNotSupported) {
     if (!(capabilities & IVibratorManager::CAP_SYNC)) {
-        Status status = manager->triggerSynced(nullptr);
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(manager->triggerSynced(nullptr));
     }
 }
 
 TEST_P(VibratorAidl, TriggerCallbackNotSupported) {
     if (!(capabilities & IVibratorManager::CAP_SYNC)) return;
     if (!(capabilities & IVibratorManager::CAP_TRIGGER_CALLBACK)) {
-        sp<CompletionCallback> callback = new CompletionCallback([] {});
-        EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
-        Status status = manager->triggerSynced(callback);
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
-        EXPECT_TRUE(manager->cancelSynced().isOk());
+        auto callback = ndk::SharedRefBase::make<CompletionCallback>([] {});
+        EXPECT_OK(manager->prepareSynced(vibratorIds));
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(manager->triggerSynced(callback));
+        EXPECT_OK(manager->cancelSynced());
     }
 }
 
+std::vector<std::string> FindVibratorManagerNames() {
+    std::vector<std::string> names;
+    constexpr auto callback = [](const char* instance, void* context) {
+        std::string fullName = std::string(IVibratorManager::descriptor) + "/" + instance;
+        static_cast<std::vector<std::string>*>(context)->emplace_back(fullName);
+    };
+    AServiceManager_forEachDeclaredInstance(IVibratorManager::descriptor,
+                                            static_cast<void*>(&names), callback);
+    return names;
+}
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VibratorAidl);
-INSTANTIATE_TEST_SUITE_P(
-        Vibrator, VibratorAidl,
-        testing::ValuesIn(android::getAidlHalInstanceNames(IVibratorManager::descriptor)),
-        android::PrintInstanceNameToString);
+INSTANTIATE_TEST_SUITE_P(Vibrator, VibratorAidl, testing::ValuesIn(FindVibratorManagerNames()),
+                         android::PrintInstanceNameToString);
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
-    ProcessState::self()->setThreadPoolMaxThreadCount(1);
-    ProcessState::self()->startThreadPool();
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
 }
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index db474d6..bc017ae 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -15,38 +15,51 @@
  */
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
-#include <android/hardware/vibrator/BnVibratorCallback.h>
-#include <android/hardware/vibrator/IVibrator.h>
-#include <android/hardware/vibrator/IVibratorManager.h>
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
+#include <aidl/android/hardware/vibrator/BnVibratorCallback.h>
+#include <aidl/android/hardware/vibrator/IVibrator.h>
+#include <aidl/android/hardware/vibrator/IVibratorManager.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <android/persistable_bundle_aidl.h>
 
 #include <cmath>
+#include <cstdlib>
+#include <ctime>
 #include <future>
+#include <iomanip>
+#include <iostream>
+#include <random>
 
-using android::ProcessState;
-using android::sp;
-using android::String16;
-using android::binder::Status;
-using android::hardware::vibrator::ActivePwle;
-using android::hardware::vibrator::BnVibratorCallback;
-using android::hardware::vibrator::Braking;
-using android::hardware::vibrator::BrakingPwle;
-using android::hardware::vibrator::CompositeEffect;
-using android::hardware::vibrator::CompositePrimitive;
-using android::hardware::vibrator::Effect;
-using android::hardware::vibrator::EffectStrength;
-using android::hardware::vibrator::IVibrator;
-using android::hardware::vibrator::IVibratorManager;
-using android::hardware::vibrator::PrimitivePwle;
+#include "persistable_bundle_utils.h"
+#include "pwle_v2_utils.h"
+#include "test_utils.h"
+
+using aidl::android::hardware::vibrator::ActivePwle;
+using aidl::android::hardware::vibrator::BnVibratorCallback;
+using aidl::android::hardware::vibrator::Braking;
+using aidl::android::hardware::vibrator::BrakingPwle;
+using aidl::android::hardware::vibrator::CompositeEffect;
+using aidl::android::hardware::vibrator::CompositePrimitive;
+using aidl::android::hardware::vibrator::Effect;
+using aidl::android::hardware::vibrator::EffectStrength;
+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;
 
-const std::vector<Effect> kEffects{android::enum_range<Effect>().begin(),
-                                   android::enum_range<Effect>().end()};
-const std::vector<EffectStrength> kEffectStrengths{android::enum_range<EffectStrength>().begin(),
-                                                   android::enum_range<EffectStrength>().end()};
+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(),
+                                                   ndk::enum_range<EffectStrength>().end()};
 
 const std::vector<Effect> kInvalidEffects = {
     static_cast<Effect>(static_cast<int32_t>(kEffects.front()) - 1),
@@ -59,8 +72,7 @@
 };
 
 const std::vector<CompositePrimitive> kCompositePrimitives{
-    android::enum_range<CompositePrimitive>().begin(),
-    android::enum_range<CompositePrimitive>().end()};
+        ndk::enum_range<CompositePrimitive>().begin(), ndk::enum_range<CompositePrimitive>().end()};
 
 const std::vector<CompositePrimitive> kRequiredPrimitives = {
         CompositePrimitive::CLICK,      CompositePrimitive::LIGHT_TICK,
@@ -74,14 +86,39 @@
 };
 
 // Timeout to wait for vibration callback completion.
-static constexpr auto VIBRATION_CALLBACK_TIMEOUT = 100ms;
+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) {
+        auto fullName = std::string(IVibratorManager::descriptor) + "/" + instance;
+        static_cast<std::vector<std::string>*>(context)->emplace_back(fullName);
+    };
+    AServiceManager_forEachDeclaredInstance(IVibratorManager::descriptor,
+                                            static_cast<void*>(&names), callback);
+    return names;
+}
+
+static std::vector<std::string> findUnmanagedVibratorNames() {
+    std::vector<std::string> names;
+    constexpr auto callback = [](const char* instance, void* context) {
+        auto fullName = std::string(IVibrator::descriptor) + "/" + instance;
+        static_cast<std::vector<std::string>*>(context)->emplace_back(fullName);
+    };
+    AServiceManager_forEachDeclaredInstance(IVibrator::descriptor, static_cast<void*>(&names),
+                                            callback);
+    return names;
+}
 
 class CompletionCallback : public BnVibratorCallback {
   public:
     CompletionCallback(const std::function<void()> &callback) : mCallback(callback) {}
-    Status onComplete() override {
+    ndk::ScopedAStatus onComplete() override {
         mCallback();
-        return Status::ok();
+        return ndk::ScopedAStatus::ok();
     }
 
   private:
@@ -93,88 +130,89 @@
     virtual void SetUp() override {
         int32_t managerIdx = std::get<0>(GetParam());
         int32_t vibratorId = std::get<1>(GetParam());
-        auto managerAidlNames = android::getAidlHalInstanceNames(IVibratorManager::descriptor);
 
         if (managerIdx < 0) {
             // Testing a unmanaged vibrator, using vibratorId as index from registered HALs
-            auto vibratorAidlNames = android::getAidlHalInstanceNames(IVibrator::descriptor);
-            ASSERT_LT(vibratorId, vibratorAidlNames.size());
-            auto vibratorName = String16(vibratorAidlNames[vibratorId].c_str());
-            vibrator = android::waitForDeclaredService<IVibrator>(vibratorName);
+            std::vector<std::string> vibratorNames = findUnmanagedVibratorNames();
+            ASSERT_LT(vibratorId, vibratorNames.size());
+            vibrator = IVibrator::fromBinder(ndk::SpAIBinder(
+                    AServiceManager_waitForService(vibratorNames[vibratorId].c_str())));
         } else {
             // Testing a managed vibrator, using vibratorId to retrieve it from the manager
-            ASSERT_LT(managerIdx, managerAidlNames.size());
-            auto managerName = String16(managerAidlNames[managerIdx].c_str());
-            auto vibratorManager = android::waitForDeclaredService<IVibratorManager>(managerName);
-            auto vibratorResult = vibratorManager->getVibrator(vibratorId, &vibrator);
-            ASSERT_TRUE(vibratorResult.isOk());
+            std::vector<std::string> managerNames = findVibratorManagerNames();
+            ASSERT_LT(managerIdx, managerNames.size());
+            auto vibratorManager = IVibratorManager::fromBinder(ndk::SpAIBinder(
+                    AServiceManager_waitForService(managerNames[managerIdx].c_str())));
+            EXPECT_OK(vibratorManager->getVibrator(vibratorId, &vibrator))
+                    << "\n  For vibrator id: " << vibratorId;
         }
 
         ASSERT_NE(vibrator, nullptr);
-        ASSERT_TRUE(vibrator->getCapabilities(&capabilities).isOk());
+        EXPECT_OK(vibrator->getInterfaceVersion(&version));
+        EXPECT_OK(vibrator->getCapabilities(&capabilities));
     }
 
     virtual void TearDown() override {
         // Reset vibrator state between tests.
-        EXPECT_TRUE(vibrator->off().isOk());
+        EXPECT_OK(vibrator->off());
     }
 
-    sp<IVibrator> vibrator;
+    std::shared_ptr<IVibrator> vibrator;
+    int32_t version;
     int32_t capabilities;
 };
 
-inline bool isUnknownOrUnsupported(Status status) {
-    return status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
-           status.transactionError() == android::UNKNOWN_TRANSACTION;
-}
-
-static float getResonantFrequencyHz(sp<IVibrator> vibrator, int32_t capabilities) {
+static float getResonantFrequencyHz(const std::shared_ptr<IVibrator>& vibrator,
+                                    int32_t capabilities) {
     float resonantFrequencyHz;
-    Status status = vibrator->getResonantFrequency(&resonantFrequencyHz);
+    ndk::ScopedAStatus status = vibrator->getResonantFrequency(&resonantFrequencyHz);
     if (capabilities & IVibrator::CAP_GET_RESONANT_FREQUENCY) {
+        EXPECT_OK(std::move(status));
         EXPECT_GT(resonantFrequencyHz, 0);
-        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
     } else {
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
     }
     return resonantFrequencyHz;
 }
 
-static float getFrequencyResolutionHz(sp<IVibrator> vibrator, int32_t capabilities) {
+static float getFrequencyResolutionHz(const std::shared_ptr<IVibrator>& vibrator,
+                                      int32_t capabilities) {
     float freqResolutionHz;
-    Status status = vibrator->getFrequencyResolution(&freqResolutionHz);
+    ndk::ScopedAStatus status = vibrator->getFrequencyResolution(&freqResolutionHz);
     if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
+        EXPECT_OK(std::move(status));
         EXPECT_GT(freqResolutionHz, 0);
-        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
     } else {
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
     }
     return freqResolutionHz;
 }
 
-static float getFrequencyMinimumHz(sp<IVibrator> vibrator, int32_t capabilities) {
+static float getFrequencyMinimumHz(const std::shared_ptr<IVibrator>& vibrator,
+                                   int32_t capabilities) {
     float freqMinimumHz;
-    Status status = vibrator->getFrequencyMinimum(&freqMinimumHz);
+    ndk::ScopedAStatus status = vibrator->getFrequencyMinimum(&freqMinimumHz);
     if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
-        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+        EXPECT_OK(std::move(status));
 
         float resonantFrequencyHz = getResonantFrequencyHz(vibrator, capabilities);
 
         EXPECT_GT(freqMinimumHz, 0);
         EXPECT_LE(freqMinimumHz, resonantFrequencyHz);
     } else {
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
     }
     return freqMinimumHz;
 }
 
-static float getFrequencyMaximumHz(sp<IVibrator> vibrator, int32_t capabilities) {
+static float getFrequencyMaximumHz(const std::shared_ptr<IVibrator>& vibrator,
+                                   int32_t capabilities) {
     std::vector<float> bandwidthAmplitudeMap;
-    Status status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap);
+    ndk::ScopedAStatus status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap);
     if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
-        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+        EXPECT_OK(std::move(status));
     } else {
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
     }
 
     float freqMaximumHz = ((bandwidthAmplitudeMap.size() - 1) *
@@ -191,7 +229,8 @@
     return 1.0;
 }
 
-static ActivePwle composeValidActivePwle(sp<IVibrator> vibrator, int32_t capabilities) {
+static ActivePwle composeValidActivePwle(const std::shared_ptr<IVibrator>& vibrator,
+                                         int32_t capabilities) {
     float frequencyHz;
     if (capabilities & IVibrator::CAP_GET_RESONANT_FREQUENCY) {
         frequencyHz = getResonantFrequencyHz(vibrator, capabilities);
@@ -212,9 +251,9 @@
 }
 
 TEST_P(VibratorAidl, OnThenOffBeforeTimeout) {
-    EXPECT_TRUE(vibrator->on(2000, nullptr /*callback*/).isOk());
+    EXPECT_OK(vibrator->on(2000, nullptr /*callback*/));
     sleep(1);
-    EXPECT_TRUE(vibrator->off().isOk());
+    EXPECT_OK(vibrator->off());
 }
 
 TEST_P(VibratorAidl, OnWithCallback) {
@@ -223,26 +262,25 @@
 
     std::promise<void> completionPromise;
     std::future<void> completionFuture{completionPromise.get_future()};
-    sp<CompletionCallback> callback =
-        new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+    auto callback = ndk::SharedRefBase::make<CompletionCallback>(
+            [&completionPromise] { completionPromise.set_value(); });
     uint32_t durationMs = 250;
     auto timeout = std::chrono::milliseconds(durationMs) + VIBRATION_CALLBACK_TIMEOUT;
-    EXPECT_TRUE(vibrator->on(durationMs, callback).isOk());
+    EXPECT_OK(vibrator->on(durationMs, callback));
     EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
-    EXPECT_TRUE(vibrator->off().isOk());
+    EXPECT_OK(vibrator->off());
 }
 
 TEST_P(VibratorAidl, OnCallbackNotSupported) {
     if (!(capabilities & IVibrator::CAP_ON_CALLBACK)) {
-        sp<CompletionCallback> callback = new CompletionCallback([] {});
-        Status status = vibrator->on(250, callback);
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        auto callback = ndk::SharedRefBase::make<CompletionCallback>([] {});
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->on(250, callback));
     }
 }
 
 TEST_P(VibratorAidl, ValidateEffect) {
     std::vector<Effect> supported;
-    ASSERT_TRUE(vibrator->getSupportedEffects(&supported).isOk());
+    EXPECT_OK(vibrator->getSupportedEffects(&supported));
 
     for (Effect effect : kEffects) {
         bool isEffectSupported =
@@ -250,15 +288,18 @@
 
         for (EffectStrength strength : kEffectStrengths) {
             int32_t lengthMs = 0;
-            Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs);
+            ndk::ScopedAStatus status =
+                    vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs);
 
             if (isEffectSupported) {
-                EXPECT_TRUE(status.isOk()) << toString(effect) << " " << toString(strength);
+                EXPECT_OK(std::move(status))
+                        << "\n  For effect: " << toString(effect) << " " << toString(strength);
                 EXPECT_GT(lengthMs, 0);
                 usleep(lengthMs * 1000);
+                EXPECT_OK(vibrator->off());
             } else {
-                EXPECT_TRUE(isUnknownOrUnsupported(status))
-                        << status << " " << toString(effect) << " " << toString(strength);
+                EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status))
+                        << "\n  For effect: " << toString(effect) << " " << toString(strength);
             }
         }
     }
@@ -269,7 +310,7 @@
         return;
 
     std::vector<Effect> supported;
-    ASSERT_TRUE(vibrator->getSupportedEffects(&supported).isOk());
+    EXPECT_OK(vibrator->getSupportedEffects(&supported));
 
     for (Effect effect : kEffects) {
         bool isEffectSupported =
@@ -278,25 +319,26 @@
         for (EffectStrength strength : kEffectStrengths) {
             std::promise<void> completionPromise;
             std::future<void> completionFuture{completionPromise.get_future()};
-            sp<CompletionCallback> callback =
-                new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+            auto callback = ndk::SharedRefBase::make<CompletionCallback>(
+                    [&completionPromise] { completionPromise.set_value(); });
             int lengthMs = 0;
-            Status status = vibrator->perform(effect, strength, callback, &lengthMs);
+            ndk::ScopedAStatus status = vibrator->perform(effect, strength, callback, &lengthMs);
 
             if (isEffectSupported) {
-                EXPECT_TRUE(status.isOk());
+                EXPECT_OK(std::move(status))
+                        << "\n  For effect: " << toString(effect) << " " << toString(strength);
                 EXPECT_GT(lengthMs, 0);
             } else {
-                EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+                EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status))
+                        << "\n  For effect: " << toString(effect) << " " << toString(strength);
             }
 
-            if (!status.isOk())
-                continue;
+            if (lengthMs <= 0) continue;
 
             auto timeout = std::chrono::milliseconds(lengthMs) + VIBRATION_CALLBACK_TIMEOUT;
             EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
 
-            EXPECT_TRUE(vibrator->off().isOk());
+            EXPECT_OK(vibrator->off());
         }
     }
 }
@@ -307,10 +349,10 @@
 
     for (Effect effect : kEffects) {
         for (EffectStrength strength : kEffectStrengths) {
-            sp<CompletionCallback> callback = new CompletionCallback([] {});
+            auto callback = ndk::SharedRefBase::make<CompletionCallback>([] {});
             int lengthMs;
-            Status status = vibrator->perform(effect, strength, callback, &lengthMs);
-            EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+            EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->perform(effect, strength, callback, &lengthMs))
+                    << "\n  For effect: " << toString(effect) << " " << toString(strength);
         }
     }
 }
@@ -319,53 +361,182 @@
     for (Effect effect : kInvalidEffects) {
         for (EffectStrength strength : kEffectStrengths) {
             int32_t lengthMs;
-            Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs);
-            EXPECT_TRUE(isUnknownOrUnsupported(status))
-                    << status << toString(effect) << " " << toString(strength);
+            EXPECT_UNKNOWN_OR_UNSUPPORTED(
+                    vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs))
+                    << "\n  For effect: " << toString(effect) << " " << toString(strength);
         }
     }
     for (Effect effect : kEffects) {
         for (EffectStrength strength : kInvalidEffectStrengths) {
             int32_t lengthMs;
-            Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs);
-            EXPECT_TRUE(isUnknownOrUnsupported(status))
-                    << status << " " << toString(effect) << " " << toString(strength);
+            EXPECT_UNKNOWN_OR_UNSUPPORTED(
+                    vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs))
+                    << "\n  For effect: " << toString(effect) << " " << toString(strength);
         }
     }
 }
 
+TEST_P(VibratorAidl, PerformVendorEffectSupported) {
+    if ((capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) == 0) return;
+
+    float scale = 0.0f;
+    float vendorScale = 0.0f;
+    for (EffectStrength strength : kEffectStrengths) {
+        PersistableBundle vendorData;
+        ::aidl::android::hardware::vibrator::testing::fillBasicData(&vendorData);
+
+        PersistableBundle nestedData;
+        ::aidl::android::hardware::vibrator::testing::fillBasicData(&nestedData);
+        vendorData.putPersistableBundle("test_nested_bundle", nestedData);
+
+        VendorEffect effect;
+        effect.vendorData = vendorData;
+        effect.strength = strength;
+        effect.scale = scale;
+        effect.vendorScale = vendorScale;
+        scale += 0.5f;
+        vendorScale += 0.2f;
+
+        auto callback = ndk::SharedRefBase::make<CompletionCallback>([] {});
+        ndk::ScopedAStatus status = vibrator->performVendorEffect(effect, callback);
+
+        // No expectations on the actual status, the effect might be refused with illegal argument
+        // or the vendor might return a service-specific error code.
+        EXPECT_TRUE(status.getExceptionCode() != EX_UNSUPPORTED_OPERATION &&
+                    status.getStatus() != STATUS_UNKNOWN_TRANSACTION)
+                << status << "\n For vendor effect with strength" << toString(strength)
+                << " and scale " << effect.scale;
+
+        if (status.isOk()) {
+            // Generic vendor data should not trigger vibrations, but if it does trigger one
+            // then we make sure the vibrator is reset by triggering off().
+            EXPECT_OK(vibrator->off());
+        }
+    }
+}
+
+TEST_P(VibratorAidl, PerformVendorEffectStability) {
+    if ((capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) == 0) return;
+
+    // Run some iterations of performVendorEffect with randomized vendor data to check basic
+    // stability of the implementation.
+    uint8_t iterations = 200;
+
+    for (EffectStrength strength : kEffectStrengths) {
+        float scale = 0.5f;
+        float vendorScale = 0.2f;
+        for (uint8_t i = 0; i < iterations; i++) {
+            PersistableBundle vendorData;
+            ::aidl::android::hardware::vibrator::testing::fillRandomData(&vendorData);
+
+            VendorEffect effect;
+            effect.vendorData = vendorData;
+            effect.strength = strength;
+            effect.scale = scale;
+            effect.vendorScale = vendorScale;
+            scale *= 2;
+            vendorScale *= 1.5f;
+
+            auto callback = ndk::SharedRefBase::make<CompletionCallback>([] {});
+            ndk::ScopedAStatus status = vibrator->performVendorEffect(effect, callback);
+
+            // No expectations on the actual status, the effect might be refused with illegal
+            // argument or the vendor might return a service-specific error code.
+            EXPECT_TRUE(status.getExceptionCode() != EX_UNSUPPORTED_OPERATION &&
+                        status.getStatus() != STATUS_UNKNOWN_TRANSACTION)
+                    << status << "\n For random vendor effect with strength " << toString(strength)
+                    << " and scale " << effect.scale;
+
+            if (status.isOk()) {
+                // Random vendor data should not trigger vibrations, but if it does trigger one
+                // then we make sure the vibrator is reset by triggering off().
+                EXPECT_OK(vibrator->off());
+            }
+        }
+    }
+}
+
+TEST_P(VibratorAidl, PerformVendorEffectEmptyVendorData) {
+    if ((capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) == 0) return;
+
+    for (EffectStrength strength : kEffectStrengths) {
+        VendorEffect effect;
+        effect.strength = strength;
+        effect.scale = 1.0f;
+        effect.vendorScale = 1.0f;
+
+        ndk::ScopedAStatus status = vibrator->performVendorEffect(effect, nullptr /*callback*/);
+
+        EXPECT_TRUE(status.getExceptionCode() == EX_SERVICE_SPECIFIC)
+                << status << "\n For vendor effect with strength " << toString(strength)
+                << " and scale " << effect.scale;
+    }
+}
+
+TEST_P(VibratorAidl, PerformVendorEffectInvalidScale) {
+    if ((capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) == 0) return;
+
+    VendorEffect effect;
+    effect.strength = EffectStrength::MEDIUM;
+
+    effect.scale = -1.0f;
+    effect.vendorScale = 1.0f;
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->performVendorEffect(effect, nullptr /*callback*/));
+
+    effect.scale = 1.0f;
+    effect.vendorScale = -1.0f;
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->performVendorEffect(effect, nullptr /*callback*/));
+}
+
+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) {
+        VendorEffect effect;
+        effect.strength = strength;
+        effect.scale = 1.0f;
+        effect.vendorScale = 1.0f;
+
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->performVendorEffect(effect, nullptr /*callback*/))
+                << "\n  For vendor effect with strength " << toString(strength);
+    }
+}
+
 TEST_P(VibratorAidl, ChangeVibrationAmplitude) {
     if (capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) {
-        EXPECT_EQ(Status::EX_NONE, vibrator->setAmplitude(0.1f).exceptionCode());
-        EXPECT_TRUE(vibrator->on(2000, nullptr /*callback*/).isOk());
-        EXPECT_EQ(Status::EX_NONE, vibrator->setAmplitude(0.5f).exceptionCode());
+        EXPECT_OK(vibrator->setAmplitude(0.1f));
+        EXPECT_OK(vibrator->on(2000, nullptr /*callback*/));
+        EXPECT_OK(vibrator->setAmplitude(0.5f));
         sleep(1);
-        EXPECT_EQ(Status::EX_NONE, vibrator->setAmplitude(1.0f).exceptionCode());
+        EXPECT_OK(vibrator->setAmplitude(1.0f));
         sleep(1);
-        EXPECT_TRUE(vibrator->off().isOk());
+        EXPECT_OK(vibrator->off());
     }
 }
 
 TEST_P(VibratorAidl, AmplitudeOutsideRangeFails) {
     if (capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) {
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(-1).exceptionCode());
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(0).exceptionCode());
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(1.1).exceptionCode());
+        EXPECT_ILLEGAL_ARGUMENT(vibrator->setAmplitude(-1));
+        EXPECT_ILLEGAL_ARGUMENT(vibrator->setAmplitude(0));
+        EXPECT_ILLEGAL_ARGUMENT(vibrator->setAmplitude(1.1));
     }
 }
 
 TEST_P(VibratorAidl, AmplitudeReturnsUnsupportedMatchingCapabilities) {
     if ((capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) == 0) {
-        Status status = vibrator->setAmplitude(1);
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->setAmplitude(1));
     }
 }
 
 TEST_P(VibratorAidl, ChangeVibrationExternalControl) {
     if (capabilities & IVibrator::CAP_EXTERNAL_CONTROL) {
-        EXPECT_TRUE(vibrator->setExternalControl(true).isOk());
+        EXPECT_OK(vibrator->setExternalControl(true));
         sleep(1);
-        EXPECT_TRUE(vibrator->setExternalControl(false).isOk());
+        EXPECT_OK(vibrator->setExternalControl(false));
         sleep(1);
     }
 }
@@ -375,15 +546,15 @@
         (capabilities & IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL) > 0;
 
     if (capabilities & IVibrator::CAP_EXTERNAL_CONTROL) {
-        EXPECT_TRUE(vibrator->setExternalControl(true).isOk());
+        EXPECT_OK(vibrator->setExternalControl(true));
 
-        Status amplitudeStatus = vibrator->setAmplitude(0.5);
         if (supportsExternalAmplitudeControl) {
-            EXPECT_TRUE(amplitudeStatus.isOk());
+            EXPECT_OK(vibrator->setAmplitude(0.5));
         } else {
-            EXPECT_TRUE(isUnknownOrUnsupported(amplitudeStatus)) << amplitudeStatus;
+            EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->setAmplitude(0.5));
         }
-        EXPECT_TRUE(vibrator->setExternalControl(false).isOk());
+
+        EXPECT_OK(vibrator->setExternalControl(false));
     } else {
         EXPECT_FALSE(supportsExternalAmplitudeControl);
     }
@@ -391,18 +562,16 @@
 
 TEST_P(VibratorAidl, ExternalControlUnsupportedMatchingCapabilities) {
     if ((capabilities & IVibrator::CAP_EXTERNAL_CONTROL) == 0) {
-        Status status = vibrator->setExternalControl(true);
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->setExternalControl(true));
     }
 }
 
 TEST_P(VibratorAidl, GetSupportedPrimitives) {
     if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
         std::vector<CompositePrimitive> supported;
+        EXPECT_OK(vibrator->getSupportedPrimitives(&supported));
 
-        EXPECT_EQ(Status::EX_NONE, vibrator->getSupportedPrimitives(&supported).exceptionCode());
-
-        for (auto primitive : kCompositePrimitives) {
+        for (CompositePrimitive primitive : kCompositePrimitives) {
             bool isPrimitiveSupported =
                 std::find(supported.begin(), supported.end(), primitive) != supported.end();
             bool isPrimitiveRequired =
@@ -417,22 +586,23 @@
 TEST_P(VibratorAidl, GetPrimitiveDuration) {
     if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
         std::vector<CompositePrimitive> supported;
-        ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk());
+        EXPECT_OK(vibrator->getSupportedPrimitives(&supported));
 
-        for (auto primitive : kCompositePrimitives) {
+        for (CompositePrimitive primitive : kCompositePrimitives) {
             bool isPrimitiveSupported =
                 std::find(supported.begin(), supported.end(), primitive) != supported.end();
             int32_t duration;
 
-            Status status = vibrator->getPrimitiveDuration(primitive, &duration);
-
             if (isPrimitiveSupported) {
-                EXPECT_EQ(Status::EX_NONE, status.exceptionCode());
+                EXPECT_OK(vibrator->getPrimitiveDuration(primitive, &duration))
+                        << "\n  For primitive: " << toString(primitive) << " " << duration;
                 if (primitive != CompositePrimitive::NOOP) {
-                    ASSERT_GT(duration, 0) << toString(primitive) << " " << duration;
+                    ASSERT_GT(duration, 0)
+                            << "\n  For primitive: " << toString(primitive) << " " << duration;
                 }
             } else {
-                EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+                EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->getPrimitiveDuration(primitive, &duration))
+                        << "\n  For primitive: " << toString(primitive);
             }
         }
     }
@@ -446,14 +616,14 @@
     std::vector<CompositePrimitive> supported;
     int32_t maxDelay, maxSize;
 
-    ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk());
-    EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionDelayMax(&maxDelay).exceptionCode());
-    EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionSizeMax(&maxSize).exceptionCode());
+    EXPECT_OK(vibrator->getSupportedPrimitives(&supported));
+    EXPECT_OK(vibrator->getCompositionDelayMax(&maxDelay));
+    EXPECT_OK(vibrator->getCompositionSizeMax(&maxSize));
 
     std::vector<CompositeEffect> composite;
 
     for (int i = 0; i < supported.size(); i++) {
-        auto primitive = supported[i];
+        CompositePrimitive primitive = supported[i];
         float t = static_cast<float>(i + 1) / supported.size();
         CompositeEffect effect;
 
@@ -467,8 +637,8 @@
     }
 
     if (composite.size() != 0) {
-        EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
-        EXPECT_TRUE(vibrator->off().isOk());
+        EXPECT_OK(vibrator->compose(composite, nullptr));
+        EXPECT_OK(vibrator->off());
     }
 }
 
@@ -477,12 +647,12 @@
         GTEST_SKIP() << "CAP_COMPOSE_EFFECTS not supported";
     }
 
-    auto unsupported = kInvalidPrimitives;
+    std::vector<CompositePrimitive> unsupported(kInvalidPrimitives);
     std::vector<CompositePrimitive> supported;
 
-    ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk());
+    EXPECT_OK(vibrator->getSupportedPrimitives(&supported));
 
-    for (auto primitive : kCompositePrimitives) {
+    for (CompositePrimitive primitive : kCompositePrimitives) {
         bool isPrimitiveSupported =
                 std::find(supported.begin(), supported.end(), primitive) != supported.end();
 
@@ -491,16 +661,15 @@
         }
     }
 
-    for (auto primitive : unsupported) {
+    for (CompositePrimitive primitive : unsupported) {
         std::vector<CompositeEffect> composite(1);
 
-        for (auto& effect : composite) {
+        for (CompositeEffect& effect : composite) {
             effect.delayMs = 0;
             effect.primitive = primitive;
             effect.scale = 1.0f;
         }
-        Status status = vibrator->compose(composite, nullptr);
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->compose(composite, nullptr));
     }
 }
 
@@ -516,18 +685,18 @@
     effect.primitive = CompositePrimitive::CLICK;
 
     effect.scale = std::nextafter(0.0f, -1.0f);
-    EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->compose(composite, nullptr).exceptionCode());
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->compose(composite, nullptr));
 
     effect.scale = 0.0f;
-    EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
-    EXPECT_TRUE(vibrator->off().isOk());
+    EXPECT_OK(vibrator->compose(composite, nullptr));
+    EXPECT_OK(vibrator->off());
 
     effect.scale = 1.0f;
-    EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
-    EXPECT_TRUE(vibrator->off().isOk());
+    EXPECT_OK(vibrator->compose(composite, nullptr));
+    EXPECT_OK(vibrator->off());
 
     effect.scale = std::nextafter(1.0f, 2.0f);
-    EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->compose(composite, nullptr).exceptionCode());
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->compose(composite, nullptr));
 }
 
 TEST_P(VibratorAidl, ComposeDelayBoundary) {
@@ -537,7 +706,7 @@
 
     int32_t maxDelay;
 
-    EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionDelayMax(&maxDelay).exceptionCode());
+    EXPECT_OK(vibrator->getCompositionDelayMax(&maxDelay));
 
     std::vector<CompositeEffect> composite(1);
     CompositeEffect& effect = composite[0];
@@ -546,19 +715,19 @@
     effect.scale = 1.0f;
 
     effect.delayMs = 0;
-    EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
-    EXPECT_TRUE(vibrator->off().isOk());
+    EXPECT_OK(vibrator->compose(composite, nullptr));
+    EXPECT_OK(vibrator->off());
 
     effect.delayMs = 1;
-    EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
-    EXPECT_TRUE(vibrator->off().isOk());
+    EXPECT_OK(vibrator->compose(composite, nullptr));
+    EXPECT_OK(vibrator->off());
 
     effect.delayMs = maxDelay;
-    EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
-    EXPECT_TRUE(vibrator->off().isOk());
+    EXPECT_OK(vibrator->compose(composite, nullptr));
+    EXPECT_OK(vibrator->off());
 
     effect.delayMs = maxDelay + 1;
-    EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->compose(composite, nullptr).exceptionCode());
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->compose(composite, nullptr));
 }
 
 TEST_P(VibratorAidl, ComposeSizeBoundary) {
@@ -568,7 +737,7 @@
 
     int32_t maxSize;
 
-    EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionSizeMax(&maxSize).exceptionCode());
+    EXPECT_OK(vibrator->getCompositionSizeMax(&maxSize));
 
     std::vector<CompositeEffect> composite(maxSize);
     CompositeEffect effect;
@@ -578,11 +747,11 @@
     effect.scale = 1.0f;
 
     std::fill(composite.begin(), composite.end(), effect);
-    EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
-    EXPECT_TRUE(vibrator->off().isOk());
+    EXPECT_OK(vibrator->compose(composite, nullptr));
+    EXPECT_OK(vibrator->off());
 
     composite.emplace_back(effect);
-    EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->compose(composite, nullptr).exceptionCode());
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->compose(composite, nullptr));
 }
 
 TEST_P(VibratorAidl, ComposeCallback) {
@@ -591,18 +760,17 @@
     }
 
     std::vector<CompositePrimitive> supported;
+    EXPECT_OK(vibrator->getSupportedPrimitives(&supported));
 
-    ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk());
-
-    for (auto primitive : supported) {
+    for (CompositePrimitive primitive : supported) {
         if (primitive == CompositePrimitive::NOOP) {
             continue;
         }
 
         std::promise<void> completionPromise;
         std::future<void> completionFuture{completionPromise.get_future()};
-        sp<CompletionCallback> callback =
-                new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+        auto callback = ndk::SharedRefBase::make<CompletionCallback>(
+                [&completionPromise] { completionPromise.set_value(); });
         CompositeEffect effect;
         std::vector<CompositeEffect> composite;
         int32_t durationMs;
@@ -615,50 +783,50 @@
         effect.scale = 1.0f;
         composite.emplace_back(effect);
 
-        EXPECT_EQ(Status::EX_NONE,
-                  vibrator->getPrimitiveDuration(primitive, &durationMs).exceptionCode())
-                << toString(primitive);
+        EXPECT_OK(vibrator->getPrimitiveDuration(primitive, &durationMs))
+                << "\n  For primitive: " << toString(primitive);
         duration = std::chrono::milliseconds(durationMs);
 
         start = high_resolution_clock::now();
-        EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, callback).exceptionCode())
-                << toString(primitive);
+        EXPECT_OK(vibrator->compose(composite, callback))
+                << "\n  For primitive: " << toString(primitive);
 
         EXPECT_EQ(completionFuture.wait_for(duration + VIBRATION_CALLBACK_TIMEOUT),
                   std::future_status::ready)
-                << toString(primitive);
+                << "\n  For primitive: " << toString(primitive);
         end = high_resolution_clock::now();
 
         elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
-        EXPECT_GE(elapsed.count(), duration.count()) << toString(primitive);
+        EXPECT_GE(elapsed.count(), duration.count())
+                << "\n  For primitive: " << toString(primitive);
 
-        EXPECT_TRUE(vibrator->off().isOk());
+        EXPECT_OK(vibrator->off()) << "\n  For primitive: " << toString(primitive);
     }
 }
 
 TEST_P(VibratorAidl, AlwaysOn) {
     if (capabilities & IVibrator::CAP_ALWAYS_ON_CONTROL) {
         std::vector<Effect> supported;
-        ASSERT_TRUE(vibrator->getSupportedAlwaysOnEffects(&supported).isOk());
+        EXPECT_OK(vibrator->getSupportedAlwaysOnEffects(&supported));
 
         for (Effect effect : kEffects) {
             bool isEffectSupported =
                 std::find(supported.begin(), supported.end(), effect) != supported.end();
 
             for (EffectStrength strength : kEffectStrengths) {
-                Status status = vibrator->alwaysOnEnable(0, effect, strength);
+                ndk::ScopedAStatus status = vibrator->alwaysOnEnable(0, effect, strength);
 
                 if (isEffectSupported) {
-                    EXPECT_EQ(Status::EX_NONE, status.exceptionCode())
-                        << toString(effect) << " " << toString(strength);
+                    EXPECT_OK(std::move(status))
+                            << "\n  For effect: " << toString(effect) << " " << toString(strength);
                 } else {
-                    EXPECT_TRUE(isUnknownOrUnsupported(status))
-                            << status << " " << toString(effect) << " " << toString(strength);
+                    EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status))
+                            << "\n  For effect: " << toString(effect) << " " << toString(strength);
                 }
             }
         }
 
-        EXPECT_EQ(Status::EX_NONE, vibrator->alwaysOnDisable(0).exceptionCode());
+        EXPECT_OK(vibrator->alwaysOnDisable(0));
     }
 }
 
@@ -668,12 +836,12 @@
 
 TEST_P(VibratorAidl, GetQFactor) {
     float qFactor;
-    Status status = vibrator->getQFactor(&qFactor);
+    ndk::ScopedAStatus status = vibrator->getQFactor(&qFactor);
     if (capabilities & IVibrator::CAP_GET_Q_FACTOR) {
+        EXPECT_OK(std::move(status));
         ASSERT_GT(qFactor, 0);
-        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
     } else {
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
     }
 }
 
@@ -687,9 +855,9 @@
 
 TEST_P(VibratorAidl, GetBandwidthAmplitudeMap) {
     std::vector<float> bandwidthAmplitudeMap;
-    Status status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap);
+    ndk::ScopedAStatus status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap);
     if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
-        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+        EXPECT_OK(std::move(status));
         ASSERT_FALSE(bandwidthAmplitudeMap.empty());
 
         int minMapSize = (getResonantFrequencyHz(vibrator, capabilities) -
@@ -702,42 +870,42 @@
             ASSERT_LE(e, 1.0);
         }
     } else {
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
     }
 }
 
 TEST_P(VibratorAidl, GetPwlePrimitiveDurationMax) {
     int32_t durationMs;
-    Status status = vibrator->getPwlePrimitiveDurationMax(&durationMs);
+    ndk::ScopedAStatus status = vibrator->getPwlePrimitiveDurationMax(&durationMs);
     if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
+        EXPECT_OK(std::move(status));
         ASSERT_NE(durationMs, 0);
-        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
     } else {
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
     }
 }
 
 TEST_P(VibratorAidl, GetPwleCompositionSizeMax) {
     int32_t maxSize;
-    Status status = vibrator->getPwleCompositionSizeMax(&maxSize);
+    ndk::ScopedAStatus status = vibrator->getPwleCompositionSizeMax(&maxSize);
     if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
+        EXPECT_OK(std::move(status));
         ASSERT_NE(maxSize, 0);
-        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
     } else {
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
     }
 }
 
 TEST_P(VibratorAidl, GetSupportedBraking) {
     std::vector<Braking> supported;
-    Status status = vibrator->getSupportedBraking(&supported);
+    ndk::ScopedAStatus status = vibrator->getSupportedBraking(&supported);
     if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
         bool isDefaultNoneSupported =
             std::find(supported.begin(), supported.end(), Braking::NONE) != supported.end();
+        EXPECT_OK(std::move(status));
         ASSERT_TRUE(isDefaultNoneSupported);
-        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
     } else {
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
     }
 }
 
@@ -746,7 +914,7 @@
         ActivePwle firstActive = composeValidActivePwle(vibrator, capabilities);
 
         std::vector<Braking> supported;
-        ASSERT_TRUE(vibrator->getSupportedBraking(&supported).isOk());
+        EXPECT_OK(vibrator->getSupportedBraking(&supported));
         bool isClabSupported =
             std::find(supported.begin(), supported.end(), Braking::CLAB) != supported.end();
         BrakingPwle firstBraking;
@@ -765,11 +933,11 @@
         secondBraking.braking = Braking::NONE;
         secondBraking.duration = 10;
 
-        auto pwleQueue =
-            std::vector<PrimitivePwle>{firstActive, firstBraking, secondActive, secondBraking};
+        std::vector<PrimitivePwle> pwleQueue = {firstActive, firstBraking, secondActive,
+                                                secondBraking};
 
-        EXPECT_EQ(Status::EX_NONE, vibrator->composePwle(pwleQueue, nullptr).exceptionCode());
-        EXPECT_TRUE(vibrator->off().isOk());
+        EXPECT_OK(vibrator->composePwle(pwleQueue, nullptr));
+        EXPECT_OK(vibrator->off());
     }
 }
 
@@ -780,8 +948,8 @@
 
     std::promise<void> completionPromise;
     std::future<void> completionFuture{completionPromise.get_future()};
-    sp<CompletionCallback> callback =
-        new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+    auto callback = ndk::SharedRefBase::make<CompletionCallback>(
+            [&completionPromise] { completionPromise.set_value(); });
     int32_t segmentDurationMaxMs;
     vibrator->getPwlePrimitiveDurationMax(&segmentDurationMaxMs);
     uint32_t durationMs = segmentDurationMaxMs * 2 + 100;  // Sum of 2 active and 1 braking below
@@ -790,27 +958,25 @@
     ActivePwle active = composeValidActivePwle(vibrator, capabilities);
 
     std::vector<Braking> supported;
-    ASSERT_TRUE(vibrator->getSupportedBraking(&supported).isOk());
+    EXPECT_OK(vibrator->getSupportedBraking(&supported));
     bool isClabSupported =
         std::find(supported.begin(), supported.end(), Braking::CLAB) != supported.end();
     BrakingPwle braking;
     braking.braking = isClabSupported ? Braking::CLAB : Braking::NONE;
     braking.duration = 100;
 
-    auto pwleQueue = std::vector<PrimitivePwle>{active, braking, active};
+    std::vector<PrimitivePwle> pwleQueue = {active, braking, active};
 
-    EXPECT_TRUE(vibrator->composePwle(pwleQueue, callback).isOk());
+    EXPECT_OK(vibrator->composePwle(pwleQueue, callback));
     EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
-    EXPECT_TRUE(vibrator->off().isOk());
+    EXPECT_OK(vibrator->off());
 }
 
 TEST_P(VibratorAidl, ComposePwleSegmentBoundary) {
     if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
         std::vector<PrimitivePwle> pwleQueue;
         // test empty queue
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-                  vibrator->composePwle(pwleQueue, nullptr).exceptionCode());
-        EXPECT_TRUE(vibrator->off().isOk());
+        EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueue, nullptr));
 
         ActivePwle active = composeValidActivePwle(vibrator, capabilities);
 
@@ -824,9 +990,7 @@
             pwleQueue.emplace_back(std::move(pwle));
         }
 
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-                  vibrator->composePwle(pwleQueue, nullptr).exceptionCode());
-        EXPECT_TRUE(vibrator->off().isOk());
+        EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueue, nullptr));
     }
 }
 
@@ -836,20 +1000,16 @@
         active.startAmplitude = getAmplitudeMax() + 1.0;  // Amplitude greater than allowed
         active.endAmplitude = getAmplitudeMax() + 1.0;    // Amplitude greater than allowed
 
-        auto pwleQueueGreater = std::vector<PrimitivePwle>{active};
+        std::vector<PrimitivePwle> pwleQueueGreater = {active};
 
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-                  vibrator->composePwle(pwleQueueGreater, nullptr).exceptionCode());
-        EXPECT_TRUE(vibrator->off().isOk());
+        EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueueGreater, nullptr));
 
         active.startAmplitude = getAmplitudeMin() - 1.0;  // Amplitude less than allowed
         active.endAmplitude = getAmplitudeMin() - 1.0;    // Amplitude less than allowed
 
-        auto pwleQueueLess = std::vector<PrimitivePwle>{active};
+        std::vector<PrimitivePwle> pwleQueueLess = {active};
 
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-                  vibrator->composePwle(pwleQueueLess, nullptr).exceptionCode());
-        EXPECT_TRUE(vibrator->off().isOk());
+        EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueueLess, nullptr));
     }
 }
 
@@ -865,20 +1025,16 @@
             freqMaximumHz + freqResolutionHz;                    // Frequency greater than allowed
         active.endFrequency = freqMaximumHz + freqResolutionHz;  // Frequency greater than allowed
 
-        auto pwleQueueGreater = std::vector<PrimitivePwle>{active};
+        std::vector<PrimitivePwle> pwleQueueGreater = {active};
 
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-                  vibrator->composePwle(pwleQueueGreater, nullptr).exceptionCode());
-        EXPECT_TRUE(vibrator->off().isOk());
+        EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueueGreater, nullptr));
 
         active.startFrequency = freqMinimumHz - freqResolutionHz;  // Frequency less than allowed
         active.endFrequency = freqMinimumHz - freqResolutionHz;    // Frequency less than allowed
 
-        auto pwleQueueLess = std::vector<PrimitivePwle>{active};
+        std::vector<PrimitivePwle> pwleQueueLess = {active};
 
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-                  vibrator->composePwle(pwleQueueLess, nullptr).exceptionCode());
-        EXPECT_TRUE(vibrator->off().isOk());
+        EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueueLess, nullptr));
     }
 }
 
@@ -890,32 +1046,196 @@
         vibrator->getPwlePrimitiveDurationMax(&segmentDurationMaxMs);
         active.duration = segmentDurationMaxMs + 10;  // Segment duration greater than allowed
 
-        auto pwleQueue = std::vector<PrimitivePwle>{active};
+        std::vector<PrimitivePwle> pwleQueue = {active};
 
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-                  vibrator->composePwle(pwleQueue, nullptr).exceptionCode());
-        EXPECT_TRUE(vibrator->off().isOk());
+        EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueue, nullptr));
     }
 }
 
+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;
-    auto managerAidlNames = android::getAidlHalInstanceNames(IVibratorManager::descriptor);
-    std::vector<int32_t> vibratorIds;
 
-    for (int i = 0; i < managerAidlNames.size(); i++) {
-        auto managerName = String16(managerAidlNames[i].c_str());
-        auto vibratorManager = android::waitForDeclaredService<IVibratorManager>(managerName);
+    std::vector<std::string> managerNames = findVibratorManagerNames();
+    std::vector<int32_t> vibratorIds;
+    for (int i = 0; i < managerNames.size(); i++) {
+        auto vibratorManager = IVibratorManager::fromBinder(
+                ndk::SpAIBinder(AServiceManager_waitForService(managerNames[i].c_str())));
         if (vibratorManager->getVibratorIds(&vibratorIds).isOk()) {
-            for (auto &vibratorId : vibratorIds) {
-                tuples.push_back(std::make_tuple(i, vibratorId));
+            for (int32_t vibratorId : vibratorIds) {
+                tuples.emplace_back(i, vibratorId);
             }
         }
     }
 
-    auto vibratorAidlNames = android::getAidlHalInstanceNames(IVibrator::descriptor);
-    for (int i = 0; i < vibratorAidlNames.size(); i++) {
-        tuples.push_back(std::make_tuple(-1, i));
+    std::vector<std::string> vibratorNames = findUnmanagedVibratorNames();
+    for (int i = 0; i < vibratorNames.size(); i++) {
+        tuples.emplace_back(-1, i);
     }
 
     return tuples;
@@ -935,8 +1255,11 @@
                          PrintGeneratedTest);
 
 int main(int argc, char **argv) {
+    // Random values are used in the implementation.
+    std::srand(std::time(nullptr));
+
     ::testing::InitGoogleTest(&argc, argv);
-    ProcessState::self()->setThreadPoolMaxThreadCount(1);
-    ProcessState::self()->startThreadPool();
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
 }
diff --git a/vibrator/aidl/vts/persistable_bundle_utils.h b/vibrator/aidl/vts/persistable_bundle_utils.h
new file mode 100644
index 0000000..a765a49
--- /dev/null
+++ b/vibrator/aidl/vts/persistable_bundle_utils.h
@@ -0,0 +1,134 @@
+/*
+ * 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_PERSISTABLE_BUNDLE_UTILS_H
+#define VIBRATOR_HAL_PERSISTABLE_BUNDLE_UTILS_H
+
+#include <android/persistable_bundle_aidl.h>
+
+#include <cstdlib>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace testing {
+
+using aidl::android::os::PersistableBundle;
+
+namespace {
+
+template <typename T>
+T nextValue() {
+    return static_cast<T>(std::rand());
+}
+
+template <>
+std::string nextValue() {
+    std::string str;
+    uint8_t entryCount = nextValue<uint8_t>();
+    for (uint8_t i = 0; i < entryCount; i++) {
+        str.push_back(nextValue<char>());
+    }
+    return str;
+}
+
+template <typename T>
+T nextValue(T limit) {
+    assert(limit > 0);
+    return static_cast<T>(std::rand()) / (static_cast<T>(RAND_MAX / limit));
+}
+
+template <typename T>
+void fillVector(std::vector<T>* values) {
+    uint8_t entryCount = nextValue<uint8_t>();
+    for (uint8_t i = 0; i < entryCount; i++) {
+        values->push_back(nextValue<T>());
+    }
+}
+
+const std::vector<std::function<void(PersistableBundle*, const std::string&)>>
+        sPersistableBundleSetters = {[](PersistableBundle* bundle, const std::string& key) -> void {
+                                         bundle->putBoolean(key, nextValue<bool>());
+                                     },
+                                     [](PersistableBundle* bundle, const std::string& key) -> void {
+                                         bundle->putInt(key, nextValue<int32_t>());
+                                     },
+                                     [](PersistableBundle* bundle, const std::string& key) -> void {
+                                         bundle->putLong(key, nextValue<int64_t>());
+                                     },
+                                     [](PersistableBundle* bundle, const std::string& key) -> void {
+                                         bundle->putDouble(key, nextValue<double>());
+                                     },
+                                     [](PersistableBundle* bundle, const std::string& key) -> void {
+                                         bundle->putString(key, nextValue<std::string>());
+                                     },
+                                     [](PersistableBundle* bundle, const std::string& key) -> void {
+                                         std::vector<bool> value;
+                                         fillVector<bool>(&value);
+                                         bundle->putBooleanVector(key, value);
+                                     },
+                                     [](PersistableBundle* bundle, const std::string& key) -> void {
+                                         std::vector<int32_t> value;
+                                         fillVector<int32_t>(&value);
+                                         bundle->putIntVector(key, value);
+                                     },
+                                     [](PersistableBundle* bundle, const std::string& key) -> void {
+                                         std::vector<int64_t> value;
+                                         fillVector<int64_t>(&value);
+                                         bundle->putLongVector(key, value);
+                                     },
+                                     [](PersistableBundle* bundle, const std::string& key) -> void {
+                                         std::vector<double> value;
+                                         fillVector<double>(&value);
+                                         bundle->putDoubleVector(key, value);
+                                     },
+                                     [](PersistableBundle* bundle, const std::string& key) -> void {
+                                         std::vector<std::string> value;
+                                         fillVector<std::string>(&value);
+                                         bundle->putStringVector(key, value);
+                                     }};
+
+}  // namespace
+
+void fillBasicData(PersistableBundle* bundle) {
+    bundle->putBoolean("test_bool", true);
+    bundle->putInt("test_int", 2147483647);
+    bundle->putLong("test_long", 2147483647L);
+    bundle->putDouble("test_double", 1.23);
+    bundle->putString("test_string", "test data");
+    bundle->putBooleanVector("test_bool_vector", {true, false, false});
+    bundle->putIntVector("test_int_vector", {1, 2, 3, 4});
+    bundle->putLongVector("test_long_vector", {100L, 200L, 300L});
+    bundle->putDoubleVector("test_double_vector", {1.1, 2.2});
+    bundle->putStringVector("test_string_vector", {"test", "val"});
+}
+
+void fillRandomData(PersistableBundle* bundle) {
+    uint8_t entryCount = nextValue<uint8_t>();
+    for (uint8_t i = 0; i < entryCount; i++) {
+        std::string key(nextValue<std::string>());
+        uint8_t setterIdx = nextValue<uint8_t>(sPersistableBundleSetters.size() - 1);
+        sPersistableBundleSetters[setterIdx](bundle, key);
+    }
+}
+
+}  // namespace testing
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+
+#endif  // VIBRATOR_HAL_PERSISTABLE_BUNDLE_UTILS_H
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/vibrator/aidl/vts/test_utils.h b/vibrator/aidl/vts/test_utils.h
new file mode 100644
index 0000000..aaf3211
--- /dev/null
+++ b/vibrator/aidl/vts/test_utils.h
@@ -0,0 +1,60 @@
+/*
+ * 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_TEST_UTILS_H
+#define VIBRATOR_HAL_TEST_UTILS_H
+
+#include <android/binder_auto_utils.h>
+#include <gtest/gtest.h>
+
+#if !defined(EXPECT_OK)
+#define EXPECT_OK(expression)                                                \
+    GTEST_AMBIGUOUS_ELSE_BLOCKER_                                            \
+    if (const ::ndk::ScopedAStatus&& _status = (expression); _status.isOk()) \
+        ;                                                                    \
+    else                                                                     \
+        ADD_FAILURE() << "Expected STATUS_OK for: " << #expression << "\n  Actual: " << _status
+#else
+#error Macro EXPECT_OK already defined unexpectedly
+#endif
+
+#if !defined(EXPECT_UNKNOWN_OR_UNSUPPORTED)
+#define EXPECT_UNKNOWN_OR_UNSUPPORTED(expression)                                                \
+    GTEST_AMBIGUOUS_ELSE_BLOCKER_                                                                \
+    if (const ::ndk::ScopedAStatus&& _status = (expression);                                     \
+        _status.getExceptionCode() == EX_UNSUPPORTED_OPERATION ||                                \
+        _status.getStatus() == STATUS_UNKNOWN_TRANSACTION)                                       \
+        ;                                                                                        \
+    else                                                                                         \
+        ADD_FAILURE() << "Expected STATUS_UNKNOWN_TRANSACTION or EX_UNSUPPORTED_OPERATION for: " \
+                      << #expression << "\n  Actual: " << _status
+#else
+#error Macro EXPECT_UNKNOWN_OR_UNSUPPORTED already defined unexpectedly
+#endif
+
+#if !defined(EXPECT_ILLEGAL_ARGUMENT)
+#define EXPECT_ILLEGAL_ARGUMENT(expression)                                  \
+    GTEST_AMBIGUOUS_ELSE_BLOCKER_                                            \
+    if (const ::ndk::ScopedAStatus&& _status = (expression);                 \
+        _status.getExceptionCode() == EX_ILLEGAL_ARGUMENT)                   \
+        ;                                                                    \
+    else                                                                     \
+        ADD_FAILURE() << "Expected EX_ILLEGAL_ARGUMENT for: " << #expression \
+                      << "\n  Actual: " << _status
+#else
+#error Macro EXPECT_ILLEGAL_ARGUMENT already defined unexpectedly
+#endif
+
+#endif  // VIBRATOR_HAL_TEST_UTILS_H
diff --git a/vibrator/bench/Android.bp b/vibrator/bench/Android.bp
index 87bdab4..cd56516 100644
--- a/vibrator/bench/Android.bp
+++ b/vibrator/bench/Android.bp
@@ -30,12 +30,12 @@
         "benchmark.cpp",
     ],
     shared_libs: [
-        "android.hardware.vibrator-V2-cpp",
+        "android.hardware.vibrator-V3-ndk",
         "android.hardware.vibrator@1.0",
         "android.hardware.vibrator@1.1",
         "android.hardware.vibrator@1.2",
         "android.hardware.vibrator@1.3",
-        "libbinder",
+        "libbinder_ndk",
         "libhardware",
         "libhidlbase",
         "libutils",
diff --git a/vibrator/bench/benchmark.cpp b/vibrator/bench/benchmark.cpp
index deaa6f2..8fe9cf7 100644
--- a/vibrator/bench/benchmark.cpp
+++ b/vibrator/bench/benchmark.cpp
@@ -16,15 +16,14 @@
 
 #include "benchmark/benchmark.h"
 
+#include <aidl/android/hardware/vibrator/BnVibratorCallback.h>
+#include <aidl/android/hardware/vibrator/IVibrator.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
 #include <android/hardware/vibrator/1.3/IVibrator.h>
-#include <android/hardware/vibrator/BnVibratorCallback.h>
-#include <android/hardware/vibrator/IVibrator.h>
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
 #include <future>
 
-using ::android::enum_range;
-using ::android::sp;
 using ::android::hardware::hidl_enum_range;
 using ::android::hardware::Return;
 using ::android::hardware::details::hidl_enum_values;
@@ -33,10 +32,11 @@
 using ::benchmark::kMicrosecond;
 using ::benchmark::State;
 using ::benchmark::internal::Benchmark;
+using ::ndk::enum_range;
 
 using namespace ::std::chrono_literals;
 
-namespace Aidl = ::android::hardware::vibrator;
+namespace Aidl = ::aidl::android::hardware::vibrator;
 namespace V1_0 = ::android::hardware::vibrator::V1_0;
 namespace V1_1 = ::android::hardware::vibrator::V1_1;
 namespace V1_2 = ::android::hardware::vibrator::V1_2;
@@ -56,8 +56,8 @@
 class BaseBench : public Fixture {
   public:
     void SetUp(State& /*state*/) override {
-        android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
-        android::ProcessState::self()->startThreadPool();
+        ABinderProcess_setThreadPoolMaxThreadCount(1);
+        ABinderProcess_startThreadPool();
     }
 
     void TearDown(State& /*state*/) override {
@@ -75,7 +75,7 @@
     auto getOtherArg(const State& state, std::size_t index) const { return state.range(index + 0); }
 
   protected:
-    sp<I> mVibrator;
+    std::shared_ptr<I> mVibrator;
 };
 
 template <typename I>
@@ -83,7 +83,12 @@
   public:
     void SetUp(State& state) override {
         BaseBench<I>::SetUp(state);
-        this->mVibrator = I::getService();
+        auto service = I::getService();
+        if (service) {
+            this->mVibrator = std::shared_ptr<I>(service.release());
+        } else {
+            this->mVibrator = nullptr;
+        }
     }
 
   protected:
@@ -356,7 +361,9 @@
   public:
     void SetUp(State& state) override {
         BaseBench::SetUp(state);
-        this->mVibrator = android::waitForVintfService<Aidl::IVibrator>();
+        auto serviceName = std::string(Aidl::IVibrator::descriptor) + "/default";
+        this->mVibrator = Aidl::IVibrator::fromBinder(
+                ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str())));
     }
 
     void TearDown(State& state) override {
@@ -373,14 +380,24 @@
         return (deviceCapabilities & capabilities) == capabilities;
     }
 
-    bool shouldSkipWithError(State& state, const android::binder::Status&& status) {
+    bool shouldSkipWithError(State& state, const ndk::ScopedAStatus&& status) {
         if (!status.isOk()) {
-            state.SkipWithError(status.toString8().c_str());
+            state.SkipWithError(status.getMessage());
             return true;
         }
         return false;
     }
 
+    void waitForComplete(std::future<void>& callbackFuture) {
+        // Wait until the HAL has finished processing previous vibration before starting a new one,
+        // so the HAL state is consistent on each run and metrics are less noisy. Some of the newest
+        // HAL implementations are waiting on previous vibration cleanup and might be significantly
+        // slower, so make sure we measure vibrations on a clean slate.
+        if (callbackFuture.valid()) {
+            callbackFuture.wait_for(VIBRATION_CALLBACK_TIMEOUT);
+        }
+    }
+
     static void SlowBenchConfig(Benchmark* b) { b->Iterations(VIBRATION_ITERATIONS); }
 };
 
@@ -397,18 +414,12 @@
     HalCallback() = default;
     ~HalCallback() = default;
 
-    android::binder::Status onComplete() override {
+    ndk::ScopedAStatus onComplete() override {
         mPromise.set_value();
-        return android::binder::Status::ok();
+        return ndk::ScopedAStatus::ok();
     }
 
-    void waitForComplete() {
-        // Wait until the HAL has finished processing previous vibration before starting a new one,
-        // so the HAL state is consistent on each run and metrics are less noisy. Some of the newest
-        // HAL implementations are waiting on previous vibration cleanup and might be significantly
-        // slower, so make sure we measure vibrations on a clean slate.
-        mPromise.get_future().wait_for(VIBRATION_CALLBACK_TIMEOUT);
-    }
+    std::future<void> getFuture() { return mPromise.get_future(); }
 
   private:
     std::promise<void> mPromise;
@@ -418,7 +429,11 @@
     auto ms = MAX_ON_DURATION_MS;
 
     for (auto _ : state) {
-        auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK) ? new HalCallback() : nullptr;
+        auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK)
+                          ? ndk::SharedRefBase::make<HalCallback>()
+                          : nullptr;
+        // Grab the future before callback promise is destroyed by the HAL.
+        auto cbFuture = cb ? cb->getFuture() : std::future<void>();
 
         // Test
         if (shouldSkipWithError(state, mVibrator->on(ms, cb))) {
@@ -430,9 +445,7 @@
         if (shouldSkipWithError(state, mVibrator->off())) {
             return;
         }
-        if (cb) {
-            cb->waitForComplete();
-        }
+        waitForComplete(cbFuture);
         state.ResumeTiming();
     }
 });
@@ -441,7 +454,11 @@
     auto ms = MAX_ON_DURATION_MS;
 
     for (auto _ : state) {
-        auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK) ? new HalCallback() : nullptr;
+        auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK)
+                          ? ndk::SharedRefBase::make<HalCallback>()
+                          : nullptr;
+        // Grab the future before callback promise is destroyed by the HAL.
+        auto cbFuture = cb ? cb->getFuture() : std::future<void>();
 
         // Setup
         state.PauseTiming();
@@ -457,9 +474,7 @@
 
         // Cleanup
         state.PauseTiming();
-        if (cb) {
-            cb->waitForComplete();
-        }
+        waitForComplete(cbFuture);
         state.ResumeTiming();
     }
 });
@@ -483,7 +498,9 @@
         return;
     }
 
-    auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK) ? new HalCallback() : nullptr;
+    auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK)
+                      ? ndk::SharedRefBase::make<HalCallback>()
+                      : nullptr;
     if (shouldSkipWithError(state, mVibrator->on(ms, cb))) {
         return;
     }
@@ -685,8 +702,11 @@
     int32_t lengthMs = 0;
 
     for (auto _ : state) {
-        auto cb = hasCapabilities(Aidl::IVibrator::CAP_PERFORM_CALLBACK) ? new HalCallback()
-                                                                         : nullptr;
+        auto cb = hasCapabilities(Aidl::IVibrator::CAP_PERFORM_CALLBACK)
+                          ? ndk::SharedRefBase::make<HalCallback>()
+                          : nullptr;
+        // Grab the future before callback promise is destroyed by the HAL.
+        auto cbFuture = cb ? cb->getFuture() : std::future<void>();
 
         // Test
         if (shouldSkipWithError(state, mVibrator->perform(effect, strength, cb, &lengthMs))) {
@@ -698,9 +718,7 @@
         if (shouldSkipWithError(state, mVibrator->off())) {
             return;
         }
-        if (cb) {
-            cb->waitForComplete();
-        }
+        waitForComplete(cbFuture);
         state.ResumeTiming();
     }
 });
@@ -799,7 +817,9 @@
     effects.push_back(effect);
 
     for (auto _ : state) {
-        auto cb = new HalCallback();
+        auto cb = ndk::SharedRefBase::make<HalCallback>();
+        // Grab the future before callback promise is moved and destroyed by the HAL.
+        auto cbFuture = cb->getFuture();
 
         // Test
         if (shouldSkipWithError(state, mVibrator->compose(effects, cb))) {
@@ -811,7 +831,7 @@
         if (shouldSkipWithError(state, mVibrator->off())) {
             return;
         }
-        cb->waitForComplete();
+        waitForComplete(cbFuture);
         state.ResumeTiming();
     }
 });
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 362ef1b..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 {
@@ -218,3 +224,8 @@
     name: "default-android.hardware.wifi-service.xml",
     srcs: ["android.hardware.wifi-service.xml"],
 }
+
+filegroup {
+    name: "default-android.hardware.wifi-service-lazy.rc",
+    srcs: ["android.hardware.wifi-service-lazy.rc"],
+}
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/aidl/default/wifi_chip.cpp b/wifi/aidl/default/wifi_chip.cpp
index 9b9c565..fccfc15 100644
--- a/wifi/aidl/default/wifi_chip.cpp
+++ b/wifi/aidl/default/wifi_chip.cpp
@@ -62,7 +62,9 @@
 std::vector<std::string> getNames(std::vector<std::shared_ptr<Iface>>& ifaces) {
     std::vector<std::string> names;
     for (const auto& iface : ifaces) {
-        names.emplace_back(iface->getName());
+        if (iface) {
+            names.emplace_back(iface->getName());
+        }
     }
     return names;
 }
@@ -971,6 +973,10 @@
     }
     std::shared_ptr<WifiNanIface> iface =
             WifiNanIface::create(ifname, is_dedicated_iface, legacy_hal_, iface_util_);
+    if (!iface) {
+        LOG(ERROR) << "Unable to create NAN iface";
+        return {nullptr, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
+    }
     nan_ifaces_.push_back(iface);
     for (const auto& callback : event_cb_handler_.getCallbacks()) {
         if (!callback->onIfaceAdded(IfaceType::NAN_IFACE, ifname).isOk()) {
diff --git a/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp b/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp
index 21d50ac..c68d8fd 100644
--- a/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp
+++ b/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp
@@ -177,8 +177,7 @@
     return iface;
 }
 
-std::shared_ptr<IWifiApIface> getWifiApIface(const char* instance_name) {
-    std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(instance_name);
+std::shared_ptr<IWifiApIface> getWifiApIface(std::shared_ptr<IWifiChip> wifi_chip) {
     if (!wifi_chip.get()) {
         return nullptr;
     }
@@ -193,6 +192,11 @@
     return iface;
 }
 
+std::shared_ptr<IWifiApIface> getWifiApIface(const char* instance_name) {
+    std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(instance_name);
+    return getWifiApIface(wifi_chip);
+}
+
 std::shared_ptr<IWifiApIface> getBridgedWifiApIface(std::shared_ptr<IWifiChip> wifi_chip) {
     if (!wifi_chip.get()) {
         return nullptr;
diff --git a/wifi/aidl/vts/functional/wifi_aidl_test_utils.h b/wifi/aidl/vts/functional/wifi_aidl_test_utils.h
index 1369dd4..9b47a9f 100644
--- a/wifi/aidl/vts/functional/wifi_aidl_test_utils.h
+++ b/wifi/aidl/vts/functional/wifi_aidl_test_utils.h
@@ -40,6 +40,7 @@
 std::shared_ptr<IWifiStaIface> getWifiStaIface(const char* instance_name);
 std::shared_ptr<IWifiNanIface> getWifiNanIface(const char* instance_name);
 std::shared_ptr<IWifiApIface> getWifiApIface(const char* instance_name);
+std::shared_ptr<IWifiApIface> getWifiApIface(std::shared_ptr<IWifiChip> wifi_chip);
 std::shared_ptr<IWifiApIface> getBridgedWifiApIface(const char* instance_name);
 std::shared_ptr<IWifiApIface> getBridgedWifiApIface(std::shared_ptr<IWifiChip> wifi_chip);
 // Configure the chip in a mode to support the creation of the provided iface type.
diff --git a/wifi/aidl/vts/functional/wifi_ap_iface_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_ap_iface_aidl_test.cpp
index d39cfb4..a58fd5b 100644
--- a/wifi/aidl/vts/functional/wifi_ap_iface_aidl_test.cpp
+++ b/wifi/aidl/vts/functional/wifi_ap_iface_aidl_test.cpp
@@ -37,12 +37,21 @@
                 "/system/bin/cmd wifi get-softap-supported-features",
                 "wifi_softap_bridged_ap_supported");
         stopWifiService(getInstanceName());
+
+        wifi_chip_ = getWifiChip(getInstanceName());
+        ASSERT_NE(nullptr, wifi_chip_.get());
+
+        bool isApSupported = doesChipSupportConcurrencyType(wifi_chip_, IfaceConcurrencyType::AP);
+        if (!isApSupported) {
+            GTEST_SKIP() << "AP interfaces are not supported";
+        }
     }
 
     void TearDown() override { stopWifiService(getInstanceName()); }
 
   protected:
     bool isBridgedSupport_ = false;
+    std::shared_ptr<IWifiChip> wifi_chip_;
     const char* getInstanceName() { return GetParam().c_str(); }
 };
 
@@ -50,7 +59,7 @@
  * SetMacAddress
  */
 TEST_P(WifiApIfaceAidlTest, SetMacAddress) {
-    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(getInstanceName());
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(wifi_chip_);
     ASSERT_NE(nullptr, wifi_ap_iface.get());
     std::array<uint8_t, 6> mac = {0x12, 0x22, 0x33, 0x52, 0x10, 0x44};
     EXPECT_TRUE(wifi_ap_iface->setMacAddress(mac).isOk());
@@ -60,7 +69,7 @@
  * SetCountryCode
  */
 TEST_P(WifiApIfaceAidlTest, SetCountryCode) {
-    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(getInstanceName());
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(wifi_chip_);
     ASSERT_NE(nullptr, wifi_ap_iface.get());
 
     const std::array<uint8_t, 2> country_code = {0x55, 0x53};
@@ -71,7 +80,7 @@
  * GetFactoryMacAddress
  */
 TEST_P(WifiApIfaceAidlTest, GetFactoryMacAddress) {
-    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(getInstanceName());
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(wifi_chip_);
     ASSERT_NE(nullptr, wifi_ap_iface.get());
 
     std::array<uint8_t, 6> mac;
@@ -84,7 +93,7 @@
  * GetBridgedInstances - non-bridged mode
  */
 TEST_P(WifiApIfaceAidlTest, GetBridgedInstances) {
-    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(getInstanceName());
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(wifi_chip_);
     ASSERT_NE(nullptr, wifi_ap_iface.get());
 
     std::vector<std::string> instances;
@@ -99,7 +108,7 @@
     if (!isBridgedSupport_) {
         GTEST_SKIP() << "Missing Bridged AP support";
     }
-    std::shared_ptr<IWifiApIface> wifi_ap_iface = getBridgedWifiApIface(getInstanceName());
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getBridgedWifiApIface(wifi_chip_);
     ASSERT_NE(nullptr, wifi_ap_iface.get());
 
     std::vector<std::string> instances;
@@ -111,7 +120,7 @@
  * ResetToFactoryMacAddress - non-bridged mode
  */
 TEST_P(WifiApIfaceAidlTest, ResetToFactoryMacAddress) {
-    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(getInstanceName());
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(wifi_chip_);
     ASSERT_NE(nullptr, wifi_ap_iface.get());
     EXPECT_TRUE(wifi_ap_iface->resetToFactoryMacAddress().isOk());
 }
@@ -123,7 +132,7 @@
     if (!isBridgedSupport_) {
         GTEST_SKIP() << "Missing Bridged AP support";
     }
-    std::shared_ptr<IWifiApIface> wifi_ap_iface = getBridgedWifiApIface(getInstanceName());
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getBridgedWifiApIface(wifi_chip_);
     ASSERT_NE(nullptr, wifi_ap_iface.get());
     EXPECT_TRUE(wifi_ap_iface->resetToFactoryMacAddress().isOk());
 }
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];
 
diff --git a/wifi/netlinkinterceptor/aidl/default/Android.bp b/wifi/netlinkinterceptor/aidl/default/Android.bp
index 6bdd9fc..52f15e4 100644
--- a/wifi/netlinkinterceptor/aidl/default/Android.bp
+++ b/wifi/netlinkinterceptor/aidl/default/Android.bp
@@ -76,3 +76,13 @@
     sub_dir: "vintf",
     installable: false,
 }
+
+filegroup {
+    name: "android.hardware.net.nlinterceptor-service.rc",
+    srcs: ["nlinterceptor.rc"],
+}
+
+filegroup {
+    name: "android.hardware.net.nlinterceptor.xml",
+    srcs: ["nlinterceptor.xml"],
+}
diff --git a/wifi/supplicant/1.1/vts/Android.mk b/wifi/supplicant/1.1/vts/Android.mk
deleted file mode 100644
index 6361f9b..0000000
--- a/wifi/supplicant/1.1/vts/Android.mk
+++ /dev/null
@@ -1,2 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/wifi/supplicant/aidl/Android.bp b/wifi/supplicant/aidl/Android.bp
index b7242ed..8d16cb7 100644
--- a/wifi/supplicant/aidl/Android.bp
+++ b/wifi/supplicant/aidl/Android.bp
@@ -71,5 +71,5 @@
         },
 
     ],
-    frozen: true,
+    frozen: false,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl
index 330f2aa..6bae4cf 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl
@@ -41,4 +41,5 @@
   TRUST_ON_FIRST_USE = (1 << 4) /* 16 */,
   SET_TLS_MINIMUM_VERSION = (1 << 5) /* 32 */,
   TLS_V1_3 = (1 << 6) /* 64 */,
+  RSN_OVERRIDING = (1 << 7) /* 128 */,
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl
index a9434c4..b6e57c6 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl
@@ -50,4 +50,8 @@
      * TLS V1.3
      */
     TLS_V1_3 = 1 << 6,
+    /**
+     * RSN Overriding
+     */
+    RSN_OVERRIDING = 1 << 7,
 }
diff --git a/wifi/supplicant/aidl/vts/functional/Android.bp b/wifi/supplicant/aidl/vts/functional/Android.bp
index 4166850..4ffec3f 100644
--- a/wifi/supplicant/aidl/vts/functional/Android.bp
+++ b/wifi/supplicant/aidl/vts/functional/Android.bp
@@ -46,7 +46,7 @@
         "android.hardware.wifi.common-V1-ndk",
         "android.hardware.wifi.supplicant@1.0",
         "android.hardware.wifi.supplicant@1.1",
-        "android.hardware.wifi.supplicant-V3-ndk",
+        "android.hardware.wifi.supplicant-V4-ndk",
         "libwifi-system",
         "libwifi-system-iface",
         "VtsHalWifiV1_0TargetTestUtil",
@@ -84,7 +84,7 @@
         "android.hardware.wifi.common-V1-ndk",
         "android.hardware.wifi.supplicant@1.0",
         "android.hardware.wifi.supplicant@1.1",
-        "android.hardware.wifi.supplicant-V3-ndk",
+        "android.hardware.wifi.supplicant-V4-ndk",
         "libwifi-system",
         "libwifi-system-iface",
         "VtsHalWifiV1_0TargetTestUtil",
@@ -122,7 +122,7 @@
         "android.hardware.wifi.common-V1-ndk",
         "android.hardware.wifi.supplicant@1.0",
         "android.hardware.wifi.supplicant@1.1",
-        "android.hardware.wifi.supplicant-V3-ndk",
+        "android.hardware.wifi.supplicant-V4-ndk",
         "libwifi-system",
         "libwifi-system-iface",
         "VtsHalWifiV1_0TargetTestUtil",