Merge "health: Remove 2.0 HAL implementation." into main
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 25246d8..92cafbd 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -11,6 +11,9 @@
     },
     {
       "name": "VtsHalTvInputV1_0TargetTest"
+    },
+    {
+      "name": "CtsStrictJavaPackagesTestCases"
     }
   ],
   "auto-presubmit": [
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index 5a009fe..89d186c 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -34,6 +34,7 @@
     name: "android.hardware.audio.common",
     defaults: [
         "android.hardware.audio_defaults",
+        "latest_android_media_audio_common_types_import_interface",
     ],
     srcs: [
         "android/hardware/audio/common/AudioOffloadMetadata.aidl",
@@ -42,10 +43,7 @@
         "android/hardware/audio/common/SinkMetadata.aidl",
         "android/hardware/audio/common/SourceMetadata.aidl",
     ],
-    frozen: true,
-    imports: [
-        "android.media.audio.common.types-V2",
-    ],
+    frozen: false,
     backend: {
         cpp: {
             enabled: true,
@@ -83,7 +81,7 @@
 }
 
 // Note: This should always be one version ahead of the last frozen version
-latest_android_hardware_audio_common = "android.hardware.audio.common-V2"
+latest_android_hardware_audio_common = "android.hardware.audio.common-V3"
 
 // Modules that depend on android.hardware.audio.common directly can include
 // the following cc_defaults to avoid explicitly managing dependency versions
@@ -109,10 +107,21 @@
     ],
 }
 
+aidl_interface_defaults {
+    name: "latest_android_hardware_audio_common_import_interface",
+    imports: [
+        latest_android_hardware_audio_common,
+    ],
+}
+
 aidl_interface {
     name: "android.hardware.audio.core",
     defaults: [
         "android.hardware.audio_defaults",
+        "latest_android_hardware_audio_common_import_interface",
+        "latest_android_hardware_audio_core_sounddose_import_interface",
+        "latest_android_hardware_audio_effect_import_interface",
+        "latest_android_media_audio_common_types_import_interface",
     ],
     srcs: [
         "android/hardware/audio/core/AudioPatch.aidl",
@@ -137,10 +146,6 @@
     imports: [
         "android.hardware.common-V2",
         "android.hardware.common.fmq-V1",
-        "android.hardware.audio.common-V2",
-        "android.hardware.audio.core.sounddose-V1",
-        "android.hardware.audio.effect-V1",
-        "android.media.audio.common.types-V2",
     ],
     backend: {
         // The C++ backend is disabled transitively due to use of FMQ.
@@ -167,11 +172,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-V1"
+latest_android_hardware_audio_core = "android.hardware.audio.core-V2"
 
 // Modules that depend on android.hardware.audio.core directly can include
 // the following cc_defaults to avoid explicitly managing dependency versions
@@ -190,18 +195,23 @@
     ],
 }
 
+aidl_interface_defaults {
+    name: "latest_android_hardware_audio_core_import_interface",
+    imports: [
+        latest_android_hardware_audio_core,
+    ],
+}
+
 // Used for the standalone sounddose HAL
 aidl_interface {
     name: "android.hardware.audio.core.sounddose",
     defaults: [
         "android.hardware.audio_defaults",
+        "latest_android_media_audio_common_types_import_interface",
     ],
     srcs: [
         "android/hardware/audio/core/sounddose/ISoundDose.aidl",
     ],
-    imports: [
-        "android.media.audio.common.types-V2",
-    ],
     backend: {
         // The C++ backend is disabled transitively due to use of FMQ by the core HAL.
         cpp: {
@@ -220,11 +230,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-V1"
+latest_android_hardware_audio_core_sounddose = "android.hardware.audio.core.sounddose-V2"
 
 // Modules that depend on android.hardware.audio.core.sounddose directly can include
 // the following cc_defaults to avoid explicitly managing dependency versions
@@ -237,16 +247,32 @@
 }
 
 cc_defaults {
+    name: "latest_android_hardware_audio_core_sounddose_ndk_export_shared_lib_header",
+    export_shared_lib_headers: [
+        latest_android_hardware_audio_core_sounddose + "-ndk",
+    ],
+}
+
+cc_defaults {
     name: "latest_android_hardware_audio_core_sounddose_ndk_static",
     static_libs: [
         latest_android_hardware_audio_core_sounddose + "-ndk",
     ],
 }
 
+aidl_interface_defaults {
+    name: "latest_android_hardware_audio_core_sounddose_import_interface",
+    imports: [
+        latest_android_hardware_audio_core_sounddose,
+    ],
+}
+
 aidl_interface {
     name: "android.hardware.audio.effect",
     defaults: [
         "android.hardware.audio_defaults",
+        "latest_android_hardware_audio_common_import_interface",
+        "latest_android_media_audio_common_types_import_interface",
     ],
     srcs: [
         "android/hardware/audio/effect/AcousticEchoCanceler.aidl",
@@ -271,6 +297,7 @@
         "android/hardware/audio/effect/PresetReverb.aidl",
         "android/hardware/audio/effect/Processing.aidl",
         "android/hardware/audio/effect/Range.aidl",
+        "android/hardware/audio/effect/Spatializer.aidl",
         "android/hardware/audio/effect/State.aidl",
         "android/hardware/audio/effect/VendorExtension.aidl",
         "android/hardware/audio/effect/Virtualizer.aidl",
@@ -280,8 +307,6 @@
     imports: [
         "android.hardware.common-V2",
         "android.hardware.common.fmq-V1",
-        "android.hardware.audio.common-V2",
-        "android.media.audio.common.types-V2",
     ],
     backend: {
         // The C++ backend is disabled transitively due to use of FMQ.
@@ -303,11 +328,11 @@
             ],
         },
     ],
-    frozen: true,
+    frozen: false,
 
 }
 
-latest_android_hardware_audio_effect = "android.hardware.audio.effect-V1"
+latest_android_hardware_audio_effect = "android.hardware.audio.effect-V2"
 
 cc_defaults {
     name: "latest_android_hardware_audio_effect_ndk_shared",
@@ -322,3 +347,10 @@
         latest_android_hardware_audio_effect + "-ndk",
     ],
 }
+
+aidl_interface_defaults {
+    name: "latest_android_hardware_audio_effect_import_interface",
+    imports: [
+        latest_android_hardware_audio_effect,
+    ],
+}
diff --git a/audio/aidl/TEST_MAPPING b/audio/aidl/TEST_MAPPING
index 81c99f7..2b6207e 100644
--- a/audio/aidl/TEST_MAPPING
+++ b/audio/aidl/TEST_MAPPING
@@ -51,5 +51,10 @@
     {
       "name": "VtsHalNSTargetTest"
     }
+  ],
+  "postsubmit": [
+    {
+      "name": "VtsHalSpatializerTargetTest"
+    }
   ]
 }
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
index e14e9c0..07a85f8 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
@@ -74,6 +74,7 @@
   boolean supportsVariableLatency();
   int getAAudioMixerBurstCount();
   int getAAudioHardwareBurstMinUsec();
+  void prepareToDisconnectExternalDevice(int portId);
   const int DEFAULT_AAUDIO_MIXER_BURST_COUNT = 2;
   const int DEFAULT_AAUDIO_HARDWARE_BURST_MIN_DURATION_US = 1000;
   @VintfStability
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Flags.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Flags.aidl
index bcbf870..046c220 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Flags.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Flags.aidl
@@ -43,6 +43,8 @@
   boolean audioModeIndication;
   boolean audioSourceIndication;
   boolean bypass;
+  boolean sinkMetadataIndication;
+  boolean sourceMetadataIndication;
   @Backing(type="byte") @VintfStability
   enum Type {
     INSERT = 0,
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl
index 0422bd9..ff33c42 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl
@@ -41,6 +41,8 @@
   boolean offload;
   android.hardware.audio.effect.Parameter.VolumeStereo volumeStereo;
   android.hardware.audio.effect.Parameter.Specific specific;
+  android.hardware.audio.common.SinkMetadata sinkMetadata;
+  android.hardware.audio.common.SourceMetadata sourceMetadata;
   @VintfStability
   union Id {
     android.hardware.audio.effect.VendorExtension vendorEffectTag;
@@ -60,6 +62,7 @@
     android.hardware.audio.effect.Visualizer.Id visualizerTag;
     android.hardware.audio.effect.Volume.Id volumeTag;
     android.hardware.audio.effect.Parameter.Tag commonTag;
+    android.hardware.audio.effect.Spatializer.Id spatializerTag;
   }
   @VintfStability
   parcelable Common {
@@ -91,5 +94,6 @@
     android.hardware.audio.effect.Virtualizer virtualizer;
     android.hardware.audio.effect.Visualizer visualizer;
     android.hardware.audio.effect.Volume volume;
+    android.hardware.audio.effect.Spatializer spatializer;
   }
 }
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Range.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Range.aidl
index 93edc5e..40ee6b5 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Range.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Range.aidl
@@ -50,6 +50,7 @@
   android.hardware.audio.effect.Range.VirtualizerRange[] virtualizer;
   android.hardware.audio.effect.Range.VisualizerRange[] visualizer;
   android.hardware.audio.effect.Range.VolumeRange[] volume;
+  android.hardware.audio.effect.Range.SpatializerRange[] spatializer;
   @VintfStability
   parcelable AcousticEchoCancelerRange {
     android.hardware.audio.effect.AcousticEchoCanceler min;
@@ -111,6 +112,11 @@
     android.hardware.audio.effect.PresetReverb max;
   }
   @VintfStability
+  parcelable SpatializerRange {
+    android.hardware.audio.effect.Spatializer min;
+    android.hardware.audio.effect.Spatializer max;
+  }
+  @VintfStability
   parcelable VendorExtensionRange {
     android.hardware.audio.effect.VendorExtension min;
     android.hardware.audio.effect.VendorExtension max;
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Spatializer.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Spatializer.aidl
new file mode 100644
index 0000000..98ecee0
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Spatializer.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.audio.effect;
+@VintfStability
+union Spatializer {
+  android.hardware.audio.effect.VendorExtension vendor;
+  android.media.audio.common.AudioChannelLayout[] supportedChannelLayout;
+  android.media.audio.common.Spatialization.Level spatializationLevel;
+  android.media.audio.common.Spatialization.Mode spatializationMode;
+  int headTrackingSensorId;
+  android.media.audio.common.HeadTracking.Mode headTrackingMode;
+  android.media.audio.common.HeadTracking.ConnectionMode headTrackingConnectionMode;
+  android.media.audio.common.HeadTracking.SensorData headTrackingSensorData;
+  @VintfStability
+  union Id {
+    android.hardware.audio.effect.VendorExtension vendorExtensionTag;
+    android.hardware.audio.effect.Spatializer.Tag commonTag;
+  }
+}
diff --git a/audio/aidl/android/hardware/audio/core/IModule.aidl b/audio/aidl/android/hardware/audio/core/IModule.aidl
index e736c32..3c5f7f6 100644
--- a/audio/aidl/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/android/hardware/audio/core/IModule.aidl
@@ -206,8 +206,10 @@
      * after successful connection of an external device.
      *
      * Handling of a disconnect is done in a reverse order:
-     *  1. Reset port configuration using the 'resetAudioPortConfig' method.
-     *  2. Release the connected device port by calling the 'disconnectExternalDevice'
+     *  1. Notify the HAL module to prepare for device disconnection using
+     *     'prepareToDisconnectExternalDevice' method.
+     *  2. Reset port configuration using the 'resetAudioPortConfig' method.
+     *  3. Release the connected device port by calling the 'disconnectExternalDevice'
      *     method. This also removes the audio routes associated with this
      *     device port.
      *
@@ -234,11 +236,15 @@
      * instance previously instantiated using the 'connectExternalDevice'
      * method.
      *
-     * The framework will call this method before closing streams and resetting
-     * patches. This call can be used by the HAL module to prepare itself to
-     * device disconnection. If the HAL module indicates an error after the first
-     * call, the framework will call this method once again after closing associated
-     * streams and patches.
+     * On AIDL HAL v1, the framework will call this method before closing streams
+     * and resetting patches. This call can be used by the HAL module to prepare
+     * itself to device disconnection. If the HAL module indicates an error after
+     * the first call, the framework will call this method once again after closing
+     * associated streams and patches.
+     *
+     * On AIDL HAL v2 and later, the framework will call 'prepareToDisconnectExternalDevice'
+     * method to notify the HAL module to prepare itself for device disconnection. The
+     * framework will only call this method after closing associated streams and patches.
      *
      * @throws EX_ILLEGAL_ARGUMENT In the following cases:
      *                             - If the port can not be found by the ID.
@@ -912,4 +918,23 @@
      * @throw EX_UNSUPPORTED_OPERATION If the module does not support aaudio MMAP.
      */
     int getAAudioHardwareBurstMinUsec();
+
+    /**
+     * Notify the HAL module to prepare for disconnecting an external device.
+     *
+     * This method is used to inform the HAL module that 'disconnectExternalDevice' will be
+     * called soon. The HAL module can rely on this method to abort active data operations
+     * early. The 'portId' must be of a connected device Port instance previously instantiated
+     * using 'connectExternalDevice' method. 'disconnectExternalDevice' method will be called
+     * soon after this method with the same 'portId'.
+     *
+     * Note: This method is called after the external device is disconnected. The system does
+     * not try to predict the disconnection event.
+     *
+     * @param portId The ID of the audio port corresponding to the disconnected device
+     * @throws EX_ILLEGAL_ARGUMENT In the following cases:
+     *                             - If the port can not be found by the ID.
+     *                             - If this is not a connected device port.
+     */
+    void prepareToDisconnectExternalDevice(int portId);
 }
diff --git a/audio/aidl/android/hardware/audio/effect/Flags.aidl b/audio/aidl/android/hardware/audio/effect/Flags.aidl
index 28685c3..70668a3 100644
--- a/audio/aidl/android/hardware/audio/effect/Flags.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Flags.aidl
@@ -144,4 +144,18 @@
      * Set to true if the effect instance bypass audio data (no processing).
      */
     boolean bypass;
+
+    /**
+     * Effect instance sets this flag to true if it requires record AudioTrack metadata update. In
+     * this case the framework must call IEffect.setParameter to notify effect instance when there
+     * is a change in sinkMetadata.
+     */
+    boolean sinkMetadataIndication;
+
+    /**
+     * Effect instance sets this flag to true if it requires playback AudioTrack metadata update. In
+     * this case the framework must call IEffect.setParameter to notify effect instance when there
+     * is a change in sourceMetadata.
+     */
+    boolean sourceMetadataIndication;
 }
diff --git a/audio/aidl/android/hardware/audio/effect/Parameter.aidl b/audio/aidl/android/hardware/audio/effect/Parameter.aidl
index 0954055..6fd9161 100644
--- a/audio/aidl/android/hardware/audio/effect/Parameter.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Parameter.aidl
@@ -16,6 +16,8 @@
 
 package android.hardware.audio.effect;
 
+import android.hardware.audio.common.SinkMetadata;
+import android.hardware.audio.common.SourceMetadata;
 import android.hardware.audio.effect.AcousticEchoCanceler;
 import android.hardware.audio.effect.AutomaticGainControlV1;
 import android.hardware.audio.effect.AutomaticGainControlV2;
@@ -28,6 +30,7 @@
 import android.hardware.audio.effect.LoudnessEnhancer;
 import android.hardware.audio.effect.NoiseSuppression;
 import android.hardware.audio.effect.PresetReverb;
+import android.hardware.audio.effect.Spatializer;
 import android.hardware.audio.effect.VendorExtension;
 import android.hardware.audio.effect.Virtualizer;
 import android.hardware.audio.effect.Visualizer;
@@ -103,6 +106,11 @@
          * directly.
          */
         Parameter.Tag commonTag;
+
+        /**
+         * Parameter tag defined for Spatializer parameters.
+         */
+        Spatializer.Id spatializerTag;
     }
 
     /**
@@ -189,6 +197,23 @@
         Virtualizer virtualizer;
         Visualizer visualizer;
         Volume volume;
+        Spatializer spatializer;
     }
     Specific specific;
+
+    /**
+     * SinkMetadata defines the metadata of record AudioTracks which the effect instance associate
+     * with.
+     * The effect engine is required to set Flags.sinkMetadataIndication to true if it wants to
+     * receive sinkMetadata update from the audio framework.
+     */
+    SinkMetadata sinkMetadata;
+
+    /**
+     * SourceMetadata defines the metadata of playback AudioTracks which the effect instance
+     * associate with.
+     * The effect engine is required to set Flags.sourceMetadataIndication to true if it wants to
+     * receive sourceMetadata update from the audio framework.
+     */
+    SourceMetadata sourceMetadata;
 }
diff --git a/audio/aidl/android/hardware/audio/effect/Range.aidl b/audio/aidl/android/hardware/audio/effect/Range.aidl
index 567320a..e5acb68 100644
--- a/audio/aidl/android/hardware/audio/effect/Range.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Range.aidl
@@ -28,6 +28,7 @@
 import android.hardware.audio.effect.LoudnessEnhancer;
 import android.hardware.audio.effect.NoiseSuppression;
 import android.hardware.audio.effect.PresetReverb;
+import android.hardware.audio.effect.Spatializer;
 import android.hardware.audio.effect.VendorExtension;
 import android.hardware.audio.effect.Virtualizer;
 import android.hardware.audio.effect.Visualizer;
@@ -169,6 +170,12 @@
     }
 
     @VintfStability
+    parcelable SpatializerRange {
+        Spatializer min;
+        Spatializer max;
+    }
+
+    @VintfStability
     parcelable VendorExtensionRange {
         VendorExtension min;
         VendorExtension max;
@@ -217,4 +224,5 @@
     VirtualizerRange[] virtualizer;
     VisualizerRange[] visualizer;
     VolumeRange[] volume;
+    SpatializerRange[] spatializer;
 }
diff --git a/audio/aidl/android/hardware/audio/effect/Spatializer.aidl b/audio/aidl/android/hardware/audio/effect/Spatializer.aidl
new file mode 100644
index 0000000..71e3ffe
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Spatializer.aidl
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.VendorExtension;
+import android.media.audio.common.AudioChannelLayout;
+import android.media.audio.common.HeadTracking;
+import android.media.audio.common.Spatialization;
+
+/**
+ * Union representing parameters for audio spatialization effects.
+ *
+ * Sound spatialization simulates sounds around the listener as if they were emanating from virtual
+ * positions based on the original recording.
+ * For more details, refer to the documentation:
+ * https://developer.android.com/reference/android/media/Spatializer.
+ *
+ * android.hardware.audio.effect.Spatializer specifies parameters for the implementation of audio
+ * spatialization effects.
+ *
+ * A Spatializer implementation must report its supported parameter ranges using Capability.Range.
+ * spatializer.
+ */
+@VintfStability
+union Spatializer {
+    /**
+     * Parameter tag to identify the parameters for getParameter().
+     */
+    @VintfStability
+    union Id {
+        VendorExtension vendorExtensionTag;
+        Spatializer.Tag commonTag;
+    }
+
+    /**
+     * Vendor extension implementation for additional parameters.
+     */
+    VendorExtension vendor;
+
+    /**
+     * List of supported input channel layouts.
+     */
+    AudioChannelLayout[] supportedChannelLayout;
+
+    /**
+     * Level of spatialization.
+     */
+    Spatialization.Level spatializationLevel;
+
+    /**
+     * Spatialization mode, Binaural or Transaural for example.
+     */
+    Spatialization.Mode spatializationMode;
+
+    /**
+     * Identifies the head tracking sensor using its unique sensor ID.
+     * The value corresponds to android.hardware.sensors.SensorInfo.sensorHandle.
+     */
+    int headTrackingSensorId;
+
+    /**
+     * Head tracking mode for spatialization.
+     */
+    HeadTracking.Mode headTrackingMode;
+
+    /**
+     * Head tracking sensor connection mode for spatialization.
+     */
+    HeadTracking.ConnectionMode headTrackingConnectionMode;
+
+    /**
+     * Headtracking sensor data.
+     */
+    HeadTracking.SensorData headTrackingSensorData;
+}
diff --git a/audio/aidl/common/Android.bp b/audio/aidl/common/Android.bp
index 4c6a74e..85ece3b 100644
--- a/audio/aidl/common/Android.bp
+++ b/audio/aidl/common/Android.bp
@@ -45,8 +45,8 @@
     name: "libaudioaidlranges",
     host_supported: true,
     vendor_available: true,
-    static_libs: [
-        "android.hardware.audio.effect-V1-ndk",
+    defaults: [
+        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     export_include_dirs: ["include"],
     header_libs: ["libaudioaidl_headers"],
@@ -59,8 +59,10 @@
     name: "libaudioaidlcommon_test",
     host_supported: true,
     vendor_available: true,
+    defaults: [
+        "latest_android_media_audio_common_types_ndk_static",
+    ],
     static_libs: [
-        "android.media.audio.common.types-V1-ndk",
         "libaudioaidlcommon",
     ],
     shared_libs: [
diff --git a/audio/aidl/common/include/Utils.h b/audio/aidl/common/include/Utils.h
index 3b08de7..ef312d5 100644
--- a/audio/aidl/common/include/Utils.h
+++ b/audio/aidl/common/include/Utils.h
@@ -174,4 +174,12 @@
     return result;
 }
 
+constexpr int32_t frameCountFromDurationUs(long durationUs, int32_t sampleRateHz) {
+    return (static_cast<long long>(durationUs) * sampleRateHz) / 1000000LL;
+}
+
+constexpr int32_t frameCountFromDurationMs(int32_t durationMs, int32_t sampleRateHz) {
+    return frameCountFromDurationUs(durationMs * 1000, sampleRateHz);
+}
+
 }  // namespace aidl::android::hardware::audio::common
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 9aa86b5..6d0b95e 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -40,35 +40,13 @@
 }
 
 cc_library {
-    name: "libaudioservicesounddoseimpl",
-    vendor: true,
-    defaults: [
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_core_sounddose_ndk_shared",
-        "latest_android_hardware_audio_sounddose_ndk_shared",
-    ],
-    export_include_dirs: ["include"],
-    srcs: [
-        "SoundDose.cpp",
-    ],
-    shared_libs: [
-        "libbase",
-        "libbinder_ndk",
-        "libcutils",
-        "libutils",
-    ],
-    visibility: [
-        "//hardware/interfaces/audio/aidl/sounddose/default",
-    ],
-}
-
-cc_library {
     name: "libaudioserviceexampleimpl",
     defaults: [
         "aidlaudioservice_defaults",
         "latest_android_media_audio_common_types_ndk_shared",
         "latest_android_hardware_audio_core_ndk_shared",
         "latest_android_hardware_audio_core_sounddose_ndk_shared",
+        "latest_android_hardware_bluetooth_audio_ndk_shared",
     ],
     export_include_dirs: ["include"],
     srcs: [
@@ -116,7 +94,7 @@
         "audio_policy_engine_configuration_aidl_default",
     ],
     shared_libs: [
-        "android.hardware.bluetooth.audio-V3-ndk",
+        "android.hardware.bluetooth.audio-impl",
         "libaudio_aidl_conversion_common_ndk",
         "libbluetooth_audio_session_aidl",
         "libmedia_helper",
@@ -141,15 +119,16 @@
     vintf_fragments: ["android.hardware.audio.service-aidl.xml"],
     defaults: [
         "aidlaudioservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
         "latest_android_hardware_audio_core_sounddose_ndk_shared",
         "latest_android_hardware_audio_core_ndk_shared",
+        "latest_android_hardware_bluetooth_audio_ndk_shared",
+        "latest_android_media_audio_common_types_ndk_shared",
     ],
     static_libs: [
         "libaudioserviceexampleimpl",
     ],
     shared_libs: [
-        "android.hardware.bluetooth.audio-V3-ndk",
+        "android.hardware.bluetooth.audio-impl",
         "libaudio_aidl_conversion_common_ndk",
         "libbluetooth_audio_session_aidl",
         "libmedia_helper",
@@ -221,6 +200,7 @@
     vendor: true,
     shared_libs: [
         "libaudioaidlcommon",
+        "libaudioutils",
         "libbase",
         "libbinder_ndk",
         "libcutils",
diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp
index d09552b..2a8e58f 100644
--- a/audio/aidl/default/Configuration.cpp
+++ b/audio/aidl/default/Configuration.cpp
@@ -302,8 +302,9 @@
 //   2. The canonical r_submix configuration only lists 'STEREO' and '48000',
 //      however the framework attempts to open streams for other sample rates
 //      as well. The legacy r_submix implementation allowed that, but libaudiohal@aidl
-//      will not find a mix port to use. Because of that, list all channel
-//      masks and sample rates that the legacy implementation allowed.
+//      will not find a mix port to use. Because of that, list all sample rates that
+//      the legacy implementation allowed (note that mono was not allowed, the framework
+//      is expected to upmix mono tracks into stereo if needed).
 //   3. The legacy implementation had a hard limit on the number of routes (10),
 //      and this is checked indirectly by AudioPlaybackCaptureTest#testPlaybackCaptureDoS
 //      CTS test. Instead of hardcoding the number of routes, we can use
@@ -319,10 +320,10 @@
 //    - no profiles specified
 //
 // Mix ports:
-//  * "r_submix output", maximum 20 opened streams, maximum 10 active streams
-//    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-//  * "r_submix input", maximum 20 opened streams, maximum 10 active streams
-//    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+//  * "r_submix output", maximum 10 opened streams, maximum 10 active streams
+//    - profile PCM 16-bit; STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+//  * "r_submix input", maximum 10 opened streams, maximum 10 active streams
+//    - profile PCM 16-bit; STEREO; 8000, 11025, 16000, 32000, 44100, 48000
 //
 // Routes:
 //  "r_submix output" -> "Remote Submix Out"
@@ -331,9 +332,8 @@
 std::unique_ptr<Configuration> getRSubmixConfiguration() {
     static const Configuration configuration = []() {
         Configuration c;
-        const std::vector<AudioProfile> standardPcmAudioProfiles{
-                createProfile(PcmType::INT_16_BIT,
-                              {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
+        const std::vector<AudioProfile> remoteSubmixPcmAudioProfiles{
+                createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO},
                               {8000, 11025, 16000, 32000, 44100, 48000})};
 
         // Device ports
@@ -343,25 +343,25 @@
                            createDeviceExt(AudioDeviceType::OUT_SUBMIX, 0,
                                            AudioDeviceDescription::CONNECTION_VIRTUAL));
         c.ports.push_back(rsubmixOutDevice);
-        c.connectedProfiles[rsubmixOutDevice.id] = standardPcmAudioProfiles;
+        c.connectedProfiles[rsubmixOutDevice.id] = remoteSubmixPcmAudioProfiles;
 
         AudioPort rsubmixInDevice =
                 createPort(c.nextPortId++, "Remote Submix In", 0, true,
                            createDeviceExt(AudioDeviceType::IN_SUBMIX, 0,
                                            AudioDeviceDescription::CONNECTION_VIRTUAL));
         c.ports.push_back(rsubmixInDevice);
-        c.connectedProfiles[rsubmixInDevice.id] = standardPcmAudioProfiles;
+        c.connectedProfiles[rsubmixInDevice.id] = remoteSubmixPcmAudioProfiles;
 
         // Mix ports
 
         AudioPort rsubmixOutMix =
-                createPort(c.nextPortId++, "r_submix output", 0, false, createPortMixExt(20, 10));
-        rsubmixOutMix.profiles = standardPcmAudioProfiles;
+                createPort(c.nextPortId++, "r_submix output", 0, false, createPortMixExt(10, 10));
+        rsubmixOutMix.profiles = remoteSubmixPcmAudioProfiles;
         c.ports.push_back(rsubmixOutMix);
 
         AudioPort rsubmixInMix =
-                createPort(c.nextPortId++, "r_submix input", 0, true, createPortMixExt(20, 10));
-        rsubmixInMix.profiles = standardPcmAudioProfiles;
+                createPort(c.nextPortId++, "r_submix input", 0, true, createPortMixExt(10, 10));
+        rsubmixInMix.profiles = remoteSubmixPcmAudioProfiles;
         c.ports.push_back(rsubmixInMix);
 
         c.routes.push_back(createRoute({rsubmixOutMix}, rsubmixOutDevice));
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index 1045009..b8e1df8 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -18,7 +18,6 @@
 #include <set>
 
 #define LOG_TAG "AHAL_Module"
-#include <Utils.h>
 #include <aidl/android/media/audio/common/AudioInputFlags.h>
 #include <aidl/android/media/audio/common/AudioOutputFlags.h>
 #include <android-base/logging.h>
@@ -35,6 +34,7 @@
 #include "core-impl/SoundDose.h"
 #include "core-impl/utils.h"
 
+using aidl::android::hardware::audio::common::frameCountFromDurationMs;
 using aidl::android::hardware::audio::common::getFrameSizeInBytes;
 using aidl::android::hardware::audio::common::isBitPositionFlagSet;
 using aidl::android::hardware::audio::common::isValidAudioMode;
@@ -93,32 +93,6 @@
     return std::all_of(profiles.begin(), profiles.end(), isDynamicProfile);
 }
 
-// Note: does not assign an ID to the config.
-bool generateDefaultPortConfig(const AudioPort& port, AudioPortConfig* config) {
-    const bool allowDynamicConfig = port.ext.getTag() == AudioPortExt::device;
-    *config = {};
-    config->portId = port.id;
-    for (const auto& profile : port.profiles) {
-        if (isDynamicProfile(profile)) continue;
-        config->format = profile.format;
-        config->channelMask = *profile.channelMasks.begin();
-        config->sampleRate = Int{.value = *profile.sampleRates.begin()};
-        config->flags = port.flags;
-        config->ext = port.ext;
-        return true;
-    }
-    if (allowDynamicConfig) {
-        config->format = AudioFormatDescription{};
-        config->channelMask = AudioChannelLayout{};
-        config->sampleRate = Int{.value = 0};
-        config->flags = port.flags;
-        config->ext = port.ext;
-        return true;
-    }
-    LOG(ERROR) << __func__ << ": port " << port.id << " only has dynamic profiles";
-    return false;
-}
-
 bool findAudioProfile(const AudioPort& port, const AudioFormatDescription& format,
                       AudioProfile* profile) {
     if (auto profilesIt =
@@ -202,15 +176,18 @@
         LOG(ERROR) << __func__ << ": non-positive buffer size " << in_bufferSizeFrames;
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
-    if (in_bufferSizeFrames < kMinimumStreamBufferSizeFrames) {
-        LOG(ERROR) << __func__ << ": insufficient buffer size " << in_bufferSizeFrames
-                   << ", must be at least " << kMinimumStreamBufferSizeFrames;
-        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
-    }
     auto& configs = getConfig().portConfigs;
     auto portConfigIt = findById<AudioPortConfig>(configs, in_portConfigId);
+    const int32_t nominalLatencyMs = getNominalLatencyMs(*portConfigIt);
     // Since this is a private method, it is assumed that
     // validity of the portConfigId has already been checked.
+    const int32_t minimumStreamBufferSizeFrames =
+            calculateBufferSizeFrames(nominalLatencyMs, portConfigIt->sampleRate.value().value);
+    if (in_bufferSizeFrames < minimumStreamBufferSizeFrames) {
+        LOG(ERROR) << __func__ << ": insufficient buffer size " << in_bufferSizeFrames
+                   << ", must be at least " << minimumStreamBufferSizeFrames;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
     const size_t frameSize =
             getFrameSizeInBytes(portConfigIt->format.value(), portConfigIt->channelMask.value());
     if (frameSize == 0) {
@@ -238,11 +215,12 @@
         StreamContext temp(
                 std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
                 std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
-                portConfigIt->portId, portConfigIt->format.value(),
-                portConfigIt->channelMask.value(), portConfigIt->sampleRate.value().value, flags,
+                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, params);
+                asyncCallback, outEventCallback,
+                std::weak_ptr<sounddose::StreamDataProcessorInterface>{}, params);
         if (temp.isValid()) {
             *out_context = std::move(temp);
         } else {
@@ -325,6 +303,29 @@
     return ndk::ScopedAStatus::ok();
 }
 
+bool Module::generateDefaultPortConfig(const AudioPort& port, AudioPortConfig* config) {
+    const bool allowDynamicConfig = port.ext.getTag() == AudioPortExt::device;
+    for (const auto& profile : port.profiles) {
+        if (isDynamicProfile(profile)) continue;
+        config->format = profile.format;
+        config->channelMask = *profile.channelMasks.begin();
+        config->sampleRate = Int{.value = *profile.sampleRates.begin()};
+        config->flags = port.flags;
+        config->ext = port.ext;
+        return true;
+    }
+    if (allowDynamicConfig) {
+        config->format = AudioFormatDescription{};
+        config->channelMask = AudioChannelLayout{};
+        config->sampleRate = Int{.value = 0};
+        config->flags = port.flags;
+        config->ext = port.ext;
+        return true;
+    }
+    LOG(ERROR) << __func__ << ": port " << port.id << " only has dynamic profiles";
+    return false;
+}
+
 void Module::populateConnectedProfiles() {
     Configuration& config = getConfig();
     for (const AudioPort& port : config.ports) {
@@ -358,6 +359,12 @@
     return internal::getConfiguration(getType());
 }
 
+int32_t Module::getNominalLatencyMs(const AudioPortConfig&) {
+    // Arbitrary value. Implementations must override this method to provide their actual latency.
+    static constexpr int32_t kLatencyMs = 5;
+    return kLatencyMs;
+}
+
 std::vector<AudioRoute*> Module::getAudioRoutesForAudioPortImpl(int32_t portId) {
     std::vector<AudioRoute*> result;
     auto& routes = getConfig().routes;
@@ -608,36 +615,35 @@
 
     std::vector<AudioRoute*> routesToMixPorts = getAudioRoutesForAudioPortImpl(templateId);
     std::set<int32_t> routableMixPortIds = getRoutableAudioPortIds(templateId, &routesToMixPorts);
-    if (hasDynamicProfilesOnly(connectedPort.profiles)) {
-        if (!mDebug.simulateDeviceConnections) {
-            RETURN_STATUS_IF_ERROR(populateConnectedDevicePort(&connectedPort));
-        } else {
-            auto& connectedProfiles = getConfig().connectedProfiles;
-            if (auto connectedProfilesIt = connectedProfiles.find(templateId);
-                connectedProfilesIt != connectedProfiles.end()) {
-                connectedPort.profiles = connectedProfilesIt->second;
-            }
+    const int32_t nextPortId = getConfig().nextPortId++;
+    if (!mDebug.simulateDeviceConnections) {
+        // Even if the device port has static profiles, the HAL module might need to update
+        // them, or abort the connection process.
+        RETURN_STATUS_IF_ERROR(populateConnectedDevicePort(&connectedPort, nextPortId));
+    } else if (hasDynamicProfilesOnly(connectedPort.profiles)) {
+        auto& connectedProfiles = getConfig().connectedProfiles;
+        if (auto connectedProfilesIt = connectedProfiles.find(templateId);
+            connectedProfilesIt != connectedProfiles.end()) {
+            connectedPort.profiles = connectedProfilesIt->second;
         }
-        if (hasDynamicProfilesOnly(connectedPort.profiles)) {
-            // Possible case 2. Check if all routable mix ports have static profiles.
-            if (auto dynamicMixPortIt = std::find_if(ports.begin(), ports.end(),
-                                                     [&routableMixPortIds](const auto& p) {
-                                                         return routableMixPortIds.count(p.id) >
-                                                                        0 &&
-                                                                hasDynamicProfilesOnly(p.profiles);
-                                                     });
-                dynamicMixPortIt != ports.end()) {
-                LOG(ERROR) << __func__
-                           << ": connected port only has dynamic profiles after connecting "
-                           << "external device " << connectedPort.toString() << ", and there exist "
-                           << "a routable mix port with dynamic profiles: "
-                           << dynamicMixPortIt->toString();
-                return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-            }
+    }
+    if (hasDynamicProfilesOnly(connectedPort.profiles)) {
+        // Possible case 2. Check if all routable mix ports have static profiles.
+        if (auto dynamicMixPortIt = std::find_if(ports.begin(), ports.end(),
+                                                 [&routableMixPortIds](const auto& p) {
+                                                     return routableMixPortIds.count(p.id) > 0 &&
+                                                            hasDynamicProfilesOnly(p.profiles);
+                                                 });
+            dynamicMixPortIt != ports.end()) {
+            LOG(ERROR) << __func__ << ": connected port only has dynamic profiles after connecting "
+                       << "external device " << connectedPort.toString() << ", and there exist "
+                       << "a routable mix port with dynamic profiles: "
+                       << dynamicMixPortIt->toString();
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
         }
     }
 
-    connectedPort.id = getConfig().nextPortId++;
+    connectedPort.id = nextPortId;
     auto [connectedPortsIt, _] =
             mConnectedDevicePorts.insert(std::pair(connectedPort.id, std::set<int32_t>()));
     LOG(DEBUG) << __func__ << ": template port " << templateId << " external device connected, "
@@ -751,6 +757,28 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Module::prepareToDisconnectExternalDevice(int32_t in_portId) {
+    auto& ports = getConfig().ports;
+    auto portIt = findById<AudioPort>(ports, in_portId);
+    if (portIt == ports.end()) {
+        LOG(ERROR) << __func__ << ": port id " << in_portId << " not found";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    if (portIt->ext.getTag() != AudioPortExt::Tag::device) {
+        LOG(ERROR) << __func__ << ": port id " << in_portId << " is not a device port";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    auto connectedPortsIt = mConnectedDevicePorts.find(in_portId);
+    if (connectedPortsIt == mConnectedDevicePorts.end()) {
+        LOG(ERROR) << __func__ << ": port id " << in_portId << " is not a connected device port";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+
+    onPrepareToDisconnectExternalDevice(*portIt);
+
+    return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus Module::getAudioPatches(std::vector<AudioPatch>* _aidl_return) {
     *_aidl_return = getConfig().patches;
     LOG(DEBUG) << __func__ << ": returning " << _aidl_return->size() << " patches";
@@ -964,11 +992,21 @@
             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
         }
     }
+    // Find the highest sample rate among mix port configs.
+    std::map<int32_t, AudioPortConfig*> sampleRates;
+    std::vector<AudioPortConfig*>& mixPortConfigs =
+            sources[0]->ext.getTag() == AudioPortExt::mix ? sources : sinks;
+    for (auto mix : mixPortConfigs) {
+        sampleRates.emplace(mix->sampleRate.value().value, mix);
+    }
     *_aidl_return = in_requested;
-    _aidl_return->minimumStreamBufferSizeFrames = kMinimumStreamBufferSizeFrames;
+    auto maxSampleRateIt = std::max_element(sampleRates.begin(), sampleRates.end());
+    const int32_t latencyMs = getNominalLatencyMs(*(maxSampleRateIt->second));
+    _aidl_return->minimumStreamBufferSizeFrames =
+            calculateBufferSizeFrames(latencyMs, maxSampleRateIt->first);
     _aidl_return->latenciesMs.clear();
     _aidl_return->latenciesMs.insert(_aidl_return->latenciesMs.end(),
-                                     _aidl_return->sinkPortConfigIds.size(), kLatencyMs);
+                                     _aidl_return->sinkPortConfigIds.size(), latencyMs);
     AudioPatch oldPatch{};
     if (existing == patches.end()) {
         _aidl_return->id = getConfig().nextPatchId++;
@@ -996,6 +1034,18 @@
 
 ndk::ScopedAStatus Module::setAudioPortConfig(const AudioPortConfig& in_requested,
                                               AudioPortConfig* out_suggested, bool* _aidl_return) {
+    auto generate = [this](const AudioPort& port, AudioPortConfig* config) {
+        return generateDefaultPortConfig(port, config);
+    };
+    return setAudioPortConfigImpl(in_requested, generate, out_suggested, _aidl_return);
+}
+
+ndk::ScopedAStatus Module::setAudioPortConfigImpl(
+        const AudioPortConfig& in_requested,
+        const std::function<bool(const ::aidl::android::media::audio::common::AudioPort& port,
+                                 ::aidl::android::media::audio::common::AudioPortConfig* config)>&
+                fillPortConfig,
+        AudioPortConfig* out_suggested, bool* applied) {
     LOG(DEBUG) << __func__ << ": requested " << in_requested.toString();
     auto& configs = getConfig().portConfigs;
     auto existing = configs.end();
@@ -1024,7 +1074,8 @@
         *out_suggested = *existing;
     } else {
         AudioPortConfig newConfig;
-        if (generateDefaultPortConfig(*portIt, &newConfig)) {
+        newConfig.portId = portIt->id;
+        if (fillPortConfig(*portIt, &newConfig)) {
             *out_suggested = newConfig;
         } else {
             LOG(ERROR) << __func__ << ": unable generate a default config for port " << portId;
@@ -1129,17 +1180,17 @@
     if (existing == configs.end() && requestedIsValid && requestedIsFullySpecified) {
         out_suggested->id = getConfig().nextPortId++;
         configs.push_back(*out_suggested);
-        *_aidl_return = true;
+        *applied = true;
         LOG(DEBUG) << __func__ << ": created new port config " << out_suggested->toString();
     } else if (existing != configs.end() && requestedIsValid) {
         *existing = *out_suggested;
-        *_aidl_return = true;
+        *applied = true;
         LOG(DEBUG) << __func__ << ": updated port config " << out_suggested->toString();
     } else {
         LOG(DEBUG) << __func__ << ": not applied; existing config ? " << (existing != configs.end())
                    << "; requested is valid? " << requestedIsValid << ", fully specified? "
                    << requestedIsFullySpecified;
-        *_aidl_return = false;
+        *applied = false;
     }
     return ndk::ScopedAStatus::ok();
 }
@@ -1210,7 +1261,7 @@
         // Reset master mute if it failed.
         onMasterMuteChanged(mMasterMute);
     }
-    return std::move(result);
+    return result;
 }
 
 ndk::ScopedAStatus Module::getMasterVolume(float* _aidl_return) {
@@ -1232,7 +1283,7 @@
                        << "), error=" << result;
             onMasterVolumeChanged(mMasterVolume);
         }
-        return std::move(result);
+        return result;
     }
     LOG(ERROR) << __func__ << ": invalid master volume value: " << in_volume;
     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
@@ -1491,7 +1542,7 @@
     return mIsMmapSupported.value();
 }
 
-ndk::ScopedAStatus Module::populateConnectedDevicePort(AudioPort* audioPort) {
+ndk::ScopedAStatus Module::populateConnectedDevicePort(AudioPort* audioPort, int32_t) {
     if (audioPort->ext.getTag() != AudioPortExt::device) {
         LOG(ERROR) << __func__ << ": not a device port: " << audioPort->toString();
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
@@ -1520,6 +1571,11 @@
     LOG(DEBUG) << __func__ << ": do nothing and return";
 }
 
+void Module::onPrepareToDisconnectExternalDevice(
+        const ::aidl::android::media::audio::common::AudioPort& audioPort __unused) {
+    LOG(DEBUG) << __func__ << ": do nothing and return";
+}
+
 ndk::ScopedAStatus Module::onMasterMuteChanged(bool mute __unused) {
     LOG(VERBOSE) << __func__ << ": do nothing and return ok";
     return ndk::ScopedAStatus::ok();
@@ -1553,11 +1609,6 @@
     return result;
 }
 
-Module::BtProfileHandles Module::getBtProfileManagerHandles() {
-    return std::make_tuple(std::weak_ptr<IBluetooth>(), std::weak_ptr<IBluetoothA2dp>(),
-                           std::weak_ptr<IBluetoothLe>());
-}
-
 ndk::ScopedAStatus Module::bluetoothParametersUpdated() {
     return mStreams.bluetoothParametersUpdated();
 }
diff --git a/audio/aidl/default/ModulePrimary.cpp b/audio/aidl/default/ModulePrimary.cpp
index 9919c7f..3da6d48 100644
--- a/audio/aidl/default/ModulePrimary.cpp
+++ b/audio/aidl/default/ModulePrimary.cpp
@@ -58,4 +58,12 @@
                                                   offloadInfo);
 }
 
+int32_t ModulePrimary::getNominalLatencyMs(const AudioPortConfig&) {
+    // 85 ms is chosen considering 4096 frames @ 48 kHz. This is the value which allows
+    // the virtual Android device implementation to pass CTS. Hardware implementations
+    // should have significantly lower latency.
+    static constexpr int32_t kLatencyMs = 85;
+    return kLatencyMs;
+}
+
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index f7298c0..a805b87 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -90,6 +90,14 @@
     return true;
 }
 
+void StreamContext::startStreamDataProcessor() {
+    auto streamDataProcessor = mStreamDataProcessor.lock();
+    if (streamDataProcessor != nullptr) {
+        streamDataProcessor->startDataProcessor(mSampleRate, getChannelCount(mChannelLayout),
+                                                mFormat);
+    }
+}
+
 void StreamContext::reset() {
     mCommandMQ.reset();
     mReplyMQ.reset();
@@ -130,7 +138,7 @@
     reply->status = STATUS_OK;
     if (isConnected) {
         reply->observable.frames = mContext->getFrameCount();
-        reply->observable.timeNs = ::android::elapsedRealtimeNano();
+        reply->observable.timeNs = ::android::uptimeNanos();
         if (auto status = mDriver->refinePosition(&reply->observable); status == ::android::OK) {
             return;
         }
@@ -307,7 +315,7 @@
     const size_t frameSize = mContext->getFrameSize();
     size_t actualFrameCount = 0;
     bool fatal = false;
-    int32_t latency = Module::kLatencyMs;
+    int32_t latency = mContext->getNominalLatencyMs();
     if (isConnected) {
         if (::android::status_t status = mDriver->transfer(mDataBuffer.get(), byteCount / frameSize,
                                                            &actualFrameCount, &latency);
@@ -573,8 +581,8 @@
     const size_t readByteCount = dataMQ->availableToRead();
     const size_t frameSize = mContext->getFrameSize();
     bool fatal = false;
-    int32_t latency = Module::kLatencyMs;
-    if (bool success = readByteCount > 0 ? dataMQ->read(&mDataBuffer[0], readByteCount) : true) {
+    int32_t latency = mContext->getNominalLatencyMs();
+    if (readByteCount > 0 ? dataMQ->read(&mDataBuffer[0], readByteCount) : true) {
         const bool isConnected = mIsConnected;
         LOG(VERBOSE) << __func__ << ": reading of " << readByteCount << " bytes from data MQ"
                      << " succeeded; connected? " << isConnected;
@@ -593,6 +601,10 @@
                 fatal = true;
                 LOG(ERROR) << __func__ << ": write failed: " << status;
             }
+            auto streamDataProcessor = mContext->getStreamDataProcessor().lock();
+            if (streamDataProcessor != nullptr) {
+                streamDataProcessor->process(mDataBuffer.get(), actualFrameCount * frameSize);
+            }
         } else {
             if (mContext->getAsyncCallback() == nullptr) {
                 usleep(3000);  // Simulate blocking transfer delay.
@@ -836,7 +848,7 @@
 }
 
 StreamInHwGainHelper::StreamInHwGainHelper(const StreamContext* context)
-    : mChannelCount(getChannelCount(context->getChannelLayout())) {}
+    : mChannelCount(getChannelCount(context->getChannelLayout())), mHwGains(mChannelCount, 0.0f) {}
 
 ndk::ScopedAStatus StreamInHwGainHelper::getHwGainImpl(std::vector<float>* _aidl_return) {
     *_aidl_return = mHwGains;
@@ -967,7 +979,8 @@
 }
 
 StreamOutHwVolumeHelper::StreamOutHwVolumeHelper(const StreamContext* context)
-    : mChannelCount(getChannelCount(context->getChannelLayout())) {}
+    : mChannelCount(getChannelCount(context->getChannelLayout())),
+      mHwVolumes(mChannelCount, 0.0f) {}
 
 ndk::ScopedAStatus StreamOutHwVolumeHelper::getHwVolumeImpl(std::vector<float>* _aidl_return) {
     *_aidl_return = mHwVolumes;
diff --git a/audio/aidl/default/XsdcConversion.cpp b/audio/aidl/default/XsdcConversion.cpp
index 9e30347..1720949 100644
--- a/audio/aidl/default/XsdcConversion.cpp
+++ b/audio/aidl/default/XsdcConversion.cpp
@@ -205,24 +205,28 @@
 ConversionResult<AudioIoFlags> convertIoFlagsToAidl(
         const std::vector<ap_xsd::AudioInOutFlag>& flags, const ap_xsd::Role role,
         bool flagsForMixPort) {
-    int flagMask = 0;
+    int legacyFlagMask = 0;
     if ((role == ap_xsd::Role::sink && flagsForMixPort) ||
         (role == ap_xsd::Role::source && !flagsForMixPort)) {
         for (const ap_xsd::AudioInOutFlag& flag : flags) {
             audio_input_flags_t legacyFlag;
             if (::android::InputFlagConverter::fromString(ap_xsd::toString(flag), legacyFlag)) {
-                flagMask |= static_cast<int>(legacyFlag);
+                legacyFlagMask |= static_cast<int>(legacyFlag);
             }
         }
-        return AudioIoFlags::make<AudioIoFlags::Tag::input>(flagMask);
+        return AudioIoFlags::make<AudioIoFlags::Tag::input>(
+                VALUE_OR_FATAL(legacy2aidl_audio_input_flags_t_int32_t_mask(
+                        static_cast<audio_input_flags_t>(legacyFlagMask))));
     } else {
         for (const ap_xsd::AudioInOutFlag& flag : flags) {
             audio_output_flags_t legacyFlag;
             if (::android::OutputFlagConverter::fromString(ap_xsd::toString(flag), legacyFlag)) {
-                flagMask |= static_cast<int>(legacyFlag);
+                legacyFlagMask |= static_cast<int>(legacyFlag);
             }
         }
-        return AudioIoFlags::make<AudioIoFlags::Tag::output>(flagMask);
+        return AudioIoFlags::make<AudioIoFlags::Tag::output>(
+                VALUE_OR_FATAL(legacy2aidl_audio_output_flags_t_int32_t_mask(
+                        static_cast<audio_output_flags_t>(legacyFlagMask))));
     }
 }
 
diff --git a/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
index 8727232..5e18f1b 100644
--- a/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
+++ b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
@@ -76,7 +76,7 @@
                           .proxy = std::nullopt},
                    .flags = {.type = Flags::Type::PRE_PROC,
                              .insert = Flags::Insert::FIRST,
-                             .volume = Flags::Volume::CTRL},
+                             .volume = Flags::Volume::NONE},
                    .name = AcousticEchoCancelerSw::kEffectName,
                    .implementor = "The Android Open Source Project"},
         .capability = AcousticEchoCancelerSw::kCapability};
diff --git a/audio/aidl/default/acousticEchoCanceler/Android.bp b/audio/aidl/default/acousticEchoCanceler/Android.bp
index bfb7212..35d4a56 100644
--- a/audio/aidl/default/acousticEchoCanceler/Android.bp
+++ b/audio/aidl/default/acousticEchoCanceler/Android.bp
@@ -27,8 +27,6 @@
     name: "libaecsw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "AcousticEchoCancelerSw.cpp",
diff --git a/audio/aidl/default/alsa/Mixer.cpp b/audio/aidl/default/alsa/Mixer.cpp
index 126c033..e72502b 100644
--- a/audio/aidl/default/alsa/Mixer.cpp
+++ b/audio/aidl/default/alsa/Mixer.cpp
@@ -20,9 +20,24 @@
 #define LOG_TAG "AHAL_AlsaMixer"
 #include <android-base/logging.h>
 #include <android/binder_status.h>
+#include <error/expected_utils.h>
 
 #include "Mixer.h"
 
+namespace ndk {
+
+// This enables use of 'error/expected_utils' for ScopedAStatus.
+
+inline bool errorIsOk(const ScopedAStatus& s) {
+    return s.isOk();
+}
+
+inline std::string errorToString(const ScopedAStatus& s) {
+    return s.getDescription();
+}
+
+}  // namespace ndk
+
 namespace aidl::android::hardware::audio::core::alsa {
 
 // static
@@ -93,6 +108,36 @@
     }
 }
 
+ndk::ScopedAStatus Mixer::getMasterMute(bool* muted) {
+    return getMixerControlMute(MASTER_SWITCH, muted);
+}
+
+ndk::ScopedAStatus Mixer::getMasterVolume(float* volume) {
+    return getMixerControlVolume(MASTER_VOLUME, volume);
+}
+
+ndk::ScopedAStatus Mixer::getMicGain(float* gain) {
+    return getMixerControlVolume(MIC_GAIN, gain);
+}
+
+ndk::ScopedAStatus Mixer::getMicMute(bool* muted) {
+    return getMixerControlMute(MIC_SWITCH, muted);
+}
+
+ndk::ScopedAStatus Mixer::getVolumes(std::vector<float>* volumes) {
+    struct mixer_ctl* mctl;
+    RETURN_STATUS_IF_ERROR(findControl(Mixer::HW_VOLUME, &mctl));
+    std::vector<int> percents;
+    std::lock_guard l(mMixerAccess);
+    if (int err = getMixerControlPercent(mctl, &percents); err != 0) {
+        LOG(ERROR) << __func__ << ": failed to get volume, err=" << err;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    std::transform(percents.begin(), percents.end(), std::back_inserter(*volumes),
+                   [](int percent) -> float { return std::clamp(percent / 100.0f, 0.0f, 1.0f); });
+    return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus Mixer::setMasterMute(bool muted) {
     return setMixerControlMute(MASTER_SWITCH, muted);
 }
@@ -110,35 +155,70 @@
 }
 
 ndk::ScopedAStatus Mixer::setVolumes(const std::vector<float>& volumes) {
-    if (!isValid()) {
-        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-    }
-    auto it = mMixerControls.find(Mixer::HW_VOLUME);
-    if (it == mMixerControls.end()) {
-        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
-    }
+    struct mixer_ctl* mctl;
+    RETURN_STATUS_IF_ERROR(findControl(Mixer::HW_VOLUME, &mctl));
     std::vector<int> percents;
     std::transform(
             volumes.begin(), volumes.end(), std::back_inserter(percents),
             [](float volume) -> int { return std::floor(std::clamp(volume, 0.0f, 1.0f) * 100); });
     std::lock_guard l(mMixerAccess);
-    if (int err = setMixerControlPercent(it->second, percents); err != 0) {
+    if (int err = setMixerControlPercent(mctl, percents); err != 0) {
         LOG(ERROR) << __func__ << ": failed to set volume, err=" << err;
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     }
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Mixer::setMixerControlMute(Mixer::Control ctl, bool muted) {
+ndk::ScopedAStatus Mixer::findControl(Control ctl, struct mixer_ctl** result) {
     if (!isValid()) {
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     }
-    auto it = mMixerControls.find(ctl);
-    if (it == mMixerControls.end()) {
-        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    if (auto it = mMixerControls.find(ctl); it != mMixerControls.end()) {
+        *result = it->second;
+        return ndk::ScopedAStatus::ok();
     }
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Mixer::getMixerControlMute(Control ctl, bool* muted) {
+    struct mixer_ctl* mctl;
+    RETURN_STATUS_IF_ERROR(findControl(ctl, &mctl));
     std::lock_guard l(mMixerAccess);
-    if (int err = setMixerControlValue(it->second, muted ? 0 : 1); err != 0) {
+    std::vector<int> mutedValues;
+    if (int err = getMixerControlValues(mctl, &mutedValues); err != 0) {
+        LOG(ERROR) << __func__ << ": failed to get " << ctl << ", err=" << err;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if (mutedValues.empty()) {
+        LOG(ERROR) << __func__ << ": got no values for " << ctl;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    *muted = mutedValues[0] != 0;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Mixer::getMixerControlVolume(Control ctl, float* volume) {
+    struct mixer_ctl* mctl;
+    RETURN_STATUS_IF_ERROR(findControl(ctl, &mctl));
+    std::lock_guard l(mMixerAccess);
+    std::vector<int> percents;
+    if (int err = getMixerControlPercent(mctl, &percents); err != 0) {
+        LOG(ERROR) << __func__ << ": failed to get " << ctl << ", err=" << err;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if (percents.empty()) {
+        LOG(ERROR) << __func__ << ": got no values for " << ctl;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    *volume = std::clamp(percents[0] / 100.0f, 0.0f, 1.0f);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Mixer::setMixerControlMute(Control ctl, bool muted) {
+    struct mixer_ctl* mctl;
+    RETURN_STATUS_IF_ERROR(findControl(ctl, &mctl));
+    std::lock_guard l(mMixerAccess);
+    if (int err = setMixerControlValue(mctl, muted ? 0 : 1); err != 0) {
         LOG(ERROR) << __func__ << ": failed to set " << ctl << " to " << muted << ", err=" << err;
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     }
@@ -146,54 +226,72 @@
 }
 
 ndk::ScopedAStatus Mixer::setMixerControlVolume(Control ctl, float volume) {
-    if (!isValid()) {
-        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-    }
-    auto it = mMixerControls.find(ctl);
-    if (it == mMixerControls.end()) {
-        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
-    }
+    struct mixer_ctl* mctl;
+    RETURN_STATUS_IF_ERROR(findControl(ctl, &mctl));
     volume = std::clamp(volume, 0.0f, 1.0f);
     std::lock_guard l(mMixerAccess);
-    if (int err = setMixerControlPercent(it->second, std::floor(volume * 100)); err != 0) {
+    if (int err = setMixerControlPercent(mctl, std::floor(volume * 100)); err != 0) {
         LOG(ERROR) << __func__ << ": failed to set " << ctl << " to " << volume << ", err=" << err;
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     }
     return ndk::ScopedAStatus::ok();
 }
 
+int Mixer::getMixerControlPercent(struct mixer_ctl* ctl, std::vector<int>* percents) {
+    const unsigned int n = mixer_ctl_get_num_values(ctl);
+    percents->resize(n);
+    for (unsigned int id = 0; id < n; id++) {
+        if (int valueOrError = mixer_ctl_get_percent(ctl, id); valueOrError >= 0) {
+            (*percents)[id] = valueOrError;
+        } else {
+            return valueOrError;
+        }
+    }
+    return 0;
+}
+
+int Mixer::getMixerControlValues(struct mixer_ctl* ctl, std::vector<int>* values) {
+    const unsigned int n = mixer_ctl_get_num_values(ctl);
+    values->resize(n);
+    for (unsigned int id = 0; id < n; id++) {
+        if (int valueOrError = mixer_ctl_get_value(ctl, id); valueOrError >= 0) {
+            (*values)[id] = valueOrError;
+        } else {
+            return valueOrError;
+        }
+    }
+    return 0;
+}
+
 int Mixer::setMixerControlPercent(struct mixer_ctl* ctl, int percent) {
-    int ret = 0;
     const unsigned int n = mixer_ctl_get_num_values(ctl);
     for (unsigned int id = 0; id < n; id++) {
         if (int error = mixer_ctl_set_percent(ctl, id, percent); error != 0) {
-            ret = error;
+            return error;
         }
     }
-    return ret;
+    return 0;
 }
 
 int Mixer::setMixerControlPercent(struct mixer_ctl* ctl, const std::vector<int>& percents) {
-    int ret = 0;
     const unsigned int n = mixer_ctl_get_num_values(ctl);
     for (unsigned int id = 0; id < n; id++) {
         if (int error = mixer_ctl_set_percent(ctl, id, id < percents.size() ? percents[id] : 0);
             error != 0) {
-            ret = error;
+            return error;
         }
     }
-    return ret;
+    return 0;
 }
 
 int Mixer::setMixerControlValue(struct mixer_ctl* ctl, int value) {
-    int ret = 0;
     const unsigned int n = mixer_ctl_get_num_values(ctl);
     for (unsigned int id = 0; id < n; id++) {
         if (int error = mixer_ctl_set_value(ctl, id, value); error != 0) {
-            ret = error;
+            return error;
         }
     }
-    return ret;
+    return 0;
 }
 
 }  // namespace aidl::android::hardware::audio::core::alsa
diff --git a/audio/aidl/default/alsa/Mixer.h b/audio/aidl/default/alsa/Mixer.h
index 8fba1e0..41f19a8 100644
--- a/audio/aidl/default/alsa/Mixer.h
+++ b/audio/aidl/default/alsa/Mixer.h
@@ -39,6 +39,11 @@
 
     bool isValid() const { return mMixer != nullptr; }
 
+    ndk::ScopedAStatus getMasterMute(bool* muted);
+    ndk::ScopedAStatus getMasterVolume(float* volume);
+    ndk::ScopedAStatus getMicGain(float* gain);
+    ndk::ScopedAStatus getMicMute(bool* muted);
+    ndk::ScopedAStatus getVolumes(std::vector<float>* volumes);
     ndk::ScopedAStatus setMasterMute(bool muted);
     ndk::ScopedAStatus setMasterVolume(float volume);
     ndk::ScopedAStatus setMicGain(float gain);
@@ -60,9 +65,16 @@
     static const std::map<Control, std::vector<ControlNamesAndExpectedCtlType>> kPossibleControls;
     static Controls initializeMixerControls(struct mixer* mixer);
 
+    ndk::ScopedAStatus findControl(Control ctl, struct mixer_ctl** result);
+    ndk::ScopedAStatus getMixerControlMute(Control ctl, bool* muted);
+    ndk::ScopedAStatus getMixerControlVolume(Control ctl, float* volume);
     ndk::ScopedAStatus setMixerControlMute(Control ctl, bool muted);
     ndk::ScopedAStatus setMixerControlVolume(Control ctl, float volume);
 
+    int getMixerControlPercent(struct mixer_ctl* ctl, std::vector<int>* percents)
+            REQUIRES(mMixerAccess);
+    int getMixerControlValues(struct mixer_ctl* ctl, std::vector<int>* values)
+            REQUIRES(mMixerAccess);
     int setMixerControlPercent(struct mixer_ctl* ctl, int percent) REQUIRES(mMixerAccess);
     int setMixerControlPercent(struct mixer_ctl* ctl, const std::vector<int>& percents)
             REQUIRES(mMixerAccess);
diff --git a/audio/aidl/default/alsa/ModuleAlsa.cpp b/audio/aidl/default/alsa/ModuleAlsa.cpp
index 8512631..9a2cce7 100644
--- a/audio/aidl/default/alsa/ModuleAlsa.cpp
+++ b/audio/aidl/default/alsa/ModuleAlsa.cpp
@@ -34,7 +34,7 @@
 
 namespace aidl::android::hardware::audio::core {
 
-ndk::ScopedAStatus ModuleAlsa::populateConnectedDevicePort(AudioPort* audioPort) {
+ndk::ScopedAStatus ModuleAlsa::populateConnectedDevicePort(AudioPort* audioPort, int32_t) {
     auto deviceProfile = alsa::getDeviceProfile(*audioPort);
     if (!deviceProfile.has_value()) {
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
diff --git a/audio/aidl/default/alsa/StreamAlsa.cpp b/audio/aidl/default/alsa/StreamAlsa.cpp
index 403b94b..e57d538 100644
--- a/audio/aidl/default/alsa/StreamAlsa.cpp
+++ b/audio/aidl/default/alsa/StreamAlsa.cpp
@@ -119,7 +119,7 @@
 
 ::android::status_t StreamAlsa::refinePosition(StreamDescriptor::Position* position) {
     if (mAlsaDeviceProxies.empty()) {
-        LOG(FATAL) << __func__ << ": no opened devices";
+        LOG(WARNING) << __func__ << ": no opened devices";
         return ::android::NO_INIT;
     }
     // Since the proxy can only count transferred frames since its creation,
diff --git a/audio/aidl/default/android.hardware.audio.effect.service-aidl.xml b/audio/aidl/default/android.hardware.audio.effect.service-aidl.xml
index fdc53a3..05a825d 100644
--- a/audio/aidl/default/android.hardware.audio.effect.service-aidl.xml
+++ b/audio/aidl/default/android.hardware.audio.effect.service-aidl.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
   <hal format="aidl">
     <name>android.hardware.audio.effect</name>
-    <version>1</version>
+    <version>2</version>
     <fqname>IFactory/default</fqname>
   </hal>
 </manifest>
diff --git a/audio/aidl/default/android.hardware.audio.service-aidl.xml b/audio/aidl/default/android.hardware.audio.service-aidl.xml
index 57f61c9..2a51876 100644
--- a/audio/aidl/default/android.hardware.audio.service-aidl.xml
+++ b/audio/aidl/default/android.hardware.audio.service-aidl.xml
@@ -1,22 +1,22 @@
 <manifest version="1.0" type="device">
   <hal format="aidl">
     <name>android.hardware.audio.core</name>
-    <version>1</version>
+    <version>2</version>
     <fqname>IModule/default</fqname>
   </hal>
   <hal format="aidl">
     <name>android.hardware.audio.core</name>
-    <version>1</version>
+    <version>2</version>
     <fqname>IModule/r_submix</fqname>
   </hal>
   <hal format="aidl">
     <name>android.hardware.audio.core</name>
-    <version>1</version>
+    <version>2</version>
     <fqname>IModule/bluetooth</fqname>
   </hal>
   <hal format="aidl">
     <name>android.hardware.audio.core</name>
-    <version>1</version>
+    <version>2</version>
     <fqname>IConfig/default</fqname>
   </hal>
   <!-- Uncomment when these modules present in the configuration
diff --git a/audio/aidl/default/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml
index 00de797..827ff80 100644
--- a/audio/aidl/default/audio_effects_config.xml
+++ b/audio/aidl/default/audio_effects_config.xml
@@ -47,6 +47,7 @@
         <library name="visualizer" path="libvisualizeraidl.so"/>
         <library name="volumesw" path="libvolumesw.so"/>
         <library name="extensioneffect" path="libextensioneffect.so"/>
+        <library name="spatializersw" path="libspatializersw.so"/>
     </libraries>
 
     <!-- list of effects to load.
@@ -96,8 +97,9 @@
             <libsw library="bundle" uuid="ce772f20-847d-11df-bb17-0002a5d5c51b"/>
         </effectProxy>
         <effect name="extension_effect" library="extensioneffect" uuid="fa81dd00-588b-11ed-9b6a-0242ac120002" type="fa81de0e-588b-11ed-9b6a-0242ac120002"/>
-        <effect name="acoustic_echo_canceler" library="aecsw" uuid="bb392ec0-8d4d-11e0-a896-0002a5d5c51b"/>
-        <effect name="noise_suppression" library="nssw" uuid="c06c8400-8e06-11e0-9cb6-0002a5d5c51b"/>
+        <effect name="acoustic_echo_canceler" library="pre_processing" uuid="bb392ec0-8d4d-11e0-a896-0002a5d5c51b"/>
+        <effect name="noise_suppression" library="pre_processing" uuid="c06c8400-8e06-11e0-9cb6-0002a5d5c51b"/>
+        <effect name="spatializer" library="spatializersw" uuid="fa81a880-588b-11ed-9b6a-0242ac120002"/>
     </effects>
 
     <preprocess>
diff --git a/audio/aidl/default/automaticGainControlV1/Android.bp b/audio/aidl/default/automaticGainControlV1/Android.bp
index 4ae8e63..05c2c54 100644
--- a/audio/aidl/default/automaticGainControlV1/Android.bp
+++ b/audio/aidl/default/automaticGainControlV1/Android.bp
@@ -27,8 +27,6 @@
     name: "libagc1sw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "AutomaticGainControlV1Sw.cpp",
diff --git a/audio/aidl/default/automaticGainControlV2/Android.bp b/audio/aidl/default/automaticGainControlV2/Android.bp
index 631cf58..dedc555 100644
--- a/audio/aidl/default/automaticGainControlV2/Android.bp
+++ b/audio/aidl/default/automaticGainControlV2/Android.bp
@@ -27,8 +27,6 @@
     name: "libagc2sw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "AutomaticGainControlV2Sw.cpp",
diff --git a/audio/aidl/default/bassboost/Android.bp b/audio/aidl/default/bassboost/Android.bp
index 82b2f20..9f47770 100644
--- a/audio/aidl/default/bassboost/Android.bp
+++ b/audio/aidl/default/bassboost/Android.bp
@@ -27,8 +27,6 @@
     name: "libbassboostsw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "BassBoostSw.cpp",
diff --git a/audio/aidl/default/bluetooth/DevicePortProxy.cpp b/audio/aidl/default/bluetooth/DevicePortProxy.cpp
index 12e204a..d772c20 100644
--- a/audio/aidl/default/bluetooth/DevicePortProxy.cpp
+++ b/audio/aidl/default/bluetooth/DevicePortProxy.cpp
@@ -14,16 +14,30 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AHAL_BluetoothPortProxy"
+#define LOG_TAG "AHAL_BluetoothAudioPort"
 
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <audio_utils/primitives.h>
-#include <inttypes.h>
 #include <log/log.h>
 
+#include "BluetoothAudioSessionControl.h"
 #include "core-impl/DevicePortProxy.h"
 
+using aidl::android::hardware::audio::common::SinkMetadata;
+using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::hardware::bluetooth::audio::AudioConfiguration;
+using aidl::android::hardware::bluetooth::audio::BluetoothAudioSessionControl;
+using aidl::android::hardware::bluetooth::audio::BluetoothAudioStatus;
+using aidl::android::hardware::bluetooth::audio::ChannelMode;
+using aidl::android::hardware::bluetooth::audio::PcmConfiguration;
+using aidl::android::hardware::bluetooth::audio::PortStatusCallbacks;
+using aidl::android::hardware::bluetooth::audio::PresentationPosition;
+using aidl::android::hardware::bluetooth::audio::SessionType;
+using aidl::android::media::audio::common::AudioDeviceDescription;
+using aidl::android::media::audio::common::AudioDeviceType;
+using android::base::StringPrintf;
+
 namespace android::bluetooth::audio::aidl {
 
 namespace {
@@ -33,20 +47,6 @@
 
 }  // namespace
 
-using ::aidl::android::hardware::audio::common::SinkMetadata;
-using ::aidl::android::hardware::audio::common::SourceMetadata;
-using ::aidl::android::hardware::bluetooth::audio::AudioConfiguration;
-using ::aidl::android::hardware::bluetooth::audio::BluetoothAudioSessionControl;
-using ::aidl::android::hardware::bluetooth::audio::BluetoothAudioStatus;
-using ::aidl::android::hardware::bluetooth::audio::ChannelMode;
-using ::aidl::android::hardware::bluetooth::audio::PcmConfiguration;
-using ::aidl::android::hardware::bluetooth::audio::PortStatusCallbacks;
-using ::aidl::android::hardware::bluetooth::audio::PresentationPosition;
-using ::aidl::android::hardware::bluetooth::audio::SessionType;
-using ::aidl::android::media::audio::common::AudioDeviceDescription;
-using ::aidl::android::media::audio::common::AudioDeviceType;
-using ::android::base::StringPrintf;
-
 std::ostream& operator<<(std::ostream& os, const BluetoothStreamState& state) {
     switch (state) {
         case BluetoothStreamState::DISABLED:
@@ -254,12 +254,7 @@
     return (mCookie != ::aidl::android::hardware::bluetooth::audio::kObserversCookieUndefined);
 }
 
-bool BluetoothAudioPortAidl::getPreferredDataIntervalUs(size_t* interval_us) const {
-    if (!interval_us) {
-        LOG(ERROR) << __func__ << ": bad input arg";
-        return false;
-    }
-
+bool BluetoothAudioPortAidl::getPreferredDataIntervalUs(size_t& interval_us) const {
     if (!inUse()) {
         LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
         return false;
@@ -272,16 +267,11 @@
         return false;
     }
 
-    *interval_us = hal_audio_cfg.get<AudioConfiguration::pcmConfig>().dataIntervalUs;
+    interval_us = hal_audio_cfg.get<AudioConfiguration::pcmConfig>().dataIntervalUs;
     return true;
 }
 
-bool BluetoothAudioPortAidl::loadAudioConfig(PcmConfiguration* audio_cfg) const {
-    if (!audio_cfg) {
-        LOG(ERROR) << __func__ << ": bad input arg";
-        return false;
-    }
-
+bool BluetoothAudioPortAidl::loadAudioConfig(PcmConfiguration& audio_cfg) {
     if (!inUse()) {
         LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
         return false;
@@ -293,15 +283,26 @@
         LOG(ERROR) << __func__ << ": unsupported audio cfg tag";
         return false;
     }
-    *audio_cfg = hal_audio_cfg.get<AudioConfiguration::pcmConfig>();
+    audio_cfg = hal_audio_cfg.get<AudioConfiguration::pcmConfig>();
     LOG(VERBOSE) << __func__ << debugMessage() << ", state*=" << getState() << ", PcmConfig=["
-                 << audio_cfg->toString() << "]";
-    if (audio_cfg->channelMode == ChannelMode::UNKNOWN) {
+                 << audio_cfg.toString() << "]";
+    if (audio_cfg.channelMode == ChannelMode::UNKNOWN) {
         return false;
     }
     return true;
 }
 
+bool BluetoothAudioPortAidlOut::loadAudioConfig(PcmConfiguration& audio_cfg) {
+    if (!BluetoothAudioPortAidl::loadAudioConfig(audio_cfg)) return false;
+    // WAR to support Mono / 16 bits per sample as the Bluetooth stack requires
+    if (audio_cfg.channelMode == ChannelMode::MONO && audio_cfg.bitsPerSample == 16) {
+        mIsStereoToMono = true;
+        audio_cfg.channelMode = ChannelMode::STEREO;
+        LOG(INFO) << __func__ << ": force channels = to be AUDIO_CHANNEL_OUT_STEREO";
+    }
+    return true;
+}
+
 bool BluetoothAudioPortAidl::standby() {
     if (!inUse()) {
         LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
@@ -435,7 +436,7 @@
                 retval = condWaitState(BluetoothStreamState::SUSPENDING);
             } else {
                 LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState()
-                           << " Hal fails";
+                           << " failure to suspend stream";
             }
         }
     }
diff --git a/audio/aidl/default/bluetooth/ModuleBluetooth.cpp b/audio/aidl/default/bluetooth/ModuleBluetooth.cpp
index 3c33207..9084b30 100644
--- a/audio/aidl/default/bluetooth/ModuleBluetooth.cpp
+++ b/audio/aidl/default/bluetooth/ModuleBluetooth.cpp
@@ -18,50 +18,112 @@
 
 #include <android-base/logging.h>
 
-#include "BluetoothAudioSessionControl.h"
+#include "BluetoothAudioSession.h"
 #include "core-impl/ModuleBluetooth.h"
 #include "core-impl/StreamBluetooth.h"
 
+using aidl::android::hardware::audio::common::SinkMetadata;
+using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::hardware::bluetooth::audio::ChannelMode;
+using aidl::android::hardware::bluetooth::audio::PcmConfiguration;
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioConfigBase;
+using aidl::android::media::audio::common::AudioDeviceDescription;
+using aidl::android::media::audio::common::AudioDeviceType;
+using aidl::android::media::audio::common::AudioFormatDescription;
+using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::AudioIoFlags;
+using aidl::android::media::audio::common::AudioOffloadInfo;
+using aidl::android::media::audio::common::AudioPort;
+using aidl::android::media::audio::common::AudioPortConfig;
+using aidl::android::media::audio::common::AudioPortExt;
+using aidl::android::media::audio::common::AudioProfile;
+using aidl::android::media::audio::common::Int;
+using aidl::android::media::audio::common::MicrophoneInfo;
+using aidl::android::media::audio::common::PcmType;
+using android::bluetooth::audio::aidl::BluetoothAudioPortAidl;
+using android::bluetooth::audio::aidl::BluetoothAudioPortAidlIn;
+using android::bluetooth::audio::aidl::BluetoothAudioPortAidlOut;
+
+// TODO(b/312265159) bluetooth audio should be in its own process
+// Remove this and the shared_libs when that happens
+extern "C" binder_status_t createIBluetoothAudioProviderFactory();
+
 namespace aidl::android::hardware::audio::core {
 
-using ::aidl::android::hardware::audio::common::SinkMetadata;
-using ::aidl::android::hardware::audio::common::SourceMetadata;
-using ::aidl::android::hardware::bluetooth::audio::BluetoothAudioSession;
-using ::aidl::android::media::audio::common::AudioDeviceDescription;
-using ::aidl::android::media::audio::common::AudioDeviceType;
-using ::aidl::android::media::audio::common::AudioOffloadInfo;
-using ::aidl::android::media::audio::common::AudioPort;
-using ::aidl::android::media::audio::common::AudioPortExt;
-using ::aidl::android::media::audio::common::MicrophoneInfo;
-using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidl;
-using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidlOut;
+namespace {
+
+PcmType pcmTypeFromBitsPerSample(int8_t bitsPerSample) {
+    if (bitsPerSample == 8)
+        return PcmType::UINT_8_BIT;
+    else if (bitsPerSample == 16)
+        return PcmType::INT_16_BIT;
+    else if (bitsPerSample == 24)
+        return PcmType::INT_24_BIT;
+    else if (bitsPerSample == 32)
+        return PcmType::INT_32_BIT;
+    ALOGE("Unsupported bitsPerSample: %d", bitsPerSample);
+    return PcmType::DEFAULT;
+}
+
+AudioChannelLayout channelLayoutFromChannelMode(ChannelMode mode) {
+    if (mode == ChannelMode::MONO) {
+        return AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+                AudioChannelLayout::LAYOUT_MONO);
+    } else if (mode == ChannelMode::STEREO || mode == ChannelMode::DUALMONO) {
+        return AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+                AudioChannelLayout::LAYOUT_STEREO);
+    }
+    ALOGE("Unsupported channel mode: %s", toString(mode).c_str());
+    return AudioChannelLayout{};
+}
+
+}  // namespace
+
+ModuleBluetooth::ModuleBluetooth(std::unique_ptr<Module::Configuration>&& config)
+    : Module(Type::BLUETOOTH, std::move(config)) {
+    // TODO(b/312265159) bluetooth audio should be in its own process
+    // Remove this and the shared_libs when that happens
+    binder_status_t status = createIBluetoothAudioProviderFactory();
+    if (status != STATUS_OK) {
+        LOG(ERROR) << "Failed to create bluetooth audio provider factory. Status: "
+                   << ::android::statusToString(status);
+    }
+}
 
 ndk::ScopedAStatus ModuleBluetooth::getBluetoothA2dp(
         std::shared_ptr<IBluetoothA2dp>* _aidl_return) {
-    if (!mBluetoothA2dp) {
-        auto handle = ndk::SharedRefBase::make<BluetoothA2dp>();
-        handle->registerHandler(std::bind(&ModuleBluetooth::bluetoothParametersUpdated, this));
-        mBluetoothA2dp = handle;
-    }
-    *_aidl_return = mBluetoothA2dp.getInstance();
+    *_aidl_return = getBtA2dp().getInstance();
     LOG(DEBUG) << __func__ << ": returning instance of IBluetoothA2dp: " << _aidl_return->get();
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus ModuleBluetooth::getBluetoothLe(std::shared_ptr<IBluetoothLe>* _aidl_return) {
+    *_aidl_return = getBtLe().getInstance();
+    LOG(DEBUG) << __func__ << ": returning instance of IBluetoothLe: " << _aidl_return->get();
+    return ndk::ScopedAStatus::ok();
+}
+
+ChildInterface<BluetoothA2dp>& ModuleBluetooth::getBtA2dp() {
+    if (!mBluetoothA2dp) {
+        auto handle = ndk::SharedRefBase::make<BluetoothA2dp>();
+        handle->registerHandler(std::bind(&ModuleBluetooth::bluetoothParametersUpdated, this));
+        mBluetoothA2dp = handle;
+    }
+    return mBluetoothA2dp;
+}
+
+ChildInterface<BluetoothLe>& ModuleBluetooth::getBtLe() {
     if (!mBluetoothLe) {
         auto handle = ndk::SharedRefBase::make<BluetoothLe>();
         handle->registerHandler(std::bind(&ModuleBluetooth::bluetoothParametersUpdated, this));
         mBluetoothLe = handle;
     }
-    *_aidl_return = mBluetoothLe.getInstance();
-    LOG(DEBUG) << __func__ << ": returning instance of IBluetoothLe: " << _aidl_return->get();
-    return ndk::ScopedAStatus::ok();
+    return mBluetoothLe;
 }
 
-Module::BtProfileHandles ModuleBluetooth::getBtProfileManagerHandles() {
-    return std::make_tuple(std::weak_ptr<IBluetooth>(), mBluetoothA2dp.getInstance(),
-                           mBluetoothLe.getInstance());
+ModuleBluetooth::BtProfileHandles ModuleBluetooth::getBtProfileManagerHandles() {
+    return std::make_tuple(std::weak_ptr<IBluetooth>(), getBtA2dp().getPtr(), getBtLe().getPtr());
 }
 
 ndk::ScopedAStatus ModuleBluetooth::getMicMute(bool* _aidl_return __unused) {
@@ -74,61 +136,130 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
+ndk::ScopedAStatus ModuleBluetooth::setAudioPortConfig(const AudioPortConfig& in_requested,
+                                                       AudioPortConfig* out_suggested,
+                                                       bool* _aidl_return) {
+    auto fillConfig = [this](const AudioPort& port, AudioPortConfig* config) {
+        if (port.ext.getTag() == AudioPortExt::device) {
+            CachedProxy proxy;
+            auto status = findOrCreateProxy(port, proxy);
+            if (status.isOk()) {
+                const auto& pcmConfig = proxy.pcmConfig;
+                LOG(DEBUG) << "setAudioPortConfig: suggesting port config from "
+                           << pcmConfig.toString();
+                const auto pcmType = pcmTypeFromBitsPerSample(pcmConfig.bitsPerSample);
+                const auto channelMask = channelLayoutFromChannelMode(pcmConfig.channelMode);
+                if (pcmType != PcmType::DEFAULT && channelMask != AudioChannelLayout{}) {
+                    config->format =
+                            AudioFormatDescription{.type = AudioFormatType::PCM, .pcm = pcmType};
+                    config->channelMask = channelMask;
+                    config->sampleRate = Int{.value = pcmConfig.sampleRateHz};
+                    config->flags = port.flags;
+                    config->ext = port.ext;
+                    return true;
+                }
+            }
+        }
+        return generateDefaultPortConfig(port, config);
+    };
+    return Module::setAudioPortConfigImpl(in_requested, fillConfig, out_suggested, _aidl_return);
+}
+
+ndk::ScopedAStatus ModuleBluetooth::checkAudioPatchEndpointsMatch(
+        const std::vector<AudioPortConfig*>& sources, const std::vector<AudioPortConfig*>& sinks) {
+    // Both sources and sinks must be non-empty, this is guaranteed by 'setAudioPatch'.
+    const bool isInput = sources[0]->ext.getTag() == AudioPortExt::device;
+    const int32_t devicePortId = isInput ? sources[0]->portId : sinks[0]->portId;
+    const auto proxyIt = mProxies.find(devicePortId);
+    if (proxyIt == mProxies.end()) return ndk::ScopedAStatus::ok();
+    const auto& pcmConfig = proxyIt->second.pcmConfig;
+    const AudioPortConfig* mixPortConfig = isInput ? sinks[0] : sources[0];
+    if (!StreamBluetooth::checkConfigParams(
+                pcmConfig, AudioConfigBase{.sampleRate = mixPortConfig->sampleRate->value,
+                                           .channelMask = *(mixPortConfig->channelMask),
+                                           .format = *(mixPortConfig->format)})) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+    if (int32_t handle = mixPortConfig->ext.get<AudioPortExt::mix>().handle; handle > 0) {
+        mConnections.insert(std::pair(handle, devicePortId));
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+void ModuleBluetooth::onExternalDeviceConnectionChanged(const AudioPort& audioPort,
+                                                        bool connected) {
+    if (!connected) mProxies.erase(audioPort.id);
+}
+
 ndk::ScopedAStatus ModuleBluetooth::createInputStream(
         StreamContext&& context, const SinkMetadata& sinkMetadata,
         const std::vector<MicrophoneInfo>& microphones, std::shared_ptr<StreamIn>* result) {
+    CachedProxy proxy;
+    RETURN_STATUS_IF_ERROR(fetchAndCheckProxy(context, proxy));
     return createStreamInstance<StreamInBluetooth>(result, std::move(context), sinkMetadata,
-                                                   microphones, getBtProfileManagerHandles());
+                                                   microphones, getBtProfileManagerHandles(),
+                                                   proxy.ptr, proxy.pcmConfig);
 }
 
 ndk::ScopedAStatus ModuleBluetooth::createOutputStream(
         StreamContext&& context, const SourceMetadata& sourceMetadata,
         const std::optional<AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) {
+    CachedProxy proxy;
+    RETURN_STATUS_IF_ERROR(fetchAndCheckProxy(context, proxy));
     return createStreamInstance<StreamOutBluetooth>(result, std::move(context), sourceMetadata,
-                                                    offloadInfo, getBtProfileManagerHandles());
+                                                    offloadInfo, getBtProfileManagerHandles(),
+                                                    proxy.ptr, proxy.pcmConfig);
 }
 
-ndk::ScopedAStatus ModuleBluetooth::populateConnectedDevicePort(AudioPort* audioPort) {
+ndk::ScopedAStatus ModuleBluetooth::populateConnectedDevicePort(AudioPort* audioPort,
+                                                                int32_t nextPortId) {
     if (audioPort->ext.getTag() != AudioPortExt::device) {
         LOG(ERROR) << __func__ << ": not a device port: " << audioPort->toString();
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
+    if (!::aidl::android::hardware::bluetooth::audio::BluetoothAudioSession::IsAidlAvailable()) {
+        LOG(ERROR) << __func__ << ": IBluetoothAudioProviderFactory AIDL service not available";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
     const auto& devicePort = audioPort->ext.get<AudioPortExt::device>();
     const auto& description = devicePort.device.type;
-    // Since the configuration of the BT module is static, there is nothing to populate here.
-    // However, this method must return an error when the device can not be connected,
-    // this is determined by the status of BT profiles.
+    // This method must return an error when the device can not be connected.
     if (description.connection == AudioDeviceDescription::CONNECTION_BT_A2DP) {
         bool isA2dpEnabled = false;
         if (!!mBluetoothA2dp) {
-            RETURN_STATUS_IF_ERROR(mBluetoothA2dp.getInstance()->isEnabled(&isA2dpEnabled));
+            RETURN_STATUS_IF_ERROR((*mBluetoothA2dp).isEnabled(&isA2dpEnabled));
         }
-        return isA2dpEnabled ? ndk::ScopedAStatus::ok()
-                             : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+        LOG(DEBUG) << __func__ << ": isA2dpEnabled: " << isA2dpEnabled;
+        if (!isA2dpEnabled) return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     } else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE) {
         bool isLeEnabled = false;
         if (!!mBluetoothLe) {
-            RETURN_STATUS_IF_ERROR(mBluetoothLe.getInstance()->isEnabled(&isLeEnabled));
+            RETURN_STATUS_IF_ERROR((*mBluetoothLe).isEnabled(&isLeEnabled));
         }
-        return isLeEnabled ? ndk::ScopedAStatus::ok()
-                           : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+        LOG(DEBUG) << __func__ << ": isLeEnabled: " << isLeEnabled;
+        if (!isLeEnabled) return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     } else if (description.connection == AudioDeviceDescription::CONNECTION_WIRELESS &&
                description.type == AudioDeviceType::OUT_HEARING_AID) {
-        // Hearing aids can use a number of profiles, thus the only way to check
-        // connectivity is to try to talk to the BT HAL.
-        if (!BluetoothAudioSession::IsAidlAvailable()) {
-            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-        }
-        std::shared_ptr<BluetoothAudioPortAidl> proxy = std::shared_ptr<BluetoothAudioPortAidl>(
-                std::make_shared<BluetoothAudioPortAidlOut>());
-        if (proxy->registerPort(description)) {
-            proxy->unregisterPort();
-            return ndk::ScopedAStatus::ok();
-        }
-        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+        // Hearing aids can use a number of profiles, no single switch exists.
+    } else {
+        LOG(ERROR) << __func__ << ": unsupported device type: " << audioPort->toString();
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
-    LOG(ERROR) << __func__ << ": unsupported device type: " << audioPort->toString();
-    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    CachedProxy proxy;
+    RETURN_STATUS_IF_ERROR(createProxy(*audioPort, nextPortId, proxy));
+    // Since the device is already connected and configured by the BT stack, provide
+    // the current configuration instead of all possible profiles.
+    const auto& pcmConfig = proxy.pcmConfig;
+    audioPort->profiles.clear();
+    audioPort->profiles.push_back(
+            AudioProfile{.format = AudioFormatDescription{.type = AudioFormatType::PCM,
+                                                          .pcm = pcmTypeFromBitsPerSample(
+                                                                  pcmConfig.bitsPerSample)},
+                         .channelMasks = std::vector<AudioChannelLayout>(
+                                 {channelLayoutFromChannelMode(pcmConfig.channelMode)}),
+                         .sampleRates = std::vector<int>({pcmConfig.sampleRateHz})});
+    LOG(DEBUG) << __func__ << ": " << audioPort->toString();
+    return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus ModuleBluetooth::onMasterMuteChanged(bool) {
@@ -141,4 +272,77 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
+int32_t ModuleBluetooth::getNominalLatencyMs(const AudioPortConfig& portConfig) {
+    const auto connectionsIt = mConnections.find(portConfig.ext.get<AudioPortExt::mix>().handle);
+    if (connectionsIt != mConnections.end()) {
+        const auto proxyIt = mProxies.find(connectionsIt->second);
+        if (proxyIt != mProxies.end()) {
+            auto proxy = proxyIt->second.ptr;
+            size_t dataIntervalUs = 0;
+            if (!proxy->getPreferredDataIntervalUs(dataIntervalUs)) {
+                LOG(WARNING) << __func__ << ": could not fetch preferred data interval";
+            }
+            const bool isInput = portConfig.flags->getTag() == AudioIoFlags::input;
+            return isInput ? StreamInBluetooth::getNominalLatencyMs(dataIntervalUs)
+                           : StreamOutBluetooth::getNominalLatencyMs(dataIntervalUs);
+        }
+    }
+    LOG(ERROR) << __func__ << ": no connection or proxy found for " << portConfig.toString();
+    return Module::getNominalLatencyMs(portConfig);
+}
+
+ndk::ScopedAStatus ModuleBluetooth::createProxy(const AudioPort& audioPort, int32_t instancePortId,
+                                                CachedProxy& proxy) {
+    const bool isInput = audioPort.flags.getTag() == AudioIoFlags::input;
+    proxy.ptr = isInput ? std::shared_ptr<BluetoothAudioPortAidl>(
+                                  std::make_shared<BluetoothAudioPortAidlIn>())
+                        : std::shared_ptr<BluetoothAudioPortAidl>(
+                                  std::make_shared<BluetoothAudioPortAidlOut>());
+    const auto& devicePort = audioPort.ext.get<AudioPortExt::device>();
+    if (const auto device = devicePort.device.type; !proxy.ptr->registerPort(device)) {
+        LOG(ERROR) << __func__ << ": failed to register BT port for " << device.toString();
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if (!proxy.ptr->loadAudioConfig(proxy.pcmConfig)) {
+        LOG(ERROR) << __func__ << ": state=" << proxy.ptr->getState()
+                   << ", failed to load audio config";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    mProxies.insert(std::pair(instancePortId, proxy));
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleBluetooth::fetchAndCheckProxy(const StreamContext& context,
+                                                       CachedProxy& proxy) {
+    const auto connectionsIt = mConnections.find(context.getMixPortHandle());
+    if (connectionsIt != mConnections.end()) {
+        const auto proxyIt = mProxies.find(connectionsIt->second);
+        if (proxyIt != mProxies.end()) {
+            proxy = proxyIt->second;
+            mProxies.erase(proxyIt);
+        }
+        mConnections.erase(connectionsIt);
+    }
+    if (proxy.ptr != nullptr) {
+        if (!StreamBluetooth::checkConfigParams(
+                    proxy.pcmConfig, AudioConfigBase{.sampleRate = context.getSampleRate(),
+                                                     .channelMask = context.getChannelLayout(),
+                                                     .format = context.getFormat()})) {
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+        }
+    }
+    // Not having a proxy is OK, it may happen in VTS tests when streams are opened on unconnected
+    // mix ports.
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleBluetooth::findOrCreateProxy(const AudioPort& audioPort,
+                                                      CachedProxy& proxy) {
+    if (auto proxyIt = mProxies.find(audioPort.id); proxyIt != mProxies.end()) {
+        proxy = proxyIt->second;
+        return ndk::ScopedAStatus::ok();
+    }
+    return createProxy(audioPort, audioPort.id, proxy);
+}
+
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/bluetooth/StreamBluetooth.cpp b/audio/aidl/default/bluetooth/StreamBluetooth.cpp
index 91a33c2..a73af1b 100644
--- a/audio/aidl/default/bluetooth/StreamBluetooth.cpp
+++ b/audio/aidl/default/bluetooth/StreamBluetooth.cpp
@@ -14,88 +14,69 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AHAL_StreamBluetooth"
+#include <algorithm>
 
+#define LOG_TAG "AHAL_StreamBluetooth"
 #include <Utils.h>
 #include <android-base/logging.h>
 #include <audio_utils/clock.h>
 
-#include "BluetoothAudioSessionControl.h"
+#include "BluetoothAudioSession.h"
 #include "core-impl/StreamBluetooth.h"
 
-namespace aidl::android::hardware::audio::core {
+using aidl::android::hardware::audio::common::frameCountFromDurationUs;
+using aidl::android::hardware::audio::common::SinkMetadata;
+using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::hardware::audio::core::VendorParameter;
+using aidl::android::hardware::bluetooth::audio::ChannelMode;
+using aidl::android::hardware::bluetooth::audio::PcmConfiguration;
+using aidl::android::hardware::bluetooth::audio::PresentationPosition;
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioConfigBase;
+using aidl::android::media::audio::common::AudioDevice;
+using aidl::android::media::audio::common::AudioDeviceAddress;
+using aidl::android::media::audio::common::AudioFormatDescription;
+using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::AudioOffloadInfo;
+using aidl::android::media::audio::common::MicrophoneDynamicInfo;
+using aidl::android::media::audio::common::MicrophoneInfo;
+using android::bluetooth::audio::aidl::BluetoothAudioPortAidl;
+using android::bluetooth::audio::aidl::BluetoothAudioPortAidlIn;
+using android::bluetooth::audio::aidl::BluetoothAudioPortAidlOut;
+using android::bluetooth::audio::aidl::BluetoothStreamState;
 
-using ::aidl::android::hardware::audio::common::SinkMetadata;
-using ::aidl::android::hardware::audio::common::SourceMetadata;
-using ::aidl::android::hardware::audio::core::VendorParameter;
-using ::aidl::android::hardware::bluetooth::audio::ChannelMode;
-using ::aidl::android::hardware::bluetooth::audio::PcmConfiguration;
-using ::aidl::android::hardware::bluetooth::audio::PresentationPosition;
-using ::aidl::android::media::audio::common::AudioChannelLayout;
-using ::aidl::android::media::audio::common::AudioDevice;
-using ::aidl::android::media::audio::common::AudioDeviceAddress;
-using ::aidl::android::media::audio::common::AudioFormatDescription;
-using ::aidl::android::media::audio::common::AudioFormatType;
-using ::aidl::android::media::audio::common::AudioOffloadInfo;
-using ::aidl::android::media::audio::common::MicrophoneDynamicInfo;
-using ::aidl::android::media::audio::common::MicrophoneInfo;
-using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidl;
-using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidlIn;
-using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidlOut;
-using ::android::bluetooth::audio::aidl::BluetoothStreamState;
+namespace aidl::android::hardware::audio::core {
 
 constexpr int kBluetoothDefaultInputBufferMs = 20;
 constexpr int kBluetoothDefaultOutputBufferMs = 10;
 // constexpr int kBluetoothSpatializerOutputBufferMs = 10;
+constexpr int kBluetoothDefaultRemoteDelayMs = 200;
 
-size_t getFrameCount(uint64_t durationUs, uint32_t sampleRate) {
-    return (durationUs * sampleRate) / 1000000;
-}
-
-// pcm configuration params are not really used by the module
 StreamBluetooth::StreamBluetooth(StreamContext* context, const Metadata& metadata,
-                                 Module::BtProfileHandles&& btHandles)
+                                 ModuleBluetooth::BtProfileHandles&& btHandles,
+                                 const std::shared_ptr<BluetoothAudioPortAidl>& btDeviceProxy,
+                                 const PcmConfiguration& pcmConfig)
     : StreamCommonImpl(context, metadata),
-      mSampleRate(getContext().getSampleRate()),
-      mChannelLayout(getContext().getChannelLayout()),
-      mFormat(getContext().getFormat()),
       mFrameSizeBytes(getContext().getFrameSize()),
       mIsInput(isInput(metadata)),
-      mBluetoothA2dp(std::move(std::get<Module::BtInterface::BTA2DP>(btHandles))),
-      mBluetoothLe(std::move(std::get<Module::BtInterface::BTLE>(btHandles))) {
-    mPreferredDataIntervalUs =
-            mIsInput ? kBluetoothDefaultInputBufferMs : kBluetoothDefaultOutputBufferMs;
-    mPreferredFrameCount = getFrameCount(mPreferredDataIntervalUs, mSampleRate);
-    mIsInitialized = false;
-    mIsReadyToClose = false;
-}
+      mBluetoothA2dp(std::move(std::get<ModuleBluetooth::BtInterface::BTA2DP>(btHandles))),
+      mBluetoothLe(std::move(std::get<ModuleBluetooth::BtInterface::BTLE>(btHandles))),
+      mPreferredDataIntervalUs(pcmConfig.dataIntervalUs != 0
+                                       ? pcmConfig.dataIntervalUs
+                                       : (mIsInput ? kBluetoothDefaultInputBufferMs
+                                                   : kBluetoothDefaultOutputBufferMs) *
+                                                 1000),
+      mPreferredFrameCount(
+              frameCountFromDurationUs(mPreferredDataIntervalUs, pcmConfig.sampleRateHz)),
+      mBtDeviceProxy(btDeviceProxy) {}
 
 ::android::status_t StreamBluetooth::init() {
-    return ::android::OK;  // defering this till we get AudioDeviceDescription
-}
-
-const StreamCommonInterface::ConnectedDevices& StreamBluetooth::getConnectedDevices() const {
     std::lock_guard guard(mLock);
-    return StreamCommonImpl::getConnectedDevices();
-}
-
-ndk::ScopedAStatus StreamBluetooth::setConnectedDevices(
-        const std::vector<AudioDevice>& connectedDevices) {
-    if (mIsInput && connectedDevices.size() > 1) {
-        LOG(ERROR) << __func__ << ": wrong device size(" << connectedDevices.size()
-                   << ") for input stream";
-        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    if (mBtDeviceProxy == nullptr) {
+        // This is a normal situation in VTS tests.
+        LOG(INFO) << __func__ << ": no BT HAL proxy, stream is non-functional";
     }
-    for (const auto& connectedDevice : connectedDevices) {
-        if (connectedDevice.address.getTag() != AudioDeviceAddress::mac) {
-            LOG(ERROR) << __func__ << ": bad device address" << connectedDevice.address.toString();
-            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
-        }
-    }
-    std::lock_guard guard(mLock);
-    RETURN_STATUS_IF_ERROR(StreamCommonImpl::setConnectedDevices(connectedDevices));
-    mIsInitialized = false;  // updated connected device list, need initialization
-    return ndk::ScopedAStatus::ok();
+    return ::android::OK;
 }
 
 ::android::status_t StreamBluetooth::drain(StreamDescriptor::DrainMode) {
@@ -115,167 +96,111 @@
 ::android::status_t StreamBluetooth::transfer(void* buffer, size_t frameCount,
                                               size_t* actualFrameCount, int32_t* latencyMs) {
     std::lock_guard guard(mLock);
-    if (!mIsInitialized || mIsReadyToClose) {
-        // 'setConnectedDevices' has been called or stream is ready to close, so no transfers
+    if (mBtDeviceProxy == nullptr || mBtDeviceProxy->getState() == BluetoothStreamState::DISABLED) {
         *actualFrameCount = 0;
         *latencyMs = StreamDescriptor::LATENCY_UNKNOWN;
         return ::android::OK;
     }
     *actualFrameCount = 0;
     *latencyMs = 0;
-    for (auto proxy : mBtDeviceProxies) {
-        if (!proxy->start()) {
-            LOG(ERROR) << __func__ << ": state = " << proxy->getState() << " failed to start ";
-            return -EIO;
-        }
-        const size_t fc = std::min(frameCount, mPreferredFrameCount);
-        const size_t bytesToTransfer = fc * mFrameSizeBytes;
-        if (mIsInput) {
-            const size_t totalRead = proxy->readData(buffer, bytesToTransfer);
-            *actualFrameCount = std::max(*actualFrameCount, totalRead / mFrameSizeBytes);
-        } else {
-            const size_t totalWrite = proxy->writeData(buffer, bytesToTransfer);
-            *actualFrameCount = std::max(*actualFrameCount, totalWrite / mFrameSizeBytes);
-        }
-        PresentationPosition presentation_position;
-        if (!proxy->getPresentationPosition(presentation_position)) {
-            LOG(ERROR) << __func__ << ": getPresentationPosition returned error ";
-            return ::android::UNKNOWN_ERROR;
-        }
-        *latencyMs =
-                std::max(*latencyMs, (int32_t)(presentation_position.remoteDeviceAudioDelayNanos /
-                                               NANOS_PER_MILLISECOND));
+    if (!mBtDeviceProxy->start()) {
+        LOG(ERROR) << __func__ << ": state= " << mBtDeviceProxy->getState() << " failed to start";
+        return -EIO;
     }
+    const size_t fc = std::min(frameCount, mPreferredFrameCount);
+    const size_t bytesToTransfer = fc * mFrameSizeBytes;
+    if (mIsInput) {
+        const size_t totalRead = mBtDeviceProxy->readData(buffer, bytesToTransfer);
+        *actualFrameCount = std::max(*actualFrameCount, totalRead / mFrameSizeBytes);
+    } else {
+        const size_t totalWrite = mBtDeviceProxy->writeData(buffer, bytesToTransfer);
+        *actualFrameCount = std::max(*actualFrameCount, totalWrite / mFrameSizeBytes);
+    }
+    PresentationPosition presentation_position;
+    if (!mBtDeviceProxy->getPresentationPosition(presentation_position)) {
+        presentation_position.remoteDeviceAudioDelayNanos =
+                kBluetoothDefaultRemoteDelayMs * NANOS_PER_MILLISECOND;
+        LOG(WARNING) << __func__ << ": getPresentationPosition failed, latency info is unavailable";
+    }
+    // TODO(b/317117580): incorporate logic from
+    //                    packages/modules/Bluetooth/system/audio_bluetooth_hw/stream_apis.cc
+    //                    out_calculate_feeding_delay_ms / in_calculate_starving_delay_ms
+    *latencyMs = std::max(*latencyMs, (int32_t)(presentation_position.remoteDeviceAudioDelayNanos /
+                                                NANOS_PER_MILLISECOND));
     return ::android::OK;
 }
 
-::android::status_t StreamBluetooth::initialize() {
-    if (!::aidl::android::hardware::bluetooth::audio::BluetoothAudioSession::IsAidlAvailable()) {
-        LOG(ERROR) << __func__ << ": IBluetoothAudioProviderFactory service not available";
-        return ::android::UNKNOWN_ERROR;
-    }
-    if (StreamCommonImpl::getConnectedDevices().empty()) {
-        LOG(ERROR) << __func__ << ", has no connected devices";
-        return ::android::NO_INIT;
-    }
-    // unregister older proxies (if any)
-    for (auto proxy : mBtDeviceProxies) {
-        proxy->stop();
-        proxy->unregisterPort();
-    }
-    mBtDeviceProxies.clear();
-    for (auto it = StreamCommonImpl::getConnectedDevices().begin();
-         it != StreamCommonImpl::getConnectedDevices().end(); ++it) {
-        std::shared_ptr<BluetoothAudioPortAidl> proxy =
-                mIsInput ? std::shared_ptr<BluetoothAudioPortAidl>(
-                                   std::make_shared<BluetoothAudioPortAidlIn>())
-                         : std::shared_ptr<BluetoothAudioPortAidl>(
-                                   std::make_shared<BluetoothAudioPortAidlOut>());
-        if (proxy->registerPort(it->type)) {
-            LOG(ERROR) << __func__ << ": cannot init HAL";
-            return ::android::UNKNOWN_ERROR;
-        }
-        PcmConfiguration config;
-        if (!proxy->loadAudioConfig(&config)) {
-            LOG(ERROR) << __func__ << ": state=" << proxy->getState()
-                       << " failed to get audio config";
-            return ::android::UNKNOWN_ERROR;
-        }
-        // TODO: Ensure minimum duration for spatialized output?
-        // WAR to support Mono / 16 bits per sample as the Bluetooth stack required
-        if (!mIsInput && config.channelMode == ChannelMode::MONO && config.bitsPerSample == 16) {
-            proxy->forcePcmStereoToMono(true);
-            config.channelMode = ChannelMode::STEREO;
-            LOG(INFO) << __func__ << ": force channels = to be AUDIO_CHANNEL_OUT_STEREO";
-        }
-        if (!checkConfigParams(config)) {
-            LOG(ERROR) << __func__ << " checkConfigParams failed";
-            return ::android::UNKNOWN_ERROR;
-        }
-        mBtDeviceProxies.push_back(std::move(proxy));
-    }
-    mIsInitialized = true;
-    return ::android::OK;
-}
-
-bool StreamBluetooth::checkConfigParams(
-        ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& config) {
-    if ((int)mSampleRate != config.sampleRateHz) {
-        LOG(ERROR) << __func__ << ": Sample Rate mismatch, stream val = " << mSampleRate
-                   << " hal val = " << config.sampleRateHz;
+// static
+bool StreamBluetooth::checkConfigParams(const PcmConfiguration& pcmConfig,
+                                        const AudioConfigBase& config) {
+    if ((int)config.sampleRate != pcmConfig.sampleRateHz) {
+        LOG(ERROR) << __func__ << ": sample rate mismatch, stream value=" << config.sampleRate
+                   << ", BT HAL value=" << pcmConfig.sampleRateHz;
         return false;
     }
-    auto channelCount = aidl::android::hardware::audio::common::getChannelCount(mChannelLayout);
-    if ((config.channelMode == ChannelMode::MONO && channelCount != 1) ||
-        (config.channelMode == ChannelMode::STEREO && channelCount != 2)) {
-        LOG(ERROR) << __func__ << ": Channel count mismatch, stream val = " << channelCount
-                   << " hal val = " << toString(config.channelMode);
+    const auto channelCount =
+            aidl::android::hardware::audio::common::getChannelCount(config.channelMask);
+    if ((pcmConfig.channelMode == ChannelMode::MONO && channelCount != 1) ||
+        (pcmConfig.channelMode == ChannelMode::STEREO && channelCount != 2)) {
+        LOG(ERROR) << __func__ << ": Channel count mismatch, stream value=" << channelCount
+                   << ", BT HAL value=" << toString(pcmConfig.channelMode);
         return false;
     }
-    if (mFormat.type != AudioFormatType::PCM) {
-        LOG(ERROR) << __func__ << ": unexpected format type "
-                   << aidl::android::media::audio::common::toString(mFormat.type);
+    if (config.format.type != AudioFormatType::PCM) {
+        LOG(ERROR) << __func__
+                   << ": unexpected stream format type: " << toString(config.format.type);
         return false;
     }
-    int8_t bps = aidl::android::hardware::audio::common::getPcmSampleSizeInBytes(mFormat.pcm) * 8;
-    if (bps != config.bitsPerSample) {
-        LOG(ERROR) << __func__ << ": bits per sample mismatch, stream val = " << bps
-                   << " hal val = " << config.bitsPerSample;
+    const int8_t bitsPerSample =
+            aidl::android::hardware::audio::common::getPcmSampleSizeInBytes(config.format.pcm) * 8;
+    if (bitsPerSample != pcmConfig.bitsPerSample) {
+        LOG(ERROR) << __func__ << ": bits per sample mismatch, stream value=" << bitsPerSample
+                   << ", BT HAL value=" << pcmConfig.bitsPerSample;
         return false;
     }
-    if (config.dataIntervalUs > 0) {
-        mPreferredDataIntervalUs =
-                std::min((int32_t)mPreferredDataIntervalUs, config.dataIntervalUs);
-        mPreferredFrameCount = getFrameCount(mPreferredDataIntervalUs, mSampleRate);
-    }
     return true;
 }
 
 ndk::ScopedAStatus StreamBluetooth::prepareToClose() {
     std::lock_guard guard(mLock);
-    mIsReadyToClose = true;
+    if (mBtDeviceProxy != nullptr) {
+        if (mBtDeviceProxy->getState() != BluetoothStreamState::DISABLED) {
+            mBtDeviceProxy->stop();
+        }
+    }
     return ndk::ScopedAStatus::ok();
 }
 
 ::android::status_t StreamBluetooth::standby() {
     std::lock_guard guard(mLock);
-    if (!mIsInitialized) {
-        if (auto status = initialize(); status != ::android::OK) return status;
-    }
-    for (auto proxy : mBtDeviceProxies) {
-        if (!proxy->suspend()) {
-            LOG(ERROR) << __func__ << ": state = " << proxy->getState() << " failed to stand by ";
-            return -EIO;
-        }
-    }
+    if (mBtDeviceProxy != nullptr) mBtDeviceProxy->suspend();
     return ::android::OK;
 }
 
 ::android::status_t StreamBluetooth::start() {
     std::lock_guard guard(mLock);
-    if (!mIsInitialized) return initialize();
+    if (mBtDeviceProxy != nullptr) mBtDeviceProxy->start();
     return ::android::OK;
 }
 
 void StreamBluetooth::shutdown() {
     std::lock_guard guard(mLock);
-    for (auto proxy : mBtDeviceProxies) {
-        proxy->stop();
-        proxy->unregisterPort();
+    if (mBtDeviceProxy != nullptr) {
+        mBtDeviceProxy->stop();
+        mBtDeviceProxy = nullptr;
     }
-    mBtDeviceProxies.clear();
 }
 
 ndk::ScopedAStatus StreamBluetooth::updateMetadataCommon(const Metadata& metadata) {
     std::lock_guard guard(mLock);
-    if (!mIsInitialized) return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    if (mBtDeviceProxy == nullptr) {
+        return ndk::ScopedAStatus::ok();
+    }
     bool isOk = true;
     if (isInput(metadata)) {
-        isOk = mBtDeviceProxies[0]->updateSinkMetadata(std::get<SinkMetadata>(metadata));
+        isOk = mBtDeviceProxy->updateSinkMetadata(std::get<SinkMetadata>(metadata));
     } else {
-        for (auto proxy : mBtDeviceProxies) {
-            if (!proxy->updateSourceMetadata(std::get<SourceMetadata>(metadata))) isOk = false;
-        }
+        isOk = mBtDeviceProxy->updateSourceMetadata(std::get<SourceMetadata>(metadata));
     }
     return isOk ? ndk::ScopedAStatus::ok()
                 : ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
@@ -283,7 +208,6 @@
 
 ndk::ScopedAStatus StreamBluetooth::bluetoothParametersUpdated() {
     if (mIsInput) {
-        LOG(WARNING) << __func__ << ": not handled";
         return ndk::ScopedAStatus::ok();
     }
     auto applyParam = [](const std::shared_ptr<BluetoothAudioPortAidl>& proxy,
@@ -300,15 +224,10 @@
     bool hasLeParam, enableLe;
     auto btLe = mBluetoothLe.lock();
     hasLeParam = btLe != nullptr && btLe->isEnabled(&enableLe).isOk();
-    std::unique_lock lock(mLock);
-    ::android::base::ScopedLockAssertion lock_assertion(mLock);
-    if (!mIsInitialized) {
-        LOG(WARNING) << __func__ << ": init not done";
-        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-    }
-    for (auto proxy : mBtDeviceProxies) {
-        if ((hasA2dpParam && proxy->isA2dp() && !applyParam(proxy, enableA2dp)) ||
-            (hasLeParam && proxy->isLeAudio() && !applyParam(proxy, enableLe))) {
+    std::lock_guard guard(mLock);
+    if (mBtDeviceProxy != nullptr) {
+        if ((hasA2dpParam && mBtDeviceProxy->isA2dp() && !applyParam(mBtDeviceProxy, enableA2dp)) ||
+            (hasLeParam && mBtDeviceProxy->isLeAudio() && !applyParam(mBtDeviceProxy, enableLe))) {
             LOG(DEBUG) << __func__ << ": applyParam failed";
             return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
         }
@@ -316,11 +235,20 @@
     return ndk::ScopedAStatus::ok();
 }
 
+// static
+int32_t StreamInBluetooth::getNominalLatencyMs(size_t dataIntervalUs) {
+    if (dataIntervalUs == 0) dataIntervalUs = kBluetoothDefaultInputBufferMs * 1000LL;
+    return dataIntervalUs / 1000LL;
+}
+
 StreamInBluetooth::StreamInBluetooth(StreamContext&& context, const SinkMetadata& sinkMetadata,
                                      const std::vector<MicrophoneInfo>& microphones,
-                                     Module::BtProfileHandles&& btProfileHandles)
+                                     ModuleBluetooth::BtProfileHandles&& btProfileHandles,
+                                     const std::shared_ptr<BluetoothAudioPortAidl>& btDeviceProxy,
+                                     const PcmConfiguration& pcmConfig)
     : StreamIn(std::move(context), microphones),
-      StreamBluetooth(&mContextInstance, sinkMetadata, std::move(btProfileHandles)) {}
+      StreamBluetooth(&mContextInstance, sinkMetadata, std::move(btProfileHandles), btDeviceProxy,
+                      pcmConfig) {}
 
 ndk::ScopedAStatus StreamInBluetooth::getActiveMicrophones(
         std::vector<MicrophoneDynamicInfo>* _aidl_return __unused) {
@@ -328,11 +256,20 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
+// static
+int32_t StreamOutBluetooth::getNominalLatencyMs(size_t dataIntervalUs) {
+    if (dataIntervalUs == 0) dataIntervalUs = kBluetoothDefaultOutputBufferMs * 1000LL;
+    return dataIntervalUs / 1000LL;
+}
+
 StreamOutBluetooth::StreamOutBluetooth(StreamContext&& context,
                                        const SourceMetadata& sourceMetadata,
                                        const std::optional<AudioOffloadInfo>& offloadInfo,
-                                       Module::BtProfileHandles&& btProfileHandles)
+                                       ModuleBluetooth::BtProfileHandles&& btProfileHandles,
+                                       const std::shared_ptr<BluetoothAudioPortAidl>& btDeviceProxy,
+                                       const PcmConfiguration& pcmConfig)
     : StreamOut(std::move(context), offloadInfo),
-      StreamBluetooth(&mContextInstance, sourceMetadata, std::move(btProfileHandles)) {}
+      StreamBluetooth(&mContextInstance, sourceMetadata, std::move(btProfileHandles), btDeviceProxy,
+                      pcmConfig) {}
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/downmix/Android.bp b/audio/aidl/default/downmix/Android.bp
index 6d15cdb..8657283 100644
--- a/audio/aidl/default/downmix/Android.bp
+++ b/audio/aidl/default/downmix/Android.bp
@@ -27,8 +27,6 @@
     name: "libdownmixsw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "DownmixSw.cpp",
diff --git a/audio/aidl/default/dynamicProcessing/Android.bp b/audio/aidl/default/dynamicProcessing/Android.bp
index 1c0312d..c0a648d 100644
--- a/audio/aidl/default/dynamicProcessing/Android.bp
+++ b/audio/aidl/default/dynamicProcessing/Android.bp
@@ -27,8 +27,6 @@
     name: "libdynamicsprocessingsw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "DynamicsProcessingSw.cpp",
diff --git a/audio/aidl/default/envReverb/Android.bp b/audio/aidl/default/envReverb/Android.bp
index dd4219a..2443c2a 100644
--- a/audio/aidl/default/envReverb/Android.bp
+++ b/audio/aidl/default/envReverb/Android.bp
@@ -27,8 +27,6 @@
     name: "libenvreverbsw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "EnvReverbSw.cpp",
diff --git a/audio/aidl/default/equalizer/Android.bp b/audio/aidl/default/equalizer/Android.bp
index 3610563..42708d1 100644
--- a/audio/aidl/default/equalizer/Android.bp
+++ b/audio/aidl/default/equalizer/Android.bp
@@ -27,8 +27,6 @@
     name: "libequalizersw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "EqualizerSw.cpp",
diff --git a/audio/aidl/default/extension/Android.bp b/audio/aidl/default/extension/Android.bp
index 4e5d352..5fee479 100644
--- a/audio/aidl/default/extension/Android.bp
+++ b/audio/aidl/default/extension/Android.bp
@@ -27,8 +27,6 @@
     name: "libextensioneffect",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "ExtensionEffect.cpp",
diff --git a/audio/aidl/default/hapticGenerator/Android.bp b/audio/aidl/default/hapticGenerator/Android.bp
index 0df9a94..8fb9a3d 100644
--- a/audio/aidl/default/hapticGenerator/Android.bp
+++ b/audio/aidl/default/hapticGenerator/Android.bp
@@ -27,8 +27,6 @@
     name: "libhapticgeneratorsw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "HapticGeneratorSw.cpp",
diff --git a/audio/aidl/default/include/core-impl/Bluetooth.h b/audio/aidl/default/include/core-impl/Bluetooth.h
index 44899bc..002cb19 100644
--- a/audio/aidl/default/include/core-impl/Bluetooth.h
+++ b/audio/aidl/default/include/core-impl/Bluetooth.h
@@ -46,9 +46,9 @@
 class BluetoothA2dp : public BnBluetoothA2dp, public ParamChangeHandler {
   public:
     BluetoothA2dp() = default;
+    ndk::ScopedAStatus isEnabled(bool* _aidl_return) override;
 
   private:
-    ndk::ScopedAStatus isEnabled(bool* _aidl_return) override;
     ndk::ScopedAStatus setEnabled(bool in_enabled) override;
     ndk::ScopedAStatus supportsOffloadReconfiguration(bool* _aidl_return) override;
     ndk::ScopedAStatus reconfigureOffload(
@@ -61,9 +61,9 @@
 class BluetoothLe : public BnBluetoothLe, public ParamChangeHandler {
   public:
     BluetoothLe() = default;
+    ndk::ScopedAStatus isEnabled(bool* _aidl_return) override;
 
   private:
-    ndk::ScopedAStatus isEnabled(bool* _aidl_return) override;
     ndk::ScopedAStatus setEnabled(bool in_enabled) override;
     ndk::ScopedAStatus supportsOffloadReconfiguration(bool* _aidl_return) override;
     ndk::ScopedAStatus reconfigureOffload(
diff --git a/audio/aidl/default/include/core-impl/ChildInterface.h b/audio/aidl/default/include/core-impl/ChildInterface.h
index 3b74c5e..f5f1855 100644
--- a/audio/aidl/default/include/core-impl/ChildInterface.h
+++ b/audio/aidl/default/include/core-impl/ChildInterface.h
@@ -40,6 +40,7 @@
     explicit operator bool() const { return !!this->first; }
     C& operator*() const { return *(this->first); }
     C* operator->() const { return this->first; }
+    std::shared_ptr<C> getPtr() { return this->first; }
     // Use 'getInstance' when returning the interface instance.
     std::shared_ptr<C> getInstance() {
         (void)getBinder();
diff --git a/audio/aidl/default/include/core-impl/DevicePortProxy.h b/audio/aidl/default/include/core-impl/DevicePortProxy.h
index 13b8c91..ccb23bb 100644
--- a/audio/aidl/default/include/core-impl/DevicePortProxy.h
+++ b/audio/aidl/default/include/core-impl/DevicePortProxy.h
@@ -25,11 +25,10 @@
 #include <aidl/android/hardware/audio/common/SourceMetadata.h>
 #include <aidl/android/hardware/bluetooth/audio/BluetoothAudioStatus.h>
 #include <aidl/android/hardware/bluetooth/audio/PcmConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/PresentationPosition.h>
 #include <aidl/android/hardware/bluetooth/audio/SessionType.h>
 #include <aidl/android/media/audio/common/AudioDeviceDescription.h>
 
-#include "BluetoothAudioSessionControl.h"
-
 namespace android::bluetooth::audio::aidl {
 
 enum class BluetoothStreamState : uint8_t {
@@ -74,12 +73,7 @@
      * Bluetooth stack
      */
     virtual bool loadAudioConfig(
-            ::aidl::android::hardware::bluetooth::audio::PcmConfiguration*) const = 0;
-
-    /**
-     * WAR to support Mono mode / 16 bits per sample
-     */
-    virtual void forcePcmStereoToMono(bool) = 0;
+            ::aidl::android::hardware::bluetooth::audio::PcmConfiguration&) = 0;
 
     /**
      * When the Audio framework / HAL wants to change the stream state, it invokes
@@ -146,7 +140,7 @@
 
     virtual bool isLeAudio() const = 0;
 
-    virtual bool getPreferredDataIntervalUs(size_t*) const = 0;
+    virtual bool getPreferredDataIntervalUs(size_t&) const = 0;
 
     virtual size_t writeData(const void*, size_t) const { return 0; }
 
@@ -163,10 +157,8 @@
 
     void unregisterPort() override;
 
-    bool loadAudioConfig(::aidl::android::hardware::bluetooth::audio::PcmConfiguration* audio_cfg)
-            const override;
-
-    void forcePcmStereoToMono(bool force) override { mIsStereoToMono = force; }
+    bool loadAudioConfig(
+            ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& audio_cfg) override;
 
     bool standby() override;
     bool start() override;
@@ -194,7 +186,7 @@
 
     bool isLeAudio() const override;
 
-    bool getPreferredDataIntervalUs(size_t* interval_us) const override;
+    bool getPreferredDataIntervalUs(size_t& interval_us) const override;
 
   protected:
     uint16_t mCookie;
@@ -229,6 +221,9 @@
 
 class BluetoothAudioPortAidlOut : public BluetoothAudioPortAidl {
   public:
+    bool loadAudioConfig(
+            ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& audio_cfg) override;
+
     // The audio data path to the Bluetooth stack (Software encoding)
     size_t writeData(const void* buffer, size_t bytes) const override;
 };
@@ -239,4 +234,4 @@
     size_t readData(void* buffer, size_t bytes) const override;
 };
 
-}  // namespace android::bluetooth::audio::aidl
\ No newline at end of file
+}  // namespace android::bluetooth::audio::aidl
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index 718c07d..ce71d70 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -16,12 +16,14 @@
 
 #pragma once
 
+#include <functional>
 #include <iostream>
 #include <map>
 #include <memory>
 #include <optional>
 #include <set>
 
+#include <Utils.h>
 #include <aidl/android/hardware/audio/core/BnModule.h>
 
 #include "core-impl/ChildInterface.h"
@@ -45,13 +47,6 @@
         int32_t nextPatchId = 1;
     };
     enum Type : int { DEFAULT, R_SUBMIX, STUB, USB, BLUETOOTH };
-    enum BtInterface : int { BTCONF, BTA2DP, BTLE };
-    typedef std::tuple<std::weak_ptr<IBluetooth>, std::weak_ptr<IBluetoothA2dp>,
-                       std::weak_ptr<IBluetoothLe>>
-            BtProfileHandles;
-
-    // This value is used by default for all AudioPatches and reported by all streams.
-    static constexpr int32_t kLatencyMs = 10;
 
     static std::shared_ptr<Module> createInstance(Type type) {
         return createInstance(type, std::make_unique<Configuration>());
@@ -76,6 +71,7 @@
             const ::aidl::android::media::audio::common::AudioPort& in_templateIdAndAdditionalData,
             ::aidl::android::media::audio::common::AudioPort* _aidl_return) override;
     ndk::ScopedAStatus disconnectExternalDevice(int32_t in_portId) override;
+    ndk::ScopedAStatus prepareToDisconnectExternalDevice(int32_t in_portId) override;
     ndk::ScopedAStatus getAudioPatches(std::vector<AudioPatch>* _aidl_return) override;
     ndk::ScopedAStatus getAudioPort(
             int32_t in_portId,
@@ -145,8 +141,6 @@
     ndk::ScopedAStatus getAAudioMixerBurstCount(int32_t* _aidl_return) override;
     ndk::ScopedAStatus getAAudioHardwareBurstMinUsec(int32_t* _aidl_return) override;
 
-    // This value is used for all AudioPatches.
-    static constexpr int32_t kMinimumStreamBufferSizeFrames = 256;
     // The maximum stream buffer size is 1 GiB = 2 ** 30 bytes;
     static constexpr int32_t kMaximumStreamBufferSizeBytes = 1 << 30;
 
@@ -175,7 +169,7 @@
     bool mMicMute = false;
     bool mMasterMute = false;
     float mMasterVolume = 1.0f;
-    ChildInterface<sounddose::ISoundDose> mSoundDose;
+    ChildInterface<sounddose::SoundDose> mSoundDose;
     std::optional<bool> mIsMmapSupported;
 
   protected:
@@ -195,7 +189,7 @@
     // If the module is unable to populate the connected device port correctly, the returned error
     // code must correspond to the errors of `IModule.connectedExternalDevice` method.
     virtual ndk::ScopedAStatus populateConnectedDevicePort(
-            ::aidl::android::media::audio::common::AudioPort* audioPort);
+            ::aidl::android::media::audio::common::AudioPort* audioPort, int32_t nextPortId);
     // If the module finds that the patch endpoints configurations are not matched, the returned
     // error code must correspond to the errors of `IModule.setAudioPatch` method.
     virtual ndk::ScopedAStatus checkAudioPatchEndpointsMatch(
@@ -203,12 +197,26 @@
             const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks);
     virtual void onExternalDeviceConnectionChanged(
             const ::aidl::android::media::audio::common::AudioPort& audioPort, bool connected);
+    virtual void onPrepareToDisconnectExternalDevice(
+            const ::aidl::android::media::audio::common::AudioPort& audioPort);
     virtual ndk::ScopedAStatus onMasterMuteChanged(bool mute);
     virtual ndk::ScopedAStatus onMasterVolumeChanged(float volume);
     virtual std::vector<::aidl::android::media::audio::common::MicrophoneInfo> getMicrophoneInfos();
     virtual std::unique_ptr<Configuration> initializeConfig();
+    virtual int32_t getNominalLatencyMs(
+            const ::aidl::android::media::audio::common::AudioPortConfig& portConfig);
 
     // Utility and helper functions accessible to subclasses.
+    static int32_t calculateBufferSizeFrames(int32_t latencyMs, int32_t sampleRateHz) {
+        const int32_t rawSizeFrames =
+                aidl::android::hardware::audio::common::frameCountFromDurationMs(latencyMs,
+                                                                                 sampleRateHz);
+        if (latencyMs >= 5) return rawSizeFrames;
+        int32_t powerOf2 = 1;
+        while (powerOf2 < rawSizeFrames) powerOf2 <<= 1;
+        return powerOf2;
+    }
+
     ndk::ScopedAStatus bluetoothParametersUpdated();
     void cleanUpPatch(int32_t patchId);
     ndk::ScopedAStatus createStreamContext(
@@ -221,13 +229,16 @@
     std::set<int32_t> findConnectedPortConfigIds(int32_t portConfigId);
     ndk::ScopedAStatus findPortIdForNewStream(
             int32_t in_portConfigId, ::aidl::android::media::audio::common::AudioPort** port);
+    // Note: does not assign an ID to the config.
+    bool generateDefaultPortConfig(const ::aidl::android::media::audio::common::AudioPort& port,
+                                   ::aidl::android::media::audio::common::AudioPortConfig* config);
     std::vector<AudioRoute*> getAudioRoutesForAudioPortImpl(int32_t portId);
-    virtual BtProfileHandles getBtProfileManagerHandles();
     Configuration& getConfig();
     const ConnectedDevicePorts& getConnectedDevicePorts() const { return mConnectedDevicePorts; }
     bool getMasterMute() const { return mMasterMute; }
     bool getMasterVolume() const { return mMasterVolume; }
     bool getMicMute() const { return mMicMute; }
+    const ModuleDebug& getModuleDebug() const { return mDebug; }
     const Patches& getPatches() const { return mPatches; }
     std::set<int32_t> getRoutableAudioPortIds(int32_t portId,
                                               std::vector<AudioRoute*>* routes = nullptr);
@@ -238,6 +249,12 @@
     template <typename C>
     std::set<int32_t> portIdsFromPortConfigIds(C portConfigIds);
     void registerPatch(const AudioPatch& patch);
+    ndk::ScopedAStatus setAudioPortConfigImpl(
+            const ::aidl::android::media::audio::common::AudioPortConfig& in_requested,
+            const std::function<bool(const ::aidl::android::media::audio::common::AudioPort& port,
+                                     ::aidl::android::media::audio::common::AudioPortConfig*
+                                             config)>& fillPortConfig,
+            ::aidl::android::media::audio::common::AudioPortConfig* out_suggested, bool* applied);
     ndk::ScopedAStatus updateStreamsConnectedState(const AudioPatch& oldPatch,
                                                    const AudioPatch& newPatch);
 };
diff --git a/audio/aidl/default/include/core-impl/ModuleAlsa.h b/audio/aidl/default/include/core-impl/ModuleAlsa.h
index 2774fe5..3392b41 100644
--- a/audio/aidl/default/include/core-impl/ModuleAlsa.h
+++ b/audio/aidl/default/include/core-impl/ModuleAlsa.h
@@ -33,7 +33,8 @@
   protected:
     // Extension methods of 'Module'.
     ndk::ScopedAStatus populateConnectedDevicePort(
-            ::aidl::android::media::audio::common::AudioPort* audioPort) override;
+            ::aidl::android::media::audio::common::AudioPort* audioPort,
+            int32_t nextPortId) override;
 };
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/ModuleBluetooth.h b/audio/aidl/default/include/core-impl/ModuleBluetooth.h
index 7ac2d34..9451411 100644
--- a/audio/aidl/default/include/core-impl/ModuleBluetooth.h
+++ b/audio/aidl/default/include/core-impl/ModuleBluetooth.h
@@ -16,24 +16,49 @@
 
 #pragma once
 
+#include <map>
+
 #include "core-impl/Bluetooth.h"
+#include "core-impl/DevicePortProxy.h"
 #include "core-impl/Module.h"
 
 namespace aidl::android::hardware::audio::core {
 
 class ModuleBluetooth final : public Module {
   public:
-    ModuleBluetooth(std::unique_ptr<Configuration>&& config)
-        : Module(Type::BLUETOOTH, std::move(config)) {}
+    enum BtInterface : int { BTSCO, BTA2DP, BTLE };
+    typedef std::tuple<std::weak_ptr<IBluetooth>, std::weak_ptr<IBluetoothA2dp>,
+                       std::weak_ptr<IBluetoothLe>>
+            BtProfileHandles;
+
+    ModuleBluetooth(std::unique_ptr<Configuration>&& config);
 
   private:
-    BtProfileHandles getBtProfileManagerHandles() override;
+    struct CachedProxy {
+        std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl> ptr;
+        ::aidl::android::hardware::bluetooth::audio::PcmConfiguration pcmConfig;
+    };
+
+    ChildInterface<BluetoothA2dp>& getBtA2dp();
+    ChildInterface<BluetoothLe>& getBtLe();
+    BtProfileHandles getBtProfileManagerHandles();
 
     ndk::ScopedAStatus getBluetoothA2dp(std::shared_ptr<IBluetoothA2dp>* _aidl_return) override;
     ndk::ScopedAStatus getBluetoothLe(std::shared_ptr<IBluetoothLe>* _aidl_return) override;
     ndk::ScopedAStatus getMicMute(bool* _aidl_return) override;
     ndk::ScopedAStatus setMicMute(bool in_mute) override;
 
+    ndk::ScopedAStatus setAudioPortConfig(
+            const ::aidl::android::media::audio::common::AudioPortConfig& in_requested,
+            ::aidl::android::media::audio::common::AudioPortConfig* out_suggested,
+            bool* _aidl_return) override;
+
+    ndk::ScopedAStatus checkAudioPatchEndpointsMatch(
+            const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sources,
+            const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks)
+            override;
+    void onExternalDeviceConnectionChanged(
+            const ::aidl::android::media::audio::common::AudioPort& audioPort, bool connected);
     ndk::ScopedAStatus createInputStream(
             StreamContext&& context,
             const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
@@ -46,12 +71,24 @@
                     offloadInfo,
             std::shared_ptr<StreamOut>* result) override;
     ndk::ScopedAStatus populateConnectedDevicePort(
-            ::aidl::android::media::audio::common::AudioPort* audioPort) override;
+            ::aidl::android::media::audio::common::AudioPort* audioPort,
+            int32_t nextPortId) override;
     ndk::ScopedAStatus onMasterMuteChanged(bool mute) override;
     ndk::ScopedAStatus onMasterVolumeChanged(float volume) override;
+    int32_t getNominalLatencyMs(
+            const ::aidl::android::media::audio::common::AudioPortConfig& portConfig) override;
 
-    ChildInterface<IBluetoothA2dp> mBluetoothA2dp;
-    ChildInterface<IBluetoothLe> mBluetoothLe;
+    ndk::ScopedAStatus createProxy(
+            const ::aidl::android::media::audio::common::AudioPort& audioPort,
+            int32_t instancePortId, CachedProxy& proxy);
+    ndk::ScopedAStatus fetchAndCheckProxy(const StreamContext& context, CachedProxy& proxy);
+    ndk::ScopedAStatus findOrCreateProxy(
+            const ::aidl::android::media::audio::common::AudioPort& audioPort, CachedProxy& proxy);
+
+    ChildInterface<BluetoothA2dp> mBluetoothA2dp;
+    ChildInterface<BluetoothLe> mBluetoothLe;
+    std::map<int32_t /*instantiated device port ID*/, CachedProxy> mProxies;
+    std::map<int32_t /*mix port handle*/, int32_t /*instantiated device port ID*/> mConnections;
 };
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/ModulePrimary.h b/audio/aidl/default/include/core-impl/ModulePrimary.h
index ee86d64..82c8a03 100644
--- a/audio/aidl/default/include/core-impl/ModulePrimary.h
+++ b/audio/aidl/default/include/core-impl/ModulePrimary.h
@@ -39,6 +39,8 @@
             const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
                     offloadInfo,
             std::shared_ptr<StreamOut>* result) override;
+    int32_t getNominalLatencyMs(
+            const ::aidl::android::media::audio::common::AudioPortConfig& portConfig) override;
 
   private:
     ChildInterface<ITelephony> mTelephony;
diff --git a/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h b/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h
index ebf4558..613ac62 100644
--- a/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h
+++ b/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h
@@ -29,6 +29,10 @@
     // IModule interfaces
     ndk::ScopedAStatus getMicMute(bool* _aidl_return) override;
     ndk::ScopedAStatus setMicMute(bool in_mute) override;
+    ndk::ScopedAStatus setAudioPortConfig(
+            const ::aidl::android::media::audio::common::AudioPortConfig& in_requested,
+            ::aidl::android::media::audio::common::AudioPortConfig* out_suggested,
+            bool* _aidl_return) override;
 
     // Module interfaces
     ndk::ScopedAStatus createInputStream(
@@ -43,13 +47,17 @@
                     offloadInfo,
             std::shared_ptr<StreamOut>* result) override;
     ndk::ScopedAStatus populateConnectedDevicePort(
-            ::aidl::android::media::audio::common::AudioPort* audioPort) override;
+            ::aidl::android::media::audio::common::AudioPort* audioPort,
+            int32_t nextPortId) override;
     ndk::ScopedAStatus checkAudioPatchEndpointsMatch(
             const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sources,
             const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks)
             override;
     ndk::ScopedAStatus onMasterMuteChanged(bool mute) override;
     ndk::ScopedAStatus onMasterVolumeChanged(float volume) override;
+    int32_t getNominalLatencyMs(
+            const ::aidl::android::media::audio::common::AudioPortConfig& portConfig) override;
+    // TODO(b/307586684): Report proper minimum stream buffer size by overriding 'setAudioPatch'.
 };
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/ModuleUsb.h b/audio/aidl/default/include/core-impl/ModuleUsb.h
index 6ee8f8a..d9ac4f0 100644
--- a/audio/aidl/default/include/core-impl/ModuleUsb.h
+++ b/audio/aidl/default/include/core-impl/ModuleUsb.h
@@ -44,7 +44,8 @@
                     offloadInfo,
             std::shared_ptr<StreamOut>* result) override;
     ndk::ScopedAStatus populateConnectedDevicePort(
-            ::aidl::android::media::audio::common::AudioPort* audioPort) override;
+            ::aidl::android::media::audio::common::AudioPort* audioPort,
+            int32_t nextPortId) override;
     ndk::ScopedAStatus checkAudioPatchEndpointsMatch(
             const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sources,
             const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks)
diff --git a/audio/aidl/default/include/core-impl/SoundDose.h b/audio/aidl/default/include/core-impl/SoundDose.h
index 2a069d9..c0edc9f 100644
--- a/audio/aidl/default/include/core-impl/SoundDose.h
+++ b/audio/aidl/default/include/core-impl/SoundDose.h
@@ -20,11 +20,23 @@
 
 #include <aidl/android/hardware/audio/core/sounddose/BnSoundDose.h>
 #include <aidl/android/media/audio/common/AudioDevice.h>
-
-using aidl::android::media::audio::common::AudioDevice;
+#include <aidl/android/media/audio/common/AudioFormatDescription.h>
 
 namespace aidl::android::hardware::audio::core::sounddose {
 
+// Interface used for processing the data received by a stream.
+class StreamDataProcessorInterface {
+  public:
+    virtual ~StreamDataProcessorInterface() = default;
+
+    virtual void startDataProcessor(
+            uint32_t samplerate, uint32_t channelCount,
+            const ::aidl::android::media::audio::common::AudioFormatDescription& format) = 0;
+    virtual void setAudioDevice(
+            const ::aidl::android::media::audio::common::AudioDevice& audioDevice) = 0;
+    virtual void process(const void* buffer, size_t size) = 0;
+};
+
 class SoundDose : public BnSoundDose {
   public:
     SoundDose() : mRs2Value(DEFAULT_MAX_RS2){};
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index 88fddec..aa9fb19 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -44,6 +44,7 @@
 #include <utils/Errors.h>
 
 #include "core-impl/ChildInterface.h"
+#include "core-impl/SoundDose.h"
 #include "core-impl/utils.h"
 
 namespace aidl::android::hardware::audio::core {
@@ -80,59 +81,28 @@
 
     StreamContext() = default;
     StreamContext(std::unique_ptr<CommandMQ> commandMQ, std::unique_ptr<ReplyMQ> replyMQ,
-                  int portId,
                   const ::aidl::android::media::audio::common::AudioFormatDescription& format,
                   const ::aidl::android::media::audio::common::AudioChannelLayout& channelLayout,
                   int sampleRate, const ::aidl::android::media::audio::common::AudioIoFlags& flags,
-                  int32_t mixPortHandle, std::unique_ptr<DataMQ> dataMQ,
+                  int32_t nominalLatencyMs, int32_t mixPortHandle, std::unique_ptr<DataMQ> dataMQ,
                   std::shared_ptr<IStreamCallback> asyncCallback,
                   std::shared_ptr<IStreamOutEventCallback> outEventCallback,
+                  std::weak_ptr<sounddose::StreamDataProcessorInterface> streamDataProcessor,
                   DebugParameters debugParameters)
         : mCommandMQ(std::move(commandMQ)),
           mInternalCommandCookie(std::rand()),
           mReplyMQ(std::move(replyMQ)),
-          mPortId(portId),
           mFormat(format),
           mChannelLayout(channelLayout),
           mSampleRate(sampleRate),
           mFlags(flags),
+          mNominalLatencyMs(nominalLatencyMs),
           mMixPortHandle(mixPortHandle),
           mDataMQ(std::move(dataMQ)),
           mAsyncCallback(asyncCallback),
           mOutEventCallback(outEventCallback),
+          mStreamDataProcessor(streamDataProcessor),
           mDebugParameters(debugParameters) {}
-    StreamContext(StreamContext&& other)
-        : mCommandMQ(std::move(other.mCommandMQ)),
-          mInternalCommandCookie(other.mInternalCommandCookie),
-          mReplyMQ(std::move(other.mReplyMQ)),
-          mPortId(other.mPortId),
-          mFormat(other.mFormat),
-          mChannelLayout(other.mChannelLayout),
-          mSampleRate(other.mSampleRate),
-          mFlags(std::move(other.mFlags)),
-          mMixPortHandle(other.mMixPortHandle),
-          mDataMQ(std::move(other.mDataMQ)),
-          mAsyncCallback(std::move(other.mAsyncCallback)),
-          mOutEventCallback(std::move(other.mOutEventCallback)),
-          mDebugParameters(std::move(other.mDebugParameters)),
-          mFrameCount(other.mFrameCount) {}
-    StreamContext& operator=(StreamContext&& other) {
-        mCommandMQ = std::move(other.mCommandMQ);
-        mInternalCommandCookie = other.mInternalCommandCookie;
-        mReplyMQ = std::move(other.mReplyMQ);
-        mPortId = std::move(other.mPortId);
-        mFormat = std::move(other.mFormat);
-        mChannelLayout = std::move(other.mChannelLayout);
-        mSampleRate = other.mSampleRate;
-        mFlags = std::move(other.mFlags);
-        mMixPortHandle = other.mMixPortHandle;
-        mDataMQ = std::move(other.mDataMQ);
-        mAsyncCallback = std::move(other.mAsyncCallback);
-        mOutEventCallback = std::move(other.mOutEventCallback);
-        mDebugParameters = std::move(other.mDebugParameters);
-        mFrameCount = other.mFrameCount;
-        return *this;
-    }
 
     void fillDescriptor(StreamDescriptor* desc);
     std::shared_ptr<IStreamCallback> getAsyncCallback() const { return mAsyncCallback; }
@@ -151,10 +121,14 @@
     size_t getFrameSize() const;
     int getInternalCommandCookie() const { return mInternalCommandCookie; }
     int32_t getMixPortHandle() const { return mMixPortHandle; }
+    int32_t getNominalLatencyMs() const { return mNominalLatencyMs; }
     std::shared_ptr<IStreamOutEventCallback> getOutEventCallback() const {
         return mOutEventCallback;
     }
-    int getPortId() const { return mPortId; }
+    std::weak_ptr<sounddose::StreamDataProcessorInterface> getStreamDataProcessor() const {
+        return mStreamDataProcessor;
+    }
+    void startStreamDataProcessor();
     ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
     int getTransientStateDelayMs() const { return mDebugParameters.transientStateDelayMs; }
     int getSampleRate() const { return mSampleRate; }
@@ -167,18 +141,20 @@
     long getFrameCount() const { return mFrameCount; }
 
   private:
+    // Fields are non const to allow move assignment.
     std::unique_ptr<CommandMQ> mCommandMQ;
     int mInternalCommandCookie;  // The value used to confirm that the command was posted internally
     std::unique_ptr<ReplyMQ> mReplyMQ;
-    int mPortId;
     ::aidl::android::media::audio::common::AudioFormatDescription mFormat;
     ::aidl::android::media::audio::common::AudioChannelLayout mChannelLayout;
     int mSampleRate;
     ::aidl::android::media::audio::common::AudioIoFlags mFlags;
+    int32_t mNominalLatencyMs;
     int32_t mMixPortHandle;
     std::unique_ptr<DataMQ> mDataMQ;
     std::shared_ptr<IStreamCallback> mAsyncCallback;
     std::shared_ptr<IStreamOutEventCallback> mOutEventCallback;  // Only used by output streams
+    std::weak_ptr<sounddose::StreamDataProcessorInterface> mStreamDataProcessor;
     DebugParameters mDebugParameters;
     long mFrameCount = 0;
 };
diff --git a/audio/aidl/default/include/core-impl/StreamBluetooth.h b/audio/aidl/default/include/core-impl/StreamBluetooth.h
index c2f8c1d..35c3183 100644
--- a/audio/aidl/default/include/core-impl/StreamBluetooth.h
+++ b/audio/aidl/default/include/core-impl/StreamBluetooth.h
@@ -24,15 +24,23 @@
 #include <aidl/android/hardware/audio/core/IBluetoothLe.h>
 
 #include "core-impl/DevicePortProxy.h"
-#include "core-impl/Module.h"
+#include "core-impl/ModuleBluetooth.h"
 #include "core-impl/Stream.h"
 
 namespace aidl::android::hardware::audio::core {
 
 class StreamBluetooth : public StreamCommonImpl {
   public:
-    StreamBluetooth(StreamContext* context, const Metadata& metadata,
-                    Module::BtProfileHandles&& btHandles);
+    static bool checkConfigParams(
+            const ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& pcmConfig,
+            const ::aidl::android::media::audio::common::AudioConfigBase& config);
+
+    StreamBluetooth(
+            StreamContext* context, const Metadata& metadata,
+            ModuleBluetooth::BtProfileHandles&& btHandles,
+            const std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl>&
+                    btDeviceProxy,
+            const ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& pcmConfig);
     // Methods of 'DriverInterface'.
     ::android::status_t init() override;
     ::android::status_t drain(StreamDescriptor::DrainMode) override;
@@ -47,40 +55,35 @@
     // Overridden methods of 'StreamCommonImpl', called on a Binder thread.
     ndk::ScopedAStatus updateMetadataCommon(const Metadata& metadata) override;
     ndk::ScopedAStatus prepareToClose() override;
-    const ConnectedDevices& getConnectedDevices() const override;
-    ndk::ScopedAStatus setConnectedDevices(const ConnectedDevices& devices) override;
     ndk::ScopedAStatus bluetoothParametersUpdated() override;
 
   private:
-    // Audio Pcm Config
-    const uint32_t mSampleRate;
-    const ::aidl::android::media::audio::common::AudioChannelLayout mChannelLayout;
-    const ::aidl::android::media::audio::common::AudioFormatDescription mFormat;
     const size_t mFrameSizeBytes;
     const bool mIsInput;
     const std::weak_ptr<IBluetoothA2dp> mBluetoothA2dp;
     const std::weak_ptr<IBluetoothLe> mBluetoothLe;
-    size_t mPreferredDataIntervalUs;
-    size_t mPreferredFrameCount;
-
+    const size_t mPreferredDataIntervalUs;
+    const size_t mPreferredFrameCount;
     mutable std::mutex mLock;
-    bool mIsInitialized GUARDED_BY(mLock);
-    bool mIsReadyToClose GUARDED_BY(mLock);
-    std::vector<std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl>>
-            mBtDeviceProxies GUARDED_BY(mLock);
-
-    ::android::status_t initialize() REQUIRES(mLock);
-    bool checkConfigParams(::aidl::android::hardware::bluetooth::audio::PcmConfiguration& config);
+    // The lock is also used to serialize calls to the proxy.
+    std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl> mBtDeviceProxy
+            GUARDED_BY(mLock);  // proxy may be null if the stream is not connected to a device
 };
 
 class StreamInBluetooth final : public StreamIn, public StreamBluetooth {
   public:
     friend class ndk::SharedRefBase;
+
+    static int32_t getNominalLatencyMs(size_t dataIntervalUs);
+
     StreamInBluetooth(
             StreamContext&& context,
             const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
-            Module::BtProfileHandles&& btHandles);
+            ModuleBluetooth::BtProfileHandles&& btHandles,
+            const std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl>&
+                    btDeviceProxy,
+            const ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& pcmConfig);
 
   private:
     void onClose(StreamDescriptor::State) override { defaultOnClose(); }
@@ -92,12 +95,18 @@
 class StreamOutBluetooth final : public StreamOut, public StreamBluetooth {
   public:
     friend class ndk::SharedRefBase;
+
+    static int32_t getNominalLatencyMs(size_t dataIntervalUs);
+
     StreamOutBluetooth(
             StreamContext&& context,
             const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
                     offloadInfo,
-            Module::BtProfileHandles&& btHandles);
+            ModuleBluetooth::BtProfileHandles&& btHandles,
+            const std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl>&
+                    btDeviceProxy,
+            const ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& pcmConfig);
 
   private:
     void onClose(StreamDescriptor::State) override { defaultOnClose(); }
diff --git a/audio/aidl/default/include/core-impl/StreamPrimary.h b/audio/aidl/default/include/core-impl/StreamPrimary.h
index b3ddd0b..8d5c57d 100644
--- a/audio/aidl/default/include/core-impl/StreamPrimary.h
+++ b/audio/aidl/default/include/core-impl/StreamPrimary.h
@@ -27,10 +27,18 @@
   public:
     StreamPrimary(StreamContext* context, const Metadata& metadata);
 
+    ::android::status_t start() override;
+    ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
+                                 int32_t* latencyMs) override;
+    ::android::status_t refinePosition(StreamDescriptor::Position* position) override;
+
   protected:
     std::vector<alsa::DeviceProfile> getDeviceProfiles() override;
 
-    const bool mIsInput;
+    const bool mIsAsynchronous;
+    int64_t mStartTimeNs = 0;
+    long mFramesSinceStart = 0;
+    bool mSkipNextTransfer = false;
 };
 
 class StreamInPrimary final : public StreamIn, public StreamSwitcher, public StreamInHwGainHelper {
@@ -79,6 +87,10 @@
 
     ndk::ScopedAStatus getHwVolume(std::vector<float>* _aidl_return) override;
     ndk::ScopedAStatus setHwVolume(const std::vector<float>& in_channelVolumes) override;
+
+    ndk::ScopedAStatus setConnectedDevices(
+            const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices)
+            override;
 };
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
index 94404a1..477c30e 100644
--- a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
+++ b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
@@ -16,7 +16,6 @@
 
 #pragma once
 
-#include <mutex>
 #include <vector>
 
 #include "core-impl/Stream.h"
@@ -46,7 +45,7 @@
     ndk::ScopedAStatus prepareToClose() override;
 
   private:
-    size_t getPipeSizeInFrames();
+    long getDelayInUsForFrameCount(size_t frameCount);
     size_t getStreamPipeSizeInFrames();
     ::android::status_t outWrite(void* buffer, size_t frameCount, size_t* actualFrameCount);
     ::android::status_t inRead(void* buffer, size_t frameCount, size_t* actualFrameCount);
@@ -56,13 +55,6 @@
     r_submix::AudioConfig mStreamConfig;
     std::shared_ptr<r_submix::SubmixRoute> mCurrentRoute = nullptr;
 
-    // Mutex lock to protect vector of submix routes, each of these submix routes have their mutex
-    // locks and none of the mutex locks should be taken together.
-    static std::mutex sSubmixRoutesLock;
-    static std::map<::aidl::android::media::audio::common::AudioDeviceAddress,
-                    std::shared_ptr<r_submix::SubmixRoute>>
-            sSubmixRoutes GUARDED_BY(sSubmixRoutesLock);
-
     // limit for number of read error log entries to avoid spamming the logs
     static constexpr int kMaxReadErrorLogs = 5;
     // The duration of kMaxReadFailureAttempts * READ_ATTEMPT_SLEEP_MS must be strictly inferior
@@ -71,6 +63,10 @@
     static constexpr int kMaxReadFailureAttempts = 3;
     // 5ms between two read attempts when pipe is empty
     static constexpr int kReadAttemptSleepUs = 5000;
+
+    int64_t mStartTimeNs = 0;
+    long mFramesSinceStart = 0;
+    int mReadErrorCount = 0;
 };
 
 class StreamInRemoteSubmix final : public StreamIn, public StreamSwitcher {
diff --git a/audio/aidl/default/loudnessEnhancer/Android.bp b/audio/aidl/default/loudnessEnhancer/Android.bp
index 89a72fe..cd44b50 100644
--- a/audio/aidl/default/loudnessEnhancer/Android.bp
+++ b/audio/aidl/default/loudnessEnhancer/Android.bp
@@ -27,8 +27,6 @@
     name: "libloudnessenhancersw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "LoudnessEnhancerSw.cpp",
diff --git a/audio/aidl/default/noiseSuppression/Android.bp b/audio/aidl/default/noiseSuppression/Android.bp
index dad3d49..f24ded6 100644
--- a/audio/aidl/default/noiseSuppression/Android.bp
+++ b/audio/aidl/default/noiseSuppression/Android.bp
@@ -27,8 +27,6 @@
     name: "libnssw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "NoiseSuppressionSw.cpp",
diff --git a/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp
index 99f2caf..a3208df 100644
--- a/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp
+++ b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp
@@ -67,7 +67,7 @@
                           .proxy = std::nullopt},
                    .flags = {.type = Flags::Type::PRE_PROC,
                              .insert = Flags::Insert::FIRST,
-                             .volume = Flags::Volume::CTRL},
+                             .volume = Flags::Volume::NONE},
                    .name = NoiseSuppressionSw::kEffectName,
                    .implementor = "The Android Open Source Project"}};
 
diff --git a/audio/aidl/default/presetReverb/Android.bp b/audio/aidl/default/presetReverb/Android.bp
index 18bdd17..d600141 100644
--- a/audio/aidl/default/presetReverb/Android.bp
+++ b/audio/aidl/default/presetReverb/Android.bp
@@ -27,8 +27,6 @@
     name: "libpresetreverbsw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "PresetReverbSw.cpp",
diff --git a/audio/aidl/default/primary/StreamPrimary.cpp b/audio/aidl/default/primary/StreamPrimary.cpp
index e01be8a..7325a91 100644
--- a/audio/aidl/default/primary/StreamPrimary.cpp
+++ b/audio/aidl/default/primary/StreamPrimary.cpp
@@ -14,11 +14,11 @@
  * limitations under the License.
  */
 
-#include <limits>
-
 #define LOG_TAG "AHAL_StreamPrimary"
 #include <android-base/logging.h>
 #include <android-base/properties.h>
+#include <audio_utils/clock.h>
+#include <error/Result.h>
 #include <error/expected_utils.h>
 
 #include "PrimaryMixer.h"
@@ -37,7 +37,59 @@
 namespace aidl::android::hardware::audio::core {
 
 StreamPrimary::StreamPrimary(StreamContext* context, const Metadata& metadata)
-    : StreamAlsa(context, metadata, 3 /*readWriteRetries*/), mIsInput(isInput(metadata)) {}
+    : StreamAlsa(context, metadata, 3 /*readWriteRetries*/),
+      mIsAsynchronous(!!getContext().getAsyncCallback()) {
+    context->startStreamDataProcessor();
+}
+
+::android::status_t StreamPrimary::start() {
+    RETURN_STATUS_IF_ERROR(StreamAlsa::start());
+    mStartTimeNs = ::android::uptimeNanos();
+    mFramesSinceStart = 0;
+    mSkipNextTransfer = false;
+    return ::android::OK;
+}
+
+::android::status_t StreamPrimary::transfer(void* buffer, size_t frameCount,
+                                            size_t* actualFrameCount, int32_t* latencyMs) {
+    // This is a workaround for the emulator implementation which has a host-side buffer
+    // and is not being able to achieve real-time behavior similar to ADSPs (b/302587331).
+    if (!mSkipNextTransfer) {
+        RETURN_STATUS_IF_ERROR(
+                StreamAlsa::transfer(buffer, frameCount, actualFrameCount, latencyMs));
+    } else {
+        LOG(DEBUG) << __func__ << ": skipping transfer (" << frameCount << " frames)";
+        *actualFrameCount = frameCount;
+        if (mIsInput) memset(buffer, 0, frameCount * mFrameSizeBytes);
+        mSkipNextTransfer = false;
+    }
+    if (!mIsAsynchronous) {
+        const long bufferDurationUs =
+                (*actualFrameCount) * MICROS_PER_SECOND / mContext.getSampleRate();
+        const auto totalDurationUs =
+                (::android::uptimeNanos() - mStartTimeNs) / NANOS_PER_MICROSECOND;
+        mFramesSinceStart += *actualFrameCount;
+        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);
+        } else {
+            mSkipNextTransfer = true;
+        }
+    } else {
+        LOG(VERBOSE) << __func__ << ": asynchronous transfer";
+    }
+    return ::android::OK;
+}
+
+::android::status_t StreamPrimary::refinePosition(StreamDescriptor::Position*) {
+    // Since not all data is actually sent to the HAL, use the position maintained by Stream class
+    // which accounts for all frames passed from / to the client.
+    return ::android::OK;
+}
 
 std::vector<alsa::DeviceProfile> StreamPrimary::getDeviceProfiles() {
     static const std::vector<alsa::DeviceProfile> kBuiltInSource{
@@ -64,7 +116,8 @@
             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;
+           device.type.connection == AudioDeviceDescription::CONNECTION_BUS /*deprecated */ ||
+           (device.type.type == AudioDeviceType::IN_BUS && device.type.connection.empty());
 }
 
 StreamSwitcher::DeviceSwitchBehavior StreamInPrimary::switchCurrentStream(
@@ -99,6 +152,11 @@
     if (isStubStream()) {
         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
     }
+    float gain;
+    RETURN_STATUS_IF_ERROR(primary::PrimaryMixer::getInstance().getMicGain(&gain));
+    _aidl_return->resize(0);
+    _aidl_return->resize(mChannelCount, gain);
+    RETURN_STATUS_IF_ERROR(setHwGainImpl(*_aidl_return));
     return getHwGainImpl(_aidl_return);
 }
 
@@ -130,7 +188,8 @@
     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;
+           device.type.connection == AudioDeviceDescription::CONNECTION_BUS /*deprecated*/ ||
+           (device.type.type == AudioDeviceType::OUT_BUS && device.type.connection.empty());
 }
 
 StreamSwitcher::DeviceSwitchBehavior StreamOutPrimary::switchCurrentStream(
@@ -165,6 +224,9 @@
     if (isStubStream()) {
         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
     }
+    RETURN_STATUS_IF_ERROR(primary::PrimaryMixer::getInstance().getVolumes(_aidl_return));
+    _aidl_return->resize(mChannelCount);
+    RETURN_STATUS_IF_ERROR(setHwVolumeImpl(*_aidl_return));
     return getHwVolumeImpl(_aidl_return);
 }
 
@@ -183,4 +245,15 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus StreamOutPrimary::setConnectedDevices(
+        const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
+    if (!devices.empty()) {
+        auto streamDataProcessor = mContextInstance.getStreamDataProcessor().lock();
+        if (streamDataProcessor != nullptr) {
+            streamDataProcessor->setAudioDevice(devices[0]);
+        }
+    }
+    return StreamSwitcher::setConnectedDevices(devices);
+}
+
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp b/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp
index f8c775f..7bc783c 100644
--- a/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp
+++ b/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp
@@ -21,18 +21,42 @@
 #include <android-base/logging.h>
 #include <error/expected_utils.h>
 
+#include "SubmixRoute.h"
 #include "core-impl/ModuleRemoteSubmix.h"
 #include "core-impl/StreamRemoteSubmix.h"
 
 using aidl::android::hardware::audio::common::SinkMetadata;
 using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::media::audio::common::AudioDeviceAddress;
+using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::AudioIoFlags;
 using aidl::android::media::audio::common::AudioOffloadInfo;
 using aidl::android::media::audio::common::AudioPort;
 using aidl::android::media::audio::common::AudioPortConfig;
+using aidl::android::media::audio::common::AudioPortExt;
+using aidl::android::media::audio::common::AudioProfile;
+using aidl::android::media::audio::common::Int;
 using aidl::android::media::audio::common::MicrophoneInfo;
 
 namespace aidl::android::hardware::audio::core {
 
+namespace {
+
+std::optional<r_submix::AudioConfig> getRemoteEndConfig(const AudioPort& audioPort) {
+    const auto& deviceAddress = audioPort.ext.get<AudioPortExt::device>().device.address;
+    const bool isInput = audioPort.flags.getTag() == AudioIoFlags::input;
+    if (auto submixRoute = r_submix::SubmixRoute::findRoute(deviceAddress);
+        submixRoute != nullptr) {
+        if ((isInput && submixRoute->isStreamOutOpen()) ||
+            (!isInput && submixRoute->isStreamInOpen())) {
+            return submixRoute->getPipeConfig();
+        }
+    }
+    return {};
+}
+
+}  // namespace
+
 ndk::ScopedAStatus ModuleRemoteSubmix::getMicMute(bool* _aidl_return __unused) {
     LOG(DEBUG) << __func__ << ": is not supported";
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
@@ -43,6 +67,26 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
+ndk::ScopedAStatus ModuleRemoteSubmix::setAudioPortConfig(const AudioPortConfig& in_requested,
+                                                          AudioPortConfig* out_suggested,
+                                                          bool* _aidl_return) {
+    auto fillConfig = [this](const AudioPort& port, AudioPortConfig* config) {
+        if (port.ext.getTag() == AudioPortExt::device) {
+            if (auto pipeConfig = getRemoteEndConfig(port); pipeConfig.has_value()) {
+                LOG(DEBUG) << "setAudioPortConfig: suggesting port config from the remote end.";
+                config->format = pipeConfig->format;
+                config->channelMask = pipeConfig->channelLayout;
+                config->sampleRate = Int{.value = pipeConfig->sampleRate};
+                config->flags = port.flags;
+                config->ext = port.ext;
+                return true;
+            }
+        }
+        return generateDefaultPortConfig(port, config);
+    };
+    return Module::setAudioPortConfigImpl(in_requested, fillConfig, out_suggested, _aidl_return);
+}
+
 ndk::ScopedAStatus ModuleRemoteSubmix::createInputStream(
         StreamContext&& context, const SinkMetadata& sinkMetadata,
         const std::vector<MicrophoneInfo>& microphones, std::shared_ptr<StreamIn>* result) {
@@ -57,8 +101,23 @@
                                                        offloadInfo);
 }
 
-ndk::ScopedAStatus ModuleRemoteSubmix::populateConnectedDevicePort(AudioPort* audioPort) {
-    // Find the corresponding mix port and copy its profiles.
+ndk::ScopedAStatus ModuleRemoteSubmix::populateConnectedDevicePort(AudioPort* audioPort, int32_t) {
+    if (audioPort->ext.getTag() != AudioPortExt::device) {
+        LOG(ERROR) << __func__ << ": not a device port: " << audioPort->toString();
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    // If there is already a pipe with a stream for the port address, provide its configuration as
+    // the only option. Otherwise, find the corresponding mix port and copy its profiles.
+    if (auto pipeConfig = getRemoteEndConfig(*audioPort); pipeConfig.has_value()) {
+        audioPort->profiles.clear();
+        audioPort->profiles.push_back(AudioProfile{
+                .format = pipeConfig->format,
+                .channelMasks = std::vector<AudioChannelLayout>({pipeConfig->channelLayout}),
+                .sampleRates = std::vector<int>({pipeConfig->sampleRate})});
+        LOG(DEBUG) << __func__ << ": populated from remote end as: " << audioPort->toString();
+        return ndk::ScopedAStatus::ok();
+    }
+
     // At this moment, the port has the same ID as the template port, see connectExternalDevice.
     std::vector<AudioRoute*> routes = getAudioRoutesForAudioPortImpl(audioPort->id);
     if (routes.empty()) {
@@ -77,6 +136,7 @@
         RETURN_STATUS_IF_ERROR(getAudioPort(route->sinkPortId, &mixPort));
     }
     audioPort->profiles = mixPort.profiles;
+    LOG(DEBUG) << __func__ << ": populated from the mix port as: " << audioPort->toString();
     return ndk::ScopedAStatus::ok();
 }
 
@@ -106,4 +166,12 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
+int32_t ModuleRemoteSubmix::getNominalLatencyMs(const AudioPortConfig&) {
+    // See the note on kDefaultPipePeriodCount.
+    static constexpr int32_t kMaxLatencyMs =
+            (r_submix::kDefaultPipeSizeInFrames * 1000) / r_submix::kDefaultSampleRateHz;
+    static constexpr int32_t kMinLatencyMs = kMaxLatencyMs / r_submix::kDefaultPipePeriodCount;
+    return kMinLatencyMs;
+}
+
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
index 9c9c08b..3ee354b 100644
--- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
+++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
@@ -16,8 +16,9 @@
 
 #define LOG_TAG "AHAL_StreamRemoteSubmix"
 #include <android-base/logging.h>
-
-#include <cmath>
+#include <audio_utils/clock.h>
+#include <error/Result.h>
+#include <error/expected_utils.h>
 
 #include "core-impl/StreamRemoteSubmix.h"
 
@@ -42,50 +43,27 @@
     mStreamConfig.sampleRate = context->getSampleRate();
 }
 
-std::mutex StreamRemoteSubmix::sSubmixRoutesLock;
-std::map<AudioDeviceAddress, std::shared_ptr<SubmixRoute>> StreamRemoteSubmix::sSubmixRoutes;
-
 ::android::status_t StreamRemoteSubmix::init() {
-    {
-        std::lock_guard guard(sSubmixRoutesLock);
-        auto routeItr = sSubmixRoutes.find(mDeviceAddress);
-        if (routeItr != sSubmixRoutes.end()) {
-            mCurrentRoute = routeItr->second;
-        }
-    }
-    // If route is not available for this port, add it.
+    mCurrentRoute = SubmixRoute::findOrCreateRoute(mDeviceAddress, mStreamConfig);
     if (mCurrentRoute == nullptr) {
-        // Initialize the pipe.
-        mCurrentRoute = std::make_shared<SubmixRoute>();
-        if (::android::OK != mCurrentRoute->createPipe(mStreamConfig)) {
-            LOG(ERROR) << __func__ << ": create pipe failed";
+        return ::android::NO_INIT;
+    }
+    if (!mCurrentRoute->isStreamConfigValid(mIsInput, mStreamConfig)) {
+        LOG(ERROR) << __func__ << ": invalid stream config";
+        return ::android::NO_INIT;
+    }
+    sp<MonoPipe> sink = mCurrentRoute->getSink();
+    if (sink == nullptr) {
+        LOG(ERROR) << __func__ << ": nullptr sink when opening stream";
+        return ::android::NO_INIT;
+    }
+    if ((!mIsInput || mCurrentRoute->isStreamInOpen()) && sink->isShutdown()) {
+        LOG(DEBUG) << __func__ << ": Shut down sink when opening stream";
+        if (::android::OK != mCurrentRoute->resetPipe()) {
+            LOG(ERROR) << __func__ << ": reset pipe failed";
             return ::android::NO_INIT;
         }
-        {
-            std::lock_guard guard(sSubmixRoutesLock);
-            sSubmixRoutes.emplace(mDeviceAddress, mCurrentRoute);
-        }
-    } else {
-        if (!mCurrentRoute->isStreamConfigValid(mIsInput, mStreamConfig)) {
-            LOG(ERROR) << __func__ << ": invalid stream config";
-            return ::android::NO_INIT;
-        }
-        sp<MonoPipe> sink = mCurrentRoute->getSink();
-        if (sink == nullptr) {
-            LOG(ERROR) << __func__ << ": nullptr sink when opening stream";
-            return ::android::NO_INIT;
-        }
-        // If the sink has been shutdown or pipe recreation is forced, delete the pipe and
-        // recreate it.
-        if (sink->isShutdown()) {
-            LOG(DEBUG) << __func__ << ": Non-nullptr shut down sink when opening stream";
-            if (::android::OK != mCurrentRoute->resetPipe()) {
-                LOG(ERROR) << __func__ << ": reset pipe failed";
-                return ::android::NO_INIT;
-            }
-        }
     }
-
     mCurrentRoute->openStream(mIsInput);
     return ::android::OK;
 }
@@ -112,19 +90,14 @@
 
 ::android::status_t StreamRemoteSubmix::start() {
     mCurrentRoute->exitStandby(mIsInput);
+    mStartTimeNs = ::android::uptimeNanos();
+    mFramesSinceStart = 0;
     return ::android::OK;
 }
 
 ndk::ScopedAStatus StreamRemoteSubmix::prepareToClose() {
     if (!mIsInput) {
-        std::shared_ptr<SubmixRoute> route = nullptr;
-        {
-            std::lock_guard guard(sSubmixRoutesLock);
-            auto routeItr = sSubmixRoutes.find(mDeviceAddress);
-            if (routeItr != sSubmixRoutes.end()) {
-                route = routeItr->second;
-            }
-        }
+        std::shared_ptr<SubmixRoute> route = SubmixRoute::findRoute(mDeviceAddress);
         if (route != nullptr) {
             sp<MonoPipe> sink = route->getSink();
             if (sink == nullptr) {
@@ -133,6 +106,8 @@
             LOG(DEBUG) << __func__ << ": shutting down MonoPipe sink";
 
             sink->shutdown(true);
+            // The client already considers this stream as closed, release the output end.
+            route->closeStream(mIsInput);
         } else {
             LOG(DEBUG) << __func__ << ": stream already closed.";
             ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
@@ -149,39 +124,31 @@
     if (!mCurrentRoute->hasAtleastOneStreamOpen()) {
         mCurrentRoute->releasePipe();
         LOG(DEBUG) << __func__ << ": pipe destroyed";
-
-        std::lock_guard guard(sSubmixRoutesLock);
-        sSubmixRoutes.erase(mDeviceAddress);
+        SubmixRoute::removeRoute(mDeviceAddress);
     }
     mCurrentRoute.reset();
 }
 
 ::android::status_t StreamRemoteSubmix::transfer(void* buffer, size_t frameCount,
                                                  size_t* actualFrameCount, int32_t* latencyMs) {
-    *latencyMs = (getStreamPipeSizeInFrames() * MILLIS_PER_SECOND) / mStreamConfig.sampleRate;
+    *latencyMs = getDelayInUsForFrameCount(getStreamPipeSizeInFrames()) / 1000;
     LOG(VERBOSE) << __func__ << ": Latency " << *latencyMs << "ms";
-
-    sp<MonoPipe> sink = mCurrentRoute->getSink();
-    if (sink != nullptr) {
-        if (sink->isShutdown()) {
-            sink.clear();
-            LOG(VERBOSE) << __func__ << ": pipe shutdown, ignoring the transfer.";
-            // the pipe has already been shutdown, this buffer will be lost but we must simulate
-            // timing so we don't drain the output faster than realtime
-            const size_t delayUs = static_cast<size_t>(
-                    std::roundf(frameCount * MICROS_PER_SECOND / mStreamConfig.sampleRate));
-            usleep(delayUs);
-
-            *actualFrameCount = frameCount;
-            return ::android::OK;
-        }
-    } else {
-        LOG(ERROR) << __func__ << ": transfer without a pipe!";
-        return ::android::UNEXPECTED_NULL;
-    }
     mCurrentRoute->exitStandby(mIsInput);
-    return (mIsInput ? inRead(buffer, frameCount, actualFrameCount)
-                     : outWrite(buffer, frameCount, actualFrameCount));
+    RETURN_STATUS_IF_ERROR(mIsInput ? inRead(buffer, frameCount, actualFrameCount)
+                                    : outWrite(buffer, frameCount, actualFrameCount));
+    const long bufferDurationUs =
+            (*actualFrameCount) * MICROS_PER_SECOND / mContext.getSampleRate();
+    const auto totalDurationUs = (::android::uptimeNanos() - mStartTimeNs) / NANOS_PER_MICROSECOND;
+    mFramesSinceStart += *actualFrameCount;
+    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);
+    }
+    return ::android::OK;
 }
 
 ::android::status_t StreamRemoteSubmix::refinePosition(StreamDescriptor::Position* position) {
@@ -202,9 +169,13 @@
     return ::android::OK;
 }
 
+long StreamRemoteSubmix::getDelayInUsForFrameCount(size_t frameCount) {
+    return frameCount * MICROS_PER_SECOND / mStreamConfig.sampleRate;
+}
+
 // Calculate the maximum size of the pipe buffer in frames for the specified stream.
 size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() {
-    auto pipeConfig = mCurrentRoute->mPipeConfig;
+    auto pipeConfig = mCurrentRoute->getPipeConfig();
     const size_t maxFrameSize = std::max(mStreamConfig.frameSize, pipeConfig.frameSize);
     return (pipeConfig.frameCount * pipeConfig.frameSize) / maxFrameSize;
 }
@@ -215,12 +186,7 @@
     if (sink != nullptr) {
         if (sink->isShutdown()) {
             sink.clear();
-            LOG(VERBOSE) << __func__ << ": pipe shutdown, ignoring the write.";
-            // the pipe has already been shutdown, this buffer will be lost but we must
-            // simulate timing so we don't drain the output faster than realtime
-            const size_t delayUs = static_cast<size_t>(
-                    std::roundf(frameCount * MICROS_PER_SECOND / mStreamConfig.sampleRate));
-            usleep(delayUs);
+            LOG(DEBUG) << __func__ << ": pipe shutdown, ignoring the write";
             *actualFrameCount = frameCount;
             return ::android::OK;
         }
@@ -229,17 +195,21 @@
         return ::android::UNKNOWN_ERROR;
     }
 
-    const size_t availableToWrite = sink->availableToWrite();
+    LOG(VERBOSE) << __func__ << ": " << mDeviceAddress.toString() << ", " << frameCount
+                 << " frames";
+
+    const bool shouldBlockWrite = mCurrentRoute->shouldBlockWrite();
+    size_t availableToWrite = sink->availableToWrite();
     // NOTE: sink has been checked above and sink and source life cycles are synchronized
     sp<MonoPipeReader> source = mCurrentRoute->getSource();
     // If the write to the sink should be blocked, flush enough frames from the pipe to make space
     // to write the most recent data.
-    if (!mCurrentRoute->shouldBlockWrite() && availableToWrite < frameCount) {
+    if (!shouldBlockWrite && availableToWrite < frameCount) {
         static uint8_t flushBuffer[64];
         const size_t flushBufferSizeFrames = sizeof(flushBuffer) / mStreamConfig.frameSize;
         size_t framesToFlushFromSource = frameCount - availableToWrite;
-        LOG(VERBOSE) << __func__ << ": flushing " << framesToFlushFromSource
-                     << " frames from the pipe to avoid blocking";
+        LOG(DEBUG) << __func__ << ": flushing " << framesToFlushFromSource
+                   << " frames from the pipe to avoid blocking";
         while (framesToFlushFromSource) {
             const size_t flushSize = std::min(framesToFlushFromSource, flushBufferSizeFrames);
             framesToFlushFromSource -= flushSize;
@@ -247,7 +217,14 @@
             source->read(flushBuffer, flushSize);
         }
     }
+    availableToWrite = sink->availableToWrite();
 
+    if (!shouldBlockWrite && frameCount > availableToWrite) {
+        LOG(WARNING) << __func__ << ": writing " << availableToWrite << " vs. requested "
+                     << frameCount;
+        // Truncate the request to avoid blocking.
+        frameCount = availableToWrite;
+    }
     ssize_t writtenFrames = sink->write(buffer, frameCount);
     if (writtenFrames < 0) {
         if (writtenFrames == (ssize_t)::android::NEGOTIATE) {
@@ -261,97 +238,65 @@
             writtenFrames = sink->write(buffer, frameCount);
         }
     }
-    sink.clear();
 
     if (writtenFrames < 0) {
         LOG(ERROR) << __func__ << ": failed writing to pipe with " << writtenFrames;
         *actualFrameCount = 0;
         return ::android::UNKNOWN_ERROR;
     }
-    LOG(VERBOSE) << __func__ << ": wrote " << writtenFrames << "frames";
+    if (writtenFrames > 0 && frameCount > (size_t)writtenFrames) {
+        LOG(WARNING) << __func__ << ": wrote " << writtenFrames << " vs. requested " << frameCount;
+    }
     *actualFrameCount = writtenFrames;
     return ::android::OK;
 }
 
 ::android::status_t StreamRemoteSubmix::inRead(void* buffer, size_t frameCount,
                                                size_t* actualFrameCount) {
+    // in any case, it is emulated that data for the entire buffer was available
+    memset(buffer, 0, mStreamConfig.frameSize * frameCount);
+    *actualFrameCount = frameCount;
+
     // about to read from audio source
     sp<MonoPipeReader> source = mCurrentRoute->getSource();
     if (source == nullptr) {
-        int readErrorCount = mCurrentRoute->notifyReadError();
-        if (readErrorCount < kMaxReadErrorLogs) {
+        if (++mReadErrorCount < kMaxReadErrorLogs) {
             LOG(ERROR) << __func__
                        << ": no audio pipe yet we're trying to read! (not all errors will be "
                           "logged)";
-        } else {
-            LOG(ERROR) << __func__ << ": Read errors " << readErrorCount;
         }
-        const size_t delayUs = static_cast<size_t>(
-                std::roundf(frameCount * MICROS_PER_SECOND / mStreamConfig.sampleRate));
-        usleep(delayUs);
-        memset(buffer, 0, mStreamConfig.frameSize * frameCount);
-        *actualFrameCount = frameCount;
         return ::android::OK;
     }
 
+    LOG(VERBOSE) << __func__ << ": " << mDeviceAddress.toString() << ", " << frameCount
+                 << " frames";
     // read the data from the pipe
-    int attempts = 0;
-    const size_t delayUs = static_cast<size_t>(std::roundf(kReadAttemptSleepUs));
     char* buff = (char*)buffer;
-    size_t remainingFrames = frameCount;
-    int availableToRead = source->availableToRead();
-
-    while ((remainingFrames > 0) && (availableToRead > 0) && (attempts < kMaxReadFailureAttempts)) {
-        LOG(VERBOSE) << __func__ << ": frames available to read " << availableToRead;
-
+    size_t actuallyRead = 0;
+    long remainingFrames = frameCount;
+    const int64_t deadlineTimeNs = ::android::uptimeNanos() +
+                                   getDelayInUsForFrameCount(frameCount) * NANOS_PER_MICROSECOND;
+    while (remainingFrames > 0) {
         ssize_t framesRead = source->read(buff, remainingFrames);
-
         LOG(VERBOSE) << __func__ << ": frames read " << framesRead;
-
         if (framesRead > 0) {
             remainingFrames -= framesRead;
             buff += framesRead * mStreamConfig.frameSize;
-            availableToRead -= framesRead;
-            LOG(VERBOSE) << __func__ << ": (attempts = " << attempts << ") got " << framesRead
-                         << " frames, remaining=" << remainingFrames;
-        } else {
-            attempts++;
-            LOG(WARNING) << __func__ << ": read returned " << framesRead
-                         << " , read failure attempts = " << attempts;
-            usleep(delayUs);
+            LOG(VERBOSE) << __func__ << ": got " << framesRead
+                         << " frames, remaining =" << remainingFrames;
+            actuallyRead += framesRead;
+        }
+        if (::android::uptimeNanos() >= deadlineTimeNs) break;
+        if (framesRead <= 0) {
+            LOG(VERBOSE) << __func__ << ": read returned " << framesRead
+                         << ", read failure, sleeping for " << kReadAttemptSleepUs << " us";
+            usleep(kReadAttemptSleepUs);
         }
     }
-    // done using the source
-    source.clear();
-
-    if (remainingFrames > 0) {
-        const size_t remainingBytes = remainingFrames * mStreamConfig.frameSize;
-        LOG(VERBOSE) << __func__ << ": clearing remaining_frames = " << remainingFrames;
-        memset(((char*)buffer) + (mStreamConfig.frameSize * frameCount) - remainingBytes, 0,
-               remainingBytes);
+    if (actuallyRead < frameCount) {
+        LOG(WARNING) << __func__ << ": read " << actuallyRead << " vs. requested " << frameCount;
     }
-
-    long readCounterFrames = mCurrentRoute->updateReadCounterFrames(frameCount);
-    *actualFrameCount = frameCount;
-
-    // compute how much we need to sleep after reading the data by comparing the wall clock with
-    //   the projected time at which we should return.
-    // wall clock after reading from the pipe
-    auto recordDurationUs = std::chrono::steady_clock::now() - mCurrentRoute->getRecordStartTime();
-
-    // readCounterFrames contains the number of frames that have been read since the beginning of
-    // recording (including this call): it's converted to usec and compared to how long we've been
-    // recording for, which gives us how long we must wait to sync the projected recording time, and
-    // the observed recording time.
-    const int projectedVsObservedOffsetUs =
-            std::roundf((readCounterFrames * MICROS_PER_SECOND / mStreamConfig.sampleRate) -
-                        recordDurationUs.count());
-
-    LOG(VERBOSE) << __func__ << ": record duration " << recordDurationUs.count()
-                 << " microseconds, will wait: " << projectedVsObservedOffsetUs << " microseconds";
-    if (projectedVsObservedOffsetUs > 0) {
-        usleep(projectedVsObservedOffsetUs);
-    }
+    mCurrentRoute->updateReadCounterFrames(*actualFrameCount);
     return ::android::OK;
 }
 
diff --git a/audio/aidl/default/r_submix/SubmixRoute.cpp b/audio/aidl/default/r_submix/SubmixRoute.cpp
index ddac64d..7d706c2 100644
--- a/audio/aidl/default/r_submix/SubmixRoute.cpp
+++ b/audio/aidl/default/r_submix/SubmixRoute.cpp
@@ -23,9 +23,49 @@
 #include "SubmixRoute.h"
 
 using aidl::android::hardware::audio::common::getChannelCount;
+using aidl::android::media::audio::common::AudioDeviceAddress;
 
 namespace aidl::android::hardware::audio::core::r_submix {
 
+// static
+SubmixRoute::RoutesMonitor SubmixRoute::getRoutes() {
+    static std::mutex submixRoutesLock;
+    static RoutesMap submixRoutes;
+    return RoutesMonitor(submixRoutesLock, submixRoutes);
+}
+
+// static
+std::shared_ptr<SubmixRoute> SubmixRoute::findOrCreateRoute(const AudioDeviceAddress& deviceAddress,
+                                                            const AudioConfig& pipeConfig) {
+    auto routes = getRoutes();
+    auto routeItr = routes->find(deviceAddress);
+    if (routeItr != routes->end()) {
+        return routeItr->second;
+    }
+    auto route = std::make_shared<SubmixRoute>();
+    if (::android::OK != route->createPipe(pipeConfig)) {
+        LOG(ERROR) << __func__ << ": create pipe failed";
+        return nullptr;
+    }
+    routes->emplace(deviceAddress, route);
+    return route;
+}
+
+// static
+std::shared_ptr<SubmixRoute> SubmixRoute::findRoute(const AudioDeviceAddress& deviceAddress) {
+    auto routes = getRoutes();
+    auto routeItr = routes->find(deviceAddress);
+    if (routeItr != routes->end()) {
+        return routeItr->second;
+    }
+    return nullptr;
+}
+
+// static
+void SubmixRoute::removeRoute(const AudioDeviceAddress& deviceAddress) {
+    getRoutes()->erase(deviceAddress);
+}
+
 // Verify a submix input or output stream can be opened.
 bool SubmixRoute::isStreamConfigValid(bool isInput, const AudioConfig& streamConfig) {
     // If the stream is already open, don't open it again.
@@ -44,6 +84,7 @@
 // Compare this stream config with existing pipe config, returning false if they do *not*
 // match, true otherwise.
 bool SubmixRoute::isStreamConfigCompatible(const AudioConfig& streamConfig) {
+    std::lock_guard guard(mLock);
     if (streamConfig.channelLayout != mPipeConfig.channelLayout) {
         LOG(ERROR) << __func__ << ": channel count mismatch, stream channels = "
                    << streamConfig.channelLayout.toString()
@@ -81,11 +122,6 @@
     return (mStreamInOpen || (mStreamInStandby && (mReadCounterFrames != 0)));
 }
 
-int SubmixRoute::notifyReadError() {
-    std::lock_guard guard(mLock);
-    return ++mReadErrorCount;
-}
-
 long SubmixRoute::updateReadCounterFrames(size_t frameCount) {
     std::lock_guard guard(mLock);
     mReadCounterFrames += frameCount;
@@ -103,7 +139,9 @@
         }
         mStreamInStandby = true;
         mReadCounterFrames = 0;
-        mReadErrorCount = 0;
+        if (mSink != nullptr) {
+            mSink->shutdown(false);
+        }
     } else {
         mStreamOutOpen = true;
     }
@@ -112,8 +150,7 @@
 void SubmixRoute::closeStream(bool isInput) {
     std::lock_guard guard(mLock);
     if (isInput) {
-        mInputRefCount--;
-        if (mInputRefCount == 0) {
+        if (--mInputRefCount == 0) {
             mStreamInOpen = false;
             if (mSink != nullptr) {
                 mSink->shutdown(true);
@@ -166,17 +203,14 @@
         LOG(FATAL) << __func__ << ": Negotiation for the source failed, index = " << index;
         return ::android::BAD_INDEX;
     }
-    LOG(VERBOSE) << __func__ << ": created pipe";
-
-    mPipeConfig = streamConfig;
-    mPipeConfig.frameCount = sink->maxFrames();
-
-    LOG(VERBOSE) << __func__ << ": Pipe frame size : " << mPipeConfig.frameSize
-                 << ", pipe frames : " << mPipeConfig.frameCount;
+    LOG(VERBOSE) << __func__ << ": Pipe frame size : " << streamConfig.frameSize
+                 << ", pipe frames : " << sink->maxFrames();
 
     // Save references to the source and sink.
     {
         std::lock_guard guard(mLock);
+        mPipeConfig = streamConfig;
+        mPipeConfig.frameCount = sink->maxFrames();
         mSink = std::move(sink);
         mSource = std::move(source);
     }
@@ -185,15 +219,15 @@
 }
 
 // Release references to the sink and source.
-void SubmixRoute::releasePipe() {
+AudioConfig SubmixRoute::releasePipe() {
     std::lock_guard guard(mLock);
     mSink.clear();
     mSource.clear();
+    return mPipeConfig;
 }
 
 ::android::status_t SubmixRoute::resetPipe() {
-    releasePipe();
-    return createPipe(mPipeConfig);
+    return createPipe(releasePipe());
 }
 
 void SubmixRoute::standby(bool isInput) {
@@ -214,9 +248,6 @@
         if (mStreamInStandby || mStreamOutStandbyTransition) {
             mStreamInStandby = false;
             mStreamOutStandbyTransition = false;
-            // keep track of when we exit input standby (== first read == start "real recording")
-            // or when we start recording silence, and reset projected time
-            mRecordStartTime = std::chrono::steady_clock::now();
             mReadCounterFrames = 0;
         }
     } else {
diff --git a/audio/aidl/default/r_submix/SubmixRoute.h b/audio/aidl/default/r_submix/SubmixRoute.h
index 1a98df2..160df41 100644
--- a/audio/aidl/default/r_submix/SubmixRoute.h
+++ b/audio/aidl/default/r_submix/SubmixRoute.h
@@ -14,16 +14,19 @@
  * limitations under the License.
  */
 
+#pragma once
+
 #include <mutex>
 
+#include <android-base/thread_annotations.h>
 #include <audio_utils/clock.h>
 
 #include <media/nbaio/MonoPipe.h>
 #include <media/nbaio/MonoPipeReader.h>
 
 #include <aidl/android/media/audio/common/AudioChannelLayout.h>
-
-#include "core-impl/Stream.h"
+#include <aidl/android/media/audio/common/AudioDeviceAddress.h>
+#include <aidl/android/media/audio/common/AudioFormatDescription.h>
 
 using aidl::android::media::audio::common::AudioChannelLayout;
 using aidl::android::media::audio::common::AudioFormatDescription;
@@ -36,9 +39,13 @@
 namespace aidl::android::hardware::audio::core::r_submix {
 
 static constexpr int kDefaultSampleRateHz = 48000;
-// Size at default sample rate
-// NOTE: This value will be rounded up to the nearest power of 2 by MonoPipe().
-static constexpr int kDefaultPipeSizeInFrames = (1024 * 4);
+// Value used to divide the MonoPipe buffer into segments that are written to the source and
+// read from the sink. The maximum latency of the device is the size of the MonoPipe's buffer
+// the minimum latency is the MonoPipe buffer size divided by this value.
+static constexpr int kDefaultPipePeriodCount = 4;
+// Size at the default sample rate
+// NOTE: This value will be rounded up to the nearest power of 2 by MonoPipe.
+static constexpr int kDefaultPipeSizeInFrames = 1024 * kDefaultPipePeriodCount;
 
 // Configuration of the audio stream.
 struct AudioConfig {
@@ -54,7 +61,13 @@
 
 class SubmixRoute {
   public:
-    AudioConfig mPipeConfig;
+    static std::shared_ptr<SubmixRoute> findOrCreateRoute(
+            const ::aidl::android::media::audio::common::AudioDeviceAddress& deviceAddress,
+            const AudioConfig& pipeConfig);
+    static std::shared_ptr<SubmixRoute> findRoute(
+            const ::aidl::android::media::audio::common::AudioDeviceAddress& deviceAddress);
+    static void removeRoute(
+            const ::aidl::android::media::audio::common::AudioDeviceAddress& deviceAddress);
 
     bool isStreamInOpen() {
         std::lock_guard guard(mLock);
@@ -76,14 +89,6 @@
         std::lock_guard guard(mLock);
         return mReadCounterFrames;
     }
-    int getReadErrorCount() {
-        std::lock_guard guard(mLock);
-        return mReadErrorCount;
-    }
-    std::chrono::time_point<std::chrono::steady_clock> getRecordStartTime() {
-        std::lock_guard guard(mLock);
-        return mRecordStartTime;
-    }
     sp<MonoPipe> getSink() {
         std::lock_guard guard(mLock);
         return mSink;
@@ -92,6 +97,10 @@
         std::lock_guard guard(mLock);
         return mSource;
     }
+    AudioConfig getPipeConfig() {
+        std::lock_guard guard(mLock);
+        return mPipeConfig;
+    }
 
     bool isStreamConfigValid(bool isInput, const AudioConfig& streamConfig);
     void closeStream(bool isInput);
@@ -100,17 +109,31 @@
     bool hasAtleastOneStreamOpen();
     int notifyReadError();
     void openStream(bool isInput);
-    void releasePipe();
+    AudioConfig releasePipe();
     ::android::status_t resetPipe();
     bool shouldBlockWrite();
     void standby(bool isInput);
     long updateReadCounterFrames(size_t frameCount);
 
   private:
+    using RoutesMap = std::map<::aidl::android::media::audio::common::AudioDeviceAddress,
+                               std::shared_ptr<r_submix::SubmixRoute>>;
+    class RoutesMonitor {
+      public:
+        RoutesMonitor(std::mutex& mutex, RoutesMap& routes) : mLock(mutex), mRoutes(routes) {}
+        RoutesMap* operator->() { return &mRoutes; }
+
+      private:
+        std::lock_guard<std::mutex> mLock;
+        RoutesMap& mRoutes;
+    };
+
+    static RoutesMonitor getRoutes();
+
     bool isStreamConfigCompatible(const AudioConfig& streamConfig);
 
     std::mutex mLock;
-
+    AudioConfig mPipeConfig GUARDED_BY(mLock);
     bool mStreamInOpen GUARDED_BY(mLock) = false;
     int mInputRefCount GUARDED_BY(mLock) = 0;
     bool mStreamInStandby GUARDED_BY(mLock) = true;
@@ -119,9 +142,6 @@
     bool mStreamOutStandby GUARDED_BY(mLock) = true;
     // how many frames have been requested to be read since standby
     long mReadCounterFrames GUARDED_BY(mLock) = 0;
-    int mReadErrorCount GUARDED_BY(mLock) = 0;
-    // wall clock when recording starts
-    std::chrono::time_point<std::chrono::steady_clock> mRecordStartTime GUARDED_BY(mLock);
 
     // Pipe variables: they handle the ring buffer that "pipes" audio:
     //  - from the submix virtual audio output == what needs to be played
diff --git a/audio/aidl/default/spatializer/Android.bp b/audio/aidl/default/spatializer/Android.bp
new file mode 100644
index 0000000..05ed365
--- /dev/null
+++ b/audio/aidl/default/spatializer/Android.bp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+    name: "libspatializersw",
+    defaults: [
+        "aidlaudioeffectservice_defaults",
+    ],
+    srcs: [
+        "SpatializerSw.cpp",
+        ":effectCommonFile",
+    ],
+    relative_install_path: "soundfx",
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
+    ],
+}
diff --git a/audio/aidl/default/spatializer/SpatializerSw.cpp b/audio/aidl/default/spatializer/SpatializerSw.cpp
new file mode 100644
index 0000000..434ed5a
--- /dev/null
+++ b/audio/aidl/default/spatializer/SpatializerSw.cpp
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHAL_SpatializerSw"
+
+#include "SpatializerSw.h"
+
+#include <android-base/logging.h>
+#include <system/audio_effects/effect_uuid.h>
+
+#include <optional>
+
+using aidl::android::hardware::audio::common::getChannelCount;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::getEffectImplUuidSpatializerSw;
+using aidl::android::hardware::audio::effect::getEffectTypeUuidSpatializer;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::SpatializerSw;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioUuid;
+using aidl::android::media::audio::common::HeadTracking;
+using aidl::android::media::audio::common::Spatialization;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+                                           std::shared_ptr<IEffect>* instanceSpp) {
+    if (!in_impl_uuid || *in_impl_uuid != getEffectImplUuidSpatializerSw()) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (!instanceSpp) {
+        LOG(ERROR) << __func__ << " invalid input parameter!";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+
+    *instanceSpp = ndk::SharedRefBase::make<SpatializerSw>();
+    LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
+    return EX_NONE;
+}
+
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+    if (!in_impl_uuid || *in_impl_uuid != getEffectImplUuidSpatializerSw()) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    *_aidl_return = SpatializerSw::kDescriptor;
+    return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+const std::string SpatializerSw::kEffectName = "SpatializerSw";
+
+const std::vector<Range::SpatializerRange> SpatializerSw::kRanges = {
+        MAKE_RANGE(Spatializer, supportedChannelLayout, std::vector<AudioChannelLayout>{},
+                   std::vector<AudioChannelLayout>{}),
+        MAKE_RANGE(Spatializer, spatializationLevel, Spatialization::Level::NONE,
+                   Spatialization::Level::BED_PLUS_OBJECTS),
+        MAKE_RANGE(Spatializer, spatializationMode, Spatialization::Mode::BINAURAL,
+                   Spatialization::Mode::TRANSAURAL),
+        MAKE_RANGE(Spatializer, headTrackingSensorId, std::numeric_limits<int>::min(),
+                   std::numeric_limits<int>::max()),
+        MAKE_RANGE(Spatializer, headTrackingMode, HeadTracking::Mode::OTHER,
+                   HeadTracking::Mode::RELATIVE_SCREEN),
+        MAKE_RANGE(Spatializer, headTrackingConnectionMode,
+                   HeadTracking::ConnectionMode::FRAMEWORK_PROCESSED,
+                   HeadTracking::ConnectionMode::DIRECT_TO_SENSOR_TUNNEL)};
+const Capability SpatializerSw::kCapability = {.range = {SpatializerSw::kRanges}};
+const Descriptor SpatializerSw::kDescriptor = {
+        .common = {.id = {.type = getEffectTypeUuidSpatializer(),
+                          .uuid = getEffectImplUuidSpatializerSw()},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::FIRST,
+                             .hwAcceleratorMode = Flags::HardwareAccelerator::NONE},
+                   .name = SpatializerSw::kEffectName,
+                   .implementor = "The Android Open Source Project"},
+        .capability = SpatializerSw::kCapability};
+
+ndk::ScopedAStatus SpatializerSw::getDescriptor(Descriptor* _aidl_return) {
+    LOG(DEBUG) << __func__ << kDescriptor.toString();
+    *_aidl_return = kDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus SpatializerSw::setParameterSpecific(const Parameter::Specific& specific) {
+    RETURN_IF(Parameter::Specific::spatializer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+              "EffectNotSupported");
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    auto& param = specific.get<Parameter::Specific::spatializer>();
+    RETURN_IF(!inRange(param, kRanges), EX_ILLEGAL_ARGUMENT, "outOfRange");
+
+    return mContext->setParam(param.getTag(), param);
+}
+
+ndk::ScopedAStatus SpatializerSw::getParameterSpecific(const Parameter::Id& id,
+                                                       Parameter::Specific* specific) {
+    auto tag = id.getTag();
+    RETURN_IF(Parameter::Id::spatializerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+    auto spatializerId = id.get<Parameter::Id::spatializerTag>();
+    auto spatializerTag = spatializerId.getTag();
+    switch (spatializerTag) {
+        case Spatializer::Id::commonTag: {
+            auto specificTag = spatializerId.get<Spatializer::Id::commonTag>();
+            std::optional<Spatializer> param = mContext->getParam(specificTag);
+            if (!param.has_value()) {
+                return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                        EX_ILLEGAL_ARGUMENT, "SpatializerTagNotSupported");
+            }
+            specific->set<Parameter::Specific::spatializer>(param.value());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "SpatializerTagNotSupported");
+        }
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> SpatializerSw::createContext(const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+    } else {
+        mContext = std::make_shared<SpatializerSwContext>(1 /* statusFmqDepth */, common);
+    }
+    return mContext;
+}
+
+std::shared_ptr<EffectContext> SpatializerSw::getContext() {
+    return mContext;
+}
+
+RetCode SpatializerSw::releaseContext() {
+    if (mContext) {
+        mContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+SpatializerSw::~SpatializerSw() {
+    cleanUp();
+    LOG(DEBUG) << __func__;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status SpatializerSw::effectProcessImpl(float* in, float* out, int samples) {
+    RETURN_VALUE_IF(!mContext, (IEffect::Status{EX_NULL_POINTER, 0, 0}), "nullContext");
+    return mContext->process(in, out, samples);
+}
+
+SpatializerSwContext::SpatializerSwContext(int statusDepth, const Parameter::Common& common)
+    : EffectContext(statusDepth, common) {
+    LOG(DEBUG) << __func__;
+}
+
+SpatializerSwContext::~SpatializerSwContext() {
+    LOG(DEBUG) << __func__;
+}
+
+template <typename TAG>
+std::optional<Spatializer> SpatializerSwContext::getParam(TAG tag) {
+    if (mParamsMap.find(tag) != mParamsMap.end()) {
+        return mParamsMap.at(tag);
+    }
+    return std::nullopt;
+}
+
+template <typename TAG>
+ndk::ScopedAStatus SpatializerSwContext::setParam(TAG tag, Spatializer spatializer) {
+    mParamsMap[tag] = spatializer;
+    return ndk::ScopedAStatus::ok();
+}
+
+IEffect::Status SpatializerSwContext::process(float* in, float* out, int samples) {
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+    IEffect::Status status = {EX_ILLEGAL_ARGUMENT, 0, 0};
+
+    const auto inputChannelCount = getChannelCount(mCommon.input.base.channelMask);
+    const auto outputChannelCount = getChannelCount(mCommon.output.base.channelMask);
+    if (outputChannelCount < 2 || inputChannelCount < outputChannelCount) {
+        LOG(ERROR) << __func__ << " invalid channel count, in: " << inputChannelCount
+                   << " out: " << outputChannelCount;
+        return status;
+    }
+
+    int iFrames = samples / inputChannelCount;
+    for (int i = 0; i < iFrames; i++) {
+        std::memcpy(out, in, outputChannelCount);
+        in += inputChannelCount;
+        out += outputChannelCount;
+    }
+    return {STATUS_OK, static_cast<int32_t>(iFrames * inputChannelCount),
+            static_cast<int32_t>(iFrames * outputChannelCount)};
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/spatializer/SpatializerSw.h b/audio/aidl/default/spatializer/SpatializerSw.h
new file mode 100644
index 0000000..b205704
--- /dev/null
+++ b/audio/aidl/default/spatializer/SpatializerSw.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "effect-impl/EffectContext.h"
+#include "effect-impl/EffectImpl.h"
+
+#include <fmq/AidlMessageQueue.h>
+
+#include <unordered_map>
+#include <vector>
+
+namespace aidl::android::hardware::audio::effect {
+
+class SpatializerSwContext final : public EffectContext {
+  public:
+    SpatializerSwContext(int statusDepth, const Parameter::Common& common);
+    ~SpatializerSwContext();
+
+    template <typename TAG>
+    std::optional<Spatializer> getParam(TAG tag);
+    template <typename TAG>
+    ndk::ScopedAStatus setParam(TAG tag, Spatializer spatializer);
+
+    IEffect::Status process(float* in, float* out, int samples);
+
+  private:
+    std::unordered_map<Spatializer::Tag, Spatializer> mParamsMap;
+};
+
+class SpatializerSw final : public EffectImpl {
+  public:
+    static const std::string kEffectName;
+    static const Capability kCapability;
+    static const Descriptor kDescriptor;
+    ~SpatializerSw();
+
+    ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
+                                            Parameter::Specific* specific) override;
+
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    std::shared_ptr<EffectContext> getContext() override;
+    RetCode releaseContext() override;
+
+    std::string getEffectName() override { return kEffectName; };
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+
+  private:
+    static const std::vector<Range::SpatializerRange> kRanges;
+    std::shared_ptr<SpatializerSwContext> mContext = nullptr;
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/stub/StreamStub.cpp b/audio/aidl/default/stub/StreamStub.cpp
index 660a51e..2422fe4 100644
--- a/audio/aidl/default/stub/StreamStub.cpp
+++ b/audio/aidl/default/stub/StreamStub.cpp
@@ -94,7 +94,7 @@
 }
 
 ::android::status_t StreamStub::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
-                                         int32_t* latencyMs) {
+                                         int32_t*) {
     if (!mIsInitialized) {
         LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
     }
@@ -117,7 +117,6 @@
         }
     }
     *actualFrameCount = frameCount;
-    *latencyMs = Module::kLatencyMs;
     return ::android::OK;
 }
 
diff --git a/audio/aidl/default/usb/ModuleUsb.cpp b/audio/aidl/default/usb/ModuleUsb.cpp
index f926e09..1d97bc4 100644
--- a/audio/aidl/default/usb/ModuleUsb.cpp
+++ b/audio/aidl/default/usb/ModuleUsb.cpp
@@ -87,12 +87,13 @@
                                               offloadInfo);
 }
 
-ndk::ScopedAStatus ModuleUsb::populateConnectedDevicePort(AudioPort* audioPort) {
+ndk::ScopedAStatus ModuleUsb::populateConnectedDevicePort(AudioPort* audioPort,
+                                                          int32_t nextPortId) {
     if (!isUsbDevicePort(*audioPort)) {
         LOG(ERROR) << __func__ << ": port id " << audioPort->id << " is not a usb device port";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
-    return ModuleAlsa::populateConnectedDevicePort(audioPort);
+    return ModuleAlsa::populateConnectedDevicePort(audioPort, nextPortId);
 }
 
 ndk::ScopedAStatus ModuleUsb::checkAudioPatchEndpointsMatch(
diff --git a/audio/aidl/default/virtualizer/Android.bp b/audio/aidl/default/virtualizer/Android.bp
index ed0199d..1c41bb5 100644
--- a/audio/aidl/default/virtualizer/Android.bp
+++ b/audio/aidl/default/virtualizer/Android.bp
@@ -27,8 +27,6 @@
     name: "libvirtualizersw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "VirtualizerSw.cpp",
diff --git a/audio/aidl/default/visualizer/Android.bp b/audio/aidl/default/visualizer/Android.bp
index 091daa2..68f7177 100644
--- a/audio/aidl/default/visualizer/Android.bp
+++ b/audio/aidl/default/visualizer/Android.bp
@@ -27,8 +27,6 @@
     name: "libvisualizersw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "VisualizerSw.cpp",
diff --git a/audio/aidl/default/visualizer/VisualizerSw.cpp b/audio/aidl/default/visualizer/VisualizerSw.cpp
index 0909f25..285c102 100644
--- a/audio/aidl/default/visualizer/VisualizerSw.cpp
+++ b/audio/aidl/default/visualizer/VisualizerSw.cpp
@@ -73,7 +73,7 @@
                           .proxy = std::nullopt},
                    .flags = {.type = Flags::Type::INSERT,
                              .insert = Flags::Insert::FIRST,
-                             .volume = Flags::Volume::CTRL},
+                             .volume = Flags::Volume::NONE},
                    .name = VisualizerSw::kEffectName,
                    .implementor = "The Android Open Source Project"},
         .capability = VisualizerSw::kCapability};
diff --git a/audio/aidl/default/volume/Android.bp b/audio/aidl/default/volume/Android.bp
index 418bb8d..f1a051f 100644
--- a/audio/aidl/default/volume/Android.bp
+++ b/audio/aidl/default/volume/Android.bp
@@ -27,8 +27,6 @@
     name: "libvolumesw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "VolumeSw.cpp",
diff --git a/audio/aidl/sounddose/Android.bp b/audio/aidl/sounddose/Android.bp
index 6f2f790..c65e4ff 100644
--- a/audio/aidl/sounddose/Android.bp
+++ b/audio/aidl/sounddose/Android.bp
@@ -52,11 +52,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-V1"
+latest_android_hardware_audio_sounddose = "android.hardware.audio.sounddose-V2"
 
 // 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 0de8574..85319ec 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -11,6 +11,7 @@
     name: "VtsHalAudioTargetTestDefaults",
     defaults: [
         "latest_android_hardware_audio_common_ndk_static",
+        "latest_android_hardware_audio_effect_ndk_static",
         "latest_android_media_audio_common_types_ndk_static",
         "use_libaidlvintf_gtest_helper_static",
         "VtsHalTargetTestDefaults",
@@ -20,7 +21,6 @@
         "libfmq",
     ],
     static_libs: [
-        "android.hardware.audio.effect-V1-ndk",
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
         "libaudioaidlcommon",
@@ -36,16 +36,27 @@
         "-Werror",
         "-Wthread-safety",
     ],
+    test_config_template: "VtsHalAudioTargetTestTemplate.xml",
     test_suites: [
         "general-tests",
         "vts",
     ],
     srcs: [
-        ":effectCommonFile",
         "TestUtils.cpp",
     ],
 }
 
+cc_defaults {
+    name: "VtsHalAudioEffectTargetTestDefaults",
+    defaults: [
+        "latest_android_hardware_audio_effect_ndk_static",
+        "VtsHalAudioTargetTestDefaults",
+    ],
+    srcs: [
+        ":effectCommonFile",
+    ],
+}
+
 cc_test {
     name: "VtsHalAudioCoreTargetTest",
     defaults: [
@@ -61,108 +72,116 @@
         "VtsHalAudioCoreConfigTargetTest.cpp",
         "VtsHalAudioCoreModuleTargetTest.cpp",
     ],
-    test_config: "VtsHalAudioCoreTargetTest.xml",
 }
 
 cc_test {
     name: "VtsHalAudioEffectFactoryTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalAudioEffectFactoryTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalAudioEffectTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalAudioEffectTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalBassBoostTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalBassBoostTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalDownmixTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalDownmixTargetTest.cpp"],
+    shared_libs: [
+        "libaudioutils",
+    ],
 }
 
 cc_test {
     name: "VtsHalDynamicsProcessingTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     static_libs: ["libaudioaidlranges"],
     srcs: ["VtsHalDynamicsProcessingTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalEnvironmentalReverbTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalEnvironmentalReverbTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalEqualizerTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalEqualizerTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalHapticGeneratorTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalHapticGeneratorTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalLoudnessEnhancerTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalLoudnessEnhancerTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalPresetReverbTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalPresetReverbTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalVirtualizerTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalVirtualizerTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalVisualizerTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalVisualizerTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalVolumeTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalVolumeTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalAECTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalAECTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalAGC1TargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalAGC1TargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalAGC2TargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalAGC2TargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalNSTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalNSTargetTest.cpp"],
 }
+
+cc_test {
+    name: "VtsHalSpatializerTargetTest",
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
+    srcs: ["VtsHalSpatializerTargetTest.cpp"],
+}
diff --git a/audio/aidl/vts/AudioHalBinderServiceUtil.h b/audio/aidl/vts/AudioHalBinderServiceUtil.h
index b4b4632..4ebc1b1 100644
--- a/audio/aidl/vts/AudioHalBinderServiceUtil.h
+++ b/audio/aidl/vts/AudioHalBinderServiceUtil.h
@@ -42,20 +42,9 @@
 
     ndk::SpAIBinder restartService(
             std::chrono::milliseconds timeoutMs = std::chrono::milliseconds(3000)) {
-        mDeathHandler.reset(new AidlDeathRecipient(mBinder));
-        if (STATUS_OK != mDeathHandler->linkToDeath()) {
-            LOG(ERROR) << "linkToDeath failed";
-            return nullptr;
+        if (!stopService(timeoutMs)) {
+            return {};
         }
-        if (!android::base::SetProperty("sys.audio.restart.hal", "1")) {
-            LOG(ERROR) << "SetProperty failed";
-            return nullptr;
-        }
-        if (!mDeathHandler->waitForFired(timeoutMs)) {
-            LOG(ERROR) << "Timeout wait for death";
-            return nullptr;
-        }
-        mDeathHandler.reset();
         return connectToService(mServiceName);
     }
 
@@ -71,8 +60,7 @@
 
         bool waitForFired(std::chrono::milliseconds timeoutMs) {
             std::unique_lock<std::mutex> lock(mutex);
-            condition.wait_for(lock, timeoutMs, [this]() { return fired; });
-            return fired;
+            return condition.wait_for(lock, timeoutMs, [this]() { return fired; });
         }
 
       private:
@@ -94,7 +82,23 @@
         }
     };
 
+    bool stopService(std::chrono::milliseconds timeoutMs) {
+        AidlDeathRecipient deathHandler(mBinder);
+        if (STATUS_OK != deathHandler.linkToDeath()) {
+            LOG(ERROR) << "linkToDeath failed";
+            return false;
+        }
+        if (!android::base::SetProperty("sys.audio.restart.hal", "1")) {
+            LOG(ERROR) << "SetProperty failed";
+            return false;
+        }
+        if (!deathHandler.waitForFired(timeoutMs)) {
+            LOG(ERROR) << "Timeout wait for death of " << mServiceName;
+            return false;
+        }
+        return true;
+    }
+
     std::string mServiceName;
     ndk::SpAIBinder mBinder;
-    std::unique_ptr<AidlDeathRecipient> mDeathHandler;
 };
diff --git a/audio/aidl/vts/EffectFactoryHelper.h b/audio/aidl/vts/EffectFactoryHelper.h
index a2499fd..ca36655 100644
--- a/audio/aidl/vts/EffectFactoryHelper.h
+++ b/audio/aidl/vts/EffectFactoryHelper.h
@@ -21,6 +21,7 @@
 #include <unordered_map>
 #include <vector>
 
+#include <aidl/Vintf.h>
 #include <android/binder_auto_utils.h>
 
 #include "TestUtils.h"
diff --git a/audio/aidl/vts/EffectHelper.h b/audio/aidl/vts/EffectHelper.h
index 2c8edf2..4a5c537 100644
--- a/audio/aidl/vts/EffectHelper.h
+++ b/audio/aidl/vts/EffectHelper.h
@@ -21,6 +21,7 @@
 #include <string>
 #include <type_traits>
 #include <unordered_map>
+#include <utility>
 #include <vector>
 
 #include <Utils.h>
@@ -263,12 +264,11 @@
         return s;
     }
 
-    template <typename T, typename S, Range::Tag R, typename T::Tag tag, typename Functor>
+    template <typename T, typename S, Range::Tag R, typename T::Tag tag>
     static std::set<S> getTestValueSet(
-            std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kFactoryDescList,
-            Functor functor) {
+            std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> descList) {
         std::set<S> result;
-        for (const auto& [_, desc] : kFactoryDescList) {
+        for (const auto& [_, desc] : descList) {
             if (desc.capability.range.getTag() == R) {
                 const auto& ranges = desc.capability.range.get<R>();
                 for (const auto& range : ranges) {
@@ -281,6 +281,42 @@
                 }
             }
         }
+        return result;
+    }
+
+    template <typename T, typename S, Range::Tag R, typename T::Tag tag, typename Functor>
+    static std::set<S> getTestValueSet(
+            std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> descList,
+            Functor functor) {
+        auto result = getTestValueSet<T, S, R, tag>(descList);
         return functor(result);
     }
+
+    static void processAndWriteToOutput(std::vector<float>& inputBuffer,
+                                        std::vector<float>& outputBuffer,
+                                        const std::shared_ptr<IEffect>& mEffect,
+                                        IEffect::OpenEffectReturn* mOpenEffectReturn) {
+        // Initialize AidlMessagequeues
+        auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(mOpenEffectReturn->statusMQ);
+        ASSERT_TRUE(statusMQ->isValid());
+        auto inputMQ = std::make_unique<EffectHelper::DataMQ>(mOpenEffectReturn->inputDataMQ);
+        ASSERT_TRUE(inputMQ->isValid());
+        auto outputMQ = std::make_unique<EffectHelper::DataMQ>(mOpenEffectReturn->outputDataMQ);
+        ASSERT_TRUE(outputMQ->isValid());
+
+        // Enabling the process
+        ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+        ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+
+        // Write from buffer to message queues and calling process
+        EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, inputBuffer));
+
+        // 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));
+    }
 };
diff --git a/audio/aidl/vts/ModuleConfig.cpp b/audio/aidl/vts/ModuleConfig.cpp
index 8f19547..2b86271 100644
--- a/audio/aidl/vts/ModuleConfig.cpp
+++ b/audio/aidl/vts/ModuleConfig.cpp
@@ -17,6 +17,9 @@
 #include <algorithm>
 #include <chrono>
 
+#define LOG_TAG "VtsHalAudio.ModuleConfig"
+#include <android-base/logging.h>
+
 #include <Utils.h>
 #include <aidl/android/media/audio/common/AudioInputFlags.h>
 #include <aidl/android/media/audio/common/AudioIoFlags.h>
@@ -67,20 +70,7 @@
     return {};
 }
 
-std::vector<aidl::android::media::audio::common::AudioPort>
-ModuleConfig::getAudioPortsForDeviceTypes(const std::vector<AudioDeviceType>& deviceTypes,
-                                          const std::string& connection) {
-    return getAudioPortsForDeviceTypes(mPorts, deviceTypes, connection);
-}
-
 // static
-std::vector<aidl::android::media::audio::common::AudioPort> ModuleConfig::getBuiltInMicPorts(
-        const std::vector<aidl::android::media::audio::common::AudioPort>& ports) {
-    return getAudioPortsForDeviceTypes(
-            ports, std::vector<AudioDeviceType>{AudioDeviceType::IN_MICROPHONE,
-                                                AudioDeviceType::IN_MICROPHONE_BACK});
-}
-
 std::vector<aidl::android::media::audio::common::AudioPort>
 ModuleConfig::getAudioPortsForDeviceTypes(
         const std::vector<aidl::android::media::audio::common::AudioPort>& ports,
@@ -100,6 +90,14 @@
     return result;
 }
 
+// static
+std::vector<aidl::android::media::audio::common::AudioPort> ModuleConfig::getBuiltInMicPorts(
+        const std::vector<aidl::android::media::audio::common::AudioPort>& ports) {
+    return getAudioPortsForDeviceTypes(
+            ports, std::vector<AudioDeviceType>{AudioDeviceType::IN_MICROPHONE,
+                                                AudioDeviceType::IN_MICROPHONE_BACK});
+}
+
 template <typename T>
 auto findById(const std::vector<T>& v, int32_t id) {
     return std::find_if(v.begin(), v.end(), [&](const auto& p) { return p.id == id; });
@@ -119,10 +117,7 @@
             } else {
                 mAttachedSinkDevicePorts.insert(port.id);
             }
-        } else if (devicePort.device.type.connection != AudioDeviceDescription::CONNECTION_VIRTUAL
-                   // The "virtual" connection is used for remote submix which is a dynamic
-                   // device but it can be connected and used w/o external hardware.
-                   && port.profiles.empty()) {
+        } else {
             mExternalDevicePorts.insert(port.id);
         }
     }
@@ -141,6 +136,12 @@
     return result;
 }
 
+std::vector<aidl::android::media::audio::common::AudioPort>
+ModuleConfig::getAudioPortsForDeviceTypes(const std::vector<AudioDeviceType>& deviceTypes,
+                                          const std::string& connection) const {
+    return getAudioPortsForDeviceTypes(mPorts, deviceTypes, connection);
+}
+
 std::vector<AudioPort> ModuleConfig::getConnectedExternalDevicePorts() const {
     std::vector<AudioPort> result;
     std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
@@ -229,6 +230,16 @@
     });
 }
 
+std::vector<AudioPort> ModuleConfig::getRemoteSubmixPorts(bool isInput, bool singlePort) const {
+    AudioDeviceType deviceType = isInput ? AudioDeviceType::IN_SUBMIX : AudioDeviceType::OUT_SUBMIX;
+    auto ports = getAudioPortsForDeviceTypes(std::vector<AudioDeviceType>{deviceType},
+                                             AudioDeviceDescription::CONNECTION_VIRTUAL);
+    if (singlePort) {
+        if (!ports.empty()) ports.resize(1);
+    }
+    return ports;
+}
+
 std::vector<AudioPort> ModuleConfig::getConnectedDevicesPortsForMixPort(
         bool isInput, const AudioPortConfig& mixPortConfig) const {
     const auto mixPortIt = findById<AudioPort>(mPorts, mixPortConfig.portId);
@@ -281,19 +292,29 @@
     return {};
 }
 
-std::vector<AudioPort> ModuleConfig::getRoutableMixPortsForDevicePort(const AudioPort& port) const {
-    std::set<int32_t> portIds;
-    for (const auto& route : mRoutes) {
-        if (port.id == route.sinkPortId) {
-            portIds.insert(route.sourcePortIds.begin(), route.sourcePortIds.end());
-        } else if (auto it = std::find(route.sourcePortIds.begin(), route.sourcePortIds.end(),
-                                       port.id);
-                   it != route.sourcePortIds.end()) {
-            portIds.insert(route.sinkPortId);
-        }
-    }
+std::vector<AudioPort> ModuleConfig::getRoutableDevicePortsForMixPort(const AudioPort& port,
+                                                                      bool connectedOnly) const {
+    std::set<int32_t> portIds = findRoutablePortIds(port.id);
     const bool isInput = port.flags.getTag() == AudioIoFlags::input;
-    return findMixPorts(isInput, false /*connectedOnly*/, false /*singlePort*/,
+    std::set<int32_t> devicePortIds;
+    if (connectedOnly) {
+        devicePortIds = isInput ? getConnectedSourceDevicePorts() : getConnectedSinkDevicePorts();
+    } else {
+        devicePortIds = portIds;
+    }
+    std::vector<AudioPort> result;
+    std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
+        return port.ext.getTag() == AudioPortExt::Tag::device && portIds.count(port.id) > 0 &&
+               devicePortIds.count(port.id) > 0;
+    });
+    return result;
+}
+
+std::vector<AudioPort> ModuleConfig::getRoutableMixPortsForDevicePort(const AudioPort& port,
+                                                                      bool connectedOnly) const {
+    std::set<int32_t> portIds = findRoutablePortIds(port.id);
+    const bool isInput = port.flags.getTag() == AudioIoFlags::input;
+    return findMixPorts(isInput, connectedOnly, false /*singlePort*/,
                         [&portIds](const AudioPort& p) { return portIds.count(p.id) > 0; });
 }
 
@@ -470,6 +491,20 @@
     return result;
 }
 
+std::set<int32_t> ModuleConfig::findRoutablePortIds(int32_t portId) const {
+    std::set<int32_t> portIds;
+    for (const auto& route : mRoutes) {
+        if (portId == route.sinkPortId) {
+            portIds.insert(route.sourcePortIds.begin(), route.sourcePortIds.end());
+        } else if (auto it = std::find(route.sourcePortIds.begin(), route.sourcePortIds.end(),
+                                       portId);
+                   it != route.sourcePortIds.end()) {
+            portIds.insert(route.sinkPortId);
+        }
+    }
+    return portIds;
+}
+
 std::vector<AudioPortConfig> ModuleConfig::generateAudioMixPortConfigs(
         const std::vector<AudioPort>& ports, bool isInput, bool singleProfile) const {
     std::vector<AudioPortConfig> result;
diff --git a/audio/aidl/vts/ModuleConfig.h b/audio/aidl/vts/ModuleConfig.h
index b89adc0..4a87f8c 100644
--- a/audio/aidl/vts/ModuleConfig.h
+++ b/audio/aidl/vts/ModuleConfig.h
@@ -38,9 +38,6 @@
     generateOffloadInfoIfNeeded(
             const aidl::android::media::audio::common::AudioPortConfig& portConfig);
 
-    std::vector<aidl::android::media::audio::common::AudioPort> getAudioPortsForDeviceTypes(
-            const std::vector<aidl::android::media::audio::common::AudioDeviceType>& deviceTypes,
-            const std::string& connection = "");
     static std::vector<aidl::android::media::audio::common::AudioPort> getAudioPortsForDeviceTypes(
             const std::vector<aidl::android::media::audio::common::AudioPort>& ports,
             const std::vector<aidl::android::media::audio::common::AudioDeviceType>& deviceTypes,
@@ -53,6 +50,9 @@
     std::string getError() const { return mStatus.getMessage(); }
 
     std::vector<aidl::android::media::audio::common::AudioPort> getAttachedDevicePorts() const;
+    std::vector<aidl::android::media::audio::common::AudioPort> getAudioPortsForDeviceTypes(
+            const std::vector<aidl::android::media::audio::common::AudioDeviceType>& deviceTypes,
+            const std::string& connection = "") const;
     std::vector<aidl::android::media::audio::common::AudioPort> getConnectedExternalDevicePorts()
             const;
     std::set<int32_t> getConnectedSinkDevicePorts() const;
@@ -85,6 +85,8 @@
     std::vector<aidl::android::media::audio::common::AudioPort> getMmapInMixPorts(
             bool connectedOnly /*Permanently attached and connected external devices*/,
             bool singlePort) const;
+    std::vector<aidl::android::media::audio::common::AudioPort> getRemoteSubmixPorts(
+            bool isInput, bool singlePort) const;
 
     std::vector<aidl::android::media::audio::common::AudioPort> getConnectedDevicesPortsForMixPort(
             bool isInput, const aidl::android::media::audio::common::AudioPort& mixPort) const {
@@ -103,8 +105,12 @@
     std::optional<aidl::android::media::audio::common::AudioPort>
     getSourceMixPortForConnectedDevice() const;
 
+    std::vector<aidl::android::media::audio::common::AudioPort> getRoutableDevicePortsForMixPort(
+            const aidl::android::media::audio::common::AudioPort& port,
+            bool connectedOnly /*Permanently attached and connected external devices*/) const;
     std::vector<aidl::android::media::audio::common::AudioPort> getRoutableMixPortsForDevicePort(
-            const aidl::android::media::audio::common::AudioPort& port) const;
+            const aidl::android::media::audio::common::AudioPort& port,
+            bool connectedOnly /*Permanently attached and connected external devices*/) const;
 
     std::optional<SrcSinkPair> getNonRoutableSrcSinkPair(bool isInput) const;
     std::optional<SrcSinkPair> getRoutableSrcSinkPair(bool isInput) const;
@@ -176,6 +182,7 @@
             bool isInput, bool connectedOnly, bool singlePort,
             const std::function<bool(const aidl::android::media::audio::common::AudioPort&)>& pred)
             const;
+    std::set<int32_t> findRoutablePortIds(int32_t portId) const;
     std::vector<aidl::android::media::audio::common::AudioPortConfig> generateAudioMixPortConfigs(
             const std::vector<aidl::android::media::audio::common::AudioPort>& ports, bool isInput,
             bool singleProfile) const;
diff --git a/audio/aidl/vts/TestUtils.h b/audio/aidl/vts/TestUtils.h
index 191e980..515b8a2 100644
--- a/audio/aidl/vts/TestUtils.h
+++ b/audio/aidl/vts/TestUtils.h
@@ -18,7 +18,6 @@
 
 #include <algorithm>
 #include <initializer_list>
-#include <iostream>
 
 #include <android/binder_auto_utils.h>
 #include <gtest/gtest.h>
@@ -70,6 +69,23 @@
                                          << "\n  but is has completed with: " << status;
 }
 
+inline ::testing::AssertionResult assertIsOkOrUnknownTransaction(
+        const char* expr, const ::ndk::ScopedAStatus& status) {
+    if (status.getStatus() == STATUS_UNKNOWN_TRANSACTION) {
+        return ::testing::AssertionSuccess();
+    }
+    return assertIsOk(expr, status);
+}
+
+inline ::testing::AssertionResult assertResultOrUnknownTransaction(
+        const char* exp_expr, const char* act_expr, int32_t expected,
+        const ::ndk::ScopedAStatus& status) {
+    if (status.getStatus() == STATUS_UNKNOWN_TRANSACTION) {
+        return ::testing::AssertionSuccess();
+    }
+    return assertResult(exp_expr, act_expr, expected, status);
+}
+
 }  // namespace detail
 
 }  // namespace android::hardware::audio::common::testing
@@ -93,4 +109,16 @@
         if ((flags).hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL || (flags).bypass) { \
             GTEST_SKIP() << "Skip data path for offload";                                        \
         }                                                                                        \
-    })
\ No newline at end of file
+    })
+
+// Test that the transaction status 'isOk' if it is a known transaction
+#define EXPECT_IS_OK_OR_UNKNOWN_TRANSACTION(ret)                                                 \
+    EXPECT_PRED_FORMAT1(                                                                         \
+            ::android::hardware::audio::common::testing::detail::assertIsOkOrUnknownTransaction, \
+            ret)
+
+// Test that the transaction status is as expected if it is a known transaction
+#define EXPECT_STATUS_OR_UNKNOWN_TRANSACTION(expected, ret)                                        \
+    EXPECT_PRED_FORMAT2(                                                                           \
+            ::android::hardware::audio::common::testing::detail::assertResultOrUnknownTransaction, \
+            expected, ret)
diff --git a/audio/aidl/vts/VtsHalAECTargetTest.cpp b/audio/aidl/vts/VtsHalAECTargetTest.cpp
index 39168b1..f972b84 100644
--- a/audio/aidl/vts/VtsHalAECTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAECTargetTest.cpp
@@ -18,7 +18,6 @@
 #include <string>
 #include <unordered_set>
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalAECParamTest"
 #include <android-base/logging.h>
 
diff --git a/audio/aidl/vts/VtsHalAGC1TargetTest.cpp b/audio/aidl/vts/VtsHalAGC1TargetTest.cpp
index 6066025..75da589 100644
--- a/audio/aidl/vts/VtsHalAGC1TargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAGC1TargetTest.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalAGC1ParamTest"
 #include <android-base/logging.h>
 
diff --git a/audio/aidl/vts/VtsHalAGC2TargetTest.cpp b/audio/aidl/vts/VtsHalAGC2TargetTest.cpp
index 8793e4c..5f57a88 100644
--- a/audio/aidl/vts/VtsHalAGC2TargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAGC2TargetTest.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalAGC2ParamTest"
 #include <android-base/logging.h>
 #include <android/binder_enums.h>
diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
index 53e51f4..f91795b 100644
--- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -113,10 +113,23 @@
 using ndk::ScopedAStatus;
 
 template <typename T>
-auto findById(std::vector<T>& v, int32_t id) {
+std::set<int32_t> extractIds(const std::vector<T>& v) {
+    std::set<int32_t> ids;
+    std::transform(v.begin(), v.end(), std::inserter(ids, ids.begin()),
+                   [](const auto& entity) { return entity.id; });
+    return ids;
+}
+
+template <typename T>
+auto findById(const std::vector<T>& v, int32_t id) {
     return std::find_if(v.begin(), v.end(), [&](const auto& e) { return e.id == id; });
 }
 
+template <typename T>
+auto findAny(const std::vector<T>& v, const std::set<int32_t>& ids) {
+    return std::find_if(v.begin(), v.end(), [&](const auto& e) { return ids.count(e.id) > 0; });
+}
+
 template <typename C>
 std::vector<int32_t> GetNonExistentIds(const C& allIds) {
     if (allIds.empty()) {
@@ -155,8 +168,10 @@
     static int nextId = 0;
     using Tag = AudioDeviceAddress::Tag;
     const auto& deviceDescription = port.ext.get<AudioPortExt::Tag::device>().device.type;
-    AudioDeviceAddress address;
-    if (kPointToPointConnections.count(deviceDescription.connection) == 0) {
+    AudioDeviceAddress address = port.ext.get<AudioPortExt::Tag::device>().device.address;
+    // If the address is already set, do not re-generate.
+    if (address == AudioDeviceAddress() &&
+        kPointToPointConnections.count(deviceDescription.connection) == 0) {
         switch (suggestDeviceAddressTag(deviceDescription)) {
             case Tag::id:
                 address = AudioDeviceAddress::make<Tag::id>(std::to_string(++nextId));
@@ -417,18 +432,21 @@
 // Can be used as a base for any test here, does not depend on the fixture GTest parameters.
 class AudioCoreModuleBase {
   public:
-    // Default buffer sizes are used mostly for negative tests.
-    static constexpr int kDefaultBufferSizeFrames = 256;
+    // Fixed buffer size are used for negative tests only. For any tests involving stream
+    // opening that must success, the minimum buffer size must be obtained from a patch.
+    // This is implemented by the 'StreamFixture' utility class.
+    static constexpr int kNegativeTestBufferSizeFrames = 256;
     static constexpr int kDefaultLargeBufferSizeFrames = 48000;
 
-    void SetUpImpl(const std::string& moduleName) {
-        ASSERT_NO_FATAL_FAILURE(ConnectToService(moduleName));
+    void SetUpImpl(const std::string& moduleName, bool setUpDebug = true) {
+        ASSERT_NO_FATAL_FAILURE(ConnectToService(moduleName, setUpDebug));
         ASSERT_IS_OK(module->getAudioPorts(&initialPorts));
         ASSERT_IS_OK(module->getAudioRoutes(&initialRoutes));
     }
 
     void TearDownImpl() {
         debug.reset();
+        ASSERT_NE(module, nullptr);
         std::vector<AudioPort> finalPorts;
         ASSERT_IS_OK(module->getAudioPorts(&finalPorts));
         EXPECT_NO_FATAL_FAILURE(VerifyVectorsAreEqual<AudioPort>(initialPorts, finalPorts))
@@ -439,21 +457,26 @@
                 << "The list of audio routes was not restored to the initial state";
     }
 
-    void ConnectToService(const std::string& moduleName) {
+    void ConnectToService(const std::string& moduleName, bool setUpDebug) {
         ASSERT_EQ(module, nullptr);
         ASSERT_EQ(debug, nullptr);
         module = IModule::fromBinder(binderUtil.connectToService(moduleName));
         ASSERT_NE(module, nullptr);
-        ASSERT_NO_FATAL_FAILURE(SetUpDebug());
+        if (setUpDebug) {
+            ASSERT_NO_FATAL_FAILURE(SetUpDebug());
+        }
     }
 
     void RestartService() {
         ASSERT_NE(module, nullptr);
         moduleConfig.reset();
+        const bool setUpDebug = !!debug;
         debug.reset();
         module = IModule::fromBinder(binderUtil.restartService());
         ASSERT_NE(module, nullptr);
-        ASSERT_NO_FATAL_FAILURE(SetUpDebug());
+        if (setUpDebug) {
+            ASSERT_NO_FATAL_FAILURE(SetUpDebug());
+        }
     }
 
     void SetUpDebug() {
@@ -493,9 +516,7 @@
                          const std::string& errorMessage) {
         std::vector<Entity> entities;
         { ASSERT_IS_OK((module.get()->*getter)(&entities)); }
-        std::transform(entities.begin(), entities.end(),
-                       std::inserter(*entityIds, entityIds->begin()),
-                       [](const auto& entity) { return entity.id; });
+        *entityIds = extractIds<Entity>(entities);
         EXPECT_EQ(entities.size(), entityIds->size()) << errorMessage;
     }
 
@@ -552,6 +573,8 @@
     WithDevicePortConnectedState& operator=(const WithDevicePortConnectedState&) = delete;
     ~WithDevicePortConnectedState() {
         if (mModule != nullptr) {
+            EXPECT_IS_OK_OR_UNKNOWN_TRANSACTION(mModule->prepareToDisconnectExternalDevice(getId()))
+                    << "when preparing to disconnect device port ID " << getId();
             EXPECT_IS_OK(mModule->disconnectExternalDevice(getId()))
                     << "when disconnecting device port ID " << getId();
         }
@@ -1112,6 +1135,7 @@
 template <typename T>
 struct IOTraits {
     static constexpr bool is_input = std::is_same_v<T, IStreamIn>;
+    static constexpr const char* directionStr = is_input ? "input" : "output";
     using Worker = std::conditional_t<is_input, StreamReader, StreamWriter>;
 };
 
@@ -1143,8 +1167,7 @@
     }
     ScopedAStatus SetUpNoChecks(IModule* module, const AudioPortConfig& portConfig,
                                 long bufferSizeFrames);
-    void SetUp(IModule* module, long bufferSizeFrames) {
-        ASSERT_NO_FATAL_FAILURE(SetUpPortConfig(module));
+    void SetUpStream(IModule* module, long bufferSizeFrames) {
         ASSERT_IS_OK(SetUpNoChecks(module, bufferSizeFrames)) << "port config id " << getPortId();
         ASSERT_NE(nullptr, mStream) << "port config id " << getPortId();
         EXPECT_GE(mDescriptor.bufferSizeFrames, bufferSizeFrames)
@@ -1152,6 +1175,10 @@
         mContext.emplace(mDescriptor);
         ASSERT_NO_FATAL_FAILURE(mContext.value().checkIsValid());
     }
+    void SetUp(IModule* module, long bufferSizeFrames) {
+        ASSERT_NO_FATAL_FAILURE(SetUpPortConfig(module));
+        ASSERT_NO_FATAL_FAILURE(SetUpStream(module, bufferSizeFrames));
+    }
     Stream* get() const { return mStream.get(); }
     const StreamContext* getContext() const { return mContext ? &(mContext.value()) : nullptr; }
     StreamEventReceiver* getEventReceiver() { return mStreamCallback->getEventReceiver(); }
@@ -1291,6 +1318,9 @@
     }
     int32_t getId() const { return mPatch.id; }
     const AudioPatch& get() const { return mPatch; }
+    int32_t getMinimumStreamBufferSizeFrames() const {
+        return mPatch.minimumStreamBufferSizeFrames;
+    }
     const AudioPortConfig& getSinkPortConfig() const { return mSinkPortConfig.get(); }
     const AudioPortConfig& getSrcPortConfig() const { return mSrcPortConfig.get(); }
     const AudioPortConfig& getPortConfig(bool getSink) const {
@@ -1503,8 +1533,8 @@
         EXPECT_EQ(portConnected.get(), connectedPort);
         const auto& portProfiles = connectedPort.profiles;
         if (portProfiles.empty()) {
-            const auto routableMixPorts =
-                    moduleConfig->getRoutableMixPortsForDevicePort(connectedPort);
+            const auto routableMixPorts = moduleConfig->getRoutableMixPortsForDevicePort(
+                    connectedPort, true /*connectedOnly*/);
             bool hasMixPortWithStaticProfile = false;
             for (const auto& mixPort : routableMixPorts) {
                 const auto& mixPortProfiles = mixPort.profiles;
@@ -1545,7 +1575,7 @@
         {
             aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
             args.portConfigId = portConfigId;
-            args.bufferSizeFrames = kDefaultBufferSizeFrames;
+            args.bufferSizeFrames = kNegativeTestBufferSizeFrames;
             aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
             EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openInputStream(args, &ret))
                     << "port config ID " << portConfigId;
@@ -1554,7 +1584,7 @@
         {
             aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
             args.portConfigId = portConfigId;
-            args.bufferSizeFrames = kDefaultBufferSizeFrames;
+            args.bufferSizeFrames = kNegativeTestBufferSizeFrames;
             aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
             EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
                     << "port config ID " << portConfigId;
@@ -1717,10 +1747,17 @@
     doNotSimulateConnections.flags().simulateDeviceConnections = false;
     ASSERT_NO_FATAL_FAILURE(doNotSimulateConnections.SetUp(module.get()));
     for (const auto& port : ports) {
+        // Virtual devices may not require external hardware and thus can always be connected.
+        if (port.ext.get<AudioPortExt::device>().device.type.connection ==
+            AudioDeviceDescription::CONNECTION_VIRTUAL)
+            continue;
         AudioPort portWithData = GenerateUniqueDeviceAddress(port), connectedPort;
         ScopedAStatus status = module->connectExternalDevice(portWithData, &connectedPort);
         EXPECT_STATUS(EX_ILLEGAL_STATE, status) << "static port " << portWithData.toString();
         if (status.isOk()) {
+            EXPECT_IS_OK_OR_UNKNOWN_TRANSACTION(
+                    module->prepareToDisconnectExternalDevice(connectedPort.id))
+                    << "when preparing to disconnect device port ID " << connectedPort.id;
             EXPECT_IS_OK(module->disconnectExternalDevice(connectedPort.id))
                     << "when disconnecting device port ID " << connectedPort.id;
         }
@@ -1750,6 +1787,9 @@
         invalidPort.id = portId;
         EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(invalidPort, &ignored))
                 << "port ID " << portId << ", when setting CONNECTED state";
+        EXPECT_STATUS_OR_UNKNOWN_TRANSACTION(EX_ILLEGAL_ARGUMENT,
+                                             module->prepareToDisconnectExternalDevice(portId))
+                << "port ID " << portId << ", when preparing to disconnect";
         EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(portId))
                 << "port ID " << portId << ", when setting DISCONNECTED state";
     }
@@ -1760,6 +1800,9 @@
         if (port.ext.getTag() != AudioPortExt::Tag::device) {
             EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(port, &ignored))
                     << "non-device port ID " << port.id << " when setting CONNECTED state";
+            EXPECT_STATUS_OR_UNKNOWN_TRANSACTION(EX_ILLEGAL_ARGUMENT,
+                                                 module->prepareToDisconnectExternalDevice(port.id))
+                    << "non-device port ID " << port.id << " when preparing to disconnect";
             EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
                     << "non-device port ID " << port.id << " when setting DISCONNECTED state";
         } else {
@@ -1768,6 +1811,10 @@
                 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(port, &ignored))
                         << "for a permanently attached device port ID " << port.id
                         << " when setting CONNECTED state";
+                EXPECT_STATUS_OR_UNKNOWN_TRANSACTION(
+                        EX_ILLEGAL_ARGUMENT, module->prepareToDisconnectExternalDevice(port.id))
+                        << "for a permanently attached device port ID " << port.id
+                        << " when preparing to disconnect";
                 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
                         << "for a permanently attached device port ID " << port.id
                         << " when setting DISCONNECTED state";
@@ -1785,6 +1832,9 @@
         GTEST_SKIP() << "No external devices in the module.";
     }
     for (const auto& port : ports) {
+        EXPECT_STATUS_OR_UNKNOWN_TRANSACTION(EX_ILLEGAL_ARGUMENT,
+                                             module->prepareToDisconnectExternalDevice(port.id))
+                << "when preparing to disconnect already disconnected device port ID " << port.id;
         EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
                 << "when disconnecting already disconnected device port ID " << port.id;
         AudioPort portWithData = GenerateUniqueDeviceAddress(port);
@@ -1819,6 +1869,10 @@
             // Our test assumes that 'getAudioPort' returns at least one profile, and it
             // is not a dynamic profile.
             ASSERT_NO_FATAL_FAILURE(config.SetUp(module.get()));
+            EXPECT_IS_OK_OR_UNKNOWN_TRANSACTION(
+                    module->prepareToDisconnectExternalDevice(portConnected.getId()))
+                    << "when preparing to disconnect device port ID " << port.id
+                    << " with active configuration " << config.getId();
             EXPECT_STATUS(EX_ILLEGAL_STATE, module->disconnectExternalDevice(portConnected.getId()))
                     << "when trying to disconnect device port ID " << port.id
                     << " with active configuration " << config.getId();
@@ -2563,6 +2617,260 @@
     std::vector<std::string> mStatuses;
 };
 
+// A helper which sets up necessary HAL structures for a proper stream initialization.
+//
+// The full sequence of actions to set up a stream is as follows:
+//
+//  device port -> connect if necessary -> set up port config   | -> set up patch
+//  mix port -> set up port config, unless it has been provided |
+//
+//  then, from the patch, figure out the minimum HAL buffer size -> set up stream
+//
+// This sequence is reflected in the order of fields declaration.
+// Various tests need to be able to start and stop at various point in this sequence,
+// this is why there are methods that do just part of the work.
+//
+// Note: To maximize test coverage, this class relies on simulation of external device
+// connections by the HAL module.
+template <typename Stream>
+class StreamFixture {
+  public:
+    // Tests might need to override the direction.
+    StreamFixture(bool isInput = IOTraits<Stream>::is_input) : mIsInput(isInput) {}
+
+    void SetUpPortConfigAnyMixPort(IModule* module, ModuleConfig* moduleConfig,
+                                   bool connectedOnly) {
+        const auto mixPorts = moduleConfig->getMixPorts(mIsInput, connectedOnly);
+        mSkipTestReason = "No mix ports";
+        for (const auto& mixPort : mixPorts) {
+            mSkipTestReason = "";
+            ASSERT_NO_FATAL_FAILURE(SetUpPortConfigForMixPortOrConfig(module, moduleConfig, mixPort,
+                                                                      connectedOnly));
+            if (mSkipTestReason.empty()) break;
+        }
+    }
+
+    void SetUpPortConfigForMixPortOrConfig(
+            IModule* module, ModuleConfig* moduleConfig, const AudioPort& initialMixPort,
+            bool connectedOnly, const std::optional<AudioPortConfig>& mixPortConfig = {}) {
+        if (mixPortConfig.has_value() && !connectedOnly) {
+            // Connecting an external device may cause change in mix port profiles and the provided
+            // config may become invalid.
+            LOG(FATAL) << __func__ << ": when specifying a mix port config, it is not allowed "
+                       << "to change connected devices, thus `connectedOnly` must be `true`";
+        }
+        std::optional<AudioPort> connectedDevicePort;
+        ASSERT_NO_FATAL_FAILURE(SetUpDevicePortForMixPort(module, moduleConfig, initialMixPort,
+                                                          connectedOnly, &connectedDevicePort));
+        if (!mSkipTestReason.empty()) return;
+        if (mixPortConfig.has_value()) {
+            ASSERT_NO_FATAL_FAILURE(
+                    SetUpPortConfig(module, moduleConfig, *mixPortConfig, *connectedDevicePort));
+        } else {
+            // If an external device was connected, the profiles of the mix port might have changed.
+            AudioPort mixPort;
+            ASSERT_NO_FATAL_FAILURE(module->getAudioPort(initialMixPort.id, &mixPort));
+            ASSERT_NO_FATAL_FAILURE(
+                    SetUpPortConfig(module, moduleConfig, mixPort, *connectedDevicePort));
+        }
+    }
+
+    void SetUpPortConfig(IModule* module, ModuleConfig* moduleConfig, const AudioPort& mixPort,
+                         const AudioPort& devicePort) {
+        auto mixPortConfig = moduleConfig->getSingleConfigForMixPort(mIsInput, mixPort);
+        ASSERT_TRUE(mixPortConfig.has_value())
+                << "Unable to generate port config for mix port " << mixPort.toString();
+        ASSERT_NO_FATAL_FAILURE(SetUpPortConfig(module, moduleConfig, *mixPortConfig, devicePort));
+    }
+    void SetUpPortConfig(IModule* module, ModuleConfig* moduleConfig,
+                         const AudioPortConfig& mixPortConfig, const AudioPort& devicePort) {
+        ASSERT_NO_FATAL_FAILURE(SetUpPatch(module, moduleConfig, mixPortConfig, devicePort));
+        mStream = std::make_unique<WithStream<Stream>>(mMixPortConfig->get());
+        ASSERT_NO_FATAL_FAILURE(mStream->SetUpPortConfig(module));
+    }
+
+    ScopedAStatus SetUpStreamNoChecks(IModule* module) {
+        return mStream->SetUpNoChecks(module, getMinimumStreamBufferSizeFrames());
+    }
+    void SetUpStream(IModule* module) {
+        ASSERT_NO_FATAL_FAILURE(mStream->SetUpStream(module, getMinimumStreamBufferSizeFrames()));
+    }
+
+    void SetUpStreamForDevicePort(IModule* module, ModuleConfig* moduleConfig,
+                                  const AudioPort& devicePort, bool connectedOnly = false) {
+        ASSERT_NO_FATAL_FAILURE(
+                SetUpPortConfigForDevicePort(module, moduleConfig, devicePort, connectedOnly));
+        if (!mSkipTestReason.empty()) return;
+        ASSERT_NO_FATAL_FAILURE(SetUpStream(module));
+    }
+    void SetUpStreamForAnyMixPort(IModule* module, ModuleConfig* moduleConfig,
+                                  bool connectedOnly = false) {
+        ASSERT_NO_FATAL_FAILURE(SetUpPortConfigAnyMixPort(module, moduleConfig, connectedOnly));
+        if (!mSkipTestReason.empty()) return;
+        ASSERT_NO_FATAL_FAILURE(SetUpStream(module));
+    }
+    void SetUpStreamForMixPort(IModule* module, ModuleConfig* moduleConfig,
+                               const AudioPort& mixPort, bool connectedOnly = false) {
+        ASSERT_NO_FATAL_FAILURE(
+                SetUpPortConfigForMixPortOrConfig(module, moduleConfig, mixPort, connectedOnly));
+        if (!mSkipTestReason.empty()) return;
+        ASSERT_NO_FATAL_FAILURE(SetUpStream(module));
+    }
+    void SetUpStreamForPortsPair(IModule* module, ModuleConfig* moduleConfig,
+                                 const AudioPort& mixPort, const AudioPort& devicePort) {
+        ASSERT_NO_FATAL_FAILURE(SetUpPortConfig(module, moduleConfig, mixPort, devicePort));
+        if (!mSkipTestReason.empty()) return;
+        ASSERT_NO_FATAL_FAILURE(SetUpStream(module));
+    }
+    void SetUpStreamForMixPortConfig(IModule* module, ModuleConfig* moduleConfig,
+                                     const AudioPortConfig& mixPortConfig) {
+        // Since mix port configs may change after connecting an external device,
+        // only connected device ports are considered.
+        constexpr bool connectedOnly = true;
+        const auto& ports = moduleConfig->getMixPorts(mIsInput, connectedOnly);
+        const auto mixPortIt = findById<AudioPort>(ports, mixPortConfig.portId);
+        ASSERT_NE(mixPortIt, ports.end()) << "Port id " << mixPortConfig.portId << " not found";
+        ASSERT_NO_FATAL_FAILURE(SetUpPortConfigForMixPortOrConfig(module, moduleConfig, *mixPortIt,
+                                                                  connectedOnly, mixPortConfig));
+        if (!mSkipTestReason.empty()) return;
+        ASSERT_NO_FATAL_FAILURE(SetUpStream(module));
+    }
+    void SetUpPatchForMixPortConfig(IModule* module, ModuleConfig* moduleConfig,
+                                    const AudioPortConfig& mixPortConfig) {
+        constexpr bool connectedOnly = true;
+        const auto& ports = moduleConfig->getMixPorts(mIsInput, connectedOnly);
+        const auto mixPortIt = findById<AudioPort>(ports, mixPortConfig.portId);
+        ASSERT_NE(mixPortIt, ports.end()) << "Port id " << mixPortConfig.portId << " not found";
+        std::optional<AudioPort> connectedDevicePort;
+        ASSERT_NO_FATAL_FAILURE(SetUpDevicePortForMixPort(module, moduleConfig, *mixPortIt,
+                                                          connectedOnly, &connectedDevicePort));
+        if (!mSkipTestReason.empty()) return;
+        ASSERT_NO_FATAL_FAILURE(
+                SetUpPatch(module, moduleConfig, mixPortConfig, *connectedDevicePort));
+    }
+
+    void ReconnectPatch(IModule* module) {
+        mPatch = std::make_unique<WithAudioPatch>(mIsInput, mMixPortConfig->get(),
+                                                  mDevicePortConfig->get());
+        ASSERT_NO_FATAL_FAILURE(mPatch->SetUp(module));
+    }
+    void TeardownPatch() { mPatch.reset(); }
+    // Assuming that the patch is set up, while the stream isn't yet,
+    // tear the patch down and set up stream.
+    void TeardownPatchSetUpStream(IModule* module) {
+        const int32_t bufferSize = getMinimumStreamBufferSizeFrames();
+        ASSERT_NO_FATAL_FAILURE(TeardownPatch());
+        mStream = std::make_unique<WithStream<Stream>>(mMixPortConfig->get());
+        ASSERT_NO_FATAL_FAILURE(mStream->SetUpPortConfig(module));
+        ASSERT_NO_FATAL_FAILURE(mStream->SetUpStream(module, bufferSize));
+    }
+
+    const AudioDevice& getDevice() const { return mDevice; }
+    int32_t getMinimumStreamBufferSizeFrames() const {
+        return mPatch->getMinimumStreamBufferSizeFrames();
+    }
+    const AudioPatch& getPatch() const { return mPatch->get(); }
+    const AudioPortConfig& getPortConfig() const { return mMixPortConfig->get(); }
+    int32_t getPortId() const { return mMixPortConfig->getId(); }
+    Stream* getStream() const { return mStream->get(); }
+    const StreamContext* getStreamContext() const { return mStream->getContext(); }
+    StreamEventReceiver* getStreamEventReceiver() { return mStream->getEventReceiver(); }
+    std::shared_ptr<Stream> getStreamSharedPointer() const { return mStream->getSharedPointer(); }
+    const std::string& skipTestReason() const { return mSkipTestReason; }
+
+  private:
+    void SetUpDevicePort(IModule* module, ModuleConfig* moduleConfig,
+                         const std::set<int32_t>& devicePortIds, bool connectedOnly,
+                         std::optional<AudioPort>* connectedDevicePort) {
+        const auto attachedDevicePorts = moduleConfig->getAttachedDevicePorts();
+        if (auto it = findAny<AudioPort>(attachedDevicePorts, devicePortIds);
+            it != attachedDevicePorts.end()) {
+            *connectedDevicePort = *it;
+            LOG(DEBUG) << __func__ << ": found attached port " << it->toString();
+        }
+        const auto connectedDevicePorts = moduleConfig->getConnectedExternalDevicePorts();
+        if (auto it = findAny<AudioPort>(connectedDevicePorts, devicePortIds);
+            it != connectedDevicePorts.end()) {
+            *connectedDevicePort = *it;
+            LOG(DEBUG) << __func__ << ": found connected port " << it->toString();
+        }
+        if (!connectedOnly && !connectedDevicePort->has_value()) {
+            const auto externalDevicePorts = moduleConfig->getExternalDevicePorts();
+            if (auto it = findAny<AudioPort>(externalDevicePorts, devicePortIds);
+                it != externalDevicePorts.end()) {
+                AudioPort portWithData = GenerateUniqueDeviceAddress(*it);
+                mPortConnected = std::make_unique<WithDevicePortConnectedState>(portWithData);
+                ASSERT_NO_FATAL_FAILURE(mPortConnected->SetUp(module, moduleConfig));
+                *connectedDevicePort = mPortConnected->get();
+                LOG(DEBUG) << __func__ << ": connected port " << mPortConnected->get().toString();
+            }
+        }
+    }
+    void SetUpDevicePortForMixPort(IModule* module, ModuleConfig* moduleConfig,
+                                   const AudioPort& mixPort, bool connectedOnly,
+                                   std::optional<AudioPort>* connectedDevicePort) {
+        const auto devicePorts =
+                moduleConfig->getRoutableDevicePortsForMixPort(mixPort, connectedOnly);
+        if (devicePorts.empty()) {
+            mSkipTestReason = std::string("No routable device ports found for mix port id ")
+                                      .append(std::to_string(mixPort.id));
+            LOG(DEBUG) << __func__ << ": " << mSkipTestReason;
+            return;
+        };
+        ASSERT_NO_FATAL_FAILURE(SetUpDevicePort(module, moduleConfig,
+                                                extractIds<AudioPort>(devicePorts), connectedOnly,
+                                                connectedDevicePort));
+        if (!connectedDevicePort->has_value()) {
+            mSkipTestReason = std::string("Unable to find a device port pair for mix port id ")
+                                      .append(std::to_string(mixPort.id));
+            LOG(DEBUG) << __func__ << ": " << mSkipTestReason;
+            return;
+        }
+    }
+    void SetUpPortConfigForDevicePort(IModule* module, ModuleConfig* moduleConfig,
+                                      const AudioPort& devicePort, bool connectedOnly) {
+        std::optional<AudioPort> connectedDevicePort;
+        ASSERT_NO_FATAL_FAILURE(SetUpDevicePort(module, moduleConfig, {devicePort.id},
+                                                connectedOnly, &connectedDevicePort));
+        if (!connectedDevicePort.has_value()) {
+            mSkipTestReason = std::string("Device port id ")
+                                      .append(std::to_string(devicePort.id))
+                                      .append(" is not attached and can not be connected");
+            return;
+        }
+        const auto mixPorts = moduleConfig->getRoutableMixPortsForDevicePort(
+                *connectedDevicePort, true /*connectedOnly*/);
+        if (mixPorts.empty()) {
+            mSkipTestReason = std::string("No routable mix ports found for device port id ")
+                                      .append(std::to_string(devicePort.id));
+            return;
+        }
+        ASSERT_NO_FATAL_FAILURE(
+                SetUpPortConfig(module, moduleConfig, *mixPorts.begin(), *connectedDevicePort));
+    }
+    void SetUpPatch(IModule* module, ModuleConfig* moduleConfig,
+                    const AudioPortConfig& mixPortConfig, const AudioPort& devicePort) {
+        mMixPortConfig = std::make_unique<WithAudioPortConfig>(mixPortConfig);
+        ASSERT_NO_FATAL_FAILURE(mMixPortConfig->SetUp(module));
+        mDevicePortConfig = std::make_unique<WithAudioPortConfig>(
+                moduleConfig->getSingleConfigForDevicePort(devicePort));
+        ASSERT_NO_FATAL_FAILURE(mDevicePortConfig->SetUp(module));
+        mDevice = devicePort.ext.get<AudioPortExt::device>().device;
+        mPatch = std::make_unique<WithAudioPatch>(mIsInput, mMixPortConfig->get(),
+                                                  mDevicePortConfig->get());
+        ASSERT_NO_FATAL_FAILURE(mPatch->SetUp(module));
+    }
+
+    const bool mIsInput;
+    std::string mSkipTestReason;
+    std::unique_ptr<WithDevicePortConnectedState> mPortConnected;
+    AudioDevice mDevice;
+    std::unique_ptr<WithAudioPortConfig> mMixPortConfig;
+    std::unique_ptr<WithAudioPortConfig> mDevicePortConfig;
+    std::unique_ptr<WithAudioPatch> mPatch;
+    std::unique_ptr<WithStream<Stream>> mStream;
+};
+
 template <typename Stream>
 class AudioStream : public AudioCoreModule {
   public:
@@ -2572,16 +2880,15 @@
     }
 
     void GetStreamCommon() {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
-        if (!portConfig.has_value()) {
-            GTEST_SKIP() << "No mix port for attached devices";
+        StreamFixture<Stream> stream;
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForAnyMixPort(module.get(), moduleConfig.get()));
+        if (auto reason = stream.skipTestReason(); !reason.empty()) {
+            GTEST_SKIP() << reason;
         }
-        WithStream<Stream> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
         std::shared_ptr<IStreamCommon> streamCommon1;
-        EXPECT_IS_OK(stream.get()->getStreamCommon(&streamCommon1));
+        EXPECT_IS_OK(stream.getStream()->getStreamCommon(&streamCommon1));
         std::shared_ptr<IStreamCommon> streamCommon2;
-        EXPECT_IS_OK(stream.get()->getStreamCommon(&streamCommon2));
+        EXPECT_IS_OK(stream.getStream()->getStreamCommon(&streamCommon2));
         ASSERT_NE(nullptr, streamCommon1);
         ASSERT_NE(nullptr, streamCommon2);
         EXPECT_EQ(streamCommon1->asBinder(), streamCommon2->asBinder())
@@ -2589,31 +2896,31 @@
     }
 
     void CloseTwice() {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
-        if (!portConfig.has_value()) {
-            GTEST_SKIP() << "No mix port for attached devices";
-        }
         std::shared_ptr<Stream> heldStream;
         {
-            WithStream<Stream> stream(portConfig.value());
-            ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
-            heldStream = stream.getSharedPointer();
+            StreamFixture<Stream> stream;
+            ASSERT_NO_FATAL_FAILURE(
+                    stream.SetUpStreamForAnyMixPort(module.get(), moduleConfig.get()));
+            if (auto reason = stream.skipTestReason(); !reason.empty()) {
+                GTEST_SKIP() << reason;
+            }
+            heldStream = stream.getStreamSharedPointer();
         }
         EXPECT_STATUS(EX_ILLEGAL_STATE, WithStream<Stream>::callClose(heldStream))
                 << "when closing the stream twice";
     }
 
     void PrepareToCloseTwice() {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
-        if (!portConfig.has_value()) {
-            GTEST_SKIP() << "No mix port for attached devices";
-        }
         std::shared_ptr<IStreamCommon> heldStreamCommon;
         {
-            WithStream<Stream> stream(portConfig.value());
-            ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+            StreamFixture<Stream> stream;
+            ASSERT_NO_FATAL_FAILURE(
+                    stream.SetUpStreamForAnyMixPort(module.get(), moduleConfig.get()));
+            if (auto reason = stream.skipTestReason(); !reason.empty()) {
+                GTEST_SKIP() << reason;
+            }
             std::shared_ptr<IStreamCommon> streamCommon;
-            ASSERT_IS_OK(stream.get()->getStreamCommon(&streamCommon));
+            ASSERT_IS_OK(stream.getStream()->getStreamCommon(&streamCommon));
             heldStreamCommon = streamCommon;
             EXPECT_IS_OK(streamCommon->prepareToClose());
             EXPECT_IS_OK(streamCommon->prepareToClose())
@@ -2626,9 +2933,13 @@
     void OpenAllConfigs() {
         const auto allPortConfigs =
                 moduleConfig->getPortConfigsForMixPorts(IOTraits<Stream>::is_input);
+        if (allPortConfigs.empty()) {
+            GTEST_SKIP() << "No mix ports for attached devices";
+        }
         for (const auto& portConfig : allPortConfigs) {
-            WithStream<Stream> stream(portConfig);
-            ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+            StreamFixture<Stream> stream;
+            ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPortConfig(
+                    module.get(), moduleConfig.get(), portConfig));
         }
     }
 
@@ -2648,22 +2959,21 @@
 
     void OpenInvalidDirection() {
         // Important! The direction of the port config must be reversed.
-        const auto portConfig =
-                moduleConfig->getSingleConfigForMixPort(!IOTraits<Stream>::is_input);
-        if (!portConfig.has_value()) {
-            GTEST_SKIP() << "No mix port for attached devices";
+        StreamFixture<Stream> stream(!IOTraits<Stream>::is_input);
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfigAnyMixPort(module.get(), moduleConfig.get(),
+                                                                 false /*connectedOnly*/));
+        if (auto reason = stream.skipTestReason(); !reason.empty()) {
+            GTEST_SKIP() << reason;
         }
-        WithStream<Stream> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
-        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
-                      stream.SetUpNoChecks(module.get(), kDefaultBufferSizeFrames))
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, stream.SetUpStreamNoChecks(module.get()))
                 << "port config ID " << stream.getPortId();
-        EXPECT_EQ(nullptr, stream.get());
+        EXPECT_EQ(nullptr, stream.getStream());
     }
 
     void OpenOverMaxCount() {
+        constexpr bool connectedOnly = true;
         constexpr bool isInput = IOTraits<Stream>::is_input;
-        auto ports = moduleConfig->getMixPorts(isInput, true /*connectedOnly*/);
+        auto ports = moduleConfig->getMixPorts(isInput, connectedOnly);
         bool hasSingleRun = false;
         for (const auto& port : ports) {
             const size_t maxStreamCount = port.ext.get<AudioPortExt::Tag::mix>().maxOpenStreamCount;
@@ -2676,16 +2986,16 @@
                 continue;
             }
             hasSingleRun = true;
-            std::optional<WithStream<Stream>> streamWraps[maxStreamCount + 1];
+            StreamFixture<Stream> streams[maxStreamCount + 1];
             for (size_t i = 0; i <= maxStreamCount; ++i) {
-                streamWraps[i].emplace(portConfigs[i]);
-                WithStream<Stream>& stream = streamWraps[i].value();
+                ASSERT_NO_FATAL_FAILURE(streams[i].SetUpPortConfigForMixPortOrConfig(
+                        module.get(), moduleConfig.get(), port, connectedOnly, portConfigs[i]));
+                ASSERT_EQ("", streams[i].skipTestReason());
+                auto& stream = streams[i];
                 if (i < maxStreamCount) {
-                    ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+                    ASSERT_NO_FATAL_FAILURE(stream.SetUpStream(module.get()));
                 } else {
-                    ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
-                    EXPECT_STATUS(EX_ILLEGAL_STATE,
-                                  stream.SetUpNoChecks(module.get(), kDefaultBufferSizeFrames))
+                    EXPECT_STATUS(EX_ILLEGAL_STATE, stream.SetUpStreamNoChecks(module.get()))
                             << "port config ID " << stream.getPortId() << ", maxOpenStreamCount is "
                             << maxStreamCount;
                 }
@@ -2705,12 +3015,11 @@
     }
 
     void ResetPortConfigWithOpenStream() {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
-        if (!portConfig.has_value()) {
-            GTEST_SKIP() << "No mix port for attached devices";
+        StreamFixture<Stream> stream;
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForAnyMixPort(module.get(), moduleConfig.get()));
+        if (auto reason = stream.skipTestReason(); !reason.empty()) {
+            GTEST_SKIP() << reason;
         }
-        WithStream<Stream> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
         EXPECT_STATUS(EX_ILLEGAL_STATE, module->resetAudioPortConfig(stream.getPortId()))
                 << "port config ID " << stream.getPortId();
     }
@@ -2724,14 +3033,13 @@
     }
 
     void UpdateHwAvSyncId() {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
-        if (!portConfig.has_value()) {
-            GTEST_SKIP() << "No mix port for attached devices";
+        StreamFixture<Stream> stream;
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForAnyMixPort(module.get(), moduleConfig.get()));
+        if (auto reason = stream.skipTestReason(); !reason.empty()) {
+            GTEST_SKIP() << reason;
         }
-        WithStream<Stream> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
         std::shared_ptr<IStreamCommon> streamCommon;
-        ASSERT_IS_OK(stream.get()->getStreamCommon(&streamCommon));
+        ASSERT_IS_OK(stream.getStream()->getStreamCommon(&streamCommon));
         ASSERT_NE(nullptr, streamCommon);
         const auto kStatuses = {EX_NONE, EX_ILLEGAL_ARGUMENT, EX_ILLEGAL_STATE};
         for (const auto id : {-100, -1, 0, 1, 100}) {
@@ -2744,14 +3052,13 @@
     }
 
     void GetVendorParameters() {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
-        if (!portConfig.has_value()) {
-            GTEST_SKIP() << "No mix port for attached devices";
+        StreamFixture<Stream> stream;
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForAnyMixPort(module.get(), moduleConfig.get()));
+        if (auto reason = stream.skipTestReason(); !reason.empty()) {
+            GTEST_SKIP() << reason;
         }
-        WithStream<Stream> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
         std::shared_ptr<IStreamCommon> streamCommon;
-        ASSERT_IS_OK(stream.get()->getStreamCommon(&streamCommon));
+        ASSERT_IS_OK(stream.getStream()->getStreamCommon(&streamCommon));
         ASSERT_NE(nullptr, streamCommon);
 
         bool isGetterSupported = false;
@@ -2765,14 +3072,13 @@
     }
 
     void SetVendorParameters() {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
-        if (!portConfig.has_value()) {
-            GTEST_SKIP() << "No mix port for attached devices";
+        StreamFixture<Stream> stream;
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForAnyMixPort(module.get(), moduleConfig.get()));
+        if (auto reason = stream.skipTestReason(); !reason.empty()) {
+            GTEST_SKIP() << reason;
         }
-        WithStream<Stream> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
         std::shared_ptr<IStreamCommon> streamCommon;
-        ASSERT_IS_OK(stream.get()->getStreamCommon(&streamCommon));
+        ASSERT_IS_OK(stream.getStream()->getStreamCommon(&streamCommon));
         ASSERT_NE(nullptr, streamCommon);
 
         bool isSupported = false;
@@ -2783,32 +3089,37 @@
     }
 
     void HwGainHwVolume() {
-        const auto ports =
-                moduleConfig->getMixPorts(IOTraits<Stream>::is_input, true /*connectedOnly*/);
+        // Since device connection emulation does not cover complete functionality,
+        // only use this test with connected devices.
+        constexpr bool connectedOnly = true;
+        const auto ports = moduleConfig->getMixPorts(IOTraits<Stream>::is_input, connectedOnly);
         if (ports.empty()) {
             GTEST_SKIP() << "No mix ports";
         }
         bool atLeastOneSupports = false;
         for (const auto& port : ports) {
-            const auto portConfig = moduleConfig->getSingleConfigForMixPort(true, port);
-            if (!portConfig.has_value()) continue;
-            WithStream<Stream> stream(portConfig.value());
-            ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+            SCOPED_TRACE(port.toString());
+            StreamFixture<Stream> stream;
+            ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPort(module.get(), moduleConfig.get(),
+                                                                 port, connectedOnly));
+            if (!stream.skipTestReason().empty()) continue;
+            const auto portConfig = stream.getPortConfig();
+            SCOPED_TRACE(portConfig.toString());
             std::vector<std::vector<float>> validValues, invalidValues;
             bool isSupported = false;
             if constexpr (IOTraits<Stream>::is_input) {
-                GenerateTestArrays<float>(getChannelCount(portConfig.value().channelMask.value()),
+                GenerateTestArrays<float>(getChannelCount(portConfig.channelMask.value()),
                                           IStreamIn::HW_GAIN_MIN, IStreamIn::HW_GAIN_MAX,
                                           &validValues, &invalidValues);
                 EXPECT_NO_FATAL_FAILURE(TestAccessors<std::vector<float>>(
-                        stream.get(), &IStreamIn::getHwGain, &IStreamIn::setHwGain, validValues,
-                        invalidValues, &isSupported));
+                        stream.getStream(), &IStreamIn::getHwGain, &IStreamIn::setHwGain,
+                        validValues, invalidValues, &isSupported));
             } else {
-                GenerateTestArrays<float>(getChannelCount(portConfig.value().channelMask.value()),
+                GenerateTestArrays<float>(getChannelCount(portConfig.channelMask.value()),
                                           IStreamOut::HW_VOLUME_MIN, IStreamOut::HW_VOLUME_MAX,
                                           &validValues, &invalidValues);
                 EXPECT_NO_FATAL_FAILURE(TestAccessors<std::vector<float>>(
-                        stream.get(), &IStreamOut::getHwVolume, &IStreamOut::setHwVolume,
+                        stream.getStream(), &IStreamOut::getHwVolume, &IStreamOut::setHwVolume,
                         validValues, invalidValues, &isSupported));
             }
             if (isSupported) atLeastOneSupports = true;
@@ -2822,19 +3133,22 @@
     // currently we can only pass a nullptr, and the HAL module must either reject
     // it as an invalid argument, or say that offloaded effects are not supported.
     void AddRemoveEffectInvalidArguments() {
-        const auto ports =
-                moduleConfig->getMixPorts(IOTraits<Stream>::is_input, true /*connectedOnly*/);
+        constexpr bool connectedOnly = true;
+        const auto ports = moduleConfig->getMixPorts(IOTraits<Stream>::is_input, connectedOnly);
         if (ports.empty()) {
             GTEST_SKIP() << "No mix ports";
         }
         bool atLeastOneSupports = false;
         for (const auto& port : ports) {
-            const auto portConfig = moduleConfig->getSingleConfigForMixPort(true, port);
-            if (!portConfig.has_value()) continue;
-            WithStream<Stream> stream(portConfig.value());
-            ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+            SCOPED_TRACE(port.toString());
+            StreamFixture<Stream> stream;
+            ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPort(module.get(), moduleConfig.get(),
+                                                                 port, connectedOnly));
+            if (!stream.skipTestReason().empty()) continue;
+            const auto portConfig = stream.getPortConfig();
+            SCOPED_TRACE(portConfig.toString());
             std::shared_ptr<IStreamCommon> streamCommon;
-            ASSERT_IS_OK(stream.get()->getStreamCommon(&streamCommon));
+            ASSERT_IS_OK(stream.getStream()->getStreamCommon(&streamCommon));
             ASSERT_NE(nullptr, streamCommon);
             ndk::ScopedAStatus addEffectStatus = streamCommon->addEffect(nullptr);
             ndk::ScopedAStatus removeEffectStatus = streamCommon->removeEffect(nullptr);
@@ -2854,11 +3168,14 @@
     }
 
     void OpenTwiceSamePortConfigImpl(const AudioPortConfig& portConfig) {
-        WithStream<Stream> stream1(portConfig);
-        ASSERT_NO_FATAL_FAILURE(stream1.SetUp(module.get(), kDefaultBufferSizeFrames));
+        StreamFixture<Stream> stream1;
+        ASSERT_NO_FATAL_FAILURE(
+                stream1.SetUpStreamForMixPortConfig(module.get(), moduleConfig.get(), portConfig));
+        ASSERT_EQ("", stream1.skipTestReason());
         WithStream<Stream> stream2;
-        EXPECT_STATUS(EX_ILLEGAL_STATE, stream2.SetUpNoChecks(module.get(), stream1.getPortConfig(),
-                                                              kDefaultBufferSizeFrames))
+        EXPECT_STATUS(EX_ILLEGAL_STATE,
+                      stream2.SetUpNoChecks(module.get(), stream1.getPortConfig(),
+                                            stream1.getMinimumStreamBufferSizeFrames()))
                 << "when opening a stream twice for the same port config ID "
                 << stream1.getPortId();
     }
@@ -2893,11 +3210,13 @@
         for (const auto& seq : sequences) {
             SCOPED_TRACE(std::string("Sequence ").append(seq.first));
             LOG(DEBUG) << __func__ << ": Sequence " << seq.first;
-            WithStream<Stream> stream(portConfig);
-            ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+            StreamFixture<Stream> stream;
+            ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPortConfig(
+                    module.get(), moduleConfig.get(), portConfig));
+            ASSERT_EQ("", stream.skipTestReason());
             StreamLogicDriverInvalidCommand driver(seq.second);
-            typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver,
-                                                     stream.getEventReceiver());
+            typename IOTraits<Stream>::Worker worker(*stream.getStreamContext(), &driver,
+                                                     stream.getStreamEventReceiver());
             LOG(DEBUG) << __func__ << ": starting worker...";
             ASSERT_TRUE(worker.start());
             LOG(DEBUG) << __func__ << ": joining worker...";
@@ -2950,63 +3269,59 @@
     if (ports.empty()) {
         GTEST_SKIP() << "No input mix ports for attached devices";
     }
+    bool atLeastOnePort = false;
     for (const auto& port : ports) {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(true, port);
-        ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for input mix port";
-        WithStream<IStreamIn> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
-        {
-            // The port of the stream is not connected, thus the list of active mics must be empty.
-            std::vector<MicrophoneDynamicInfo> activeMics;
-            EXPECT_IS_OK(stream.get()->getActiveMicrophones(&activeMics));
-            EXPECT_TRUE(activeMics.empty()) << "a stream on an unconnected port returns a "
-                                               "non-empty list of active microphones";
+        auto micDevicePorts = ModuleConfig::getBuiltInMicPorts(
+                moduleConfig->getConnectedSourceDevicesPortsForMixPort(port));
+        if (micDevicePorts.empty()) continue;
+        atLeastOnePort = true;
+        SCOPED_TRACE(port.toString());
+        StreamFixture<IStreamIn> stream;
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForPortsPair(module.get(), moduleConfig.get(),
+                                                               port, micDevicePorts[0]));
+        if (!stream.skipTestReason().empty()) continue;
+        std::vector<MicrophoneDynamicInfo> activeMics;
+        EXPECT_IS_OK(stream.getStream()->getActiveMicrophones(&activeMics));
+        EXPECT_FALSE(activeMics.empty());
+        for (const auto& mic : activeMics) {
+            EXPECT_NE(micInfos.end(),
+                      std::find_if(micInfos.begin(), micInfos.end(),
+                                   [&](const auto& micInfo) { return micInfo.id == mic.id; }))
+                    << "active microphone \"" << mic.id << "\" is not listed in "
+                    << "microphone infos returned by the module: "
+                    << ::android::internal::ToString(micInfos);
+            EXPECT_NE(0UL, mic.channelMapping.size())
+                    << "No channels specified for the microphone \"" << mic.id << "\"";
         }
-        if (auto micDevicePorts = ModuleConfig::getBuiltInMicPorts(
-                    moduleConfig->getConnectedSourceDevicesPortsForMixPort(port));
-            !micDevicePorts.empty()) {
-            auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(micDevicePorts[0]);
-            WithAudioPatch patch(true /*isInput*/, stream.getPortConfig(), devicePortConfig);
-            ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
-            std::vector<MicrophoneDynamicInfo> activeMics;
-            EXPECT_IS_OK(stream.get()->getActiveMicrophones(&activeMics));
-            EXPECT_FALSE(activeMics.empty());
-            for (const auto& mic : activeMics) {
-                EXPECT_NE(micInfos.end(),
-                          std::find_if(micInfos.begin(), micInfos.end(),
-                                       [&](const auto& micInfo) { return micInfo.id == mic.id; }))
-                        << "active microphone \"" << mic.id << "\" is not listed in "
-                        << "microphone infos returned by the module: "
-                        << ::android::internal::ToString(micInfos);
-                EXPECT_NE(0UL, mic.channelMapping.size())
-                        << "No channels specified for the microphone \"" << mic.id << "\"";
-            }
-        }
-        {
-            // Now the port of the stream is not connected again, re-check that there are no
-            // active microphones.
-            std::vector<MicrophoneDynamicInfo> activeMics;
-            EXPECT_IS_OK(stream.get()->getActiveMicrophones(&activeMics));
-            EXPECT_TRUE(activeMics.empty()) << "a stream on an unconnected port returns a "
-                                               "non-empty list of active microphones";
-        }
+        stream.TeardownPatch();
+        // Now the port of the stream is not connected, check that there are no active microphones.
+        std::vector<MicrophoneDynamicInfo> emptyMics;
+        EXPECT_IS_OK(stream.getStream()->getActiveMicrophones(&emptyMics));
+        EXPECT_TRUE(emptyMics.empty()) << "a stream on an unconnected port returns a "
+                                          "non-empty list of active microphones";
+    }
+    if (!atLeastOnePort) {
+        GTEST_SKIP() << "No input mix ports could be routed to built-in microphone devices";
     }
 }
 
 TEST_P(AudioStreamIn, MicrophoneDirection) {
     using MD = IStreamIn::MicrophoneDirection;
-    const auto ports = moduleConfig->getInputMixPorts(true /*connectedOnly*/);
+    constexpr bool connectedOnly = true;
+    const auto ports = moduleConfig->getInputMixPorts(connectedOnly);
     if (ports.empty()) {
         GTEST_SKIP() << "No input mix ports for attached devices";
     }
-    bool isSupported = false;
+    bool isSupported = false, atLeastOnePort = false;
     for (const auto& port : ports) {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(true, port);
-        ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for input mix port";
-        WithStream<IStreamIn> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        SCOPED_TRACE(port.toString());
+        StreamFixture<IStreamIn> stream;
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPort(module.get(), moduleConfig.get(), port,
+                                                             connectedOnly));
+        if (!stream.skipTestReason().empty()) continue;
+        atLeastOnePort = true;
         EXPECT_NO_FATAL_FAILURE(
-                TestAccessors<MD>(stream.get(), &IStreamIn::getMicrophoneDirection,
+                TestAccessors<MD>(stream.getStream(), &IStreamIn::getMicrophoneDirection,
                                   &IStreamIn::setMicrophoneDirection,
                                   std::vector<MD>(enum_range<MD>().begin(), enum_range<MD>().end()),
                                   {}, &isSupported));
@@ -3015,21 +3330,27 @@
     if (!isSupported) {
         GTEST_SKIP() << "Microphone direction is not supported";
     }
+    if (!atLeastOnePort) {
+        GTEST_SKIP() << "No input mix ports could be routed to built-in microphone devices";
+    }
 }
 
 TEST_P(AudioStreamIn, MicrophoneFieldDimension) {
-    const auto ports = moduleConfig->getInputMixPorts(true /*connectedOnly*/);
+    constexpr bool connectedOnly = true;
+    const auto ports = moduleConfig->getInputMixPorts(connectedOnly);
     if (ports.empty()) {
         GTEST_SKIP() << "No input mix ports for attached devices";
     }
-    bool isSupported = false;
+    bool isSupported = false, atLeastOnePort = false;
     for (const auto& port : ports) {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(true, port);
-        ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for input mix port";
-        WithStream<IStreamIn> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        SCOPED_TRACE(port.toString());
+        StreamFixture<IStreamIn> stream;
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPort(module.get(), moduleConfig.get(), port,
+                                                             connectedOnly));
+        if (!stream.skipTestReason().empty()) continue;
+        atLeastOnePort = true;
         EXPECT_NO_FATAL_FAILURE(TestAccessors<float>(
-                stream.get(), &IStreamIn::getMicrophoneFieldDimension,
+                stream.getStream(), &IStreamIn::getMicrophoneFieldDimension,
                 &IStreamIn::setMicrophoneFieldDimension,
                 {IStreamIn::MIC_FIELD_DIMENSION_WIDE_ANGLE,
                  IStreamIn::MIC_FIELD_DIMENSION_WIDE_ANGLE / 2.0f,
@@ -3046,6 +3367,9 @@
     if (!isSupported) {
         GTEST_SKIP() << "Microphone direction is not supported";
     }
+    if (!atLeastOnePort) {
+        GTEST_SKIP() << "No input mix ports could be routed to built-in microphone devices";
+    }
 }
 
 TEST_P(AudioStreamOut, OpenTwicePrimary) {
@@ -3060,65 +3384,79 @@
 }
 
 TEST_P(AudioStreamOut, RequireOffloadInfo) {
+    constexpr bool connectedOnly = true;
     const auto offloadMixPorts =
-            moduleConfig->getOffloadMixPorts(true /*connectedOnly*/, true /*singlePort*/);
+            moduleConfig->getOffloadMixPorts(connectedOnly, true /*singlePort*/);
     if (offloadMixPorts.empty()) {
         GTEST_SKIP()
                 << "No mix port for compressed offload that could be routed to attached devices";
     }
-    const auto config = moduleConfig->getSingleConfigForMixPort(false, *offloadMixPorts.begin());
-    ASSERT_TRUE(config.has_value()) << "No profiles specified for the compressed offload mix port";
-    WithAudioPortConfig portConfig(config.value());
-    ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get()));
+    StreamFixture<IStreamOut> stream;
+    ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfigForMixPortOrConfig(
+            module.get(), moduleConfig.get(), *offloadMixPorts.begin(), connectedOnly));
+    if (auto reason = stream.skipTestReason(); !reason.empty()) {
+        GTEST_SKIP() << reason;
+    }
+    const auto portConfig = stream.getPortConfig();
     StreamDescriptor descriptor;
-    std::shared_ptr<IStreamOut> ignored;
     aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
-    args.portConfigId = portConfig.getId();
-    args.sourceMetadata = GenerateSourceMetadata(portConfig.get());
+    args.portConfigId = portConfig.id;
+    args.sourceMetadata = GenerateSourceMetadata(portConfig);
     args.bufferSizeFrames = kDefaultLargeBufferSizeFrames;
     aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
     EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
             << "when no offload info is provided for a compressed offload mix port";
+    if (ret.stream != nullptr) {
+        (void)WithStream<IStreamOut>::callClose(ret.stream);
+    }
 }
 
 TEST_P(AudioStreamOut, RequireAsyncCallback) {
+    constexpr bool connectedOnly = true;
     const auto nonBlockingMixPorts =
-            moduleConfig->getNonBlockingMixPorts(true /*connectedOnly*/, true /*singlePort*/);
+            moduleConfig->getNonBlockingMixPorts(connectedOnly, true /*singlePort*/);
     if (nonBlockingMixPorts.empty()) {
         GTEST_SKIP()
                 << "No mix port for non-blocking output that could be routed to attached devices";
     }
-    const auto config =
-            moduleConfig->getSingleConfigForMixPort(false, *nonBlockingMixPorts.begin());
-    ASSERT_TRUE(config.has_value()) << "No profiles specified for the non-blocking mix port";
-    WithAudioPortConfig portConfig(config.value());
-    ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get()));
+    StreamFixture<IStreamOut> stream;
+    ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfigForMixPortOrConfig(
+            module.get(), moduleConfig.get(), *nonBlockingMixPorts.begin(), connectedOnly));
+    if (auto reason = stream.skipTestReason(); !reason.empty()) {
+        GTEST_SKIP() << reason;
+    }
+    const auto portConfig = stream.getPortConfig();
     StreamDescriptor descriptor;
-    std::shared_ptr<IStreamOut> ignored;
     aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
-    args.portConfigId = portConfig.getId();
-    args.sourceMetadata = GenerateSourceMetadata(portConfig.get());
-    args.offloadInfo = ModuleConfig::generateOffloadInfoIfNeeded(portConfig.get());
-    args.bufferSizeFrames = kDefaultBufferSizeFrames;
+    args.portConfigId = portConfig.id;
+    args.sourceMetadata = GenerateSourceMetadata(portConfig);
+    args.offloadInfo = ModuleConfig::generateOffloadInfoIfNeeded(portConfig);
+    args.bufferSizeFrames = stream.getPatch().minimumStreamBufferSizeFrames;
     aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
     EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
             << "when no async callback is provided for a non-blocking mix port";
+    if (ret.stream != nullptr) {
+        (void)WithStream<IStreamOut>::callClose(ret.stream);
+    }
 }
 
 TEST_P(AudioStreamOut, AudioDescriptionMixLevel) {
-    const auto ports = moduleConfig->getOutputMixPorts(true /*connectedOnly*/);
+    constexpr bool connectedOnly = true;
+    const auto ports = moduleConfig->getOutputMixPorts(connectedOnly);
     if (ports.empty()) {
-        GTEST_SKIP() << "No output mix ports";
+        GTEST_SKIP() << "No output mix ports for attached devices";
     }
-    bool atLeastOneSupports = false;
+    bool atLeastOneSupports = false, atLeastOnePort = false;
     for (const auto& port : ports) {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, port);
-        ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for output mix port";
-        WithStream<IStreamOut> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        SCOPED_TRACE(port.toString());
+        StreamFixture<IStreamOut> stream;
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPort(module.get(), moduleConfig.get(), port,
+                                                             connectedOnly));
+        if (!stream.skipTestReason().empty()) continue;
+        atLeastOnePort = true;
         bool isSupported = false;
         EXPECT_NO_FATAL_FAILURE(
-                TestAccessors<float>(stream.get(), &IStreamOut::getAudioDescriptionMixLevel,
+                TestAccessors<float>(stream.getStream(), &IStreamOut::getAudioDescriptionMixLevel,
                                      &IStreamOut::setAudioDescriptionMixLevel,
                                      {IStreamOut::AUDIO_DESCRIPTION_MIX_LEVEL_MAX,
                                       IStreamOut::AUDIO_DESCRIPTION_MIX_LEVEL_MAX - 1, 0,
@@ -3128,48 +3466,60 @@
                                      &isSupported));
         if (isSupported) atLeastOneSupports = true;
     }
+    if (!atLeastOnePort) {
+        GTEST_SKIP() << "No output mix ports could be routed to devices";
+    }
     if (!atLeastOneSupports) {
         GTEST_SKIP() << "Audio description mix level is not supported";
     }
 }
 
 TEST_P(AudioStreamOut, DualMonoMode) {
-    const auto ports = moduleConfig->getOutputMixPorts(true /*connectedOnly*/);
+    constexpr bool connectedOnly = true;
+    const auto ports = moduleConfig->getOutputMixPorts(connectedOnly);
     if (ports.empty()) {
-        GTEST_SKIP() << "No output mix ports";
+        GTEST_SKIP() << "No output mix ports for attached devices";
     }
-    bool atLeastOneSupports = false;
+    bool atLeastOneSupports = false, atLeastOnePort = false;
     for (const auto& port : ports) {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, port);
-        ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for output mix port";
-        WithStream<IStreamOut> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        SCOPED_TRACE(port.toString());
+        StreamFixture<IStreamOut> stream;
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPort(module.get(), moduleConfig.get(), port,
+                                                             connectedOnly));
+        if (!stream.skipTestReason().empty()) continue;
+        atLeastOnePort = true;
         bool isSupported = false;
         EXPECT_NO_FATAL_FAILURE(TestAccessors<AudioDualMonoMode>(
-                stream.get(), &IStreamOut::getDualMonoMode, &IStreamOut::setDualMonoMode,
+                stream.getStream(), &IStreamOut::getDualMonoMode, &IStreamOut::setDualMonoMode,
                 std::vector<AudioDualMonoMode>(enum_range<AudioDualMonoMode>().begin(),
                                                enum_range<AudioDualMonoMode>().end()),
                 {}, &isSupported));
         if (isSupported) atLeastOneSupports = true;
     }
+    if (!atLeastOnePort) {
+        GTEST_SKIP() << "No output mix ports could be routed to devices";
+    }
     if (!atLeastOneSupports) {
         GTEST_SKIP() << "Audio dual mono mode is not supported";
     }
 }
 
 TEST_P(AudioStreamOut, LatencyMode) {
-    const auto ports = moduleConfig->getOutputMixPorts(true /*connectedOnly*/);
+    constexpr bool connectedOnly = true;
+    const auto ports = moduleConfig->getOutputMixPorts(connectedOnly);
     if (ports.empty()) {
-        GTEST_SKIP() << "No output mix ports";
+        GTEST_SKIP() << "No output mix ports for attached devices";
     }
-    bool atLeastOneSupports = false;
+    bool atLeastOneSupports = false, atLeastOnePort = false;
     for (const auto& port : ports) {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, port);
-        ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for output mix port";
-        WithStream<IStreamOut> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        SCOPED_TRACE(port.toString());
+        StreamFixture<IStreamOut> stream;
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPort(module.get(), moduleConfig.get(), port,
+                                                             connectedOnly));
+        if (!stream.skipTestReason().empty()) continue;
+        atLeastOnePort = true;
         std::vector<AudioLatencyMode> supportedModes;
-        ndk::ScopedAStatus status = stream.get()->getRecommendedLatencyModes(&supportedModes);
+        ndk::ScopedAStatus status = stream.getStream()->getRecommendedLatencyModes(&supportedModes);
         if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) continue;
         atLeastOneSupports = true;
         if (!status.isOk()) {
@@ -3181,7 +3531,7 @@
                                                     enum_range<AudioLatencyMode>().end());
         for (const auto mode : supportedModes) {
             unsupportedModes.erase(mode);
-            ndk::ScopedAStatus status = stream.get()->setLatencyMode(mode);
+            ndk::ScopedAStatus status = stream.getStream()->setLatencyMode(mode);
             if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
                 ADD_FAILURE() << "When latency modes are supported, both getRecommendedLatencyModes"
                               << " and setLatencyMode must be supported";
@@ -3189,12 +3539,15 @@
             EXPECT_IS_OK(status) << "Setting of supported latency mode must succeed";
         }
         for (const auto mode : unsupportedModes) {
-            EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, stream.get()->setLatencyMode(mode));
+            EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, stream.getStream()->setLatencyMode(mode));
         }
     }
     if (!atLeastOneSupports) {
         GTEST_SKIP() << "Audio latency modes are not supported";
     }
+    if (!atLeastOnePort) {
+        GTEST_SKIP() << "No output mix ports could be routed to devices";
+    }
 }
 
 TEST_P(AudioStreamOut, PlaybackRate) {
@@ -3496,29 +3849,22 @@
         }
     }
 
-    bool ValidateObservablePosition(const AudioPortConfig& devicePortConfig) {
-        return !isTelephonyDeviceType(
-                devicePortConfig.ext.get<AudioPortExt::Tag::device>().device.type.type);
+    bool ValidateObservablePosition(const AudioDevice& device) {
+        return !isTelephonyDeviceType(device.type.type);
     }
 
     // Set up a patch first, then open a stream.
     void RunStreamIoCommandsImplSeq1(const AudioPortConfig& portConfig,
                                      std::shared_ptr<StateSequence> commandsAndStates,
                                      bool validatePositionIncrease) {
-        auto devicePorts = moduleConfig->getConnectedDevicesPortsForMixPort(
-                IOTraits<Stream>::is_input, portConfig);
-        ASSERT_FALSE(devicePorts.empty());
-        auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
-        SCOPED_TRACE(devicePortConfig.toString());
-        WithAudioPatch patch(IOTraits<Stream>::is_input, portConfig, devicePortConfig);
-        ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
-
-        WithStream<Stream> stream(patch.getPortConfig(IOTraits<Stream>::is_input));
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        StreamFixture<Stream> stream;
+        ASSERT_NO_FATAL_FAILURE(
+                stream.SetUpStreamForMixPortConfig(module.get(), moduleConfig.get(), portConfig));
+        ASSERT_EQ("", stream.skipTestReason());
         StreamLogicDefaultDriver driver(commandsAndStates,
-                                        stream.getContext()->getFrameSizeBytes());
-        typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver,
-                                                 stream.getEventReceiver());
+                                        stream.getStreamContext()->getFrameSizeBytes());
+        typename IOTraits<Stream>::Worker worker(*stream.getStreamContext(), &driver,
+                                                 stream.getStreamEventReceiver());
 
         LOG(DEBUG) << __func__ << ": starting worker...";
         ASSERT_TRUE(worker.start());
@@ -3526,7 +3872,7 @@
         worker.join();
         EXPECT_FALSE(worker.hasError()) << worker.getError();
         EXPECT_EQ("", driver.getUnexpectedStateTransition());
-        if (ValidateObservablePosition(devicePortConfig)) {
+        if (ValidateObservablePosition(stream.getDevice())) {
             if (validatePositionIncrease) {
                 EXPECT_TRUE(driver.hasObservablePositionIncrease());
             }
@@ -3534,24 +3880,21 @@
         }
     }
 
-    // Open a stream, then set up a patch for it.
+    // Open a stream, then set up a patch for it. Since first it is needed to get
+    // the minimum buffer size, a preliminary patch is set up, then removed.
     void RunStreamIoCommandsImplSeq2(const AudioPortConfig& portConfig,
                                      std::shared_ptr<StateSequence> commandsAndStates,
                                      bool validatePositionIncrease) {
-        WithStream<Stream> stream(portConfig);
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        StreamFixture<Stream> stream;
+        ASSERT_NO_FATAL_FAILURE(
+                stream.SetUpPatchForMixPortConfig(module.get(), moduleConfig.get(), portConfig));
+        ASSERT_EQ("", stream.skipTestReason());
+        ASSERT_NO_FATAL_FAILURE(stream.TeardownPatchSetUpStream(module.get()));
         StreamLogicDefaultDriver driver(commandsAndStates,
-                                        stream.getContext()->getFrameSizeBytes());
-        typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver,
-                                                 stream.getEventReceiver());
-
-        auto devicePorts = moduleConfig->getConnectedDevicesPortsForMixPort(
-                IOTraits<Stream>::is_input, portConfig);
-        ASSERT_FALSE(devicePorts.empty());
-        auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
-        SCOPED_TRACE(devicePortConfig.toString());
-        WithAudioPatch patch(IOTraits<Stream>::is_input, stream.getPortConfig(), devicePortConfig);
-        ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+                                        stream.getStreamContext()->getFrameSizeBytes());
+        typename IOTraits<Stream>::Worker worker(*stream.getStreamContext(), &driver,
+                                                 stream.getStreamEventReceiver());
+        ASSERT_NO_FATAL_FAILURE(stream.ReconnectPatch(module.get()));
 
         LOG(DEBUG) << __func__ << ": starting worker...";
         ASSERT_TRUE(worker.start());
@@ -3559,7 +3902,7 @@
         worker.join();
         EXPECT_FALSE(worker.hasError()) << worker.getError();
         EXPECT_EQ("", driver.getUnexpectedStateTransition());
-        if (ValidateObservablePosition(devicePortConfig)) {
+        if (ValidateObservablePosition(stream.getDevice())) {
             if (validatePositionIncrease) {
                 EXPECT_TRUE(driver.hasObservablePositionIncrease());
             }
@@ -4253,191 +4596,154 @@
     explicit WithRemoteSubmix(AudioDeviceAddress address) : mAddress(address) {}
     WithRemoteSubmix(const WithRemoteSubmix&) = delete;
     WithRemoteSubmix& operator=(const WithRemoteSubmix&) = delete;
+
     static std::optional<AudioPort> getRemoteSubmixAudioPort(
             ModuleConfig* moduleConfig,
             const std::optional<AudioDeviceAddress>& address = std::nullopt) {
-        AudioDeviceType deviceType = IOTraits<Stream>::is_input ? AudioDeviceType::IN_SUBMIX
-                                                                : AudioDeviceType::OUT_SUBMIX;
-        auto ports = moduleConfig->getAudioPortsForDeviceTypes(
-                std::vector<AudioDeviceType>{deviceType},
-                AudioDeviceDescription::CONNECTION_VIRTUAL);
+        auto ports =
+                moduleConfig->getRemoteSubmixPorts(IOTraits<Stream>::is_input, true /*singlePort*/);
         if (ports.empty()) return {};
         AudioPort port = ports.front();
         if (address) {
             port.ext.template get<AudioPortExt::Tag::device>().device.address = address.value();
-        } else {
-            port = GenerateUniqueDeviceAddress(port);
         }
         return port;
     }
-    std::optional<AudioDeviceAddress> getAudioDeviceAddress() const { return mAddress; }
-    void SetUp(IModule* module, ModuleConfig* moduleConfig, const AudioPort& connectedPort) {
-        mModule = module;
-        mModuleConfig = moduleConfig;
 
-        ASSERT_NO_FATAL_FAILURE(SetupPatch(connectedPort));
-        if (!mSkipTest) {
-            // open stream
-            mStream = std::make_unique<WithStream<Stream>>(
-                    mPatch->getPortConfig(IOTraits<Stream>::is_input));
-            ASSERT_NO_FATAL_FAILURE(
-                    mStream->SetUp(mModule, AudioCoreModuleBase::kDefaultBufferSizeFrames));
-        }
-        mAddress = connectedPort.ext.template get<AudioPortExt::Tag::device>().device.address;
-    }
     void SetUp(IModule* module, ModuleConfig* moduleConfig) {
-        ASSERT_NO_FATAL_FAILURE(SetUpPortConnection(module, moduleConfig));
-        SetUp(module, moduleConfig, mConnectedPort->get());
+        auto devicePort = getRemoteSubmixAudioPort(moduleConfig, mAddress);
+        ASSERT_TRUE(devicePort.has_value()) << "Device port for remote submix device not found";
+        ASSERT_NO_FATAL_FAILURE(SetUp(module, moduleConfig, *devicePort));
     }
-    void sendBurstCommands() {
-        const StreamContext* context = mStream->getContext();
-        StreamLogicDefaultDriver driver(makeBurstCommands(true), context->getFrameSizeBytes());
-        typename IOTraits<Stream>::Worker worker(*context, &driver, mStream->getEventReceiver());
 
-        LOG(DEBUG) << __func__ << ": starting worker...";
-        ASSERT_TRUE(worker.start());
-        LOG(DEBUG) << __func__ << ": joining worker...";
-        worker.join();
-        EXPECT_FALSE(worker.hasError()) << worker.getError();
-        EXPECT_EQ("", driver.getUnexpectedStateTransition());
-        if (IOTraits<Stream>::is_input) {
-            EXPECT_TRUE(driver.hasObservablePositionIncrease());
-        }
-        EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
+    void SendBurstCommandsStartWorker() {
+        const StreamContext* context = mStream->getStreamContext();
+        mWorkerDriver = std::make_unique<StreamLogicDefaultDriver>(makeBurstCommands(true),
+                                                                   context->getFrameSizeBytes());
+        mWorker = std::make_unique<typename IOTraits<Stream>::Worker>(
+                *context, mWorkerDriver.get(), mStream->getStreamEventReceiver());
+        LOG(DEBUG) << __func__ << ": starting " << IOTraits<Stream>::directionStr << " worker...";
+        ASSERT_TRUE(mWorker->start());
     }
-    bool skipTest() const { return mSkipTest; }
+
+    void SendBurstCommandsJoinWorker() {
+        // Must call 'prepareToClose' before attempting to join because the stream may be
+        // stuck due to absence of activity from the other side of the remote submix pipe.
+        std::shared_ptr<IStreamCommon> common;
+        ASSERT_IS_OK(mStream->getStream()->getStreamCommon(&common));
+        ASSERT_IS_OK(common->prepareToClose());
+        LOG(DEBUG) << __func__ << ": joining " << IOTraits<Stream>::directionStr << " worker...";
+        mWorker->join();
+        EXPECT_FALSE(mWorker->hasError()) << mWorker->getError();
+        EXPECT_EQ("", mWorkerDriver->getUnexpectedStateTransition());
+        if (IOTraits<Stream>::is_input) {
+            EXPECT_TRUE(mWorkerDriver->hasObservablePositionIncrease());
+        }
+        EXPECT_FALSE(mWorkerDriver->hasRetrogradeObservablePosition());
+        mWorker.reset();
+        mWorkerDriver.reset();
+    }
+
+    void SendBurstCommands() {
+        ASSERT_NO_FATAL_FAILURE(SendBurstCommandsStartWorker());
+        ASSERT_NO_FATAL_FAILURE(SendBurstCommandsJoinWorker());
+    }
+
+    std::optional<AudioDeviceAddress> getAudioDeviceAddress() const { return mAddress; }
+    std::string skipTestReason() const { return mStream->skipTestReason(); }
 
   private:
-    /* Connect remote submix external device */
-    void SetUpPortConnection(IModule* module, ModuleConfig* moduleConfig) {
-        auto port = getRemoteSubmixAudioPort(moduleConfig, mAddress);
-        ASSERT_TRUE(port.has_value()) << "Device AudioPort for remote submix not found";
-        mConnectedPort = std::make_unique<WithDevicePortConnectedState>(port.value());
-        ASSERT_NO_FATAL_FAILURE(mConnectedPort->SetUp(module, moduleConfig));
-    }
-    /* Get mix port config for stream and setup patch for it. */
-    void SetupPatch(const AudioPort& connectedPort) {
-        const auto portConfig =
-                mModuleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
-        if (!portConfig.has_value()) {
-            LOG(DEBUG) << __func__ << ": portConfig not found";
-            mSkipTest = true;
-            return;
-        }
-        auto devicePortConfig = mModuleConfig->getSingleConfigForDevicePort(connectedPort);
-        mPatch = std::make_unique<WithAudioPatch>(IOTraits<Stream>::is_input, portConfig.value(),
-                                                  devicePortConfig);
-        ASSERT_NO_FATAL_FAILURE(mPatch->SetUp(mModule));
+    void SetUp(IModule* module, ModuleConfig* moduleConfig, const AudioPort& devicePort) {
+        mStream = std::make_unique<StreamFixture<Stream>>();
+        ASSERT_NO_FATAL_FAILURE(
+                mStream->SetUpStreamForDevicePort(module, moduleConfig, devicePort));
+        mAddress = mStream->getDevice().address;
     }
 
-    bool mSkipTest = false;
-    IModule* mModule = nullptr;
-    ModuleConfig* mModuleConfig = nullptr;
     std::optional<AudioDeviceAddress> mAddress;
-    std::unique_ptr<WithDevicePortConnectedState> mConnectedPort;
-    std::unique_ptr<WithAudioPatch> mPatch;
-    std::unique_ptr<WithStream<Stream>> mStream;
+    std::unique_ptr<StreamFixture<Stream>> mStream;
+    std::unique_ptr<StreamLogicDefaultDriver> mWorkerDriver;
+    std::unique_ptr<typename IOTraits<Stream>::Worker> mWorker;
 };
 
 class AudioModuleRemoteSubmix : public AudioCoreModule {
   public:
     void SetUp() override {
-        ASSERT_NO_FATAL_FAILURE(AudioCoreModule::SetUp());
+        // Turn off "debug" which enables connections simulation. Since devices of the remote
+        // submix module are virtual, there is no need for simulation.
+        ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam(), false /*setUpDebug*/));
         ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
     }
-
-    void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
 };
 
 TEST_P(AudioModuleRemoteSubmix, OutputDoesNotBlockWhenNoInput) {
-    // open output stream
     WithRemoteSubmix<IStreamOut> streamOut;
     ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
-    if (streamOut.skipTest()) {
-        GTEST_SKIP() << "No mix port for attached devices";
-    }
-    // write something to stream
-    ASSERT_NO_FATAL_FAILURE(streamOut.sendBurstCommands());
+    // Note: here and in other tests any issue with connection attempts is considered as a problem.
+    ASSERT_EQ("", streamOut.skipTestReason());
+    ASSERT_NO_FATAL_FAILURE(streamOut.SendBurstCommands());
 }
 
 TEST_P(AudioModuleRemoteSubmix, OutputDoesNotBlockWhenInputStuck) {
-    // open output stream
     WithRemoteSubmix<IStreamOut> streamOut;
     ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
-    if (streamOut.skipTest()) {
-        GTEST_SKIP() << "No mix port for attached devices";
-    }
+    ASSERT_EQ("", streamOut.skipTestReason());
     auto address = streamOut.getAudioDeviceAddress();
     ASSERT_TRUE(address.has_value());
 
-    // open input stream
     WithRemoteSubmix<IStreamIn> streamIn(address.value());
     ASSERT_NO_FATAL_FAILURE(streamIn.SetUp(module.get(), moduleConfig.get()));
-    if (streamIn.skipTest()) {
-        GTEST_SKIP() << "No mix port for attached devices";
-    }
+    ASSERT_EQ("", streamIn.skipTestReason());
 
-    // write something to stream
-    ASSERT_NO_FATAL_FAILURE(streamOut.sendBurstCommands());
+    ASSERT_NO_FATAL_FAILURE(streamOut.SendBurstCommands());
 }
 
 TEST_P(AudioModuleRemoteSubmix, OutputAndInput) {
-    // open output stream
     WithRemoteSubmix<IStreamOut> streamOut;
     ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
-    if (streamOut.skipTest()) {
-        GTEST_SKIP() << "No mix port for attached devices";
-    }
+    ASSERT_EQ("", streamOut.skipTestReason());
     auto address = streamOut.getAudioDeviceAddress();
     ASSERT_TRUE(address.has_value());
 
-    // open input stream
     WithRemoteSubmix<IStreamIn> streamIn(address.value());
     ASSERT_NO_FATAL_FAILURE(streamIn.SetUp(module.get(), moduleConfig.get()));
-    if (streamIn.skipTest()) {
-        GTEST_SKIP() << "No mix port for attached devices";
-    }
+    ASSERT_EQ("", streamIn.skipTestReason());
 
-    // write something to stream
-    ASSERT_NO_FATAL_FAILURE(streamOut.sendBurstCommands());
-    // read from input stream
-    ASSERT_NO_FATAL_FAILURE(streamIn.sendBurstCommands());
+    // Start writing into the output stream.
+    ASSERT_NO_FATAL_FAILURE(streamOut.SendBurstCommandsStartWorker());
+    // Simultaneously, read from the input stream.
+    ASSERT_NO_FATAL_FAILURE(streamIn.SendBurstCommands());
+    ASSERT_NO_FATAL_FAILURE(streamOut.SendBurstCommandsJoinWorker());
 }
 
 TEST_P(AudioModuleRemoteSubmix, OpenInputMultipleTimes) {
-    // open output stream
     WithRemoteSubmix<IStreamOut> streamOut;
     ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
-    if (streamOut.skipTest()) {
-        GTEST_SKIP() << "No mix port for attached devices";
-    }
+    ASSERT_EQ("", streamOut.skipTestReason());
     auto address = streamOut.getAudioDeviceAddress();
     ASSERT_TRUE(address.has_value());
 
-    // connect remote submix input device port
-    auto port = WithRemoteSubmix<IStreamIn>::getRemoteSubmixAudioPort(moduleConfig.get(),
-                                                                      address.value());
-    ASSERT_TRUE(port.has_value()) << "Device AudioPort for remote submix not found";
-    WithDevicePortConnectedState connectedInputPort(port.value());
-    ASSERT_NO_FATAL_FAILURE(connectedInputPort.SetUp(module.get(), moduleConfig.get()));
-
-    // open input streams
-    const int streamInCount = 3;
+    const size_t streamInCount = 3;
     std::vector<std::unique_ptr<WithRemoteSubmix<IStreamIn>>> streamIns(streamInCount);
-    for (int i = 0; i < streamInCount; i++) {
-        streamIns[i] = std::make_unique<WithRemoteSubmix<IStreamIn>>();
-        ASSERT_NO_FATAL_FAILURE(
-                streamIns[i]->SetUp(module.get(), moduleConfig.get(), connectedInputPort.get()));
-        if (streamIns[i]->skipTest()) {
-            GTEST_SKIP() << "No mix port for attached devices";
-        }
+    for (size_t i = 0; i < streamInCount; i++) {
+        streamIns[i] = std::make_unique<WithRemoteSubmix<IStreamIn>>(address.value());
+        ASSERT_NO_FATAL_FAILURE(streamIns[i]->SetUp(module.get(), moduleConfig.get()));
+        ASSERT_EQ("", streamIns[i]->skipTestReason());
     }
-    // write something to output stream
-    ASSERT_NO_FATAL_FAILURE(streamOut.sendBurstCommands());
-
-    // read from input streams
-    for (int i = 0; i < streamInCount; i++) {
-        ASSERT_NO_FATAL_FAILURE(streamIns[i]->sendBurstCommands());
+    // Start writing into the output stream.
+    ASSERT_NO_FATAL_FAILURE(streamOut.SendBurstCommandsStartWorker());
+    // Simultaneously, read from input streams.
+    for (size_t i = 0; i < streamInCount; i++) {
+        ASSERT_NO_FATAL_FAILURE(streamIns[i]->SendBurstCommandsStartWorker());
+    }
+    for (size_t i = 0; i < streamInCount; i++) {
+        ASSERT_NO_FATAL_FAILURE(streamIns[i]->SendBurstCommandsJoinWorker());
+    }
+    ASSERT_NO_FATAL_FAILURE(streamOut.SendBurstCommandsJoinWorker());
+    // Clean up input streams in the reverse order because the device connection is owned
+    // by the first one.
+    for (size_t i = streamInCount; i != 0; --i) {
+        streamIns[i - 1].reset();
     }
 }
 
diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
index ca1cea9..418fedb 100644
--- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -16,13 +16,11 @@
 
 #define LOG_TAG "VtsHalAudioEffectTargetTest"
 
-#include <chrono>
 #include <memory>
 #include <string>
 #include <vector>
 
 #include <aidl/Gtest.h>
-#include <aidl/Vintf.h>
 #include <aidl/android/hardware/audio/effect/IEffect.h>
 #include <aidl/android/hardware/audio/effect/IFactory.h>
 #include <android-base/logging.h>
@@ -596,8 +594,14 @@
 
     Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::volumeStereo);
     Parameter::VolumeStereo volume = {.left = 10.0, .right = 10.0};
-    ASSERT_NO_FATAL_FAILURE(
-            setAndGetParameter(id, Parameter::make<Parameter::volumeStereo>(volume)));
+    if (mDescriptor.common.flags.volume == Flags::Volume::CTRL) {
+        Parameter get;
+        EXPECT_IS_OK(mEffect->setParameter(volume));
+        EXPECT_IS_OK(mEffect->getParameter(id, &get));
+    } else {
+        ASSERT_NO_FATAL_FAILURE(
+                setAndGetParameter(id, Parameter::make<Parameter::volumeStereo>(volume)));
+    }
 
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
     ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.xml b/audio/aidl/vts/VtsHalAudioTargetTestTemplate.xml
similarity index 86%
rename from audio/aidl/vts/VtsHalAudioCoreTargetTest.xml
rename to audio/aidl/vts/VtsHalAudioTargetTestTemplate.xml
index 9d3adc1..c92e852 100644
--- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.xml
+++ b/audio/aidl/vts/VtsHalAudioTargetTestTemplate.xml
@@ -13,7 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="Runs VtsHalAudioCoreTargetTest.">
+<configuration description="Runs {MODULE}.">
     <option name="test-suite-tag" value="apct" />
     <option name="test-suite-tag" value="apct-native" />
 
@@ -27,12 +27,12 @@
 
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
         <option name="cleanup" value="true" />
-        <option name="push" value="VtsHalAudioCoreTargetTest->/data/local/tmp/VtsHalAudioCoreTargetTest" />
+        <option name="push" value="{MODULE}->/data/local/tmp/{MODULE}" />
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.GTest" >
         <option name="native-test-device-path" value="/data/local/tmp" />
-        <option name="module-name" value="VtsHalAudioCoreTargetTest" />
+        <option name="module-name" value="{MODULE}" />
         <option name="native-test-timeout" value="10m" />
     </test>
 </configuration>
diff --git a/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp b/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
index 2d9a233..135940d 100644
--- a/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
@@ -14,9 +14,6 @@
  * limitations under the License.
  */
 
-#include <limits.h>
-
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalBassBoostTest"
 #include <android-base/logging.h>
 
diff --git a/audio/aidl/vts/VtsHalDownmixTargetTest.cpp b/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
index c01a9a2..b82bde1 100644
--- a/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
@@ -14,92 +14,120 @@
  * limitations under the License.
  */
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalDownmixTargetTest"
 #include <android-base/logging.h>
 
+#include <audio_utils/ChannelMix.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::Downmix;
 using aidl::android::hardware::audio::effect::getEffectTypeUuidDownmix;
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::IFactory;
 using aidl::android::hardware::audio::effect::Parameter;
+using android::audio_utils::channels::ChannelMix;
 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_TYPE };
-using DownmixParamTestParam =
-        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, Downmix::Type>;
+
+// minimal HAL interface version to run downmix data path test
+constexpr int32_t kMinDataTestHalVersion = 2;
 
 // Testing for enum values
-const std::vector<Downmix::Type> kTypeValues = {Downmix::Type::STRIP, Downmix::Type::FOLD};
+static const std::vector<Downmix::Type> kTypeValues = {ndk::enum_range<Downmix::Type>().begin(),
+                                                       ndk::enum_range<Downmix::Type>().end()};
 
-class DownmixParamTest : public ::testing::TestWithParam<DownmixParamTestParam>,
-                         public EffectHelper {
+// Testing for supported layouts from AudioChannelLayout.h
+static const std::vector<int32_t> kLayoutValues = {
+        AudioChannelLayout::LAYOUT_STEREO,        AudioChannelLayout::LAYOUT_2POINT1,
+        AudioChannelLayout::LAYOUT_TRI,           AudioChannelLayout::LAYOUT_TRI_BACK,
+        AudioChannelLayout::LAYOUT_3POINT1,       AudioChannelLayout::LAYOUT_2POINT0POINT2,
+        AudioChannelLayout::LAYOUT_2POINT1POINT2, AudioChannelLayout::LAYOUT_3POINT0POINT2,
+        AudioChannelLayout::LAYOUT_3POINT1POINT2, AudioChannelLayout::LAYOUT_QUAD,
+        AudioChannelLayout::LAYOUT_QUAD_SIDE,     AudioChannelLayout::LAYOUT_SURROUND,
+        AudioChannelLayout::LAYOUT_PENTA,         AudioChannelLayout::LAYOUT_5POINT1,
+        AudioChannelLayout::LAYOUT_5POINT1_SIDE,  AudioChannelLayout::LAYOUT_5POINT1POINT2,
+        AudioChannelLayout::LAYOUT_5POINT1POINT4, AudioChannelLayout::LAYOUT_6POINT1,
+        AudioChannelLayout::LAYOUT_7POINT1,       AudioChannelLayout::LAYOUT_7POINT1POINT2,
+        AudioChannelLayout::LAYOUT_7POINT1POINT4, AudioChannelLayout::LAYOUT_9POINT1POINT4,
+        AudioChannelLayout::LAYOUT_9POINT1POINT6, AudioChannelLayout::LAYOUT_13POINT_360RA,
+        AudioChannelLayout::LAYOUT_22POINT2};
+
+static const std::vector<int32_t> kChannels = {
+        AudioChannelLayout::CHANNEL_FRONT_LEFT,
+        AudioChannelLayout::CHANNEL_FRONT_RIGHT,
+        AudioChannelLayout::CHANNEL_FRONT_CENTER,
+        AudioChannelLayout::CHANNEL_LOW_FREQUENCY,
+        AudioChannelLayout::CHANNEL_BACK_LEFT,
+        AudioChannelLayout::CHANNEL_BACK_RIGHT,
+        AudioChannelLayout::CHANNEL_BACK_CENTER,
+        AudioChannelLayout::CHANNEL_SIDE_LEFT,
+        AudioChannelLayout::CHANNEL_SIDE_RIGHT,
+        AudioChannelLayout::CHANNEL_FRONT_LEFT_OF_CENTER,
+        AudioChannelLayout::CHANNEL_FRONT_RIGHT_OF_CENTER,
+        AudioChannelLayout::CHANNEL_TOP_CENTER,
+        AudioChannelLayout::CHANNEL_TOP_FRONT_LEFT,
+        AudioChannelLayout::CHANNEL_TOP_FRONT_CENTER,
+        AudioChannelLayout::CHANNEL_TOP_FRONT_RIGHT,
+        AudioChannelLayout::CHANNEL_TOP_BACK_LEFT,
+        AudioChannelLayout::CHANNEL_TOP_BACK_CENTER,
+        AudioChannelLayout::CHANNEL_TOP_BACK_RIGHT,
+        AudioChannelLayout::CHANNEL_TOP_SIDE_LEFT,
+        AudioChannelLayout::CHANNEL_TOP_SIDE_RIGHT,
+        AudioChannelLayout::CHANNEL_BOTTOM_FRONT_LEFT,
+        AudioChannelLayout::CHANNEL_BOTTOM_FRONT_CENTER,
+        AudioChannelLayout::CHANNEL_BOTTOM_FRONT_RIGHT,
+        AudioChannelLayout::CHANNEL_LOW_FREQUENCY_2,
+        AudioChannelLayout::CHANNEL_FRONT_WIDE_LEFT,
+        AudioChannelLayout::CHANNEL_FRONT_WIDE_RIGHT,
+};
+
+class DownmixEffectHelper : public EffectHelper {
   public:
-    DownmixParamTest() : mParamType(std::get<PARAM_TYPE>(GetParam())) {
-        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
-    }
-
-    void SetUp() override {
+    void SetUpDownmix(int32_t inputBufferLayout = AudioChannelLayout::LAYOUT_STEREO) {
         ASSERT_NE(nullptr, mFactory);
         ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
+        AudioChannelLayout inputChannelLayout =
+                AudioChannelLayout::make<AudioChannelLayout::layoutMask>(inputBufferLayout);
+
         Parameter::Specific specific = getDefaultParamSpecific();
         Parameter::Common common = EffectHelper::createParamCommon(
                 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
-                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
-        IEffect::OpenEffectReturn ret;
-        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */,
+                inputChannelLayout);
+        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &mOpenEffectReturn, EX_NONE));
         ASSERT_NE(nullptr, mEffect);
     }
 
-    void TearDown() override {
+    void TearDownDownmix() {
         ASSERT_NO_FATAL_FAILURE(close(mEffect));
         ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+        mOpenEffectReturn = IEffect::OpenEffectReturn{};
     }
 
-    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
-    std::shared_ptr<IFactory> mFactory;
-    std::shared_ptr<IEffect> mEffect;
-    Descriptor mDescriptor;
-    Downmix::Type mParamType = Downmix::Type::STRIP;
-
-    void SetAndGetDownmixParameters() {
-        for (auto& it : mTags) {
-            auto& tag = it.first;
-            auto& dm = it.second;
-
-            // set parameter
-            Parameter expectParam;
-            Parameter::Specific specific;
-            specific.set<Parameter::Specific::downmix>(dm);
-            expectParam.set<Parameter::specific>(specific);
-            // All values are valid, set parameter should succeed
-            EXPECT_STATUS(EX_NONE, mEffect->setParameter(expectParam)) << expectParam.toString();
-
-            // get parameter
-            Parameter getParam;
-            Parameter::Id id;
-            Downmix::Id dmId;
-            dmId.set<Downmix::Id::commonTag>(tag);
-            id.set<Parameter::Id::downmixTag>(dmId);
-            EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
-
-            EXPECT_EQ(expectParam, getParam);
-        }
+    Parameter createDownmixParam(Downmix::Type type) {
+        return Parameter::make<Parameter::specific>(
+                Parameter::Specific::make<Parameter::Specific::downmix>(
+                        Downmix::make<Downmix::type>(type)));
+    }
+    void setParameters(Downmix::Type type) {
+        // set parameter
+        auto param = createDownmixParam(type);
+        EXPECT_STATUS(EX_NONE, mEffect->setParameter(param)) << param.toString();
     }
 
-    void addTypeParam(Downmix::Type type) {
-        Downmix dm;
-        dm.set<Downmix::type>(type);
-        mTags.push_back({Downmix::type, dm});
+    void validateParameters(Downmix::Type type) {
+        auto leId = Downmix::Id::make<Downmix::Id::commonTag>(Downmix::Tag(Downmix::type));
+        auto id = Parameter::Id::make<Parameter::Id::downmixTag>(leId);
+        // get parameter
+        Parameter getParam;
+        EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+        auto expectedParam = createDownmixParam(type);
+        EXPECT_EQ(expectedParam, getParam) << "\nexpectedParam:" << expectedParam.toString()
+                                           << "\ngetParam:" << getParam.toString();
     }
 
     Parameter::Specific getDefaultParamSpecific() {
@@ -108,14 +136,289 @@
         return specific;
     }
 
-  private:
-    std::vector<std::pair<Downmix::Tag, Downmix>> mTags;
-    void CleanUp() { mTags.clear(); }
+    void setDataTestParams(int32_t layoutType) {
+        mInputBuffer.resize(kBufferSize);
+        mOutputBuffer.resize(kBufferSize);
+
+        // Get the number of channels used
+        mInputChannelCount = getChannelCount(
+                AudioChannelLayout::make<AudioChannelLayout::layoutMask>(layoutType));
+
+        // In case of downmix, output is always configured to stereo layout.
+        mOutputBufferSize = (mInputBuffer.size() / mInputChannelCount) * kOutputChannelCount;
+    }
+
+    // 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;
+        }
+        return true;
+    }
+
+    static constexpr long kInputFrameCount = 100, kOutputFrameCount = 100;
+    std::shared_ptr<IFactory> mFactory;
+    Descriptor mDescriptor;
+    std::shared_ptr<IEffect> mEffect;
+    IEffect::OpenEffectReturn mOpenEffectReturn;
+
+    std::vector<float> mInputBuffer;
+    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);
+};
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_TYPE };
+
+using DownmixParamTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, Downmix::Type>;
+
+class DownmixParamTest : public ::testing::TestWithParam<DownmixParamTestParam>,
+                         public DownmixEffectHelper {
+  public:
+    DownmixParamTest() : mParamType(std::get<PARAM_TYPE>(GetParam())) {
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    }
+
+    void SetUp() override { SetUpDownmix(); }
+
+    void TearDown() override { TearDownDownmix(); }
+
+    const Downmix::Type mParamType;
 };
 
 TEST_P(DownmixParamTest, SetAndGetType) {
-    EXPECT_NO_FATAL_FAILURE(addTypeParam(mParamType));
-    SetAndGetDownmixParameters();
+    ASSERT_NO_FATAL_FAILURE(setParameters(mParamType));
+    ASSERT_NO_FATAL_FAILURE(validateParameters(mParamType));
+}
+
+enum FoldParamName { FOLD_INSTANCE_NAME, FOLD_INPUT_LAYOUT, FOLD_TEST_CHANNEL };
+
+using DownmixDataTestParamFold =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int32_t>;
+
+class DownmixFoldDataTest : public ::testing::TestWithParam<DownmixDataTestParamFold>,
+                            public DownmixEffectHelper {
+  public:
+    DownmixFoldDataTest() : mInputChannelLayout(std::get<FOLD_INPUT_LAYOUT>(GetParam())) {
+        std::tie(mFactory, mDescriptor) = std::get<FOLD_INSTANCE_NAME>(GetParam());
+    }
+
+    void SetUp() override {
+        SetUpDownmix(mInputChannelLayout);
+        if (int32_t version;
+            mEffect->getInterfaceVersion(&version).isOk() && version < kMinDataTestHalVersion) {
+            GTEST_SKIP() << "Skipping the data test for version: " << version << "\n";
+        }
+        if (!isLayoutValid(mInputChannelLayout)) {
+            GTEST_SKIP() << "Layout not supported \n";
+        }
+        setDataTestParams(mInputChannelLayout);
+    }
+
+    void TearDown() override { TearDownDownmix(); }
+
+    void checkAtLeft(int32_t position) {
+        for (size_t i = 0, j = position; i < mOutputBufferSize;
+             i += kOutputChannelCount, j += mInputChannelCount) {
+            // Validate Left channel has audio
+            if (mInputBuffer[j] != 0) {
+                ASSERT_NE(mOutputBuffer[i], 0);
+            } else {
+                // No change in output when input is 0
+                ASSERT_EQ(mOutputBuffer[i], mInputBuffer[j]);
+            }
+            // Validate Right channel has no audio
+            ASSERT_EQ(mOutputBuffer[i + 1], 0);
+        }
+    }
+
+    void checkAtRight(int32_t position) {
+        for (size_t i = 0, j = position; i < mOutputBufferSize;
+             i += kOutputChannelCount, j += mInputChannelCount) {
+            // Validate Left channel has no audio
+            ASSERT_EQ(mOutputBuffer[i], 0);
+            // Validate Right channel has audio
+            if (mInputBuffer[j] != 0) {
+                ASSERT_NE(mOutputBuffer[i + 1], 0);
+            } else {
+                // No change in output when input is 0
+                ASSERT_EQ(mOutputBuffer[i + 1], mInputBuffer[j]);
+            }
+        }
+    }
+
+    void checkAtCenter(size_t position) {
+        for (size_t i = 0, j = position; i < mOutputBufferSize;
+             i += kOutputChannelCount, j += mInputChannelCount) {
+            // Validate both channels have audio
+            if (mInputBuffer[j] != 0) {
+                ASSERT_NE(mOutputBuffer[i], 0);
+                ASSERT_NE(mOutputBuffer[i + 1], 0);
+
+            } else {
+                // No change in output when input is 0
+                ASSERT_EQ(mOutputBuffer[i], mInputBuffer[j]);
+                ASSERT_EQ(mOutputBuffer[i + 1], mInputBuffer[j]);
+            }
+        }
+    }
+
+    void validateOutput(int32_t channel, size_t position) {
+        switch (channel) {
+            case AudioChannelLayout::CHANNEL_FRONT_LEFT:
+            case AudioChannelLayout::CHANNEL_BACK_LEFT:
+            case AudioChannelLayout::CHANNEL_SIDE_LEFT:
+            case AudioChannelLayout::CHANNEL_TOP_FRONT_LEFT:
+            case AudioChannelLayout::CHANNEL_BOTTOM_FRONT_LEFT:
+            case AudioChannelLayout::CHANNEL_TOP_BACK_LEFT:
+            case AudioChannelLayout::CHANNEL_FRONT_WIDE_LEFT:
+            case AudioChannelLayout::CHANNEL_TOP_SIDE_LEFT:
+                checkAtLeft(position);
+                break;
+
+            case AudioChannelLayout::CHANNEL_FRONT_RIGHT:
+            case AudioChannelLayout::CHANNEL_BACK_RIGHT:
+            case AudioChannelLayout::CHANNEL_SIDE_RIGHT:
+            case AudioChannelLayout::CHANNEL_TOP_FRONT_RIGHT:
+            case AudioChannelLayout::CHANNEL_BOTTOM_FRONT_RIGHT:
+            case AudioChannelLayout::CHANNEL_TOP_BACK_RIGHT:
+            case AudioChannelLayout::CHANNEL_FRONT_WIDE_RIGHT:
+            case AudioChannelLayout::CHANNEL_TOP_SIDE_RIGHT:
+            case AudioChannelLayout::CHANNEL_LOW_FREQUENCY_2:
+                checkAtRight(position);
+                break;
+
+            case AudioChannelLayout::CHANNEL_FRONT_CENTER:
+            case AudioChannelLayout::CHANNEL_BACK_CENTER:
+            case AudioChannelLayout::CHANNEL_TOP_FRONT_CENTER:
+            case AudioChannelLayout::CHANNEL_BOTTOM_FRONT_CENTER:
+            case AudioChannelLayout::CHANNEL_FRONT_LEFT_OF_CENTER:
+            case AudioChannelLayout::CHANNEL_FRONT_RIGHT_OF_CENTER:
+            case AudioChannelLayout::CHANNEL_TOP_CENTER:
+            case AudioChannelLayout::CHANNEL_TOP_BACK_CENTER:
+                checkAtCenter(position);
+                break;
+
+            case AudioChannelLayout::CHANNEL_LOW_FREQUENCY:
+                // If CHANNEL_LOW_FREQUENCY_2 is supported
+                if (mInputChannelLayout & AudioChannelLayout::CHANNEL_LOW_FREQUENCY_2) {
+                    // Validate that only Left channel has audio
+                    checkAtLeft(position);
+                } else {
+                    // Validate that both channels have audio
+                    checkAtCenter(position);
+                }
+                break;
+        }
+    }
+
+    std::set<int32_t> getInputChannelLayouts() {
+        std::set<int32_t> supportedChannels;
+        for (int32_t channel : kChannels) {
+            if ((mInputChannelLayout & channel) == channel) {
+                supportedChannels.insert(channel);
+            }
+        }
+        return supportedChannels;
+    }
+
+    int32_t mInputChannelLayout;
+};
+
+TEST_P(DownmixFoldDataTest, DownmixProcessData) {
+    // Set FOLD type parameter
+    ASSERT_NO_FATAL_FAILURE(setParameters(Downmix::Type::FOLD));
+
+    // Get all the channels from input layout
+    std::set<int32_t> supportedChannels = getInputChannelLayouts();
+
+    for (int32_t channel : supportedChannels) {
+        size_t position = std::distance(supportedChannels.begin(), supportedChannels.find(channel));
+        generateInputBuffer(position, false /*isStripe*/);
+        ASSERT_NO_FATAL_FAILURE(
+                processAndWriteToOutput(mInputBuffer, mOutputBuffer, mEffect, &mOpenEffectReturn));
+        validateOutput(channel, position);
+        std::fill(mInputBuffer.begin(), mInputBuffer.end(), 0);
+    }
+}
+
+enum StripParamName { STRIP_INSTANCE_NAME, STRIP_INPUT_LAYOUT };
+
+using DownmixStripDataTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int32_t>;
+
+class DownmixStripDataTest : public ::testing::TestWithParam<DownmixStripDataTestParam>,
+                             public DownmixEffectHelper {
+  public:
+    DownmixStripDataTest() : mInputChannelLayout(std::get<STRIP_INPUT_LAYOUT>(GetParam())) {
+        std::tie(mFactory, mDescriptor) = std::get<STRIP_INSTANCE_NAME>(GetParam());
+    }
+
+    void SetUp() override {
+        SetUpDownmix(mInputChannelLayout);
+        if (int32_t version;
+            mEffect->getInterfaceVersion(&version).isOk() && version < kMinDataTestHalVersion) {
+            GTEST_SKIP() << "Skipping the data test for version: " << version << "\n";
+        }
+        if (!isLayoutValid(mInputChannelLayout)) {
+            GTEST_SKIP() << "Layout not supported \n";
+        }
+        setDataTestParams(mInputChannelLayout);
+    }
+
+    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;
+             i += mInputChannelCount, j += kOutputChannelCount) {
+            ASSERT_EQ(mOutputBuffer[j], mInputBuffer[i]);
+            ASSERT_EQ(mOutputBuffer[j + 1], mInputBuffer[i + 1]);
+        }
+        for (size_t i = mOutputBufferSize; i < kBufferSize; i++) {
+            ASSERT_EQ(mOutputBuffer[i], mInputBuffer[i]);
+        }
+    }
+
+    int32_t mInputChannelLayout;
+};
+
+TEST_P(DownmixStripDataTest, DownmixProcessData) {
+    // Set STRIP type parameter
+    ASSERT_NO_FATAL_FAILURE(setParameters(Downmix::Type::STRIP));
+
+    // Generate input buffer, call process and compare outputs
+    generateInputBuffer(0 /*position*/, true /*isStripe*/);
+    ASSERT_NO_FATAL_FAILURE(
+            processAndWriteToOutput(mInputBuffer, mOutputBuffer, mEffect, &mOpenEffectReturn));
+    validateOutput();
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -126,7 +429,7 @@
         [](const testing::TestParamInfo<DownmixParamTest::ParamType>& info) {
             auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
             std::string type = std::to_string(static_cast<int>(std::get<PARAM_TYPE>(info.param)));
-            std::string name = getPrefix(descriptor) + "_type" + type;
+            std::string name = getPrefix(descriptor) + "_type_" + type;
             std::replace_if(
                     name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
             return name;
@@ -134,6 +437,39 @@
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DownmixParamTest);
 
+INSTANTIATE_TEST_SUITE_P(
+        DownmixTest, DownmixFoldDataTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, getEffectTypeUuidDownmix())),
+                           testing::ValuesIn(kLayoutValues)),
+        [](const testing::TestParamInfo<DownmixFoldDataTest::ParamType>& info) {
+            auto descriptor = std::get<FOLD_INSTANCE_NAME>(info.param).second;
+            std::string layout = std::to_string(std::get<FOLD_INPUT_LAYOUT>(info.param));
+            std::string name = getPrefix(descriptor) + "_fold_layout_" + layout;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DownmixFoldDataTest);
+
+INSTANTIATE_TEST_SUITE_P(
+        DownmixTest, DownmixStripDataTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, getEffectTypeUuidDownmix())),
+                           testing::ValuesIn(kLayoutValues)),
+        [](const testing::TestParamInfo<DownmixStripDataTest::ParamType>& info) {
+            auto descriptor = std::get<STRIP_INSTANCE_NAME>(info.param).second;
+            std::string layout =
+                    std::to_string(static_cast<int>(std::get<STRIP_INPUT_LAYOUT>(info.param)));
+            std::string name = getPrefix(descriptor) + "_strip_layout_" + layout;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DownmixStripDataTest);
+
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
     ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
diff --git a/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
index 2650f49..3f7a76d 100644
--- a/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
+++ b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
@@ -18,7 +18,6 @@
 #include <string>
 #include <unordered_set>
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalDynamicsProcessingTest"
 #include <android-base/logging.h>
 
diff --git a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
index 474b361..765c377 100644
--- a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalEnvironmentalReverbTest"
 #include <android-base/logging.h>
 
diff --git a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
index 09396d1..76838cef 100644
--- a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
@@ -15,15 +15,10 @@
  */
 
 #include <algorithm>
-#include <limits>
-#include <map>
-#include <memory>
-#include <optional>
 #include <string>
 #include <vector>
 
 #include <aidl/Gtest.h>
-#include <aidl/Vintf.h>
 #include <aidl/android/hardware/audio/effect/IEffect.h>
 #include <aidl/android/hardware/audio/effect/IFactory.h>
 #define LOG_TAG "VtsHalEqualizerTest"
diff --git a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
index 5a32398..d312111 100644
--- a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
@@ -18,7 +18,6 @@
 #include <utility>
 #include <vector>
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalHapticGeneratorTargetTest"
 #include <android-base/logging.h>
 #include <android/binder_enums.h>
diff --git a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
index 925f9ec..7f0091f 100644
--- a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
@@ -16,7 +16,6 @@
 
 #include <string>
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalLoudnessEnhancerTest"
 #include <android-base/logging.h>
 
diff --git a/audio/aidl/vts/VtsHalNSTargetTest.cpp b/audio/aidl/vts/VtsHalNSTargetTest.cpp
index 12d56b0..5c13512 100644
--- a/audio/aidl/vts/VtsHalNSTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalNSTargetTest.cpp
@@ -16,7 +16,6 @@
 
 #include <unordered_set>
 
-#include <aidl/Vintf.h>
 #include <aidl/android/hardware/audio/effect/NoiseSuppression.h>
 #define LOG_TAG "VtsHalNSParamTest"
 #include <android-base/logging.h>
diff --git a/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp b/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp
index 57eda09..1453495 100644
--- a/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalPresetReverbTargetTest"
 #include <android-base/logging.h>
 #include <android/binder_enums.h>
diff --git a/audio/aidl/vts/VtsHalSpatializerTargetTest.cpp b/audio/aidl/vts/VtsHalSpatializerTargetTest.cpp
new file mode 100644
index 0000000..f0b51b9
--- /dev/null
+++ b/audio/aidl/vts/VtsHalSpatializerTargetTest.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VtsHalSpatializerTest"
+#include <android-base/logging.h>
+
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::getEffectTypeUuidSpatializer;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::Parameter;
+using aidl::android::hardware::audio::effect::Range;
+using aidl::android::hardware::audio::effect::Spatializer;
+using aidl::android::media::audio::common::HeadTracking;
+using aidl::android::media::audio::common::Spatialization;
+using android::hardware::audio::common::testing::detail::TestExecutionTracer;
+using ::android::internal::ToString;
+
+enum ParamName {
+    PARAM_INSTANCE_NAME,
+    PARAM_SPATIALIZATION_LEVEL,
+    PARAM_SPATIALIZATION_MODE,
+    PARAM_HEADTRACK_SENSORID,
+    PARAM_HEADTRACK_MODE,
+    PARAM_HEADTRACK_CONNECTION_MODE
+};
+
+using SpatializerParamTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, Spatialization::Level,
+                   Spatialization::Mode, int /* sensor ID */, HeadTracking::Mode,
+                   HeadTracking::ConnectionMode>;
+
+class SpatializerParamTest : public ::testing::TestWithParam<SpatializerParamTestParam>,
+                             public EffectHelper {
+  public:
+    SpatializerParamTest()
+        : mSpatializerParams([&]() {
+              Spatialization::Level level = std::get<PARAM_SPATIALIZATION_LEVEL>(GetParam());
+              Spatialization::Mode mode = std::get<PARAM_SPATIALIZATION_MODE>(GetParam());
+              int sensorId = std::get<PARAM_HEADTRACK_SENSORID>(GetParam());
+              HeadTracking::Mode htMode = std::get<PARAM_HEADTRACK_MODE>(GetParam());
+              HeadTracking::ConnectionMode htConnectMode =
+                      std::get<PARAM_HEADTRACK_CONNECTION_MODE>(GetParam());
+              std::map<Spatializer::Tag, Spatializer> params;
+              params[Spatializer::spatializationLevel] =
+                      Spatializer::make<Spatializer::spatializationLevel>(level);
+              params[Spatializer::spatializationMode] =
+                      Spatializer::make<Spatializer::spatializationMode>(mode);
+              params[Spatializer::headTrackingSensorId] =
+                      Spatializer::make<Spatializer::headTrackingSensorId>(sensorId);
+              params[Spatializer::headTrackingMode] =
+                      Spatializer::make<Spatializer::headTrackingMode>(htMode);
+              params[Spatializer::headTrackingConnectionMode] =
+                      Spatializer::make<Spatializer::headTrackingConnectionMode>(htConnectMode);
+              return params;
+          }()) {
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    }
+
+    void SetUp() override {
+        ASSERT_NE(nullptr, mFactory);
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+        Parameter::Specific specific = getDefaultParamSpecific();
+        Parameter::Common common = EffectHelper::createParamCommon(
+                0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+        IEffect::OpenEffectReturn ret;
+        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+        ASSERT_NE(nullptr, mEffect);
+    }
+
+    void TearDown() override {
+        ASSERT_NO_FATAL_FAILURE(close(mEffect));
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+    }
+
+    Parameter::Specific getDefaultParamSpecific() {
+        Spatializer spatializer = Spatializer::make<Spatializer::headTrackingSensorId>(0);
+        Parameter::Specific specific =
+                Parameter::Specific::make<Parameter::Specific::spatializer>(spatializer);
+        return specific;
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+    const std::map<Spatializer::Tag, Spatializer> mSpatializerParams;
+};
+
+TEST_P(SpatializerParamTest, SetAndGetParam) {
+    for (const auto& it : mSpatializerParams) {
+        auto& tag = it.first;
+        auto& spatializer = it.second;
+
+        // validate parameter
+        Descriptor desc;
+        ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+        const bool valid = isParameterValid<Spatializer, Range::spatializer>(it.second, desc);
+        const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+        // set parameter
+        Parameter expectParam;
+        Parameter::Specific specific;
+        specific.set<Parameter::Specific::spatializer>(spatializer);
+        expectParam.set<Parameter::specific>(specific);
+        EXPECT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+        // only get if parameter in range and set success
+        if (expected == EX_NONE) {
+            Parameter getParam;
+            Parameter::Id id;
+            Spatializer::Id spatializerId;
+            spatializerId.set<Spatializer::Id::commonTag>(tag);
+            id.set<Parameter::Id::spatializerTag>(spatializerId);
+            // if set success, then get should match
+            EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
+            EXPECT_EQ(expectParam, getParam);
+        }
+    }
+}
+
+std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kDescPair;
+INSTANTIATE_TEST_SUITE_P(
+        SpatializerTest, SpatializerParamTest,
+        ::testing::Combine(
+                testing::ValuesIn(kDescPair = EffectFactoryHelper::getAllEffectDescriptors(
+                                          IFactory::descriptor, getEffectTypeUuidSpatializer())),
+                testing::ValuesIn(EffectHelper::getTestValueSet<
+                                  Spatializer, Spatialization::Level, Range::spatializer,
+                                  Spatializer::spatializationLevel>(kDescPair)),
+                testing::ValuesIn(EffectHelper::getTestValueSet<
+                                  Spatializer, Spatialization::Mode, Range::spatializer,
+                                  Spatializer::spatializationMode>(kDescPair)),
+                testing::ValuesIn(
+                        EffectHelper::getTestValueSet<Spatializer, int, Range::spatializer,
+                                                      Spatializer::headTrackingSensorId>(
+                                kDescPair, EffectHelper::expandTestValueBasic<int>)),
+                testing::ValuesIn(EffectHelper::getTestValueSet<
+                                  Spatializer, HeadTracking::Mode, Range::spatializer,
+                                  Spatializer::headTrackingMode>(kDescPair)),
+                testing::ValuesIn(EffectHelper::getTestValueSet<
+                                  Spatializer, HeadTracking::ConnectionMode, Range::spatializer,
+                                  Spatializer::headTrackingConnectionMode>(kDescPair))),
+        [](const testing::TestParamInfo<SpatializerParamTest::ParamType>& info) {
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string level = ToString(std::get<PARAM_SPATIALIZATION_LEVEL>(info.param));
+            std::string mode = ToString(std::get<PARAM_SPATIALIZATION_MODE>(info.param));
+            std::string sensorId = ToString(std::get<PARAM_HEADTRACK_SENSORID>(info.param));
+            std::string htMode = ToString(std::get<PARAM_HEADTRACK_MODE>(info.param));
+            std::string htConnectMode =
+                    ToString(std::get<PARAM_HEADTRACK_CONNECTION_MODE>(info.param));
+            std::string name = getPrefix(descriptor) + "_sensorID_" + level + "_mode_" + mode +
+                               "_sensorID_" + sensorId + "_HTMode_" + htMode +
+                               "_HTConnectionMode_" + htConnectMode;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SpatializerParamTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp b/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
index 3e39d3a..0c24f90 100644
--- a/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalVirtualizerTest"
 #include <android-base/logging.h>
 
diff --git a/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
index 1b8352b..db83715 100644
--- a/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
@@ -16,7 +16,6 @@
 
 #include <unordered_set>
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalVisualizerTest"
 #include <android-base/logging.h>
 #include <android/binder_enums.h>
diff --git a/audio/aidl/vts/VtsHalVolumeTargetTest.cpp b/audio/aidl/vts/VtsHalVolumeTargetTest.cpp
index 257100b..aa2c05f 100644
--- a/audio/aidl/vts/VtsHalVolumeTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalVolumeTargetTest.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalVolumeTest"
 #include <android-base/logging.h>
 
diff --git a/audio/common/all-versions/default/service/android.hardware.audio.service.rc b/audio/common/all-versions/default/service/android.hardware.audio.service.rc
index 0de4eea..a1df67a 100644
--- a/audio/common/all-versions/default/service/android.hardware.audio.service.rc
+++ b/audio/common/all-versions/default/service/android.hardware.audio.service.rc
@@ -2,7 +2,7 @@
     class hal
     user audioserver
     # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
-    group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct wakelock context_hub
+    group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct wakelock context_hub system
     capabilities BLOCK_SUSPEND SYS_NICE
     # setting RLIMIT_RTPRIO allows binder RT priority inheritance
     rlimit rtprio 10 10
diff --git a/audio/effect/4.0/xml/Android.bp b/audio/effect/4.0/xml/Android.bp
index 8c03a35..bdffe60 100644
--- a/audio/effect/4.0/xml/Android.bp
+++ b/audio/effect/4.0/xml/Android.bp
@@ -9,9 +9,9 @@
 
 genrule {
     name: "audio_effects_conf_V4_0",
-    srcs: ["audio_effects_conf.xsd"],
+    srcs: [":audio_effects_conf_V2_0"],
     out: [
         "audio_effects_conf_V4_0.xsd",
     ],
-    cmd: "cp -f $(in) $(genDir)/audio_effects_conf_V4_0.xsd",
+    cmd: "cp -f $(in) $(out)",
 }
diff --git a/audio/effect/4.0/xml/audio_effects_conf.xsd b/audio/effect/4.0/xml/audio_effects_conf.xsd
deleted file mode 120000
index 9d85fa7..0000000
--- a/audio/effect/4.0/xml/audio_effects_conf.xsd
+++ /dev/null
@@ -1 +0,0 @@
-../../2.0/xml/audio_effects_conf.xsd
\ No newline at end of file
diff --git a/audio/effect/5.0/xml/Android.bp b/audio/effect/5.0/xml/Android.bp
index 7982e2a..ed12e38 100644
--- a/audio/effect/5.0/xml/Android.bp
+++ b/audio/effect/5.0/xml/Android.bp
@@ -9,6 +9,6 @@
 
 xsd_config {
     name: "audio_effects_conf_V5_0",
-    srcs: ["audio_effects_conf.xsd"],
+    srcs: [":audio_effects_conf_V2_0"],
     package_name: "audio.effects.V5_0",
 }
diff --git a/audio/effect/5.0/xml/audio_effects_conf.xsd b/audio/effect/5.0/xml/audio_effects_conf.xsd
deleted file mode 120000
index 9d85fa7..0000000
--- a/audio/effect/5.0/xml/audio_effects_conf.xsd
+++ /dev/null
@@ -1 +0,0 @@
-../../2.0/xml/audio_effects_conf.xsd
\ No newline at end of file
diff --git a/automotive/audiocontrol/aidl/Android.bp b/automotive/audiocontrol/aidl/Android.bp
index 9ae77cd..86b63a6 100644
--- a/automotive/audiocontrol/aidl/Android.bp
+++ b/automotive/audiocontrol/aidl/Android.bp
@@ -13,9 +13,9 @@
     name: "android.hardware.automotive.audiocontrol",
     vendor_available: true,
     srcs: ["android/hardware/automotive/audiocontrol/*.aidl"],
-    imports: [
-        "android.hardware.audio.common-V1",
-        "android.media.audio.common.types-V2",
+    defaults: [
+        "latest_android_hardware_audio_common_import_interface",
+        "latest_android_media_audio_common_types_import_interface",
     ],
     stability: "vintf",
     backend: {
@@ -52,6 +52,37 @@
         },
 
     ],
-    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"
+
+cc_defaults {
+    name: "latest_android_hardware_automotive_audiocontrol_cpp_static",
+    static_libs: [
+        latest_android_hardware_automotive_audiocontrol + "-cpp",
+    ],
+}
+
+cc_defaults {
+    name: "latest_android_hardware_automotive_audiocontrol_cpp_shared",
+    shared_libs: [
+        latest_android_hardware_automotive_audiocontrol + "-cpp",
+    ],
+}
+
+cc_defaults {
+    name: "latest_android_hardware_automotive_audiocontrol_ndk_static",
+    static_libs: [
+        latest_android_hardware_automotive_audiocontrol + "-ndk",
+    ],
+}
+
+cc_defaults {
+    name: "latest_android_hardware_automotive_audiocontrol_ndk_shared",
+    shared_libs: [
+        latest_android_hardware_automotive_audiocontrol + "-ndk",
+    ],
+}
diff --git a/automotive/audiocontrol/aidl/default/audiocontrol-default.xml b/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
index 95cd7f0..bcb5669 100644
--- a/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
+++ b/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
@@ -1,7 +1,7 @@
 <manifest version="2.0" type="device">
     <hal format="aidl">
         <name>android.hardware.automotive.audiocontrol</name>
-        <version>3</version>
+        <version>4</version>
         <fqname>IAudioControl/default</fqname>
     </hal>
 </manifest>
diff --git a/automotive/audiocontrol/aidl/vts/Android.bp b/automotive/audiocontrol/aidl/vts/Android.bp
index cfc2a3e..c73ad79 100644
--- a/automotive/audiocontrol/aidl/vts/Android.bp
+++ b/automotive/audiocontrol/aidl/vts/Android.bp
@@ -24,6 +24,8 @@
 cc_test {
     name: "VtsAidlHalAudioControlTest",
     defaults: [
+        "latest_android_hardware_audio_common_cpp_static",
+        "latest_android_hardware_automotive_audiocontrol_cpp_static",
         "latest_android_media_audio_common_types_cpp_static",
         "VtsHalTargetTestDefaults",
         "use_libaidlvintf_gtest_helper_static",
@@ -38,8 +40,6 @@
         "libxml2",
     ],
     static_libs: [
-        "android.hardware.automotive.audiocontrol-V3-cpp",
-        "android.hardware.audio.common-V1-cpp",
         "libgmock",
     ],
     test_suites: [
diff --git a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
index aad07de..fe749f6 100644
--- a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
+++ b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
@@ -102,7 +102,7 @@
 
 static bool hasIpv4(std::string ifname) {
     auto ifr = ifreqs::fromName(ifname);
-    switch (const auto status = ifreqs::trySend(SIOCGIFADDR, ifr)) {
+    switch (ifreqs::trySend(SIOCGIFADDR, ifr)) {
         case 0:
             return true;
         case EADDRNOTAVAIL:
diff --git a/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.cpp b/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.cpp
index 96110db..e882160 100644
--- a/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.cpp
+++ b/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.cpp
@@ -18,9 +18,9 @@
 
 namespace android::hardware::automotive::can::V1_0::implementation::fuzzer {
 
-constexpr CanController::InterfaceType kInterfaceType[] = {CanController::InterfaceType::VIRTUAL,
-                                                           CanController::InterfaceType::SOCKETCAN,
-                                                           CanController::InterfaceType::SLCAN};
+constexpr CanController::InterfaceType kInterfaceType[] = {
+        CanController::InterfaceType::VIRTUAL, CanController::InterfaceType::SOCKETCAN,
+        CanController::InterfaceType::SLCAN, CanController::InterfaceType::INDEXED};
 constexpr FilterFlag kFilterFlag[] = {FilterFlag::DONT_CARE, FilterFlag::SET, FilterFlag::NOT_SET};
 constexpr size_t kInterfaceTypeLength = std::size(kInterfaceType);
 constexpr size_t kFilterFlagLength = std::size(kFilterFlag);
@@ -28,8 +28,8 @@
 constexpr size_t kMaxPayloadBytes = 64;
 constexpr size_t kMaxFilters = 20;
 constexpr size_t kMaxSerialNumber = 1000;
-constexpr size_t kMaxBuses = 10;
-constexpr size_t kMaxRepeat = 5;
+constexpr size_t kMaxBuses = 100;
+constexpr size_t kMaxRepeat = 100;
 
 Bus CanFuzzer::makeBus() {
     ICanController::BusConfig config = {};
@@ -56,9 +56,13 @@
 }
 
 void CanFuzzer::invokeUpInterface() {
-    const CanController::InterfaceType iftype =
-            kInterfaceType[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
-                    0, kInterfaceTypeLength - 1)];
+    CanController::InterfaceType controller;
+    if (mFuzzedDataProvider->ConsumeBool()) {
+        controller = (CanController::InterfaceType)mFuzzedDataProvider->ConsumeIntegral<uint8_t>();
+    } else {
+        controller = kInterfaceType[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
+                0, kInterfaceTypeLength - 1)];
+    }
     std::string configName;
 
     if (const bool shouldInvokeValidBus = mFuzzedDataProvider->ConsumeBool();
@@ -73,7 +77,7 @@
 
     ICanController::BusConfig config = {.name = configName};
 
-    if (iftype == CanController::InterfaceType::SOCKETCAN) {
+    if (controller == CanController::InterfaceType::SOCKETCAN) {
         CanController::BusConfig::InterfaceId::Socketcan socketcan = {};
         if (const bool shouldPassSerialSocket = mFuzzedDataProvider->ConsumeBool();
             shouldPassSerialSocket) {
@@ -83,7 +87,7 @@
             socketcan.ifname(ifname);
         }
         config.interfaceId.socketcan(socketcan);
-    } else if (iftype == CanController::InterfaceType::SLCAN) {
+    } else if (controller == CanController::InterfaceType::SLCAN) {
         CanController::BusConfig::InterfaceId::Slcan slcan = {};
         if (const bool shouldPassSerialSlcan = mFuzzedDataProvider->ConsumeBool();
             shouldPassSerialSlcan) {
@@ -93,8 +97,12 @@
             slcan.ttyname(ifname);
         }
         config.interfaceId.slcan(slcan);
-    } else if (iftype == CanController::InterfaceType::VIRTUAL) {
+    } else if (controller == CanController::InterfaceType::VIRTUAL) {
         config.interfaceId.virtualif({ifname});
+    } else if (controller == CanController::InterfaceType::INDEXED) {
+        CanController::BusConfig::InterfaceId::Indexed indexed;
+        indexed.index = mFuzzedDataProvider->ConsumeIntegral<uint8_t>();
+        config.interfaceId.indexed(indexed);
     }
 
     const size_t numInvocations =
@@ -108,8 +116,13 @@
     hidl_string configName;
     if (const bool shouldInvokeValidBus = mFuzzedDataProvider->ConsumeBool();
         (shouldInvokeValidBus) && (mBusNames.size() > 0)) {
-        const size_t busNameIndex =
-                mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, mBusNames.size() - 1);
+        size_t busNameIndex;
+        if (mBusNames.size() == 1) {
+            busNameIndex = 0;
+        } else {
+            busNameIndex =
+                    mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, mBusNames.size() - 1);
+        }
         configName = mBusNames[busNameIndex];
     } else {
         configName = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxCharacters);
@@ -122,12 +135,6 @@
     }
 }
 
-void CanFuzzer::invokeController() {
-    getSupportedInterfaceTypes();
-    invokeUpInterface();
-    invokeDownInterface();
-}
-
 void CanFuzzer::invokeBus() {
     const size_t numBuses = mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(1, kMaxBuses);
     for (size_t i = 0; i < numBuses; ++i) {
@@ -152,12 +159,22 @@
             for (uint32_t k = 0; k < numFilters; ++k) {
                 filterVector[k].id = mFuzzedDataProvider->ConsumeIntegral<uint32_t>();
                 filterVector[k].mask = mFuzzedDataProvider->ConsumeIntegral<uint32_t>();
-                filterVector[k].rtr =
-                        kFilterFlag[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
-                                0, kFilterFlagLength - 1)];
-                filterVector[k].extendedFormat =
-                        kFilterFlag[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
-                                0, kFilterFlagLength - 1)];
+                if (mFuzzedDataProvider->ConsumeBool()) {
+                    filterVector[k].rtr =
+                            (FilterFlag)mFuzzedDataProvider->ConsumeIntegral<uint8_t>();
+                } else {
+                    filterVector[k].rtr =
+                            kFilterFlag[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
+                                    0, kFilterFlagLength - 1)];
+                }
+                if (mFuzzedDataProvider->ConsumeBool()) {
+                    filterVector[k].extendedFormat =
+                            (FilterFlag)mFuzzedDataProvider->ConsumeIntegral<uint8_t>();
+                } else {
+                    filterVector[k].extendedFormat =
+                            kFilterFlag[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
+                                    0, kFilterFlagLength - 1)];
+                }
                 filterVector[k].exclude = mFuzzedDataProvider->ConsumeBool();
             }
             auto listener = listeningBus.listen(filterVector);
@@ -175,8 +192,16 @@
 
 void CanFuzzer::process(const uint8_t* data, size_t size) {
     mFuzzedDataProvider = new FuzzedDataProvider(data, size);
-    invokeController();
-    invokeBus();
+    while (mFuzzedDataProvider->remaining_bytes()) {
+        auto CanFuzzerFunction =
+                mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+                        [&]() { getSupportedInterfaceTypes(); },
+                        [&]() { invokeUpInterface(); },
+                        [&]() { invokeDownInterface(); },
+                        [&]() { invokeBus(); },
+                });
+        CanFuzzerFunction();
+    }
 }
 
 bool CanFuzzer::init() {
diff --git a/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.h b/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.h
index 930cddd..3211bd0 100644
--- a/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.h
+++ b/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.h
@@ -116,7 +116,6 @@
     hidl_vec<hidl_string> getBusNames();
     void getSupportedInterfaceTypes();
     void invokeBus();
-    void invokeController();
     void invokeUpInterface();
     void invokeDownInterface();
     FuzzedDataProvider* mFuzzedDataProvider = nullptr;
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp b/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
index c16b29a..03a9df5 100644
--- a/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
@@ -30,7 +30,7 @@
 
 std::unique_ptr<VehiclePropValue> createVehiclePropValue(
     VehiclePropertyType type, size_t vecSize) {
-    auto val = std::unique_ptr<VehiclePropValue>(new VehiclePropValue);
+    auto val = std::unique_ptr<VehiclePropValue>(new VehiclePropValue());
     switch (type) {
         case VehiclePropertyType::INT32:      // fall through
         case VehiclePropertyType::INT32_VEC:  // fall through
diff --git a/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.cpp b/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.cpp
index 8a085e5..4d0995d 100644
--- a/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.cpp
+++ b/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.cpp
@@ -76,30 +76,20 @@
 using ::android::hardware::automotive::vehicle::V2_0::vms::VmsLayerOffering;
 using ::android::hardware::automotive::vehicle::V2_0::vms::VmsOffers;
 
-constexpr const char kCarMake[] = "Default Car";
-constexpr VehicleProperty kVehicleProp[] = {VehicleProperty::INVALID,
-                                            VehicleProperty::HVAC_FAN_SPEED,
-                                            VehicleProperty::INFO_MAKE,
-                                            VehicleProperty::DISPLAY_BRIGHTNESS,
-                                            VehicleProperty::INFO_FUEL_CAPACITY,
-                                            VehicleProperty::HVAC_SEAT_TEMPERATURE};
-constexpr DiagnosticIntegerSensorIndex kDiagnosticIntIndex[] = {
-        DiagnosticIntegerSensorIndex::FUEL_SYSTEM_STATUS,
-        DiagnosticIntegerSensorIndex::MALFUNCTION_INDICATOR_LIGHT_ON,
-        DiagnosticIntegerSensorIndex::NUM_OXYGEN_SENSORS_PRESENT,
-        DiagnosticIntegerSensorIndex::FUEL_TYPE};
-constexpr DiagnosticFloatSensorIndex kDiagnosticFloatIndex[] = {
-        DiagnosticFloatSensorIndex::CALCULATED_ENGINE_LOAD,
-        DiagnosticFloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK1,
-        DiagnosticFloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK1,
-        DiagnosticFloatSensorIndex::THROTTLE_POSITION};
-constexpr size_t kVehiclePropArrayLength = std::size(kVehicleProp);
-constexpr size_t kIntSensorArrayLength = std::size(kDiagnosticIntIndex);
-constexpr size_t kFloatSensorArrayLength = std::size(kDiagnosticFloatIndex);
-constexpr VmsMessageType kAvailabilityMessageType[] = {VmsMessageType::AVAILABILITY_CHANGE,
-                                                       VmsMessageType::AVAILABILITY_RESPONSE};
-constexpr VmsMessageType kSubscriptionMessageType[] = {VmsMessageType::SUBSCRIPTIONS_CHANGE,
-                                                       VmsMessageType::SUBSCRIPTIONS_RESPONSE};
+std::string kCarMake;
+constexpr int32_t kMaxCaseMessage = 8;
+constexpr int32_t kMaxRuns = 20;
+constexpr int32_t kMaxSize = 1000;
+constexpr int32_t kMinSize = 0;
+constexpr int32_t kMaxFileSize = 100;
+float kFloatValue;
+std::vector<int32_t> kVec32;
+std::vector<int64_t> kVec64;
+std::vector<uint8_t> kVec8;
+std::vector<float> kVecFloat;
+static const std::vector<std::string> kSampleDtcs = {"P0070",
+                                                     "P0102"
+                                                     "P0123"};
 
 MockedVehicleHal::VehiclePropValuePtr MockedVehicleHal::get(
         const VehiclePropValue& requestedPropValue, StatusCode* outStatus) {
@@ -113,23 +103,23 @@
 
     switch (property) {
         case VehicleProperty::INFO_MAKE:
-            pValue = getValuePool()->obtainString(kCarMake);
+            pValue = getValuePool()->obtainString(kCarMake.c_str());
             break;
         case VehicleProperty::INFO_FUEL_CAPACITY:
             if (mFuelCapacityAttemptsLeft-- > 0) {
                 *outStatus = StatusCode::TRY_AGAIN;
             } else {
-                pValue = getValuePool()->obtainFloat(42.42);
+                pValue = getValuePool()->obtainFloat(kFloatValue);
             }
             break;
         default:
             if (requestedPropValue.prop == kCustomComplexProperty) {
                 pValue = getValuePool()->obtainComplex();
-                pValue->value.int32Values = hidl_vec<int32_t>{10, 20};
-                pValue->value.int64Values = hidl_vec<int64_t>{30, 40};
-                pValue->value.floatValues = hidl_vec<float_t>{1.1, 2.2};
-                pValue->value.bytes = hidl_vec<uint8_t>{1, 2, 3};
-                pValue->value.stringValue = kCarMake;
+                pValue->value.int32Values = hidl_vec<int32_t>{kVec32};
+                pValue->value.int64Values = hidl_vec<int64_t>{kVec64};
+                pValue->value.floatValues = hidl_vec<float_t>{kVecFloat};
+                pValue->value.bytes = hidl_vec<uint8_t>{kVec8};
+                pValue->value.stringValue = kCarMake.c_str();
                 break;
             }
             auto key = makeKey(toInt(property), areaId);
@@ -145,28 +135,72 @@
     return pValue;
 }
 
+void VehicleHalManagerFuzzer::initValue() {
+    kCarMake = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxFileSize);
+    kFloatValue = mFuzzedDataProvider->ConsumeFloatingPoint<float>();
+    fillParameter<int32_t>(mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize),
+                           kVec32);
+    fillParameter<int64_t>(mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize),
+                           kVec64);
+    fillParameter<uint8_t>(mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize),
+                           kVec8);
+    size_t size = mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize);
+    for (size_t i = 0; i < size; ++i) {
+        kVecFloat.push_back(mFuzzedDataProvider->ConsumeFloatingPoint<float>());
+    }
+}
+
 void VehicleHalManagerFuzzer::process(const uint8_t* data, size_t size) {
     mFuzzedDataProvider = new FuzzedDataProvider(data, size);
-    invokeDebug();
-    invokePropConfigs();
-    invokeSubscribe();
-    invokeSetAndGetValues();
-    invokeObd2SensorStore();
-    invokeVmsUtils();
-    invokeVehiclePropStore();
-    invokeWatchDogClient();
+    initValue();
+    /* Limited while loop runs to prevent timeouts caused
+     * by repeated calls to high-execution-time APIs.
+     */
+    size_t maxRuns = mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxRuns);
+    size_t itr = 0;
+    while (mFuzzedDataProvider->remaining_bytes() && ++itr <= maxRuns) {
+        auto invokeVehicleHalManagerFuzzer =
+                mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+                        [&]() { invokeDebug(); },
+                        [&]() { invokePropConfigs(); },
+                        [&]() { invokeSubscribe(); },
+                        [&]() { invokeSetAndGetValues(); },
+                        [&]() { invokeObd2SensorStore(); },
+                        [&]() { invokeVmsUtils(); },
+                        [&]() { invokeVehiclePropStore(); },
+                        [&]() { invokeWatchDogClient(); },
+                });
+        invokeVehicleHalManagerFuzzer();
+    }
 }
 
 void VehicleHalManagerFuzzer::invokeDebug() {
-    hidl_string debugOption = mFuzzedDataProvider->PickValueInArray(
-            {"--help", "--list", "--get", "--set", "", "invalid"});
     hidl_handle fd = {};
 
     native_handle_t* rawHandle = native_handle_create(/*numFds=*/1, /*numInts=*/0);
     fd.setTo(native_handle_clone(rawHandle), /*shouldOwn=*/true);
+    int32_t size = mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(kMinSize, kMaxFileSize);
+    hidl_vec<hidl_string> options(size);
 
-    mManager->debug(fd, {});
-    mManager->debug(fd, {debugOption});
+    for (int32_t idx = 0; idx < size; ++idx) {
+        if (idx == 0 && mFuzzedDataProvider->ConsumeBool()) {
+            options[idx] = mFuzzedDataProvider->PickValueInArray(
+                    {"--help", "--list", "--get", "--set", "", "invalid"});
+        } else if (idx == 2 && mFuzzedDataProvider->ConsumeBool()) {
+            options[idx] =
+                    mFuzzedDataProvider->PickValueInArray({"-i", "-i64", "-f", "-s", "-b", "-a"});
+        } else if (mFuzzedDataProvider->ConsumeBool()) {
+            options[idx] = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxSize);
+        } else {
+            options[idx] = std::to_string(mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+        }
+    }
+
+    if (mFuzzedDataProvider->ConsumeBool()) {
+        mManager->debug(fd, {});
+    } else {
+        mManager->debug(fd, options);
+    }
     native_handle_delete(rawHandle);
 }
 
@@ -175,178 +209,245 @@
     int32_t vehicleProp2 = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
 
     hidl_vec<int32_t> properties = {vehicleProp1, vehicleProp2};
+    auto invokePropConfigsAPI = mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+            [&]() {
+                mManager->getPropConfigs(
+                        properties, []([[maybe_unused]] StatusCode status,
+                                       [[maybe_unused]] const hidl_vec<VehiclePropConfig>& c) {});
+            },
+            [&]() {
+                mManager->getPropConfigs(
+                        {mFuzzedDataProvider->ConsumeIntegral<int32_t>()},
+                        []([[maybe_unused]] StatusCode status,
+                           [[maybe_unused]] const hidl_vec<VehiclePropConfig>& c) {});
+            },
+            [&]() {
+                mManager->getAllPropConfigs(
+                        []([[maybe_unused]] const hidl_vec<VehiclePropConfig>& propConfigs) {});
+            },
 
-    mManager->getPropConfigs(properties,
-                             []([[maybe_unused]] StatusCode status,
-                                [[maybe_unused]] const hidl_vec<VehiclePropConfig>& c) {});
-
-    mManager->getPropConfigs({toInt(kVehicleProp[abs(vehicleProp1) % kVehiclePropArrayLength])},
-                             []([[maybe_unused]] StatusCode status,
-                                [[maybe_unused]] const hidl_vec<VehiclePropConfig>& c) {});
-
-    mManager->getAllPropConfigs(
-            []([[maybe_unused]] const hidl_vec<VehiclePropConfig>& propConfigs) {});
+    });
+    invokePropConfigsAPI();
 }
 
 void VehicleHalManagerFuzzer::invokeSubscribe() {
-    int32_t vehicleProp1 = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
     int32_t vehicleProp2 = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
     int32_t vehicleProp3 = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
 
-    const auto prop1 = toInt(kVehicleProp[abs(vehicleProp1) % kVehiclePropArrayLength]);
     sp<MockedVehicleCallback> cb = new MockedVehicleCallback();
+    VehiclePropertyType type =
+            static_cast<VehiclePropertyType>(mFuzzedDataProvider->ConsumeIntegral<int32_t>());
 
-    hidl_vec<SubscribeOptions> options = {
-            SubscribeOptions{.propId = prop1, .flags = SubscribeFlags::EVENTS_FROM_CAR}};
+    auto invokeSubscribeAPI = mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+            [&]() {
+                size_t size =
+                        mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize);
+                hidl_vec<SubscribeOptions> options(size);
+                for (size_t idx = 0; idx < size; ++idx) {
+                    options[idx] = {SubscribeOptions{
+                            .propId = mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                            .flags = static_cast<SubscribeFlags>(
+                                    mFuzzedDataProvider->ConsumeIntegral<int32_t>())}};
+                }
+                mManager->subscribe(cb, options);
+            },
+            [&]() {
+                auto unsubscribedValue = mObjectPool->obtain(type);
+                if (!unsubscribedValue) {
+                    return;
+                }
+                unsubscribedValue->prop = vehicleProp2;
+                unsubscribedValue->value.int32Values[0] = INT32_MAX;
+                mHal->sendPropEvent(std::move(unsubscribedValue));
+                cb->waitForExpectedEvents(mFuzzedDataProvider->ConsumeIntegral<size_t>());
+            },
+            [&]() {
+                const auto prop1 = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+                mManager->unsubscribe(cb, prop1);
+            },
+            [&]() {
+                mHal->sendHalError(StatusCode::TRY_AGAIN, vehicleProp3,
+                                   mFuzzedDataProvider->ConsumeIntegral<int32_t>() /*areaId=*/);
+            },
 
-    mManager->subscribe(cb, options);
-
-    auto unsubscribedValue = mObjectPool->obtain(VehiclePropertyType::INT32);
-    unsubscribedValue->prop = toInt(kVehicleProp[abs(vehicleProp2) % kVehiclePropArrayLength]);
-
-    mHal->sendPropEvent(std::move(unsubscribedValue));
-    cb->getReceivedEvents();
-    cb->waitForExpectedEvents(0);
-
-    auto subscribedValue = mObjectPool->obtain(VehiclePropertyType::INT32);
-    subscribedValue->prop = toInt(kVehicleProp[abs(vehicleProp2) % kVehiclePropArrayLength]);
-    subscribedValue->value.int32Values[0] = INT32_MAX;
-
-    cb->reset();
-    VehiclePropValue actualValue(*subscribedValue.get());
-    mHal->sendPropEvent(std::move(subscribedValue));
-    cb->waitForExpectedEvents(1);
-    mManager->unsubscribe(cb, prop1);
-
-    sp<MockedVehicleCallback> cb2 = new MockedVehicleCallback();
-
-    hidl_vec<SubscribeOptions> options2 = {
-            SubscribeOptions{
-                    .propId = toInt(kVehicleProp[abs(vehicleProp3) % kVehiclePropArrayLength]),
-                    .flags = SubscribeFlags::EVENTS_FROM_CAR},
-    };
-
-    mManager->subscribe(cb2, options2);
-
-    mHal->sendHalError(StatusCode::TRY_AGAIN,
-                       toInt(kVehicleProp[abs(vehicleProp3) % kVehiclePropArrayLength]),
-                       /*areaId=*/0);
+    });
+    invokeSubscribeAPI();
 }
 
 void VehicleHalManagerFuzzer::invokeSetAndGetValues() {
-    uint32_t vehicleProp1 =
-            mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kVehiclePropArrayLength - 1);
-    uint32_t vehicleProp2 =
-            mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kVehiclePropArrayLength - 1);
-    uint32_t vehicleProp3 =
-            mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kVehiclePropArrayLength - 1);
-
-    invokeGet(kCustomComplexProperty, 0);
-    invokeGet(toInt(kVehicleProp[vehicleProp2]), 0);
-    invokeGet(toInt(kVehicleProp[vehicleProp1]), 0);
-
-    auto expectedValue = mObjectPool->obtainInt32(mFuzzedDataProvider->ConsumeIntegral<int32_t>());
-    mObjectPool->obtainInt64(mFuzzedDataProvider->ConsumeIntegral<int64_t>());
-    mObjectPool->obtainFloat(mFuzzedDataProvider->ConsumeFloatingPoint<float>());
-    mObjectPool->obtainBoolean(mFuzzedDataProvider->ConsumeBool());
-    expectedValue->prop = toInt(kVehicleProp[vehicleProp2]);
-    expectedValue->areaId = 0;
-
-    mManager->set(*expectedValue.get());
-    invokeGet(toInt(kVehicleProp[vehicleProp2]), 0);
-    expectedValue->prop = toInt(kVehicleProp[vehicleProp3]);
-    mManager->set(*expectedValue.get());
-    expectedValue->prop = toInt(VehicleProperty::INVALID);
-    mManager->set(*expectedValue.get());
+    auto invokeSetAndGetAPI = mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+            [&]() {
+                invokeGet(mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                          mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+            },
+            [&]() { mObjectPool->obtainInt64(mFuzzedDataProvider->ConsumeIntegral<int64_t>()); },
+            [&]() { mObjectPool->obtainFloat(mFuzzedDataProvider->ConsumeFloatingPoint<float>()); },
+            [&]() { mObjectPool->obtainBoolean(mFuzzedDataProvider->ConsumeBool()); },
+            [&]() {
+                int32_t vehicleProp2 = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+                auto expectedValue =
+                        mObjectPool->obtainInt32(mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+                expectedValue->prop = vehicleProp2;
+                expectedValue->areaId = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+                mManager->set(*expectedValue.get());
+            },
+    });
+    invokeSetAndGetAPI();
 }
 
 void VehicleHalManagerFuzzer::invokeObd2SensorStore() {
-    uint32_t diagnosticIntIndex =
-            mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kIntSensorArrayLength - 1);
-    int32_t diagnosticIntValue = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
-    uint32_t diagnosticFloatIndex =
-            mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kFloatSensorArrayLength - 1);
-    float diagnosticFloatValue = mFuzzedDataProvider->ConsumeFloatingPoint<float>();
+    size_t diagnosticInt = mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize);
+    size_t diagnosticFloat =
+            mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize);
 
     std::unique_ptr<Obd2SensorStore> sensorStore(
-            new Obd2SensorStore(kIntSensorArrayLength, kFloatSensorArrayLength));
-    if (sensorStore) {
-        sensorStore->setIntegerSensor(kDiagnosticIntIndex[diagnosticIntIndex], diagnosticIntValue);
-        sensorStore->setFloatSensor(kDiagnosticFloatIndex[diagnosticFloatIndex],
-                                    diagnosticFloatValue);
-        sensorStore->getIntegerSensors();
-        sensorStore->getFloatSensors();
-        sensorStore->getSensorsBitmask();
-        static std::vector<std::string> sampleDtcs = {"P0070",
-                                                      "P0102"
-                                                      "P0123"};
-        for (auto&& dtc : sampleDtcs) {
-            auto freezeFrame = createVehiclePropValue(VehiclePropertyType::MIXED, 0);
-            sensorStore->fillPropValue(dtc, freezeFrame.get());
-            freezeFrame->prop = static_cast<int>(VehicleProperty::OBD2_FREEZE_FRAME);
-        }
+            new Obd2SensorStore(diagnosticInt, diagnosticFloat));
+
+    if (!sensorStore.get()) {
+        return;
     }
+
+    auto invokeObd2SensorStoreAPI =
+            mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+                    [&]() {
+                        int32_t diagnosticIntValue =
+                                mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+                        int32_t diagnosticIntIndex =
+                                mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(
+                                        kMinSize,
+                                        toInt(DiagnosticIntegerSensorIndex::LAST_SYSTEM_INDEX) +
+                                                diagnosticInt);
+                        sensorStore->setIntegerSensor(
+                                static_cast<DiagnosticIntegerSensorIndex>(diagnosticIntIndex),
+                                diagnosticIntValue);
+                    },
+                    [&]() {
+                        float diagnosticFloatValue =
+                                mFuzzedDataProvider->ConsumeFloatingPoint<float>();
+                        int32_t diagnosticFloatIndex =
+                                mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(
+                                        kMinSize,
+                                        toInt(DiagnosticFloatSensorIndex::LAST_SYSTEM_INDEX) +
+                                                diagnosticFloat);
+                        sensorStore->setFloatSensor(
+                                static_cast<DiagnosticFloatSensorIndex>(diagnosticFloatIndex),
+                                diagnosticFloatValue);
+                    },
+                    [&]() { sensorStore->getIntegerSensors(); },
+                    [&]() { sensorStore->getFloatSensors(); },
+                    [&]() { sensorStore->getSensorsBitmask(); },
+                    [&]() {
+                        for (auto&& dtc : kSampleDtcs) {
+                            VehiclePropertyType type = static_cast<VehiclePropertyType>(
+                                    mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+                            auto freezeFrame = createVehiclePropValue(
+                                    type, mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(
+                                                  kMinSize, kMaxSize));
+                            if (!freezeFrame.get()) {
+                                return;
+                            }
+                            freezeFrame->prop = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+                            sensorStore->fillPropValue(dtc, freezeFrame.get());
+                        }
+                    },
+            });
+    invokeObd2SensorStoreAPI();
 }
 
 void VehicleHalManagerFuzzer::invokeVmsUtils() {
-    bool availabilityMsgType = mFuzzedDataProvider->ConsumeBool();
-    bool subscriptionMsgType = mFuzzedDataProvider->ConsumeBool();
+    std::unique_ptr<VehiclePropValue> message;
     int32_t intValue = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+    VmsLayer layer(mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                   mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                   mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+    VmsOffers offers = {
+            intValue,
+            {VmsLayerOffering(VmsLayer(mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                                       mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                                       mFuzzedDataProvider->ConsumeIntegral<int32_t>()))}};
+    const VmsLayerAndPublisher layer_and_publisher(
+            VmsLayer(mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                     mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                     mFuzzedDataProvider->ConsumeIntegral<int32_t>()),
+            intValue);
 
-    VmsLayer layer(1, 0, 2);
-    auto message = createSubscribeMessage(layer);
+    switch (mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(kMinSize, kMaxCaseMessage)) {
+        case 0: {
+            message = createSubscribeMessage(layer);
+            break;
+        }
+        case 1: {
+            message = createUnsubscribeMessage(layer);
+            break;
+        }
+        case 2: {
+            message = createSubscriptionsRequest();
+            break;
+        }
+        case 3: {
+            message = createOfferingMessage(offers);
+            break;
+        }
+        case 4: {
+            message = createAvailabilityRequest();
+            break;
+        }
+        case 5: {
+            std::string pub_bytes;
+            if (mFuzzedDataProvider->ConsumeBool()) {
+                pub_bytes = "pub_id";
+            } else {
+                pub_bytes = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxFileSize);
+            }
+            message = createPublisherIdRequest(pub_bytes);
+            break;
+        }
+        case 6: {
+            std::string bytes = "placeholder";
+            if (mFuzzedDataProvider->ConsumeBool()) {
+                bytes = "placeholder";
+            } else {
+                bytes = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxFileSize);
+            }
+            message = createDataMessageWithLayerPublisherInfo(layer_and_publisher, bytes);
+            break;
+        }
+        case 7: {
+            message = createBaseVmsMessage(
+                    mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize));
+            break;
+        }
+        case 8: {
+            message = createStartSessionMessage(intValue, intValue + 1);
+            break;
+        }
+    }
+
     isValidVmsMessage(*message);
-    message = createUnsubscribeMessage(layer);
-
-    VmsOffers offers = {intValue, {VmsLayerOffering(VmsLayer(1, 0, 2))}};
-    message = createOfferingMessage(offers);
-    std::vector<VmsLayer> dependencies = {VmsLayer(2, 0, 2), VmsLayer(3, 0, 3)};
-    std::vector<VmsLayerOffering> offering = {VmsLayerOffering(layer, dependencies)};
-    offers = {intValue, offering};
-    message = createOfferingMessage(offers);
-
-    message = createAvailabilityRequest();
-    message = createSubscriptionsRequest();
-
-    std::string bytes = "placeholder";
-    const VmsLayerAndPublisher layer_and_publisher(VmsLayer(2, 0, 1), intValue);
-    message = createDataMessageWithLayerPublisherInfo(layer_and_publisher, bytes);
-    parseData(*message);
-    createSubscribeToPublisherMessage(layer_and_publisher);
-    createUnsubscribeToPublisherMessage(layer_and_publisher);
-
-    std::string pub_bytes = "pub_id";
-    message = createPublisherIdRequest(pub_bytes);
-    message = createBaseVmsMessage(2);
     message->value.int32Values =
-            hidl_vec<int32_t>{toInt(VmsMessageType::PUBLISHER_ID_RESPONSE), intValue};
-    parsePublisherIdResponse(*message);
+            hidl_vec<int32_t>{mFuzzedDataProvider->ConsumeIntegral<int32_t>(), intValue};
 
-    message->value.int32Values =
-            hidl_vec<int32_t>{toInt(kSubscriptionMessageType[subscriptionMsgType]), intValue};
-    getSequenceNumberForSubscriptionsState(*message);
-
-    message->value.int32Values = hidl_vec<int32_t>{toInt(kSubscriptionMessageType[0]), intValue};
-    isSequenceNumberNewer(*message, intValue + 1);
-    invokeGetSubscribedLayers(kSubscriptionMessageType[subscriptionMsgType]);
-
-    message->value.int32Values =
-            hidl_vec<int32_t>{toInt(kAvailabilityMessageType[availabilityMsgType]), 0};
-    hasServiceNewlyStarted(*message);
-    message = createStartSessionMessage(intValue, intValue + 1);
-    parseMessageType(*message);
-
-    message->value.int32Values =
-            hidl_vec<int32_t>{toInt(kAvailabilityMessageType[availabilityMsgType]), intValue};
-    isAvailabilitySequenceNumberNewer(*message, intValue + 1);
-
-    message->value.int32Values =
-            hidl_vec<int32_t>{toInt(kAvailabilityMessageType[availabilityMsgType]), intValue};
-    getSequenceNumberForAvailabilityState(*message);
-    message = createBaseVmsMessage(3);
-    int new_service_id;
-    message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::START_SESSION), 0, -1};
-    parseStartSessionMessage(*message, -1, 0, &new_service_id);
+    auto invokeVmsUtilsAPI = mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+            [&]() { parseData(*message); },
+            [&]() { createSubscribeToPublisherMessage(layer_and_publisher); },
+            [&]() { createUnsubscribeToPublisherMessage(layer_and_publisher); },
+            [&]() { parsePublisherIdResponse(*message); },
+            [&]() { getSequenceNumberForSubscriptionsState(*message); },
+            [&]() { isSequenceNumberNewer(*message, intValue + 1); },
+            [&]() {
+                invokeGetSubscribedLayers(
+                        (VmsMessageType)mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+            },
+            [&]() { hasServiceNewlyStarted(*message); },
+            [&]() { parseMessageType(*message); },
+            [&]() { isAvailabilitySequenceNumberNewer(*message, intValue + 1); },
+            [&]() { getSequenceNumberForAvailabilityState(*message); },
+            [&]() {
+                int32_t new_service_id;
+                parseStartSessionMessage(*message, -1, 0, &new_service_id);
+            },
+    });
+    invokeVmsUtilsAPI();
 }
 
 void VehicleHalManagerFuzzer::invokeGet(int32_t property, int32_t areaId) {
@@ -367,27 +468,31 @@
     mActualStatusCode = refStatus;
 }
 
-void VehicleHalManagerFuzzer::invokeGetSubscribedLayers(VmsMessageType type) {
-    VmsOffers offers = {123,
-                        {VmsLayerOffering(VmsLayer(1, 0, 1), {VmsLayer(4, 1, 1)}),
-                         VmsLayerOffering(VmsLayer(2, 0, 1))}};
-    auto message = createBaseVmsMessage(16);
-    message->value.int32Values = hidl_vec<int32_t>{toInt(type),
-                                                   1234,  // sequence number
-                                                   2,     // number of layers
-                                                   1,     // number of associated layers
-                                                   1,     // layer 1
-                                                   0,           1,
-                                                   4,  // layer 2
-                                                   1,           1,
-                                                   2,  // associated layer
-                                                   0,           1,
-                                                   2,    // number of publisher IDs
-                                                   111,  // publisher IDs
-                                                   123};
-    isValidVmsMessage(*message);
-    getSubscribedLayers(*message, offers);
-    getAvailableLayers(*message);
+void VehicleHalManagerFuzzer::invokeGetSubscribedLayers(VmsMessageType /*type*/) {
+    int32_t intValue = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+    VmsOffers offers = {
+            intValue,
+            {VmsLayerOffering(VmsLayer(mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                                       mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                                       mFuzzedDataProvider->ConsumeIntegral<int32_t>()))}};
+    auto message = createBaseVmsMessage(
+            mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxFileSize));
+    std::vector<int32_t> v;
+    size_t size = mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize);
+    for (size_t i = 0; i < size; i++) {
+        v.push_back(mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(kMinSize, kMaxSize));
+    }
+
+    message->value.int32Values = hidl_vec<int32_t>(v);
+    if (!isValidVmsMessage(*message)) {
+        return;
+    }
+
+    if (mFuzzedDataProvider->ConsumeBool()) {
+        getSubscribedLayers(*message, offers);
+    } else {
+        getAvailableLayers(*message);
+    }
 }
 
 void VehicleHalManagerFuzzer::invokeVehiclePropStore() {
@@ -398,33 +503,49 @@
             .prop = vehicleProp,
             .access = VehiclePropertyAccess::READ,
             .changeMode = VehiclePropertyChangeMode::STATIC,
-            .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+            .areaConfigs = {VehicleAreaConfig{
+                    .areaId = (mFuzzedDataProvider->ConsumeIntegral<int32_t>())}},
     };
-    store->registerProperty(config);
     VehiclePropValue propValue{};
     propValue.prop = vehicleProp;
-    propValue.areaId = 0;
-    store->writeValue(propValue, shouldWriteStatus);
-    store->readAllValues();
-    store->getAllConfigs();
-    store->getConfigOrNull(vehicleProp);
-    store->readValuesForProperty(vehicleProp);
-    store->readValueOrNull(propValue);
-    store->readValueOrNull(propValue.prop, propValue.areaId, 0);
-    store->removeValuesForProperty(vehicleProp);
-    store->removeValue(propValue);
-    store->getConfigOrDie(vehicleProp);
+    propValue.areaId = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+
+    auto invokeVehiclePropStoreAPI =
+            mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+                    [&]() { store->registerProperty(config); },
+                    [&]() { store->writeValue(propValue, shouldWriteStatus); },
+                    [&]() { store->readAllValues(); },
+                    [&]() { store->getAllConfigs(); },
+                    [&]() { store->getConfigOrNull(vehicleProp); },
+                    [&]() { store->readValuesForProperty(vehicleProp); },
+                    [&]() { store->readValueOrNull(propValue); },
+                    [&]() {
+                        store->readValueOrNull(propValue.prop, propValue.areaId,
+                                               mFuzzedDataProvider->ConsumeIntegralInRange<int64_t>(
+                                                       kMinSize, kMaxFileSize));
+                    },
+                    [&]() { store->removeValuesForProperty(vehicleProp); },
+                    [&]() { store->removeValue(propValue); },
+                    [&]() {
+                        if (store->getConfigOrNull(vehicleProp)) {
+                            store->getConfigOrDie(vehicleProp);
+                        }
+                    },
+            });
+    invokeVehiclePropStoreAPI();
 }
 
 void VehicleHalManagerFuzzer::invokeWatchDogClient() {
-    auto service = new VehicleHalManager(mHal.get());
     sp<Looper> looper(Looper::prepare(/*opts=*/mFuzzedDataProvider->ConsumeBool()));
-    if (auto watchdogClient = ndk::SharedRefBase::make<WatchdogClient>(looper, service);
+    if (auto watchdogClient = ndk::SharedRefBase::make<WatchdogClient>(looper, mManager.get());
         watchdogClient->initialize()) {
-        watchdogClient->checkIfAlive(-1, TimeoutLength::TIMEOUT_NORMAL);
+        if (mFuzzedDataProvider->ConsumeBool()) {
+            watchdogClient->checkIfAlive(
+                    mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                    (TimeoutLength)mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+        }
         watchdogClient->prepareProcessTermination();
     }
-    delete service;
 }
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
diff --git a/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.h b/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.h
index e9335d3..26ac11e 100644
--- a/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.h
+++ b/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.h
@@ -98,6 +98,13 @@
     }
     void process(const uint8_t* data, size_t size);
 
+    template <typename T>
+    void fillParameter(size_t size, std::vector<T>& data) {
+        for (size_t i = 0; i < size; ++i) {
+            data.push_back(mFuzzedDataProvider->ConsumeIntegral<T>());
+        }
+    }
+
   private:
     FuzzedDataProvider* mFuzzedDataProvider = nullptr;
     VehiclePropValue mActualValue = VehiclePropValue{};
@@ -108,6 +115,7 @@
     std::unique_ptr<VehicleHalManager> mManager;
 
     void invokeDebug();
+    void initValue();
     void invokePropConfigs();
     void invokeSubscribe();
     void invokeSetAndGetValues();
diff --git a/automotive/vehicle/OWNERS b/automotive/vehicle/OWNERS
index d6969e5..9a6b65d 100644
--- a/automotive/vehicle/OWNERS
+++ b/automotive/vehicle/OWNERS
@@ -1,2 +1,9 @@
 ericjeong@google.com
 shanyu@google.com
+
+# GRPC VHAL
+per-file aidl/impl/grpc/** = chenhaosjtuacm@google.com, egranata@google.com
+
+# Property definition
+per-file aidl_property/** = tylertrephan@google.com
+per-file aidl/generated_lib/** = tylertrephan@google.com
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 e312a3a..6d856a8 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
@@ -1,34 +1,22 @@
 [
   {
-    "name": "VehicleApPowerStateReqIndex",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleOilLevel",
     "values": [
       {
-        "name": "STATE",
+        "name": "CRITICALLY_LOW",
         "value": 0
       },
       {
-        "name": "ADDITIONAL",
-        "value": 1
-      }
-    ]
-  },
-  {
-    "name": "EvChargeState",
-    "values": [
-      {
-        "name": "UNKNOWN",
-        "value": 0
-      },
-      {
-        "name": "CHARGING",
+        "name": "LOW",
         "value": 1
       },
       {
-        "name": "FULLY_CHARGED",
+        "name": "NORMAL",
         "value": 2
       },
       {
-        "name": "NOT_CHARGING",
+        "name": "HIGH",
         "value": 3
       },
       {
@@ -38,220 +26,123 @@
     ]
   },
   {
-    "name": "TrailerState",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "LocationCharacterization",
     "values": [
       {
-        "name": "UNKNOWN",
-        "value": 0
-      },
-      {
-        "name": "NOT_PRESENT",
+        "name": "PRIOR_LOCATIONS",
         "value": 1
       },
       {
-        "name": "PRESENT",
+        "name": "GYROSCOPE_FUSION",
         "value": 2
       },
       {
-        "name": "ERROR",
-        "value": 3
-      }
-    ]
-  },
-  {
-    "name": "ProcessTerminationReason",
-    "values": [
-      {
-        "name": "NOT_RESPONDING",
-        "value": 1
-      },
-      {
-        "name": "IO_OVERUSE",
-        "value": 2
-      },
-      {
-        "name": "MEMORY_OVERUSE",
-        "value": 3
-      }
-    ]
-  },
-  {
-    "name": "VehicleApPowerStateConfigFlag",
-    "values": [
-      {
-        "name": "ENABLE_DEEP_SLEEP_FLAG",
-        "value": 1
-      },
-      {
-        "name": "CONFIG_SUPPORT_TIMER_POWER_ON_FLAG",
-        "value": 2
-      },
-      {
-        "name": "ENABLE_HIBERNATION_FLAG",
-        "value": 3
-      }
-    ]
-  },
-  {
-    "name": "Obd2FuelType",
-    "values": [
-      {
-        "name": "NOT_AVAILABLE",
-        "value": 0
-      },
-      {
-        "name": "GASOLINE",
-        "value": 1
-      },
-      {
-        "name": "METHANOL",
-        "value": 2
-      },
-      {
-        "name": "ETHANOL",
-        "value": 3
-      },
-      {
-        "name": "DIESEL",
+        "name": "ACCELEROMETER_FUSION",
         "value": 4
       },
       {
-        "name": "LPG",
-        "value": 5
-      },
-      {
-        "name": "CNG",
-        "value": 6
-      },
-      {
-        "name": "PROPANE",
-        "value": 7
-      },
-      {
-        "name": "ELECTRIC",
+        "name": "COMPASS_FUSION",
         "value": 8
       },
       {
-        "name": "BIFUEL_RUNNING_GASOLINE",
-        "value": 9
-      },
-      {
-        "name": "BIFUEL_RUNNING_METHANOL",
-        "value": 10
-      },
-      {
-        "name": "BIFUEL_RUNNING_ETHANOL",
-        "value": 11
-      },
-      {
-        "name": "BIFUEL_RUNNING_LPG",
-        "value": 12
-      },
-      {
-        "name": "BIFUEL_RUNNING_CNG",
-        "value": 13
-      },
-      {
-        "name": "BIFUEL_RUNNING_PROPANE",
-        "value": 14
-      },
-      {
-        "name": "BIFUEL_RUNNING_ELECTRIC",
-        "value": 15
-      },
-      {
-        "name": "BIFUEL_RUNNING_ELECTRIC_AND_COMBUSTION",
+        "name": "WHEEL_SPEED_FUSION",
         "value": 16
       },
       {
-        "name": "HYBRID_GASOLINE",
-        "value": 17
+        "name": "STEERING_ANGLE_FUSION",
+        "value": 32
       },
       {
-        "name": "HYBRID_ETHANOL",
-        "value": 18
+        "name": "CAR_SPEED_FUSION",
+        "value": 64
       },
       {
-        "name": "HYBRID_DIESEL",
-        "value": 19
+        "name": "DEAD_RECKONED",
+        "value": 128
       },
       {
-        "name": "HYBRID_ELECTRIC",
-        "value": 20
-      },
-      {
-        "name": "HYBRID_RUNNING_ELECTRIC_AND_COMBUSTION",
-        "value": 21
-      },
-      {
-        "name": "HYBRID_REGENERATIVE",
-        "value": 22
-      },
-      {
-        "name": "BIFUEL_RUNNING_DIESEL",
-        "value": 23
+        "name": "RAW_GNSS_ONLY",
+        "value": 256
       }
     ]
   },
   {
-    "name": "VmsSubscriptionsStateIntegerValuesIndex",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleDisplay",
     "values": [
       {
-        "name": "MESSAGE_TYPE",
+        "name": "MAIN",
         "value": 0
       },
       {
-        "name": "SEQUENCE_NUMBER",
+        "name": "INSTRUMENT_CLUSTER",
         "value": 1
       },
       {
-        "name": "NUMBER_OF_LAYERS",
+        "name": "HUD",
         "value": 2
       },
       {
-        "name": "NUMBER_OF_ASSOCIATED_LAYERS",
+        "name": "INPUT",
         "value": 3
       },
       {
-        "name": "SUBSCRIPTIONS_START",
+        "name": "AUXILIARY",
         "value": 4
       }
     ]
   },
   {
-    "name": "VehicleArea",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "CruiseControlState",
     "values": [
       {
-        "name": "GLOBAL",
-        "value": 16777216
+        "name": "OTHER",
+        "value": 0
       },
       {
-        "name": "WINDOW",
-        "value": 50331648
+        "name": "ENABLED",
+        "value": 1
       },
       {
-        "name": "MIRROR",
-        "value": 67108864
+        "name": "ACTIVATED",
+        "value": 2
       },
       {
-        "name": "SEAT",
-        "value": 83886080
+        "name": "USER_OVERRIDE",
+        "value": 3
       },
       {
-        "name": "DOOR",
-        "value": 100663296
+        "name": "SUSPENDED",
+        "value": 4
       },
       {
-        "name": "WHEEL",
-        "value": 117440512
-      },
-      {
-        "name": "MASK",
-        "value": 251658240
+        "name": "FORCED_DEACTIVATION_WARNING",
+        "value": 5
       }
     ]
   },
   {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "HandsOnDetectionWarning",
+    "values": [
+      {
+        "name": "OTHER",
+        "value": 0
+      },
+      {
+        "name": "NO_WARNING",
+        "value": 1
+      },
+      {
+        "name": "WARNING",
+        "value": 2
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
     "name": "VehicleAreaWindow",
     "values": [
       {
@@ -297,27 +188,99 @@
     ]
   },
   {
-    "name": "ElectronicTollCollectionCardStatus",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VmsAvailabilityStateIntegerValuesIndex",
     "values": [
       {
-        "name": "UNKNOWN",
+        "name": "MESSAGE_TYPE",
         "value": 0
       },
       {
-        "name": "ELECTRONIC_TOLL_COLLECTION_CARD_VALID",
+        "name": "SEQUENCE_NUMBER",
         "value": 1
       },
       {
-        "name": "ELECTRONIC_TOLL_COLLECTION_CARD_INVALID",
+        "name": "NUMBER_OF_ASSOCIATED_LAYERS",
         "value": 2
       },
       {
-        "name": "ELECTRONIC_TOLL_COLLECTION_CARD_NOT_INSERTED",
+        "name": "LAYERS_START",
         "value": 3
       }
     ]
   },
   {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleLightSwitch",
+    "values": [
+      {
+        "name": "OFF",
+        "value": 0
+      },
+      {
+        "name": "ON",
+        "value": 1
+      },
+      {
+        "name": "DAYTIME_RUNNING",
+        "value": 2
+      },
+      {
+        "name": "AUTOMATIC",
+        "value": 256
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "Obd2IgnitionMonitorKind",
+    "values": [
+      {
+        "name": "SPARK",
+        "value": 0
+      },
+      {
+        "name": "COMPRESSION",
+        "value": 1
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleHwMotionButtonStateFlag",
+    "values": [
+      {
+        "name": "BUTTON_PRIMARY",
+        "value": 1
+      },
+      {
+        "name": "BUTTON_SECONDARY",
+        "value": 2
+      },
+      {
+        "name": "BUTTON_TERTIARY",
+        "value": 4
+      },
+      {
+        "name": "BUTTON_BACK",
+        "value": 8
+      },
+      {
+        "name": "BUTTON_FORWARD",
+        "value": 16
+      },
+      {
+        "name": "BUTTON_STYLUS_PRIMARY",
+        "value": 32
+      },
+      {
+        "name": "BUTTON_STYLUS_SECONDARY",
+        "value": 64
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
     "name": "VehiclePropertyType",
     "values": [
       {
@@ -367,1694 +330,7 @@
     ]
   },
   {
-    "name": "StatusCode",
-    "values": [
-      {
-        "name": "OK",
-        "value": 0
-      },
-      {
-        "name": "TRY_AGAIN",
-        "value": 1
-      },
-      {
-        "name": "INVALID_ARG",
-        "value": 2
-      },
-      {
-        "name": "NOT_AVAILABLE",
-        "value": 3
-      },
-      {
-        "name": "ACCESS_DENIED",
-        "value": 4
-      },
-      {
-        "name": "INTERNAL_ERROR",
-        "value": 5
-      }
-    ]
-  },
-  {
-    "name": "CreateUserStatus",
-    "values": [
-      {
-        "name": "SUCCESS",
-        "value": 1
-      },
-      {
-        "name": "FAILURE",
-        "value": 2
-      }
-    ]
-  },
-  {
-    "name": "ElectronicTollCollectionCardType",
-    "values": [
-      {
-        "name": "UNKNOWN",
-        "value": 0
-      },
-      {
-        "name": "JP_ELECTRONIC_TOLL_COLLECTION_CARD",
-        "value": 1
-      },
-      {
-        "name": "JP_ELECTRONIC_TOLL_COLLECTION_CARD_V2",
-        "value": 2
-      }
-    ]
-  },
-  {
-    "name": "VehicleAreaMirror",
-    "values": [
-      {
-        "name": "DRIVER_LEFT",
-        "value": 1
-      },
-      {
-        "name": "DRIVER_RIGHT",
-        "value": 2
-      },
-      {
-        "name": "DRIVER_CENTER",
-        "value": 4
-      }
-    ]
-  },
-  {
-    "name": "InitialUserInfoResponseAction",
-    "values": [
-      {
-        "name": "DEFAULT",
-        "value": 0
-      },
-      {
-        "name": "SWITCH",
-        "value": 1
-      },
-      {
-        "name": "CREATE",
-        "value": 2
-      }
-    ]
-  },
-  {
-    "name": "VehicleHvacFanDirection",
-    "values": [
-      {
-        "name": "UNKNOWN",
-        "value": 0
-      },
-      {
-        "name": "FACE",
-        "value": 1
-      },
-      {
-        "name": "FLOOR",
-        "value": 2
-      },
-      {
-        "name": "FACE_AND_FLOOR",
-        "value": 3
-      },
-      {
-        "name": "DEFROST",
-        "value": 4
-      },
-      {
-        "name": "DEFROST_AND_FLOOR",
-        "value": 6
-      }
-    ]
-  },
-  {
-    "name": "Obd2SecondaryAirStatus",
-    "values": [
-      {
-        "name": "UPSTREAM",
-        "value": 1
-      },
-      {
-        "name": "DOWNSTREAM_OF_CATALYCIC_CONVERTER",
-        "value": 2
-      },
-      {
-        "name": "FROM_OUTSIDE_OR_OFF",
-        "value": 4
-      },
-      {
-        "name": "PUMP_ON_FOR_DIAGNOSTICS",
-        "value": 8
-      }
-    ]
-  },
-  {
-    "name": "VmsStartSessionMessageIntegerValuesIndex",
-    "values": [
-      {
-        "name": "MESSAGE_TYPE",
-        "value": 0
-      },
-      {
-        "name": "SERVICE_ID",
-        "value": 1
-      },
-      {
-        "name": "CLIENT_ID",
-        "value": 2
-      }
-    ]
-  },
-  {
-    "name": "VehicleOilLevel",
-    "values": [
-      {
-        "name": "CRITICALLY_LOW",
-        "value": 0
-      },
-      {
-        "name": "LOW",
-        "value": 1
-      },
-      {
-        "name": "NORMAL",
-        "value": 2
-      },
-      {
-        "name": "HIGH",
-        "value": 3
-      },
-      {
-        "name": "ERROR",
-        "value": 4
-      }
-    ]
-  },
-  {
-    "name": "VehicleUnit",
-    "values": [
-      {
-        "name": "SHOULD_NOT_USE",
-        "value": 0
-      },
-      {
-        "name": "METER_PER_SEC",
-        "value": 1
-      },
-      {
-        "name": "RPM",
-        "value": 2
-      },
-      {
-        "name": "HERTZ",
-        "value": 3
-      },
-      {
-        "name": "PERCENTILE",
-        "value": 16
-      },
-      {
-        "name": "MILLIMETER",
-        "value": 32
-      },
-      {
-        "name": "METER",
-        "value": 33
-      },
-      {
-        "name": "KILOMETER",
-        "value": 35
-      },
-      {
-        "name": "MILE",
-        "value": 36
-      },
-      {
-        "name": "CELSIUS",
-        "value": 48
-      },
-      {
-        "name": "FAHRENHEIT",
-        "value": 49
-      },
-      {
-        "name": "KELVIN",
-        "value": 50
-      },
-      {
-        "name": "MILLILITER",
-        "value": 64
-      },
-      {
-        "name": "LITER",
-        "value": 65
-      },
-      {
-        "name": "GALLON",
-        "value": 66
-      },
-      {
-        "name": "US_GALLON",
-        "value": 66
-      },
-      {
-        "name": "IMPERIAL_GALLON",
-        "value": 67
-      },
-      {
-        "name": "NANO_SECS",
-        "value": 80
-      },
-      {
-        "name": "SECS",
-        "value": 83
-      },
-      {
-        "name": "YEAR",
-        "value": 89
-      },
-      {
-        "name": "WATT_HOUR",
-        "value": 96
-      },
-      {
-        "name": "MILLIAMPERE",
-        "value": 97
-      },
-      {
-        "name": "MILLIVOLT",
-        "value": 98
-      },
-      {
-        "name": "MILLIWATTS",
-        "value": 99
-      },
-      {
-        "name": "AMPERE_HOURS",
-        "value": 100
-      },
-      {
-        "name": "KILOWATT_HOUR",
-        "value": 101
-      },
-      {
-        "name": "AMPERE",
-        "value": 102
-      },
-      {
-        "name": "KILOPASCAL",
-        "value": 112
-      },
-      {
-        "name": "PSI",
-        "value": 113
-      },
-      {
-        "name": "BAR",
-        "value": 114
-      },
-      {
-        "name": "DEGREES",
-        "value": 128
-      },
-      {
-        "name": "MILES_PER_HOUR",
-        "value": 144
-      },
-      {
-        "name": "KILOMETERS_PER_HOUR",
-        "value": 145
-      }
-    ]
-  },
-  {
-    "name": "VehicleAreaWheel",
-    "values": [
-      {
-        "name": "UNKNOWN",
-        "value": 0
-      },
-      {
-        "name": "LEFT_FRONT",
-        "value": 1
-      },
-      {
-        "name": "RIGHT_FRONT",
-        "value": 2
-      },
-      {
-        "name": "LEFT_REAR",
-        "value": 4
-      },
-      {
-        "name": "RIGHT_REAR",
-        "value": 8
-      }
-    ]
-  },
-  {
-    "name": "EvsServiceState",
-    "values": [
-      {
-        "name": "OFF",
-        "value": 0
-      },
-      {
-        "name": "ON",
-        "value": 1
-      }
-    ]
-  },
-  {
-    "name": "EvsServiceRequestIndex",
-    "values": [
-      {
-        "name": "TYPE",
-        "value": 0
-      },
-      {
-        "name": "STATE",
-        "value": 1
-      }
-    ]
-  },
-  {
-    "name": "VehicleSeatOccupancyState",
-    "values": [
-      {
-        "name": "UNKNOWN",
-        "value": 0
-      },
-      {
-        "name": "VACANT",
-        "value": 1
-      },
-      {
-        "name": "OCCUPIED",
-        "value": 2
-      }
-    ]
-  },
-  {
-    "name": "VehicleProperty",
-    "values": [
-      {
-        "name": "Undefined property.",
-        "value": 0
-      },
-      {
-        "name": "VIN of vehicle",
-        "value": 286261504,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Manufacturer of vehicle",
-        "value": 286261505,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Model of vehicle",
-        "value": 286261506,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Model year of vehicle.",
-        "value": 289407235,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:YEAR"
-      },
-      {
-        "name": "Fuel capacity of the vehicle in milliliters",
-        "value": 291504388,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:MILLILITER"
-      },
-      {
-        "name": "List of fuels the vehicle may use",
-        "value": 289472773,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "FuelType"
-      },
-      {
-        "name": "INFO_EV_BATTERY_CAPACITY",
-        "value": 291504390,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:WH"
-      },
-      {
-        "name": "List of connectors this EV may use",
-        "value": 289472775,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "data_enum": "EvConnectorType",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Fuel door location",
-        "value": 289407240,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "data_enum": "PortLocationType",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "EV port location",
-        "value": 289407241,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "PortLocationType"
-      },
-      {
-        "name": "INFO_DRIVER_SEAT",
-        "value": 356516106,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "data_enum": "VehicleAreaSeat",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Exterior dimensions of vehicle.",
-        "value": 289472779,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:MILLIMETER"
-      },
-      {
-        "name": "Multiple EV port locations",
-        "value": 289472780,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "PortLocationType"
-      },
-      {
-        "name": "Current odometer value of the vehicle",
-        "value": 291504644,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:KILOMETER"
-      },
-      {
-        "name": "Speed of the vehicle",
-        "value": 291504647,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:METER_PER_SEC"
-      },
-      {
-        "name": "Speed of the vehicle for displays",
-        "value": 291504648,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:METER_PER_SEC"
-      },
-      {
-        "name": "Front bicycle model steering angle for vehicle",
-        "value": 291504649,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:DEGREES"
-      },
-      {
-        "name": "Rear bicycle model steering angle for vehicle",
-        "value": 291504656,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:DEGREES"
-      },
-      {
-        "name": "Temperature of engine coolant",
-        "value": 291504897,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:CELSIUS"
-      },
-      {
-        "name": "Engine oil level",
-        "value": 289407747,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleOilLevel"
-      },
-      {
-        "name": "Temperature of engine oil",
-        "value": 291504900,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:CELSIUS"
-      },
-      {
-        "name": "Engine rpm",
-        "value": 291504901,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:RPM"
-      },
-      {
-        "name": "Reports wheel ticks",
-        "value": 290521862,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "FUEL_LEVEL",
-        "value": 291504903,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:MILLILITER"
-      },
-      {
-        "name": "Fuel door open",
-        "value": 287310600,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "EV_BATTERY_LEVEL",
-        "value": 291504905,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:WH"
-      },
-      {
-        "name": "EV charge port open",
-        "value": 287310602,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "EV charge port connected",
-        "value": 287310603,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "EV instantaneous charge rate in milliwatts",
-        "value": 291504908,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:MW"
-      },
-      {
-        "name": "Range remaining",
-        "value": 291504904,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "unit": "VehicleUnit:METER"
-      },
-      {
-        "name": "Tire pressure",
-        "value": 392168201,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:KILOPASCAL"
-      },
-      {
-        "name": "Critically low tire pressure",
-        "value": 392168202,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:KILOPASCAL"
-      },
-      {
-        "name": "Currently selected gear",
-        "value": 289408000,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleGear"
-      },
-      {
-        "name": "CURRENT_GEAR",
-        "value": 289408001,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleGear"
-      },
-      {
-        "name": "Parking brake state.",
-        "value": 287310850,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "PARKING_BRAKE_AUTO_APPLY",
-        "value": 287310851,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Warning for fuel low level.",
-        "value": 287310853,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Night mode",
-        "value": 287310855,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "State of the vehicles turn signals",
-        "value": 289408008,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleTurnSignal"
-      },
-      {
-        "name": "Represents ignition state",
-        "value": 289408009,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleIgnitionState"
-      },
-      {
-        "name": "ABS is active",
-        "value": 287310858,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Traction Control is active",
-        "value": 287310859,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "HVAC_FAN_SPEED",
-        "value": 356517120
-      },
-      {
-        "name": "Fan direction setting",
-        "value": 356517121,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleHvacFanDirection"
-      },
-      {
-        "name": "HVAC current temperature.",
-        "value": 358614274,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:CELSIUS"
-      },
-      {
-        "name": "HVAC_TEMPERATURE_SET",
-        "value": 358614275,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "unit": "VehicleUnit:CELSIUS"
-      },
-      {
-        "name": "HVAC_DEFROSTER",
-        "value": 320865540,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "HVAC_AC_ON",
-        "value": 354419973,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "config_flags": "Supported"
-      },
-      {
-        "name": "HVAC_MAX_AC_ON",
-        "value": 354419974,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "HVAC_MAX_DEFROST_ON",
-        "value": 354419975,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "HVAC_RECIRC_ON",
-        "value": 354419976,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Enable temperature coupling between areas.",
-        "value": 354419977,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "HVAC_AUTO_ON",
-        "value": 354419978,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "HVAC_SEAT_TEMPERATURE",
-        "value": 356517131,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Side Mirror Heat",
-        "value": 339739916,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "HVAC_STEERING_WHEEL_HEAT",
-        "value": 289408269,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Temperature units for display",
-        "value": 289408270,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleUnit"
-      },
-      {
-        "name": "Actual fan speed",
-        "value": 356517135,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "HVAC_POWER_ON",
-        "value": 354419984,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Fan Positions Available",
-        "value": 356582673,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleHvacFanDirection"
-      },
-      {
-        "name": "HVAC_AUTO_RECIRC_ON",
-        "value": 354419986,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat ventilation",
-        "value": 356517139,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "HVAC_ELECTRIC_DEFROSTER_ON",
-        "value": 320865556,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Suggested values for setting HVAC temperature.",
-        "value": 291570965,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Distance units for display",
-        "value": 289408512,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleUnit"
-      },
-      {
-        "name": "Fuel volume units for display",
-        "value": 289408513,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleUnit"
-      },
-      {
-        "name": "Tire pressure units for display",
-        "value": 289408514,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleUnit"
-      },
-      {
-        "name": "EV battery units for display",
-        "value": 289408515,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleUnit"
-      },
-      {
-        "name": "Fuel consumption units for display",
-        "value": 287311364,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Speed units for display",
-        "value": 289408517,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "ANDROID_EPOCH_TIME",
-        "value": 290457094,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:WRITE_ONLY",
-        "unit": "VehicleUnit:MILLI_SECS"
-      },
-      {
-        "name": "External encryption binding seed.",
-        "value": 292554247,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Outside temperature",
-        "value": 291505923,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:CELSIUS"
-      },
-      {
-        "name": "Property to control power state of application processor",
-        "value": 289475072,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Property to report power state of application processor",
-        "value": 289475073,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "AP_POWER_BOOTUP_REASON",
-        "value": 289409538,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "DISPLAY_BRIGHTNESS",
-        "value": 289409539,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "HW_KEY_INPUT",
-        "value": 289475088,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "config_flags": ""
-      },
-      {
-        "name": "HW_ROTARY_INPUT",
-        "value": 289475104,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "data_enum": "RotaryInputType",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Defines a custom OEM partner input event.",
-        "value": 289475120,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "data_enum": "CustomInputType",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "DOOR_POS",
-        "value": 373295872,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Door move",
-        "value": 373295873,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Door lock",
-        "value": 371198722,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Mirror Z Position",
-        "value": 339741504,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Mirror Z Move",
-        "value": 339741505,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Mirror Y Position",
-        "value": 339741506,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Mirror Y Move",
-        "value": 339741507,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Mirror Lock",
-        "value": 287312708,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Mirror Fold",
-        "value": 287312709,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat memory select",
-        "value": 356518784,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:WRITE"
-      },
-      {
-        "name": "Seat memory set",
-        "value": 356518785,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:WRITE"
-      },
-      {
-        "name": "Seatbelt buckled",
-        "value": 354421634,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seatbelt height position",
-        "value": 356518787,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seatbelt height move",
-        "value": 356518788,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "SEAT_FORE_AFT_POS",
-        "value": 356518789,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "SEAT_FORE_AFT_MOVE",
-        "value": 356518790,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat backrest angle 1 position",
-        "value": 356518791,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat backrest angle 1 move",
-        "value": 356518792,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat backrest angle 2 position",
-        "value": 356518793,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat backrest angle 2 move",
-        "value": 356518794,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat height position",
-        "value": 356518795,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat height move",
-        "value": 356518796,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat depth position",
-        "value": 356518797,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat depth move",
-        "value": 356518798,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat tilt position",
-        "value": 356518799,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat tilt move",
-        "value": 356518800,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "SEAT_LUMBAR_FORE_AFT_POS",
-        "value": 356518801,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "SEAT_LUMBAR_FORE_AFT_MOVE",
-        "value": 356518802,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Lumbar side support position",
-        "value": 356518803,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Lumbar side support move",
-        "value": 356518804,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Headrest height position",
-        "value": 289409941,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Headrest height move",
-        "value": 356518806,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Headrest angle position",
-        "value": 356518807,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Headrest angle move",
-        "value": 356518808,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "SEAT_HEADREST_FORE_AFT_POS",
-        "value": 356518809,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "SEAT_HEADREST_FORE_AFT_MOVE",
-        "value": 356518810,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat Occupancy",
-        "value": 356518832,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleSeatOccupancyState"
-      },
-      {
-        "name": "Window Position",
-        "value": 322964416,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Window Move",
-        "value": 322964417,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Window Lock",
-        "value": 320867268,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "VEHICLE_MAP_SERVICE",
-        "value": 299895808,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "OBD2 Live Sensor Data",
-        "value": 299896064,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "OBD2 Freeze Frame Sensor Data",
-        "value": 299896065,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "OBD2 Freeze Frame Information",
-        "value": 299896066,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "OBD2 Freeze Frame Clear",
-        "value": 299896067,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:WRITE"
-      },
-      {
-        "name": "Headlights State",
-        "value": 289410560,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleLightState"
-      },
-      {
-        "name": "High beam lights state",
-        "value": 289410561,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleLightState"
-      },
-      {
-        "name": "Fog light state",
-        "value": 289410562,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleLightState"
-      },
-      {
-        "name": "Hazard light status",
-        "value": 289410563,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleLightState"
-      },
-      {
-        "name": "Headlight switch",
-        "value": 289410576,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleLightSwitch"
-      },
-      {
-        "name": "High beam light switch",
-        "value": 289410577,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleLightSwitch"
-      },
-      {
-        "name": "Fog light switch",
-        "value": 289410578,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleLightSwitch"
-      },
-      {
-        "name": "Hazard light switch",
-        "value": 289410579,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleLightSwitch"
-      },
-      {
-        "name": "Cabin lights",
-        "value": 289410817,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleLightState"
-      },
-      {
-        "name": "Cabin lights switch",
-        "value": 289410818,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleLightSwitch"
-      },
-      {
-        "name": "Reading lights",
-        "value": 356519683,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleLightState"
-      },
-      {
-        "name": "Reading lights switch",
-        "value": 356519684,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleLightSwitch"
-      },
-      {
-        "name": "Support customize permissions for vendor properties",
-        "value": 287313669,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Allow disabling optional featurs from vhal.",
-        "value": 286265094,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Defines the initial Android user to be used during initialization.",
-        "value": 299896583,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Defines a request to switch the foreground Android user.",
-        "value": 299896584,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Called by the Android System after an Android user was created.",
-        "value": 299896585,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Called by the Android System after an Android user was removed.",
-        "value": 299896586,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:WRITE"
-      },
-      {
-        "name": "USER_IDENTIFICATION_ASSOCIATION",
-        "value": 299896587,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "EVS_SERVICE_REQUEST",
-        "value": 289476368,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Defines a request to apply power policy.",
-        "value": 286265121,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "POWER_POLICY_GROUP_REQ",
-        "value": 286265122,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Notifies the current power policy to VHAL layer.",
-        "value": 286265123,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "WATCHDOG_ALIVE",
-        "value": 290459441,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:WRITE"
-      },
-      {
-        "name": "Defines a process terminated by car watchdog and the reason of termination.",
-        "value": 299896626,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:WRITE"
-      },
-      {
-        "name": "Defines an event that VHAL signals to car watchdog as a heartbeat.",
-        "value": 290459443,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Starts the ClusterUI in cluster display.",
-        "value": 289410868,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Changes the state of the cluster display.",
-        "value": 289476405,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Reports the current display state and ClusterUI state.",
-        "value": 299896630,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:WRITE"
-      },
-      {
-        "name": "Requests to change the cluster display state to show some ClusterUI.",
-        "value": 289410871,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:WRITE"
-      },
-      {
-        "name": "Informs the current navigation state.",
-        "value": 292556600,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:WRITE"
-      },
-      {
-        "name": "Electronic Toll Collection card type.",
-        "value": 289410873,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "ElectronicTollCollectionCardType"
-      },
-      {
-        "name": "Electronic Toll Collection card status.",
-        "value": 289410874,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "ElectronicTollCollectionCardStatus"
-      },
-      {
-        "name": "Front fog lights state",
-        "value": 289410875,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleLightState"
-      },
-      {
-        "name": "Front fog lights switch",
-        "value": 289410876,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleLightSwitch"
-      },
-      {
-        "name": "Rear fog lights state",
-        "value": 289410877,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleLightState"
-      },
-      {
-        "name": "Rear fog lights switch",
-        "value": 289410878,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleLightSwitch"
-      },
-      {
-        "name": "Indicates the maximum current draw threshold for charging set by the user",
-        "value": 291508031,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "unit": "VehicleUnit:AMPERE"
-      },
-      {
-        "name": "Indicates the maximum charge percent threshold set by the user",
-        "value": 291508032,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Charging state of the car",
-        "value": 289410881,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "EvChargeState"
-      },
-      {
-        "name": "Start or stop charging the EV battery",
-        "value": 287313730,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Estimated charge time remaining in seconds",
-        "value": 289410883,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:SECS"
-      },
-      {
-        "name": "EV_REGENERATIVE_BRAKING_STATE",
-        "value": 289410884,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "EvRegenerativeBrakingState"
-      },
-      {
-        "name": "Indicates if there is a trailer present or not.",
-        "value": 289410885,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "TrailerState"
-      },
-      {
-        "name": "VEHICLE_CURB_WEIGHT",
-        "value": 289410886,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:KILOGRAM"
-      }
-    ]
-  },
-  {
-    "name": "EvsServiceType",
-    "values": [
-      {
-        "name": "REARVIEW",
-        "value": 0
-      },
-      {
-        "name": "SURROUNDVIEW",
-        "value": 1
-      }
-    ]
-  },
-  {
-    "name": "VehiclePropertyChangeMode",
-    "values": [
-      {
-        "name": "STATIC",
-        "value": 0
-      },
-      {
-        "name": "ON_CHANGE",
-        "value": 1
-      },
-      {
-        "name": "CONTINUOUS",
-        "value": 2
-      }
-    ]
-  },
-  {
-    "name": "Obd2CompressionIgnitionMonitors",
-    "values": []
-  },
-  {
-    "name": "VehicleLightState",
-    "values": [
-      {
-        "name": "OFF",
-        "value": 0
-      },
-      {
-        "name": "ON",
-        "value": 1
-      },
-      {
-        "name": "DAYTIME_RUNNING",
-        "value": 2
-      }
-    ]
-  },
-  {
-    "name": "SwitchUserMessageType",
-    "values": [
-      {
-        "name": "UNKNOWN",
-        "value": 0
-      },
-      {
-        "name": "LEGACY_ANDROID_SWITCH",
-        "value": 1
-      },
-      {
-        "name": "ANDROID_SWITCH",
-        "value": 2
-      },
-      {
-        "name": "VEHICLE_RESPONSE",
-        "value": 3
-      },
-      {
-        "name": "VEHICLE_REQUEST",
-        "value": 4
-      },
-      {
-        "name": "ANDROID_POST_SWITCH",
-        "value": 5
-      }
-    ]
-  },
-  {
-    "name": "PortLocationType",
-    "values": [
-      {
-        "name": "UNKNOWN",
-        "value": 0
-      },
-      {
-        "name": "FRONT_LEFT",
-        "value": 1
-      },
-      {
-        "name": "FRONT_RIGHT",
-        "value": 2
-      },
-      {
-        "name": "REAR_RIGHT",
-        "value": 3
-      },
-      {
-        "name": "REAR_LEFT",
-        "value": 4
-      },
-      {
-        "name": "FRONT",
-        "value": 5
-      },
-      {
-        "name": "REAR",
-        "value": 6
-      }
-    ]
-  },
-  {
-    "name": "VehiclePropertyStatus",
-    "values": [
-      {
-        "name": "AVAILABLE",
-        "value": 0
-      },
-      {
-        "name": "UNAVAILABLE",
-        "value": 1
-      },
-      {
-        "name": "ERROR",
-        "value": 2
-      }
-    ]
-  },
-  {
-    "name": "VehicleDisplay",
-    "values": [
-      {
-        "name": "MAIN",
-        "value": 0
-      },
-      {
-        "name": "INSTRUMENT_CLUSTER",
-        "value": 1
-      }
-    ]
-  },
-  {
-    "name": "SwitchUserStatus",
-    "values": [
-      {
-        "name": "SUCCESS",
-        "value": 1
-      },
-      {
-        "name": "FAILURE",
-        "value": 2
-      }
-    ]
-  },
-  {
-    "name": "InitialUserInfoRequestType",
-    "values": [
-      {
-        "name": "UNKNOWN",
-        "value": 0
-      },
-      {
-        "name": "FIRST_BOOT",
-        "value": 1
-      },
-      {
-        "name": "FIRST_BOOT_AFTER_OTA",
-        "value": 2
-      },
-      {
-        "name": "COLD_BOOT",
-        "value": 3
-      },
-      {
-        "name": "RESUME",
-        "value": 4
-      }
-    ]
-  },
-  {
-    "name": "UserIdentificationAssociationSetValue",
-    "values": [
-      {
-        "name": "INVALID",
-        "value": 0
-      },
-      {
-        "name": "ASSOCIATE_CURRENT_USER",
-        "value": 1
-      },
-      {
-        "name": "DISASSOCIATE_CURRENT_USER",
-        "value": 2
-      },
-      {
-        "name": "DISASSOCIATE_ALL_USERS",
-        "value": 3
-      }
-    ]
-  },
-  {
+    "package": "android.hardware.automotive.vehicle",
     "name": "VehicleAreaDoor",
     "values": [
       {
@@ -2092,250 +368,477 @@
     ]
   },
   {
-    "name": "VehicleLightSwitch",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleApPowerBootupReason",
     "values": [
       {
-        "name": "OFF",
+        "name": "USER_POWER_ON",
         "value": 0
       },
       {
-        "name": "ON",
+        "name": "SYSTEM_USER_DETECTION",
         "value": 1
       },
       {
-        "name": "DAYTIME_RUNNING",
+        "name": "SYSTEM_REMOTE_ACCESS",
         "value": 2
-      },
-      {
-        "name": "AUTOMATIC",
-        "value": 256
       }
     ]
   },
   {
-    "name": "VehicleGear",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "EmergencyLaneKeepAssistState",
     "values": [
       {
-        "name": "GEAR_UNKNOWN",
+        "name": "OTHER",
         "value": 0
       },
       {
-        "name": "GEAR_NEUTRAL",
+        "name": "ENABLED",
         "value": 1
       },
       {
-        "name": "GEAR_REVERSE",
+        "name": "WARNING_LEFT",
         "value": 2
       },
       {
-        "name": "GEAR_PARK",
-        "value": 4
-      },
-      {
-        "name": "GEAR_DRIVE",
-        "value": 8
-      },
-      {
-        "name": "GEAR_1",
-        "value": 16
-      },
-      {
-        "name": "GEAR_2",
-        "value": 32
-      },
-      {
-        "name": "GEAR_3",
-        "value": 64
-      },
-      {
-        "name": "GEAR_4",
-        "value": 128
-      },
-      {
-        "name": "GEAR_5",
-        "value": 256
-      },
-      {
-        "name": "GEAR_6",
-        "value": 512
-      },
-      {
-        "name": "GEAR_7",
-        "value": 1024
-      },
-      {
-        "name": "GEAR_8",
-        "value": 2048
-      },
-      {
-        "name": "GEAR_9",
-        "value": 4096
-      }
-    ]
-  },
-  {
-    "name": "Obd2IgnitionMonitorKind",
-    "values": [
-      {
-        "name": "SPARK",
-        "value": 0
-      },
-      {
-        "name": "COMPRESSION",
-        "value": 1
-      }
-    ]
-  },
-  {
-    "name": "CustomInputType",
-    "values": [
-      {
-        "name": "CUSTOM_EVENT_F1",
-        "value": 1001
-      },
-      {
-        "name": "CUSTOM_EVENT_F2",
-        "value": 1002
-      },
-      {
-        "name": "CUSTOM_EVENT_F3",
-        "value": 1003
-      },
-      {
-        "name": "CUSTOM_EVENT_F4",
-        "value": 1004
-      },
-      {
-        "name": "CUSTOM_EVENT_F5",
-        "value": 1005
-      },
-      {
-        "name": "CUSTOM_EVENT_F6",
-        "value": 1006
-      },
-      {
-        "name": "CUSTOM_EVENT_F7",
-        "value": 1007
-      },
-      {
-        "name": "CUSTOM_EVENT_F8",
-        "value": 1008
-      },
-      {
-        "name": "CUSTOM_EVENT_F9",
-        "value": 1009
-      },
-      {
-        "name": "CUSTOM_EVENT_F10",
-        "value": 1010
-      }
-    ]
-  },
-  {
-    "name": "VehicleApPowerStateReport",
-    "values": [
-      {
-        "name": "WAIT_FOR_VHAL",
-        "value": 1
-      },
-      {
-        "name": "DEEP_SLEEP_ENTRY",
-        "value": 2
-      },
-      {
-        "name": "DEEP_SLEEP_EXIT",
+        "name": "WARNING_RIGHT",
         "value": 3
       },
       {
-        "name": "SHUTDOWN_POSTPONE",
+        "name": "ACTIVATED_STEER_LEFT",
         "value": 4
       },
       {
-        "name": "SHUTDOWN_START",
+        "name": "ACTIVATED_STEER_RIGHT",
         "value": 5
       },
       {
-        "name": "ON",
+        "name": "USER_OVERRIDE",
         "value": 6
-      },
-      {
-        "name": "SHUTDOWN_PREPARE",
-        "value": 7
-      },
-      {
-        "name": "SHUTDOWN_CANCELLED",
-        "value": 8
-      },
-      {
-        "name": "HIBERNATION_ENTRY",
-        "value": 9
-      },
-      {
-        "name": "HIBERNATION_EXIT",
-        "value": 10
       }
     ]
   },
   {
-    "name": "VmsMessageWithLayerIntegerValuesIndex",
-    "values": [
-      {
-        "name": "MESSAGE_TYPE",
-        "value": 0
-      },
-      {
-        "name": "LAYER_TYPE",
-        "value": 1
-      },
-      {
-        "name": "LAYER_SUBTYPE",
-        "value": 2
-      },
-      {
-        "name": "LAYER_VERSION",
-        "value": 3
-      }
-    ]
-  },
-  {
-    "name": "EvRegenerativeBrakingState",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "EvConnectorType",
     "values": [
       {
         "name": "UNKNOWN",
         "value": 0
       },
       {
-        "name": "DISABLED",
+        "name": "IEC_TYPE_1_AC",
         "value": 1
       },
       {
-        "name": "PARTIALLY_ENABLED",
+        "name": "IEC_TYPE_2_AC",
         "value": 2
       },
       {
-        "name": "FULLY_ENABLED",
+        "name": "IEC_TYPE_3_AC",
         "value": 3
+      },
+      {
+        "name": "IEC_TYPE_4_DC",
+        "value": 4
+      },
+      {
+        "name": "IEC_TYPE_1_CCS_DC",
+        "value": 5
+      },
+      {
+        "name": "IEC_TYPE_2_CCS_DC",
+        "value": 6
+      },
+      {
+        "name": "TESLA_ROADSTER",
+        "value": 7
+      },
+      {
+        "name": "TESLA_HPWC",
+        "value": 8
+      },
+      {
+        "name": "TESLA_SUPERCHARGER",
+        "value": 9
+      },
+      {
+        "name": "GBT_AC",
+        "value": 10
+      },
+      {
+        "name": "GBT_DC",
+        "value": 11
+      },
+      {
+        "name": "OTHER",
+        "value": 101
       }
     ]
   },
   {
-    "name": "VehiclePropertyGroup",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "UserIdentificationAssociationType",
     "values": [
       {
-        "name": "SYSTEM",
-        "value": 268435456
+        "name": "INVALID",
+        "value": 0
       },
       {
-        "name": "VENDOR",
-        "value": 536870912
+        "name": "KEY_FOB",
+        "value": 1
       },
       {
-        "name": "MASK",
-        "value": 4026531840
+        "name": "CUSTOM_1",
+        "value": 101
+      },
+      {
+        "name": "CUSTOM_2",
+        "value": 102
+      },
+      {
+        "name": "CUSTOM_3",
+        "value": 103
+      },
+      {
+        "name": "CUSTOM_4",
+        "value": 104
       }
     ]
   },
   {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleHvacFanDirection",
+    "values": [
+      {
+        "name": "UNKNOWN",
+        "value": 0
+      },
+      {
+        "name": "FACE",
+        "value": 1
+      },
+      {
+        "name": "FLOOR",
+        "value": 2
+      },
+      {
+        "name": "FACE_AND_FLOOR",
+        "value": 3
+      },
+      {
+        "name": "DEFROST",
+        "value": 4
+      },
+      {
+        "name": "DEFROST_AND_FLOOR",
+        "value": 6
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleAreaWheel",
+    "values": [
+      {
+        "name": "UNKNOWN",
+        "value": 0
+      },
+      {
+        "name": "LEFT_FRONT",
+        "value": 1
+      },
+      {
+        "name": "RIGHT_FRONT",
+        "value": 2
+      },
+      {
+        "name": "LEFT_REAR",
+        "value": 4
+      },
+      {
+        "name": "RIGHT_REAR",
+        "value": 8
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "InitialUserInfoRequestType",
+    "values": [
+      {
+        "name": "UNKNOWN",
+        "value": 0
+      },
+      {
+        "name": "FIRST_BOOT",
+        "value": 1
+      },
+      {
+        "name": "FIRST_BOOT_AFTER_OTA",
+        "value": 2
+      },
+      {
+        "name": "COLD_BOOT",
+        "value": 3
+      },
+      {
+        "name": "RESUME",
+        "value": 4
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "HandsOnDetectionDriverState",
+    "values": [
+      {
+        "name": "OTHER",
+        "value": 0
+      },
+      {
+        "name": "HANDS_ON",
+        "value": 1
+      },
+      {
+        "name": "HANDS_OFF",
+        "value": 2
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "CruiseControlCommand",
+    "values": [
+      {
+        "name": "ACTIVATE",
+        "value": 1
+      },
+      {
+        "name": "SUSPEND",
+        "value": 2
+      },
+      {
+        "name": "INCREASE_TARGET_SPEED",
+        "value": 3
+      },
+      {
+        "name": "DECREASE_TARGET_SPEED",
+        "value": 4
+      },
+      {
+        "name": "INCREASE_TARGET_TIME_GAP",
+        "value": 5
+      },
+      {
+        "name": "DECREASE_TARGET_TIME_GAP",
+        "value": 6
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "WindshieldWipersSwitch",
+    "values": [
+      {
+        "name": "OTHER",
+        "value": 0
+      },
+      {
+        "name": "OFF",
+        "value": 1
+      },
+      {
+        "name": "MIST",
+        "value": 2
+      },
+      {
+        "name": "INTERMITTENT_LEVEL_1",
+        "value": 3
+      },
+      {
+        "name": "INTERMITTENT_LEVEL_2",
+        "value": 4
+      },
+      {
+        "name": "INTERMITTENT_LEVEL_3",
+        "value": 5
+      },
+      {
+        "name": "INTERMITTENT_LEVEL_4",
+        "value": 6
+      },
+      {
+        "name": "INTERMITTENT_LEVEL_5",
+        "value": 7
+      },
+      {
+        "name": "CONTINUOUS_LEVEL_1",
+        "value": 8
+      },
+      {
+        "name": "CONTINUOUS_LEVEL_2",
+        "value": 9
+      },
+      {
+        "name": "CONTINUOUS_LEVEL_3",
+        "value": 10
+      },
+      {
+        "name": "CONTINUOUS_LEVEL_4",
+        "value": 11
+      },
+      {
+        "name": "CONTINUOUS_LEVEL_5",
+        "value": 12
+      },
+      {
+        "name": "AUTO",
+        "value": 13
+      },
+      {
+        "name": "SERVICE",
+        "value": 14
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleHwMotionToolType",
+    "values": [
+      {
+        "name": "TOOL_TYPE_UNKNOWN",
+        "value": 0
+      },
+      {
+        "name": "TOOL_TYPE_FINGER",
+        "value": 1
+      },
+      {
+        "name": "TOOL_TYPE_STYLUS",
+        "value": 2
+      },
+      {
+        "name": "TOOL_TYPE_MOUSE",
+        "value": 3
+      },
+      {
+        "name": "TOOL_TYPE_ERASER",
+        "value": 4
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "SwitchUserStatus",
+    "values": [
+      {
+        "name": "SUCCESS",
+        "value": 1
+      },
+      {
+        "name": "FAILURE",
+        "value": 2
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "EvsServiceType",
+    "values": [
+      {
+        "name": "REARVIEW",
+        "value": 0
+      },
+      {
+        "name": "SURROUNDVIEW",
+        "value": 1
+      },
+      {
+        "name": "FRONTVIEW",
+        "value": 2
+      },
+      {
+        "name": "LEFTVIEW",
+        "value": 3
+      },
+      {
+        "name": "RIGHTVIEW",
+        "value": 4
+      },
+      {
+        "name": "DRIVERVIEW",
+        "value": 5
+      },
+      {
+        "name": "FRONTPASSENGERSVIEW",
+        "value": 6
+      },
+      {
+        "name": "REARPASSENGERSVIEW",
+        "value": 7
+      },
+      {
+        "name": "USER_DEFINED",
+        "value": 1000
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "UserIdentificationAssociationValue",
+    "values": [
+      {
+        "name": "UNKNOWN",
+        "value": 1
+      },
+      {
+        "name": "ASSOCIATED_CURRENT_USER",
+        "value": 2
+      },
+      {
+        "name": "ASSOCIATED_ANOTHER_USER",
+        "value": 3
+      },
+      {
+        "name": "NOT_ASSOCIATED_ANY_USER",
+        "value": 4
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "ErrorState",
+    "values": [
+      {
+        "name": "OTHER_ERROR_STATE",
+        "value": -1
+      },
+      {
+        "name": "NOT_AVAILABLE_DISABLED",
+        "value": -2
+      },
+      {
+        "name": "NOT_AVAILABLE_SPEED_LOW",
+        "value": -3
+      },
+      {
+        "name": "NOT_AVAILABLE_SPEED_HIGH",
+        "value": -4
+      },
+      {
+        "name": "NOT_AVAILABLE_POOR_VISIBILITY",
+        "value": -5
+      },
+      {
+        "name": "NOT_AVAILABLE_SAFETY",
+        "value": -6
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
     "name": "VehicleIgnitionState",
     "values": [
       {
@@ -2365,173 +868,302 @@
     ]
   },
   {
-    "name": "VehicleHwKeyInputAction",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleAreaSeat",
     "values": [
       {
-        "name": "ACTION_DOWN",
-        "value": 0
-      },
-      {
-        "name": "ACTION_UP",
-        "value": 1
-      }
-    ]
-  },
-  {
-    "name": "DiagnosticIntegerSensorIndex",
-    "values": [
-      {
-        "name": "FUEL_SYSTEM_STATUS",
-        "value": 0
-      },
-      {
-        "name": "MALFUNCTION_INDICATOR_LIGHT_ON",
+        "name": "ROW_1_LEFT",
         "value": 1
       },
       {
-        "name": "IGNITION_MONITORS_SUPPORTED",
+        "name": "ROW_1_CENTER",
         "value": 2
       },
       {
-        "name": "IGNITION_SPECIFIC_MONITORS",
-        "value": 3
-      },
-      {
-        "name": "INTAKE_AIR_TEMPERATURE",
+        "name": "ROW_1_RIGHT",
         "value": 4
       },
       {
-        "name": "COMMANDED_SECONDARY_AIR_STATUS",
-        "value": 5
-      },
-      {
-        "name": "NUM_OXYGEN_SENSORS_PRESENT",
-        "value": 6
-      },
-      {
-        "name": "RUNTIME_SINCE_ENGINE_START",
-        "value": 7
-      },
-      {
-        "name": "DISTANCE_TRAVELED_WITH_MALFUNCTION_INDICATOR_LIGHT_ON",
-        "value": 8
-      },
-      {
-        "name": "WARMUPS_SINCE_CODES_CLEARED",
-        "value": 9
-      },
-      {
-        "name": "DISTANCE_TRAVELED_SINCE_CODES_CLEARED",
-        "value": 10
-      },
-      {
-        "name": "ABSOLUTE_BAROMETRIC_PRESSURE",
-        "value": 11
-      },
-      {
-        "name": "CONTROL_MODULE_VOLTAGE",
-        "value": 12
-      },
-      {
-        "name": "AMBIENT_AIR_TEMPERATURE",
-        "value": 13
-      },
-      {
-        "name": "TIME_WITH_MALFUNCTION_LIGHT_ON",
-        "value": 14
-      },
-      {
-        "name": "TIME_SINCE_TROUBLE_CODES_CLEARED",
-        "value": 15
-      },
-      {
-        "name": "MAX_FUEL_AIR_EQUIVALENCE_RATIO",
+        "name": "ROW_2_LEFT",
         "value": 16
       },
       {
-        "name": "MAX_OXYGEN_SENSOR_VOLTAGE",
-        "value": 17
+        "name": "ROW_2_CENTER",
+        "value": 32
       },
       {
-        "name": "MAX_OXYGEN_SENSOR_CURRENT",
-        "value": 18
+        "name": "ROW_2_RIGHT",
+        "value": 64
       },
       {
-        "name": "MAX_INTAKE_MANIFOLD_ABSOLUTE_PRESSURE",
-        "value": 19
+        "name": "ROW_3_LEFT",
+        "value": 256
       },
       {
-        "name": "MAX_AIR_FLOW_RATE_FROM_MASS_AIR_FLOW_SENSOR",
-        "value": 20
+        "name": "ROW_3_CENTER",
+        "value": 512
       },
       {
-        "name": "FUEL_TYPE",
-        "value": 21
-      },
-      {
-        "name": "FUEL_RAIL_ABSOLUTE_PRESSURE",
-        "value": 22
-      },
-      {
-        "name": "ENGINE_OIL_TEMPERATURE",
-        "value": 23
-      },
-      {
-        "name": "DRIVER_DEMAND_PERCENT_TORQUE",
-        "value": 24
-      },
-      {
-        "name": "ENGINE_ACTUAL_PERCENT_TORQUE",
-        "value": 25
-      },
-      {
-        "name": "ENGINE_REFERENCE_PERCENT_TORQUE",
-        "value": 26
-      },
-      {
-        "name": "ENGINE_PERCENT_TORQUE_DATA_IDLE",
-        "value": 27
-      },
-      {
-        "name": "ENGINE_PERCENT_TORQUE_DATA_POINT1",
-        "value": 28
-      },
-      {
-        "name": "ENGINE_PERCENT_TORQUE_DATA_POINT2",
-        "value": 29
-      },
-      {
-        "name": "ENGINE_PERCENT_TORQUE_DATA_POINT3",
-        "value": 30
-      },
-      {
-        "name": "ENGINE_PERCENT_TORQUE_DATA_POINT4",
-        "value": 31
+        "name": "ROW_3_RIGHT",
+        "value": 1024
       }
     ]
   },
   {
-    "name": "UserIdentificationAssociationValue",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "EvsServiceRequestIndex",
     "values": [
       {
-        "name": "UNKNOWN",
+        "name": "TYPE",
+        "value": 0
+      },
+      {
+        "name": "STATE",
+        "value": 1
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "LaneDepartureWarningState",
+    "values": [
+      {
+        "name": "OTHER",
+        "value": 0
+      },
+      {
+        "name": "NO_WARNING",
         "value": 1
       },
       {
-        "name": "ASSOCIATED_CURRENT_USER",
+        "name": "WARNING_LEFT",
         "value": 2
       },
       {
-        "name": "ASSOCIATED_ANOTHER_USER",
+        "name": "WARNING_RIGHT",
         "value": 3
-      },
-      {
-        "name": "NOT_ASSOCIATED_ANY_USER",
-        "value": 4
       }
     ]
   },
   {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "Obd2SparkIgnitionMonitors",
+    "values": []
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "CreateUserStatus",
+    "values": [
+      {
+        "name": "SUCCESS",
+        "value": 1
+      },
+      {
+        "name": "FAILURE",
+        "value": 2
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehiclePropertyGroup",
+    "values": [
+      {
+        "name": "SYSTEM",
+        "value": 268435456
+      },
+      {
+        "name": "VENDOR",
+        "value": 536870912
+      },
+      {
+        "name": "MASK",
+        "value": 4026531840
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleVendorPermission",
+    "values": [
+      {
+        "name": "PERMISSION_DEFAULT",
+        "value": 0
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_WINDOW",
+        "value": 1
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_WINDOW",
+        "value": 2
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_DOOR",
+        "value": 3
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_DOOR",
+        "value": 4
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_SEAT",
+        "value": 5
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_SEAT",
+        "value": 6
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_MIRROR",
+        "value": 7
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_MIRROR",
+        "value": 8
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_INFO",
+        "value": 9
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_INFO",
+        "value": 10
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_ENGINE",
+        "value": 11
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_ENGINE",
+        "value": 12
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_HVAC",
+        "value": 13
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_HVAC",
+        "value": 14
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_LIGHT",
+        "value": 15
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_LIGHT",
+        "value": 16
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_1",
+        "value": 65536
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_1",
+        "value": 69632
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_2",
+        "value": 131072
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_2",
+        "value": 135168
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_3",
+        "value": 196608
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_3",
+        "value": 200704
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_4",
+        "value": 262144
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_4",
+        "value": 266240
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_5",
+        "value": 327680
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_5",
+        "value": 331776
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_6",
+        "value": 393216
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_6",
+        "value": 397312
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_7",
+        "value": 458752
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_7",
+        "value": 462848
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_8",
+        "value": 524288
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_8",
+        "value": 528384
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_9",
+        "value": 589824
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_9",
+        "value": 593920
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_10",
+        "value": 655360
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_10",
+        "value": 659456
+      },
+      {
+        "name": "PERMISSION_NOT_ACCESSIBLE",
+        "value": 4026531840
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VmsOfferingMessageIntegerValuesIndex",
+    "values": [
+      {
+        "name": "MESSAGE_TYPE",
+        "value": 0
+      },
+      {
+        "name": "PUBLISHER_ID",
+        "value": 1
+      },
+      {
+        "name": "NUMBER_OF_OFFERS",
+        "value": 2
+      },
+      {
+        "name": "OFFERING_START",
+        "value": 3
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
     "name": "VmsBaseMessageIntegerValuesIndex",
     "values": [
       {
@@ -2541,6 +1173,473 @@
     ]
   },
   {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "Obd2CompressionIgnitionMonitors",
+    "values": []
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "LaneKeepAssistState",
+    "values": [
+      {
+        "name": "OTHER",
+        "value": 0
+      },
+      {
+        "name": "ENABLED",
+        "value": 1
+      },
+      {
+        "name": "ACTIVATED_STEER_LEFT",
+        "value": 2
+      },
+      {
+        "name": "ACTIVATED_STEER_RIGHT",
+        "value": 3
+      },
+      {
+        "name": "USER_OVERRIDE",
+        "value": 4
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleHwMotionInputAction",
+    "values": [
+      {
+        "name": "ACTION_DOWN",
+        "value": 0
+      },
+      {
+        "name": "ACTION_UP",
+        "value": 1
+      },
+      {
+        "name": "ACTION_MOVE",
+        "value": 2
+      },
+      {
+        "name": "ACTION_CANCEL",
+        "value": 3
+      },
+      {
+        "name": "ACTION_OUTSIDE",
+        "value": 4
+      },
+      {
+        "name": "ACTION_POINTER_DOWN",
+        "value": 5
+      },
+      {
+        "name": "ACTION_POINTER_UP",
+        "value": 6
+      },
+      {
+        "name": "ACTION_HOVER_MOVE",
+        "value": 7
+      },
+      {
+        "name": "ACTION_SCROLL",
+        "value": 8
+      },
+      {
+        "name": "ACTION_HOVER_ENTER",
+        "value": 9
+      },
+      {
+        "name": "ACTION_HOVER_EXIT",
+        "value": 10
+      },
+      {
+        "name": "ACTION_BUTTON_PRESS",
+        "value": 11
+      },
+      {
+        "name": "ACTION_BUTTON_RELEASE",
+        "value": 12
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleApPowerStateConfigFlag",
+    "values": [
+      {
+        "name": "ENABLE_DEEP_SLEEP_FLAG",
+        "value": 1
+      },
+      {
+        "name": "CONFIG_SUPPORT_TIMER_POWER_ON_FLAG",
+        "value": 2
+      },
+      {
+        "name": "ENABLE_HIBERNATION_FLAG",
+        "value": 4
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "Obd2SecondaryAirStatus",
+    "values": [
+      {
+        "name": "UPSTREAM",
+        "value": 1
+      },
+      {
+        "name": "DOWNSTREAM_OF_CATALYCIC_CONVERTER",
+        "value": 2
+      },
+      {
+        "name": "FROM_OUTSIDE_OR_OFF",
+        "value": 4
+      },
+      {
+        "name": "PUMP_ON_FOR_DIAGNOSTICS",
+        "value": 8
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VmsPublisherInformationIntegerValuesIndex",
+    "values": [
+      {
+        "name": "MESSAGE_TYPE",
+        "value": 0
+      },
+      {
+        "name": "PUBLISHER_ID",
+        "value": 1
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleApPowerStateReq",
+    "values": [
+      {
+        "name": "ON",
+        "value": 0
+      },
+      {
+        "name": "SHUTDOWN_PREPARE",
+        "value": 1
+      },
+      {
+        "name": "CANCEL_SHUTDOWN",
+        "value": 2
+      },
+      {
+        "name": "FINISHED",
+        "value": 3
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "WindshieldWipersState",
+    "values": [
+      {
+        "name": "OTHER",
+        "value": 0
+      },
+      {
+        "name": "OFF",
+        "value": 1
+      },
+      {
+        "name": "ON",
+        "value": 2
+      },
+      {
+        "name": "SERVICE",
+        "value": 3
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "LaneCenteringAssistState",
+    "values": [
+      {
+        "name": "OTHER",
+        "value": 0
+      },
+      {
+        "name": "ENABLED",
+        "value": 1
+      },
+      {
+        "name": "ACTIVATION_REQUESTED",
+        "value": 2
+      },
+      {
+        "name": "ACTIVATED",
+        "value": 3
+      },
+      {
+        "name": "USER_OVERRIDE",
+        "value": 4
+      },
+      {
+        "name": "FORCED_DEACTIVATION_WARNING",
+        "value": 5
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "UserIdentificationAssociationSetValue",
+    "values": [
+      {
+        "name": "INVALID",
+        "value": 0
+      },
+      {
+        "name": "ASSOCIATE_CURRENT_USER",
+        "value": 1
+      },
+      {
+        "name": "DISASSOCIATE_CURRENT_USER",
+        "value": 2
+      },
+      {
+        "name": "DISASSOCIATE_ALL_USERS",
+        "value": 3
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "Obd2CommonIgnitionMonitors",
+    "values": []
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleHwMotionInputSource",
+    "values": [
+      {
+        "name": "SOURCE_UNKNOWN",
+        "value": 0
+      },
+      {
+        "name": "SOURCE_KEYBOARD",
+        "value": 1
+      },
+      {
+        "name": "SOURCE_DPAD",
+        "value": 2
+      },
+      {
+        "name": "SOURCE_GAMEPAD",
+        "value": 3
+      },
+      {
+        "name": "SOURCE_TOUCHSCREEN",
+        "value": 4
+      },
+      {
+        "name": "SOURCE_MOUSE",
+        "value": 5
+      },
+      {
+        "name": "SOURCE_STYLUS",
+        "value": 6
+      },
+      {
+        "name": "SOURCE_BLUETOOTH_STYLUS",
+        "value": 7
+      },
+      {
+        "name": "SOURCE_TRACKBALL",
+        "value": 8
+      },
+      {
+        "name": "SOURCE_MOUSE_RELATIVE",
+        "value": 9
+      },
+      {
+        "name": "SOURCE_TOUCHPAD",
+        "value": 10
+      },
+      {
+        "name": "SOURCE_TOUCH_NAVIGATION",
+        "value": 11
+      },
+      {
+        "name": "SOURCE_ROTARY_ENCODER",
+        "value": 12
+      },
+      {
+        "name": "SOURCE_JOYSTICK",
+        "value": 13
+      },
+      {
+        "name": "SOURCE_HDMI",
+        "value": 14
+      },
+      {
+        "name": "SOURCE_SENSOR",
+        "value": 15
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "ForwardCollisionWarningState",
+    "values": [
+      {
+        "name": "OTHER",
+        "value": 0
+      },
+      {
+        "name": "NO_WARNING",
+        "value": 1
+      },
+      {
+        "name": "WARNING",
+        "value": 2
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleArea",
+    "values": [
+      {
+        "name": "GLOBAL",
+        "value": 16777216
+      },
+      {
+        "name": "WINDOW",
+        "value": 50331648
+      },
+      {
+        "name": "MIRROR",
+        "value": 67108864
+      },
+      {
+        "name": "SEAT",
+        "value": 83886080
+      },
+      {
+        "name": "DOOR",
+        "value": 100663296
+      },
+      {
+        "name": "WHEEL",
+        "value": 117440512
+      },
+      {
+        "name": "MASK",
+        "value": 251658240
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "PortLocationType",
+    "values": [
+      {
+        "name": "UNKNOWN",
+        "value": 0
+      },
+      {
+        "name": "FRONT_LEFT",
+        "value": 1
+      },
+      {
+        "name": "FRONT_RIGHT",
+        "value": 2
+      },
+      {
+        "name": "REAR_RIGHT",
+        "value": 3
+      },
+      {
+        "name": "REAR_LEFT",
+        "value": 4
+      },
+      {
+        "name": "FRONT",
+        "value": 5
+      },
+      {
+        "name": "REAR",
+        "value": 6
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "InitialUserInfoResponseAction",
+    "values": [
+      {
+        "name": "DEFAULT",
+        "value": 0
+      },
+      {
+        "name": "SWITCH",
+        "value": 1
+      },
+      {
+        "name": "CREATE",
+        "value": 2
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VmsSubscriptionsStateIntegerValuesIndex",
+    "values": [
+      {
+        "name": "MESSAGE_TYPE",
+        "value": 0
+      },
+      {
+        "name": "SEQUENCE_NUMBER",
+        "value": 1
+      },
+      {
+        "name": "NUMBER_OF_LAYERS",
+        "value": 2
+      },
+      {
+        "name": "NUMBER_OF_ASSOCIATED_LAYERS",
+        "value": 3
+      },
+      {
+        "name": "SUBSCRIPTIONS_START",
+        "value": 4
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "CruiseControlType",
+    "values": [
+      {
+        "name": "OTHER",
+        "value": 0
+      },
+      {
+        "name": "STANDARD",
+        "value": 1
+      },
+      {
+        "name": "ADAPTIVE",
+        "value": 2
+      },
+      {
+        "name": "PREDICTIVE",
+        "value": 3
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
     "name": "DiagnosticFloatSensorIndex",
     "values": [
       {
@@ -2830,7 +1929,40 @@
     ]
   },
   {
-    "name": "VmsMessageWithLayerAndPublisherIdIntegerValuesIndex",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "GsrComplianceRequirementType",
+    "values": [
+      {
+        "name": "GSR_COMPLIANCE_NOT_REQUIRED",
+        "value": 0
+      },
+      {
+        "name": "GSR_COMPLIANCE_REQUIRED_V1",
+        "value": 1
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleLightState",
+    "values": [
+      {
+        "name": "OFF",
+        "value": 0
+      },
+      {
+        "name": "ON",
+        "value": 1
+      },
+      {
+        "name": "DAYTIME_RUNNING",
+        "value": 2
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VmsMessageWithLayerIntegerValuesIndex",
     "values": [
       {
         "name": "MESSAGE_TYPE",
@@ -2847,92 +1979,61 @@
       {
         "name": "LAYER_VERSION",
         "value": 3
-      },
-      {
-        "name": "PUBLISHER_ID",
-        "value": 4
       }
     ]
   },
   {
-    "name": "FuelType",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "EvRegenerativeBrakingState",
     "values": [
       {
-        "name": "FUEL_TYPE_UNKNOWN",
+        "name": "UNKNOWN",
         "value": 0
       },
       {
-        "name": "FUEL_TYPE_UNLEADED",
+        "name": "DISABLED",
         "value": 1
       },
       {
-        "name": "FUEL_TYPE_LEADED",
+        "name": "PARTIALLY_ENABLED",
         "value": 2
       },
       {
-        "name": "FUEL_TYPE_DIESEL_1",
-        "value": 3
-      },
-      {
-        "name": "FUEL_TYPE_DIESEL_2",
-        "value": 4
-      },
-      {
-        "name": "FUEL_TYPE_BIODIESEL",
-        "value": 5
-      },
-      {
-        "name": "FUEL_TYPE_E85",
-        "value": 6
-      },
-      {
-        "name": "FUEL_TYPE_LPG",
-        "value": 7
-      },
-      {
-        "name": "FUEL_TYPE_CNG",
-        "value": 8
-      },
-      {
-        "name": "FUEL_TYPE_LNG",
-        "value": 9
-      },
-      {
-        "name": "FUEL_TYPE_ELECTRIC",
-        "value": 10
-      },
-      {
-        "name": "FUEL_TYPE_HYDROGEN",
-        "value": 11
-      },
-      {
-        "name": "FUEL_TYPE_OTHER",
-        "value": 12
-      }
-    ]
-  },
-  {
-    "name": "VehicleApPowerStateReq",
-    "values": [
-      {
-        "name": "ON",
-        "value": 0
-      },
-      {
-        "name": "SHUTDOWN_PREPARE",
-        "value": 1
-      },
-      {
-        "name": "CANCEL_SHUTDOWN",
-        "value": 2
-      },
-      {
-        "name": "FINISHED",
+        "name": "FULLY_ENABLED",
         "value": 3
       }
     ]
   },
   {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleApPowerStateReqIndex",
+    "values": [
+      {
+        "name": "STATE",
+        "value": 0
+      },
+      {
+        "name": "ADDITIONAL",
+        "value": 1
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "RotaryInputType",
+    "values": [
+      {
+        "name": "ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION",
+        "value": 0
+      },
+      {
+        "name": "ROTARY_INPUT_TYPE_AUDIO_VOLUME",
+        "value": 1
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
     "name": "VmsMessageType",
     "values": [
       {
@@ -3006,96 +2107,417 @@
     ]
   },
   {
-    "name": "Obd2CommonIgnitionMonitors",
-    "values": []
-  },
-  {
-    "name": "UserIdentificationAssociationType",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "FuelType",
     "values": [
       {
-        "name": "INVALID",
+        "name": "FUEL_TYPE_UNKNOWN",
         "value": 0
       },
       {
-        "name": "KEY_FOB",
+        "name": "FUEL_TYPE_UNLEADED",
         "value": 1
       },
       {
-        "name": "CUSTOM_1",
-        "value": 101
+        "name": "FUEL_TYPE_LEADED",
+        "value": 2
       },
       {
-        "name": "CUSTOM_2",
-        "value": 102
+        "name": "FUEL_TYPE_DIESEL_1",
+        "value": 3
       },
       {
-        "name": "CUSTOM_3",
-        "value": 103
+        "name": "FUEL_TYPE_DIESEL_2",
+        "value": 4
       },
       {
-        "name": "CUSTOM_4",
-        "value": 104
+        "name": "FUEL_TYPE_BIODIESEL",
+        "value": 5
+      },
+      {
+        "name": "FUEL_TYPE_E85",
+        "value": 6
+      },
+      {
+        "name": "FUEL_TYPE_LPG",
+        "value": 7
+      },
+      {
+        "name": "FUEL_TYPE_CNG",
+        "value": 8
+      },
+      {
+        "name": "FUEL_TYPE_LNG",
+        "value": 9
+      },
+      {
+        "name": "FUEL_TYPE_ELECTRIC",
+        "value": 10
+      },
+      {
+        "name": "FUEL_TYPE_HYDROGEN",
+        "value": 11
+      },
+      {
+        "name": "FUEL_TYPE_OTHER",
+        "value": 12
       }
     ]
   },
   {
-    "name": "EvConnectorType",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleSeatOccupancyState",
     "values": [
       {
         "name": "UNKNOWN",
         "value": 0
       },
       {
-        "name": "IEC_TYPE_1_AC",
+        "name": "VACANT",
         "value": 1
       },
       {
-        "name": "IEC_TYPE_2_AC",
+        "name": "OCCUPIED",
         "value": 2
-      },
-      {
-        "name": "IEC_TYPE_3_AC",
-        "value": 3
-      },
-      {
-        "name": "IEC_TYPE_4_DC",
-        "value": 4
-      },
-      {
-        "name": "IEC_TYPE_1_CCS_DC",
-        "value": 5
-      },
-      {
-        "name": "IEC_TYPE_2_CCS_DC",
-        "value": 6
-      },
-      {
-        "name": "TESLA_ROADSTER",
-        "value": 7
-      },
-      {
-        "name": "TESLA_HPWC",
-        "value": 8
-      },
-      {
-        "name": "TESLA_SUPERCHARGER",
-        "value": 9
-      },
-      {
-        "name": "GBT_AC",
-        "value": 10
-      },
-      {
-        "name": "GBT_DC",
-        "value": 11
-      },
-      {
-        "name": "OTHER",
-        "value": 101
       }
     ]
   },
   {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "EvStoppingMode",
+    "values": [
+      {
+        "name": "OTHER",
+        "value": 0
+      },
+      {
+        "name": "CREEP",
+        "value": 1
+      },
+      {
+        "name": "ROLL",
+        "value": 2
+      },
+      {
+        "name": "HOLD",
+        "value": 3
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "AutomaticEmergencyBrakingState",
+    "values": [
+      {
+        "name": "OTHER",
+        "value": 0
+      },
+      {
+        "name": "ENABLED",
+        "value": 1
+      },
+      {
+        "name": "ACTIVATED",
+        "value": 2
+      },
+      {
+        "name": "USER_OVERRIDE",
+        "value": 3
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleApPowerStateReport",
+    "values": [
+      {
+        "name": "WAIT_FOR_VHAL",
+        "value": 1
+      },
+      {
+        "name": "DEEP_SLEEP_ENTRY",
+        "value": 2
+      },
+      {
+        "name": "DEEP_SLEEP_EXIT",
+        "value": 3
+      },
+      {
+        "name": "SHUTDOWN_POSTPONE",
+        "value": 4
+      },
+      {
+        "name": "SHUTDOWN_START",
+        "value": 5
+      },
+      {
+        "name": "ON",
+        "value": 6
+      },
+      {
+        "name": "SHUTDOWN_PREPARE",
+        "value": 7
+      },
+      {
+        "name": "SHUTDOWN_CANCELLED",
+        "value": 8
+      },
+      {
+        "name": "HIBERNATION_ENTRY",
+        "value": 9
+      },
+      {
+        "name": "HIBERNATION_EXIT",
+        "value": 10
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "SwitchUserMessageType",
+    "values": [
+      {
+        "name": "UNKNOWN",
+        "value": 0
+      },
+      {
+        "name": "LEGACY_ANDROID_SWITCH",
+        "value": 1
+      },
+      {
+        "name": "ANDROID_SWITCH",
+        "value": 2
+      },
+      {
+        "name": "VEHICLE_RESPONSE",
+        "value": 3
+      },
+      {
+        "name": "VEHICLE_REQUEST",
+        "value": 4
+      },
+      {
+        "name": "ANDROID_POST_SWITCH",
+        "value": 5
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleAreaMirror",
+    "values": [
+      {
+        "name": "DRIVER_LEFT",
+        "value": 1
+      },
+      {
+        "name": "DRIVER_RIGHT",
+        "value": 2
+      },
+      {
+        "name": "DRIVER_CENTER",
+        "value": 4
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "TrailerState",
+    "values": [
+      {
+        "name": "UNKNOWN",
+        "value": 0
+      },
+      {
+        "name": "NOT_PRESENT",
+        "value": 1
+      },
+      {
+        "name": "PRESENT",
+        "value": 2
+      },
+      {
+        "name": "ERROR",
+        "value": 3
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "EvsServiceState",
+    "values": [
+      {
+        "name": "OFF",
+        "value": 0
+      },
+      {
+        "name": "ON",
+        "value": 1
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleHwKeyInputAction",
+    "values": [
+      {
+        "name": "ACTION_DOWN",
+        "value": 0
+      },
+      {
+        "name": "ACTION_UP",
+        "value": 1
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "BlindSpotWarningState",
+    "values": [
+      {
+        "name": "OTHER",
+        "value": 0
+      },
+      {
+        "name": "NO_WARNING",
+        "value": 1
+      },
+      {
+        "name": "WARNING",
+        "value": 2
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleGear",
+    "values": [
+      {
+        "name": "GEAR_UNKNOWN",
+        "value": 0
+      },
+      {
+        "name": "GEAR_NEUTRAL",
+        "value": 1
+      },
+      {
+        "name": "GEAR_REVERSE",
+        "value": 2
+      },
+      {
+        "name": "GEAR_PARK",
+        "value": 4
+      },
+      {
+        "name": "GEAR_DRIVE",
+        "value": 8
+      },
+      {
+        "name": "GEAR_1",
+        "value": 16
+      },
+      {
+        "name": "GEAR_2",
+        "value": 32
+      },
+      {
+        "name": "GEAR_3",
+        "value": 64
+      },
+      {
+        "name": "GEAR_4",
+        "value": 128
+      },
+      {
+        "name": "GEAR_5",
+        "value": 256
+      },
+      {
+        "name": "GEAR_6",
+        "value": 512
+      },
+      {
+        "name": "GEAR_7",
+        "value": 1024
+      },
+      {
+        "name": "GEAR_8",
+        "value": 2048
+      },
+      {
+        "name": "GEAR_9",
+        "value": 4096
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VmsStartSessionMessageIntegerValuesIndex",
+    "values": [
+      {
+        "name": "MESSAGE_TYPE",
+        "value": 0
+      },
+      {
+        "name": "SERVICE_ID",
+        "value": 1
+      },
+      {
+        "name": "CLIENT_ID",
+        "value": 2
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "Obd2FuelSystemStatus",
+    "values": [
+      {
+        "name": "OPEN_INSUFFICIENT_ENGINE_TEMPERATURE",
+        "value": 1
+      },
+      {
+        "name": "CLOSED_LOOP",
+        "value": 2
+      },
+      {
+        "name": "OPEN_ENGINE_LOAD_OR_DECELERATION",
+        "value": 4
+      },
+      {
+        "name": "OPEN_SYSTEM_FAILURE",
+        "value": 8
+      },
+      {
+        "name": "CLOSED_LOOP_BUT_FEEDBACK_FAULT",
+        "value": 16
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "ElectronicTollCollectionCardStatus",
+    "values": [
+      {
+        "name": "UNKNOWN",
+        "value": 0
+      },
+      {
+        "name": "ELECTRONIC_TOLL_COLLECTION_CARD_VALID",
+        "value": 1
+      },
+      {
+        "name": "ELECTRONIC_TOLL_COLLECTION_CARD_INVALID",
+        "value": 2
+      },
+      {
+        "name": "ELECTRONIC_TOLL_COLLECTION_CARD_NOT_INSERTED",
+        "value": 3
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
     "name": "VehicleApPowerStateShutdownParam",
     "values": [
       {
@@ -3125,271 +2547,53 @@
     ]
   },
   {
-    "name": "VmsOfferingMessageIntegerValuesIndex",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "CustomInputType",
     "values": [
       {
-        "name": "MESSAGE_TYPE",
-        "value": 0
+        "name": "CUSTOM_EVENT_F1",
+        "value": 1001
       },
       {
-        "name": "PUBLISHER_ID",
-        "value": 1
+        "name": "CUSTOM_EVENT_F2",
+        "value": 1002
       },
       {
-        "name": "NUMBER_OF_OFFERS",
-        "value": 2
+        "name": "CUSTOM_EVENT_F3",
+        "value": 1003
       },
       {
-        "name": "OFFERING_START",
-        "value": 3
+        "name": "CUSTOM_EVENT_F4",
+        "value": 1004
+      },
+      {
+        "name": "CUSTOM_EVENT_F5",
+        "value": 1005
+      },
+      {
+        "name": "CUSTOM_EVENT_F6",
+        "value": 1006
+      },
+      {
+        "name": "CUSTOM_EVENT_F7",
+        "value": 1007
+      },
+      {
+        "name": "CUSTOM_EVENT_F8",
+        "value": 1008
+      },
+      {
+        "name": "CUSTOM_EVENT_F9",
+        "value": 1009
+      },
+      {
+        "name": "CUSTOM_EVENT_F10",
+        "value": 1010
       }
     ]
   },
   {
-    "name": "VehicleAreaSeat",
-    "values": [
-      {
-        "name": "ROW_1_LEFT",
-        "value": 1
-      },
-      {
-        "name": "ROW_1_CENTER",
-        "value": 2
-      },
-      {
-        "name": "ROW_1_RIGHT",
-        "value": 4
-      },
-      {
-        "name": "ROW_2_LEFT",
-        "value": 16
-      },
-      {
-        "name": "ROW_2_CENTER",
-        "value": 32
-      },
-      {
-        "name": "ROW_2_RIGHT",
-        "value": 64
-      },
-      {
-        "name": "ROW_3_LEFT",
-        "value": 256
-      },
-      {
-        "name": "ROW_3_CENTER",
-        "value": 512
-      },
-      {
-        "name": "ROW_3_RIGHT",
-        "value": 1024
-      }
-    ]
-  },
-  {
-    "name": "VehicleVendorPermission",
-    "values": [
-      {
-        "name": "PERMISSION_DEFAULT",
-        "value": 0
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_WINDOW",
-        "value": 1
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_WINDOW",
-        "value": 2
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_DOOR",
-        "value": 3
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_DOOR",
-        "value": 4
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_SEAT",
-        "value": 5
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_SEAT",
-        "value": 6
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_MIRROR",
-        "value": 7
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_MIRROR",
-        "value": 8
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_INFO",
-        "value": 9
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_INFO",
-        "value": 10
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_ENGINE",
-        "value": 11
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_ENGINE",
-        "value": 12
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_HVAC",
-        "value": 13
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_HVAC",
-        "value": 14
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_LIGHT",
-        "value": 15
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_LIGHT",
-        "value": 16
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_1",
-        "value": 65536
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_1",
-        "value": 69632
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_2",
-        "value": 131072
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_2",
-        "value": 135168
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_3",
-        "value": 196608
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_3",
-        "value": 200704
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_4",
-        "value": 262144
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_4",
-        "value": 266240
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_5",
-        "value": 327680
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_5",
-        "value": 331776
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_6",
-        "value": 393216
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_6",
-        "value": 397312
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_7",
-        "value": 458752
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_7",
-        "value": 462848
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_8",
-        "value": 524288
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_8",
-        "value": 528384
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_9",
-        "value": 589824
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_9",
-        "value": 593920
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_10",
-        "value": 655360
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_10",
-        "value": 659456
-      },
-      {
-        "name": "PERMISSION_NOT_ACCESSIBLE",
-        "value": 4026531840
-      }
-    ]
-  },
-  {
-    "name": "VehiclePropertyAccess",
-    "values": [
-      {
-        "name": "NONE",
-        "value": 0
-      },
-      {
-        "name": "READ",
-        "value": 1
-      },
-      {
-        "name": "WRITE",
-        "value": 2
-      },
-      {
-        "name": "READ_WRITE",
-        "value": 3
-      }
-    ]
-  },
-  {
-    "name": "VmsAvailabilityStateIntegerValuesIndex",
-    "values": [
-      {
-        "name": "MESSAGE_TYPE",
-        "value": 0
-      },
-      {
-        "name": "SEQUENCE_NUMBER",
-        "value": 1
-      },
-      {
-        "name": "NUMBER_OF_ASSOCIATED_LAYERS",
-        "value": 2
-      },
-      {
-        "name": "LAYERS_START",
-        "value": 3
-      }
-    ]
-  },
-  {
-    "name": "Obd2SparkIgnitionMonitors",
-    "values": []
-  },
-  {
+    "package": "android.hardware.automotive.vehicle",
     "name": "VehicleTurnSignal",
     "values": [
       {
@@ -3407,53 +2611,1992 @@
     ]
   },
   {
-    "name": "VmsPublisherInformationIntegerValuesIndex",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "ElectronicTollCollectionCardType",
+    "values": [
+      {
+        "name": "UNKNOWN",
+        "value": 0
+      },
+      {
+        "name": "JP_ELECTRONIC_TOLL_COLLECTION_CARD",
+        "value": 1
+      },
+      {
+        "name": "JP_ELECTRONIC_TOLL_COLLECTION_CARD_V2",
+        "value": 2
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleProperty",
+    "values": [
+      {
+        "name": "Undefined property.",
+        "value": 0
+      },
+      {
+        "name": "VIN of vehicle",
+        "value": 286261504,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Manufacturer of vehicle",
+        "value": 286261505,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Model of vehicle",
+        "value": 286261506,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Model year of vehicle.",
+        "value": 289407235,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:YEAR"
+      },
+      {
+        "name": "Fuel capacity of the vehicle in milliliters",
+        "value": 291504388,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:MILLILITER"
+      },
+      {
+        "name": "List of fuels the vehicle may use.",
+        "value": 289472773,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "FuelType"
+      },
+      {
+        "name": "Nominal battery capacity for EV or hybrid vehicle",
+        "value": 291504390,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:WH"
+      },
+      {
+        "name": "List of connectors this EV may use",
+        "value": 289472775,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "data_enum": "EvConnectorType",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Fuel door location",
+        "value": 289407240,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "data_enum": "PortLocationType",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "EV port location",
+        "value": 289407241,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "PortLocationType"
+      },
+      {
+        "name": "INFO_DRIVER_SEAT",
+        "value": 356516106,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "data_enum": "VehicleAreaSeat",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Exterior dimensions of vehicle.",
+        "value": 289472779,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:MILLIMETER"
+      },
+      {
+        "name": "Multiple EV port locations",
+        "value": 289472780,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "PortLocationType"
+      },
+      {
+        "name": "Current odometer value of the vehicle",
+        "value": 291504644,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:KILOMETER"
+      },
+      {
+        "name": "Speed of the vehicle",
+        "value": 291504647,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:METER_PER_SEC"
+      },
+      {
+        "name": "Speed of the vehicle for displays",
+        "value": 291504648,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:METER_PER_SEC"
+      },
+      {
+        "name": "Front bicycle model steering angle for vehicle",
+        "value": 291504649,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:DEGREES"
+      },
+      {
+        "name": "Rear bicycle model steering angle for vehicle",
+        "value": 291504656,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:DEGREES"
+      },
+      {
+        "name": "Temperature of engine coolant",
+        "value": 291504897,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:CELSIUS"
+      },
+      {
+        "name": "Engine oil level",
+        "value": 289407747,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleOilLevel"
+      },
+      {
+        "name": "Temperature of engine oil",
+        "value": 291504900,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:CELSIUS"
+      },
+      {
+        "name": "Engine rpm",
+        "value": 291504901,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:RPM"
+      },
+      {
+        "name": "Reports wheel ticks",
+        "value": 290521862,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "FUEL_LEVEL",
+        "value": 291504903,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:MILLILITER"
+      },
+      {
+        "name": "Fuel door open",
+        "value": 287310600,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Battery level for EV or hybrid vehicle",
+        "value": 291504905,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:WH"
+      },
+      {
+        "name": "Current battery capacity for EV or hybrid vehicle",
+        "value": 291504909,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:WH"
+      },
+      {
+        "name": "EV charge port open",
+        "value": 287310602,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "EV charge port connected",
+        "value": 287310603,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "EV instantaneous charge rate in milliwatts",
+        "value": 291504908,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:MW"
+      },
+      {
+        "name": "Range remaining",
+        "value": 291504904,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "unit": "VehicleUnit:METER"
+      },
+      {
+        "name": "Tire pressure",
+        "value": 392168201,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:KILOPASCAL"
+      },
+      {
+        "name": "Critically low tire pressure",
+        "value": 392168202,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:KILOPASCAL"
+      },
+      {
+        "name": "Represents feature for engine idle automatic stop.",
+        "value": 287310624,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Currently selected gear",
+        "value": 289408000,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleGear"
+      },
+      {
+        "name": "CURRENT_GEAR",
+        "value": 289408001,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleGear"
+      },
+      {
+        "name": "Parking brake state.",
+        "value": 287310850,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "PARKING_BRAKE_AUTO_APPLY",
+        "value": 287310851,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Regenerative braking level of a electronic vehicle",
+        "value": 289408012,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Warning for fuel low level.",
+        "value": 287310853,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Night mode",
+        "value": 287310855,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "State of the vehicles turn signals",
+        "value": 289408008,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleTurnSignal"
+      },
+      {
+        "name": "Represents ignition state",
+        "value": 289408009,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleIgnitionState"
+      },
+      {
+        "name": "ABS is active",
+        "value": 287310858,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Traction Control is active",
+        "value": 287310859,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Represents property for the current stopping mode of the vehicle.",
+        "value": 289408013,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "EvStoppingMode"
+      },
+      {
+        "name": "HVAC Properties",
+        "value": 356517120,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Fan direction setting",
+        "value": 356517121,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleHvacFanDirection"
+      },
+      {
+        "name": "HVAC current temperature.",
+        "value": 358614274,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:CELSIUS"
+      },
+      {
+        "name": "HVAC_TEMPERATURE_SET",
+        "value": 358614275,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "unit": "VehicleUnit:CELSIUS"
+      },
+      {
+        "name": "HVAC_DEFROSTER",
+        "value": 320865540,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "HVAC_AC_ON",
+        "value": 354419973,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "config_flags": "Supported"
+      },
+      {
+        "name": "HVAC_MAX_AC_ON",
+        "value": 354419974,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "HVAC_MAX_DEFROST_ON",
+        "value": 354419975,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "HVAC_RECIRC_ON",
+        "value": 354419976,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Enable temperature coupling between areas.",
+        "value": 354419977,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "HVAC_AUTO_ON",
+        "value": 354419978,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "HVAC_SEAT_TEMPERATURE",
+        "value": 356517131,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Side Mirror Heat",
+        "value": 339739916,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "HVAC_STEERING_WHEEL_HEAT",
+        "value": 289408269,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Temperature units for display",
+        "value": 289408270,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleUnit"
+      },
+      {
+        "name": "Actual fan speed",
+        "value": 356517135,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "HVAC_POWER_ON",
+        "value": 354419984,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Fan Positions Available",
+        "value": 356582673,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleHvacFanDirection"
+      },
+      {
+        "name": "HVAC_AUTO_RECIRC_ON",
+        "value": 354419986,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat ventilation",
+        "value": 356517139,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "HVAC_ELECTRIC_DEFROSTER_ON",
+        "value": 320865556,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Suggested values for setting HVAC temperature.",
+        "value": 291570965,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Distance units for display",
+        "value": 289408512,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleUnit"
+      },
+      {
+        "name": "Fuel volume units for display",
+        "value": 289408513,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleUnit"
+      },
+      {
+        "name": "Tire pressure units for display",
+        "value": 289408514,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleUnit"
+      },
+      {
+        "name": "EV battery units for display",
+        "value": 289408515,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleUnit"
+      },
+      {
+        "name": "Fuel consumption units for display",
+        "value": 287311364,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Speed units for display",
+        "value": 289408517,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "ANDROID_EPOCH_TIME",
+        "value": 290457094,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:WRITE",
+        "unit": "VehicleUnit:MILLI_SECS"
+      },
+      {
+        "name": "External encryption binding seed.",
+        "value": 292554247,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Outside temperature",
+        "value": 291505923,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:CELSIUS"
+      },
+      {
+        "name": "Property to control power state of application processor",
+        "value": 289475072,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Property to report power state of application processor",
+        "value": 289475073,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "AP_POWER_BOOTUP_REASON",
+        "value": 289409538,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Property to represent brightness of the display.",
+        "value": 289409539,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Property to represent brightness of the displays which are controlled separately.",
+        "value": 289475076,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "HW_KEY_INPUT",
+        "value": 289475088,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "config_flags": ""
+      },
+      {
+        "name": "HW_KEY_INPUT_V2",
+        "value": 367004177,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "config_flags": ""
+      },
+      {
+        "name": "HW_MOTION_INPUT",
+        "value": 367004178,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "config_flags": ""
+      },
+      {
+        "name": "HW_ROTARY_INPUT",
+        "value": 289475104,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "data_enum": "RotaryInputType",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Defines a custom OEM partner input event.",
+        "value": 289475120,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "data_enum": "CustomInputType",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "DOOR_POS",
+        "value": 373295872,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Door move",
+        "value": 373295873,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Door lock",
+        "value": 371198722,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Door child lock feature enabled",
+        "value": 371198723,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Mirror Z Position",
+        "value": 339741504,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Mirror Z Move",
+        "value": 339741505,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Mirror Y Position",
+        "value": 339741506,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Mirror Y Move",
+        "value": 339741507,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Mirror Lock",
+        "value": 287312708,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Mirror Fold",
+        "value": 287312709,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Represents property for Mirror Auto Fold feature.",
+        "value": 337644358,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Represents property for Mirror Auto Tilt feature.",
+        "value": 337644359,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat memory select",
+        "value": 356518784,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:WRITE"
+      },
+      {
+        "name": "Seat memory set",
+        "value": 356518785,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:WRITE"
+      },
+      {
+        "name": "Seatbelt buckled",
+        "value": 354421634,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seatbelt height position",
+        "value": 356518787,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seatbelt height move",
+        "value": 356518788,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "SEAT_FORE_AFT_POS",
+        "value": 356518789,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "SEAT_FORE_AFT_MOVE",
+        "value": 356518790,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat backrest angle 1 position",
+        "value": 356518791,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat backrest angle 1 move",
+        "value": 356518792,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat backrest angle 2 position",
+        "value": 356518793,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat backrest angle 2 move",
+        "value": 356518794,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat height position",
+        "value": 356518795,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat height move",
+        "value": 356518796,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat depth position",
+        "value": 356518797,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat depth move",
+        "value": 356518798,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat tilt position",
+        "value": 356518799,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat tilt move",
+        "value": 356518800,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "SEAT_LUMBAR_FORE_AFT_POS",
+        "value": 356518801,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "SEAT_LUMBAR_FORE_AFT_MOVE",
+        "value": 356518802,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Lumbar side support position",
+        "value": 356518803,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Lumbar side support move",
+        "value": 356518804,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "SEAT_HEADREST_HEIGHT_POS",
+        "value": 289409941,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Headrest height position",
+        "value": 356518820,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Headrest height move",
+        "value": 356518806,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Headrest angle position",
+        "value": 356518807,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Headrest angle move",
+        "value": 356518808,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "SEAT_HEADREST_FORE_AFT_POS",
+        "value": 356518809,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "SEAT_HEADREST_FORE_AFT_MOVE",
+        "value": 356518810,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Represents property for the seat footwell lights state.",
+        "value": 356518811,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleLightState"
+      },
+      {
+        "name": "Represents property for the seat footwell lights switch.",
+        "value": 356518812,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleLightSwitch"
+      },
+      {
+        "name": "Represents property for Seat easy access feature.",
+        "value": 354421661,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "SEAT_AIRBAG_ENABLED",
+        "value": 354421662,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "SEAT_CUSHION_SIDE_SUPPORT_POS",
+        "value": 356518815,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Represents property for movement direction and speed of seat cushion side support.",
+        "value": 356518816,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "SEAT_LUMBAR_VERTICAL_POS",
+        "value": 356518817,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Represents property for vertical movement direction and speed of seat lumbar support.",
+        "value": 356518818,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "SEAT_WALK_IN_POS",
+        "value": 356518819,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat Occupancy",
+        "value": 356518832,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleSeatOccupancyState"
+      },
+      {
+        "name": "Window Position",
+        "value": 322964416,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Window Move",
+        "value": 322964417,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Window Lock",
+        "value": 320867268,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "WINDSHIELD_WIPERS_PERIOD",
+        "value": 322964421,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:MILLI_SECS"
+      },
+      {
+        "name": "Windshield wipers state.",
+        "value": 322964422,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "WindshieldWipersState"
+      },
+      {
+        "name": "Windshield wipers switch.",
+        "value": 322964423,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "WindshieldWipersSwitch"
+      },
+      {
+        "name": "Steering wheel depth position",
+        "value": 289410016,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Steering wheel depth movement",
+        "value": 289410017,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Steering wheel height position",
+        "value": 289410018,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Steering wheel height movement",
+        "value": 289410019,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Steering wheel theft lock feature enabled",
+        "value": 287312868,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Steering wheel locked",
+        "value": 287312869,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Steering wheel easy access feature enabled",
+        "value": 287312870,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Property that represents the current position of the glove box door.",
+        "value": 356518896,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Lock or unlock the glove box.",
+        "value": 354421745,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "VEHICLE_MAP_SERVICE",
+        "value": 299895808,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Characterization of inputs used for computing location.",
+        "value": 289410064,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "OBD2 Live Sensor Data",
+        "value": 299896064,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "OBD2 Freeze Frame Sensor Data",
+        "value": 299896065,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "OBD2 Freeze Frame Information",
+        "value": 299896066,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "OBD2 Freeze Frame Clear",
+        "value": 299896067,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:WRITE"
+      },
+      {
+        "name": "Headlights State",
+        "value": 289410560,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleLightState"
+      },
+      {
+        "name": "High beam lights state",
+        "value": 289410561,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleLightState"
+      },
+      {
+        "name": "Fog light state",
+        "value": 289410562,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleLightState"
+      },
+      {
+        "name": "Hazard light status",
+        "value": 289410563,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleLightState"
+      },
+      {
+        "name": "Headlight switch",
+        "value": 289410576,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleLightSwitch"
+      },
+      {
+        "name": "High beam light switch",
+        "value": 289410577,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleLightSwitch"
+      },
+      {
+        "name": "Fog light switch",
+        "value": 289410578,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleLightSwitch"
+      },
+      {
+        "name": "Hazard light switch",
+        "value": 289410579,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleLightSwitch"
+      },
+      {
+        "name": "Cabin lights",
+        "value": 289410817,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleLightState"
+      },
+      {
+        "name": "Cabin lights switch",
+        "value": 289410818,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleLightSwitch"
+      },
+      {
+        "name": "Reading lights",
+        "value": 356519683,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleLightState"
+      },
+      {
+        "name": "Reading lights switch",
+        "value": 356519684,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleLightSwitch"
+      },
+      {
+        "name": "Steering wheel lights state",
+        "value": 289410828,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleLightState"
+      },
+      {
+        "name": "Steering wheel lights switch",
+        "value": 289410829,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleLightSwitch"
+      },
+      {
+        "name": "Support customize permissions for vendor properties",
+        "value": 287313669,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Allow disabling optional featurs from vhal.",
+        "value": 286265094,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Defines the initial Android user to be used during initialization.",
+        "value": 299896583,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Defines a request to switch the foreground Android user.",
+        "value": 299896584,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Called by the Android System after an Android user was created.",
+        "value": 299896585,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Called by the Android System after an Android user was removed.",
+        "value": 299896586,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:WRITE"
+      },
+      {
+        "name": "USER_IDENTIFICATION_ASSOCIATION",
+        "value": 299896587,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "EVS_SERVICE_REQUEST",
+        "value": 289476368,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Defines a request to apply power policy.",
+        "value": 286265121,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "POWER_POLICY_GROUP_REQ",
+        "value": 286265122,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Notifies the current power policy to VHAL layer.",
+        "value": 286265123,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "WATCHDOG_ALIVE",
+        "value": 290459441,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:WRITE"
+      },
+      {
+        "name": "Defines a process terminated by car watchdog and the reason of termination.",
+        "value": 299896626,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:WRITE"
+      },
+      {
+        "name": "Defines an event that VHAL signals to car watchdog as a heartbeat.",
+        "value": 290459443,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Starts the ClusterUI in cluster display.",
+        "value": 289410868,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Changes the state of the cluster display.",
+        "value": 289476405,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Reports the current display state and ClusterUI state.",
+        "value": 299896630,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:WRITE"
+      },
+      {
+        "name": "Requests to change the cluster display state to show some ClusterUI.",
+        "value": 289410871,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:WRITE"
+      },
+      {
+        "name": "Informs the current navigation state.",
+        "value": 292556600,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:WRITE"
+      },
+      {
+        "name": "Electronic Toll Collection card type.",
+        "value": 289410873,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "ElectronicTollCollectionCardType"
+      },
+      {
+        "name": "Electronic Toll Collection card status.",
+        "value": 289410874,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "ElectronicTollCollectionCardStatus"
+      },
+      {
+        "name": "Front fog lights state",
+        "value": 289410875,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleLightState"
+      },
+      {
+        "name": "Front fog lights switch",
+        "value": 289410876,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleLightSwitch"
+      },
+      {
+        "name": "Rear fog lights state",
+        "value": 289410877,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleLightState"
+      },
+      {
+        "name": "Rear fog lights switch",
+        "value": 289410878,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleLightSwitch"
+      },
+      {
+        "name": "Indicates the maximum current draw threshold for charging set by the user",
+        "value": 291508031,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "unit": "VehicleUnit:AMPERE"
+      },
+      {
+        "name": "Indicates the maximum charge percent threshold set by the user",
+        "value": 291508032,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Charging state of the car",
+        "value": 289410881,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "EvChargeState"
+      },
+      {
+        "name": "Start or stop charging the EV battery",
+        "value": 287313730,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Estimated charge time remaining in seconds",
+        "value": 289410883,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:SECS"
+      },
+      {
+        "name": "EV_REGENERATIVE_BRAKING_STATE",
+        "value": 289410884,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "EvRegenerativeBrakingState"
+      },
+      {
+        "name": "Indicates if there is a trailer present or not.",
+        "value": 289410885,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "TrailerState"
+      },
+      {
+        "name": "VEHICLE_CURB_WEIGHT",
+        "value": 289410886,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:KILOGRAM"
+      },
+      {
+        "name": "GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT",
+        "value": 289410887,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "GsrComplianceRequirementType"
+      },
+      {
+        "name": "SUPPORTED_PROPERTY_IDS",
+        "value": 289476424,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Request the head unit to be shutdown.",
+        "value": 289410889,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:WRITE",
+        "data_enum": "VehicleApPowerStateShutdownParam"
+      },
+      {
+        "name": "Whether the vehicle is currently in use.",
+        "value": 287313738,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Start of ADAS Properties",
+        "value": 287313920,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "AUTOMATIC_EMERGENCY_BRAKING_STATE",
+        "value": 289411073,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "ErrorState"
+      },
+      {
+        "name": "FORWARD_COLLISION_WARNING_ENABLED",
+        "value": 287313922,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "FORWARD_COLLISION_WARNING_STATE",
+        "value": 289411075,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "ErrorState"
+      },
+      {
+        "name": "BLIND_SPOT_WARNING_ENABLED",
+        "value": 287313924,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "BLIND_SPOT_WARNING_STATE",
+        "value": 339742725,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "ErrorState"
+      },
+      {
+        "name": "LANE_DEPARTURE_WARNING_ENABLED",
+        "value": 287313926,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "LANE_DEPARTURE_WARNING_STATE",
+        "value": 289411079,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "ErrorState"
+      },
+      {
+        "name": "LANE_KEEP_ASSIST_ENABLED",
+        "value": 287313928,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "LANE_KEEP_ASSIST_STATE",
+        "value": 289411081,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "ErrorState"
+      },
+      {
+        "name": "LANE_CENTERING_ASSIST_ENABLED",
+        "value": 287313930,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "LANE_CENTERING_ASSIST_COMMAND",
+        "value": 289411083,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:WRITE",
+        "data_enum": "LaneCenteringAssistCommand"
+      },
+      {
+        "name": "LANE_CENTERING_ASSIST_STATE",
+        "value": 289411084,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "ErrorState"
+      },
+      {
+        "name": "EMERGENCY_LANE_KEEP_ASSIST_ENABLED",
+        "value": 287313933
+      },
+      {
+        "name": "EMERGENCY_LANE_KEEP_ASSIST_STATE",
+        "value": 289411086,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "ErrorState"
+      },
+      {
+        "name": "CRUISE_CONTROL_ENABLED",
+        "value": 287313935,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "CRUISE_CONTROL_TYPE",
+        "value": 289411088,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "ErrorState"
+      },
+      {
+        "name": "CRUISE_CONTROL_STATE",
+        "value": 289411089,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "ErrorState"
+      },
+      {
+        "name": "CRUISE_CONTROL_COMMAND",
+        "value": 289411090,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:WRITE",
+        "data_enum": "CruiseControlCommand"
+      },
+      {
+        "name": "CRUISE_CONTROL_TARGET_SPEED",
+        "value": 291508243,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:METER_PER_SEC"
+      },
+      {
+        "name": "ADAPTIVE_CRUISE_CONTROL_TARGET_TIME_GAP",
+        "value": 289411092,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "unit": "VehicleUnit:MILLI_SECS"
+      },
+      {
+        "name": "ADAPTIVE_CRUISE_CONTROL_LEAD_VEHICLE_MEASURED_DISTANCE",
+        "value": 289411093,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:MILLIMETER"
+      },
+      {
+        "name": "HANDS_ON_DETECTION_ENABLED",
+        "value": 287313942,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "HANDS_ON_DETECTION_DRIVER_STATE",
+        "value": 289411095,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "ErrorState"
+      },
+      {
+        "name": "HANDS_ON_DETECTION_WARNING",
+        "value": 289411096,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "ErrorState"
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "DiagnosticIntegerSensorIndex",
+    "values": [
+      {
+        "name": "FUEL_SYSTEM_STATUS",
+        "value": 0
+      },
+      {
+        "name": "MALFUNCTION_INDICATOR_LIGHT_ON",
+        "value": 1
+      },
+      {
+        "name": "IGNITION_MONITORS_SUPPORTED",
+        "value": 2
+      },
+      {
+        "name": "IGNITION_SPECIFIC_MONITORS",
+        "value": 3
+      },
+      {
+        "name": "INTAKE_AIR_TEMPERATURE",
+        "value": 4
+      },
+      {
+        "name": "COMMANDED_SECONDARY_AIR_STATUS",
+        "value": 5
+      },
+      {
+        "name": "NUM_OXYGEN_SENSORS_PRESENT",
+        "value": 6
+      },
+      {
+        "name": "RUNTIME_SINCE_ENGINE_START",
+        "value": 7
+      },
+      {
+        "name": "DISTANCE_TRAVELED_WITH_MALFUNCTION_INDICATOR_LIGHT_ON",
+        "value": 8
+      },
+      {
+        "name": "WARMUPS_SINCE_CODES_CLEARED",
+        "value": 9
+      },
+      {
+        "name": "DISTANCE_TRAVELED_SINCE_CODES_CLEARED",
+        "value": 10
+      },
+      {
+        "name": "ABSOLUTE_BAROMETRIC_PRESSURE",
+        "value": 11
+      },
+      {
+        "name": "CONTROL_MODULE_VOLTAGE",
+        "value": 12
+      },
+      {
+        "name": "AMBIENT_AIR_TEMPERATURE",
+        "value": 13
+      },
+      {
+        "name": "TIME_WITH_MALFUNCTION_LIGHT_ON",
+        "value": 14
+      },
+      {
+        "name": "TIME_SINCE_TROUBLE_CODES_CLEARED",
+        "value": 15
+      },
+      {
+        "name": "MAX_FUEL_AIR_EQUIVALENCE_RATIO",
+        "value": 16
+      },
+      {
+        "name": "MAX_OXYGEN_SENSOR_VOLTAGE",
+        "value": 17
+      },
+      {
+        "name": "MAX_OXYGEN_SENSOR_CURRENT",
+        "value": 18
+      },
+      {
+        "name": "MAX_INTAKE_MANIFOLD_ABSOLUTE_PRESSURE",
+        "value": 19
+      },
+      {
+        "name": "MAX_AIR_FLOW_RATE_FROM_MASS_AIR_FLOW_SENSOR",
+        "value": 20
+      },
+      {
+        "name": "FUEL_TYPE",
+        "value": 21
+      },
+      {
+        "name": "FUEL_RAIL_ABSOLUTE_PRESSURE",
+        "value": 22
+      },
+      {
+        "name": "ENGINE_OIL_TEMPERATURE",
+        "value": 23
+      },
+      {
+        "name": "DRIVER_DEMAND_PERCENT_TORQUE",
+        "value": 24
+      },
+      {
+        "name": "ENGINE_ACTUAL_PERCENT_TORQUE",
+        "value": 25
+      },
+      {
+        "name": "ENGINE_REFERENCE_PERCENT_TORQUE",
+        "value": 26
+      },
+      {
+        "name": "ENGINE_PERCENT_TORQUE_DATA_IDLE",
+        "value": 27
+      },
+      {
+        "name": "ENGINE_PERCENT_TORQUE_DATA_POINT1",
+        "value": 28
+      },
+      {
+        "name": "ENGINE_PERCENT_TORQUE_DATA_POINT2",
+        "value": 29
+      },
+      {
+        "name": "ENGINE_PERCENT_TORQUE_DATA_POINT3",
+        "value": 30
+      },
+      {
+        "name": "ENGINE_PERCENT_TORQUE_DATA_POINT4",
+        "value": 31
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleUnit",
+    "values": [
+      {
+        "name": "SHOULD_NOT_USE",
+        "value": 0
+      },
+      {
+        "name": "METER_PER_SEC",
+        "value": 1
+      },
+      {
+        "name": "RPM",
+        "value": 2
+      },
+      {
+        "name": "HERTZ",
+        "value": 3
+      },
+      {
+        "name": "PERCENTILE",
+        "value": 16
+      },
+      {
+        "name": "MILLIMETER",
+        "value": 32
+      },
+      {
+        "name": "METER",
+        "value": 33
+      },
+      {
+        "name": "KILOMETER",
+        "value": 35
+      },
+      {
+        "name": "MILE",
+        "value": 36
+      },
+      {
+        "name": "CELSIUS",
+        "value": 48
+      },
+      {
+        "name": "FAHRENHEIT",
+        "value": 49
+      },
+      {
+        "name": "KELVIN",
+        "value": 50
+      },
+      {
+        "name": "MILLILITER",
+        "value": 64
+      },
+      {
+        "name": "LITER",
+        "value": 65
+      },
+      {
+        "name": "GALLON",
+        "value": 66
+      },
+      {
+        "name": "US_GALLON",
+        "value": 66
+      },
+      {
+        "name": "IMPERIAL_GALLON",
+        "value": 67
+      },
+      {
+        "name": "NANO_SECS",
+        "value": 80
+      },
+      {
+        "name": "MILLI_SECS",
+        "value": 81
+      },
+      {
+        "name": "SECS",
+        "value": 83
+      },
+      {
+        "name": "YEAR",
+        "value": 89
+      },
+      {
+        "name": "WATT_HOUR",
+        "value": 96
+      },
+      {
+        "name": "MILLIAMPERE",
+        "value": 97
+      },
+      {
+        "name": "MILLIVOLT",
+        "value": 98
+      },
+      {
+        "name": "MILLIWATTS",
+        "value": 99
+      },
+      {
+        "name": "AMPERE_HOURS",
+        "value": 100
+      },
+      {
+        "name": "KILOWATT_HOUR",
+        "value": 101
+      },
+      {
+        "name": "AMPERE",
+        "value": 102
+      },
+      {
+        "name": "KILOPASCAL",
+        "value": 112
+      },
+      {
+        "name": "PSI",
+        "value": 113
+      },
+      {
+        "name": "BAR",
+        "value": 114
+      },
+      {
+        "name": "DEGREES",
+        "value": 128
+      },
+      {
+        "name": "MILES_PER_HOUR",
+        "value": 144
+      },
+      {
+        "name": "KILOMETERS_PER_HOUR",
+        "value": 145
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "LaneCenteringAssistCommand",
+    "values": [
+      {
+        "name": "ACTIVATE",
+        "value": 1
+      },
+      {
+        "name": "DEACTIVATE",
+        "value": 2
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "Obd2FuelType",
+    "values": [
+      {
+        "name": "NOT_AVAILABLE",
+        "value": 0
+      },
+      {
+        "name": "GASOLINE",
+        "value": 1
+      },
+      {
+        "name": "METHANOL",
+        "value": 2
+      },
+      {
+        "name": "ETHANOL",
+        "value": 3
+      },
+      {
+        "name": "DIESEL",
+        "value": 4
+      },
+      {
+        "name": "LPG",
+        "value": 5
+      },
+      {
+        "name": "CNG",
+        "value": 6
+      },
+      {
+        "name": "PROPANE",
+        "value": 7
+      },
+      {
+        "name": "ELECTRIC",
+        "value": 8
+      },
+      {
+        "name": "BIFUEL_RUNNING_GASOLINE",
+        "value": 9
+      },
+      {
+        "name": "BIFUEL_RUNNING_METHANOL",
+        "value": 10
+      },
+      {
+        "name": "BIFUEL_RUNNING_ETHANOL",
+        "value": 11
+      },
+      {
+        "name": "BIFUEL_RUNNING_LPG",
+        "value": 12
+      },
+      {
+        "name": "BIFUEL_RUNNING_CNG",
+        "value": 13
+      },
+      {
+        "name": "BIFUEL_RUNNING_PROPANE",
+        "value": 14
+      },
+      {
+        "name": "BIFUEL_RUNNING_ELECTRIC",
+        "value": 15
+      },
+      {
+        "name": "BIFUEL_RUNNING_ELECTRIC_AND_COMBUSTION",
+        "value": 16
+      },
+      {
+        "name": "HYBRID_GASOLINE",
+        "value": 17
+      },
+      {
+        "name": "HYBRID_ETHANOL",
+        "value": 18
+      },
+      {
+        "name": "HYBRID_DIESEL",
+        "value": 19
+      },
+      {
+        "name": "HYBRID_ELECTRIC",
+        "value": 20
+      },
+      {
+        "name": "HYBRID_RUNNING_ELECTRIC_AND_COMBUSTION",
+        "value": 21
+      },
+      {
+        "name": "HYBRID_REGENERATIVE",
+        "value": 22
+      },
+      {
+        "name": "BIFUEL_RUNNING_DIESEL",
+        "value": 23
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "ProcessTerminationReason",
+    "values": [
+      {
+        "name": "NOT_RESPONDING",
+        "value": 1
+      },
+      {
+        "name": "IO_OVERUSE",
+        "value": 2
+      },
+      {
+        "name": "MEMORY_OVERUSE",
+        "value": 3
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VmsMessageWithLayerAndPublisherIdIntegerValuesIndex",
     "values": [
       {
         "name": "MESSAGE_TYPE",
         "value": 0
       },
       {
-        "name": "PUBLISHER_ID",
-        "value": 1
-      }
-    ]
-  },
-  {
-    "name": "RotaryInputType",
-    "values": [
-      {
-        "name": "ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION",
-        "value": 0
-      },
-      {
-        "name": "ROTARY_INPUT_TYPE_AUDIO_VOLUME",
-        "value": 1
-      }
-    ]
-  },
-  {
-    "name": "Obd2FuelSystemStatus",
-    "values": [
-      {
-        "name": "OPEN_INSUFFICIENT_ENGINE_TEMPERATURE",
+        "name": "LAYER_TYPE",
         "value": 1
       },
       {
-        "name": "CLOSED_LOOP",
+        "name": "LAYER_SUBTYPE",
         "value": 2
       },
       {
-        "name": "OPEN_ENGINE_LOAD_OR_DECELERATION",
+        "name": "LAYER_VERSION",
+        "value": 3
+      },
+      {
+        "name": "PUBLISHER_ID",
         "value": 4
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "EvChargeState",
+    "values": [
+      {
+        "name": "UNKNOWN",
+        "value": 0
       },
       {
-        "name": "OPEN_SYSTEM_FAILURE",
-        "value": 8
+        "name": "CHARGING",
+        "value": 1
       },
       {
-        "name": "CLOSED_LOOP_BUT_FEEDBACK_FAULT",
-        "value": 16
+        "name": "FULLY_CHARGED",
+        "value": 2
+      },
+      {
+        "name": "NOT_CHARGING",
+        "value": 3
+      },
+      {
+        "name": "ERROR",
+        "value": 4
       }
     ]
   }
diff --git a/automotive/vehicle/aidl/emu_metadata/generate_emulator_metadata.py b/automotive/vehicle/aidl/emu_metadata/generate_emulator_metadata.py
index b2eb172..5706571 100755
--- a/automotive/vehicle/aidl/emu_metadata/generate_emulator_metadata.py
+++ b/automotive/vehicle/aidl/emu_metadata/generate_emulator_metadata.py
@@ -19,23 +19,56 @@
 
 from pathlib import Path
 
+RE_PACKAGE = re.compile(r"\npackage\s([\.a-z0-9]*);")
+RE_IMPORT = re.compile(r"\nimport\s([\.a-zA-Z0-9]*);")
 RE_ENUM = re.compile(r"\s*enum\s+(\w*) {\n(.*)}", re.MULTILINE | re.DOTALL)
-RE_COMMENT = re.compile(r"(?:(?:\/\*\*)((?:.|\n)*?)(?:\*\/))?(?:\n|^)\s*(\w*)(?:\s+=\s*)?((?:[a-zA-Z0-9]|\s|\+|)*),", re.DOTALL)
+RE_COMMENT = re.compile(r"(?:(?:\/\*\*)((?:.|\n)*?)(?:\*\/))?(?:\n|^)\s*(\w*)(?:\s+=\s*)?((?:[\.\-a-zA-Z0-9]|\s|\+|)*),",
+                        re.DOTALL)
 RE_BLOCK_COMMENT_TITLE = re.compile("^(?:\s|\*)*((?:\w|\s|\.)*)\n(?:\s|\*)*(?:\n|$)")
-RE_BLOCK_COMMENT_ANNOTATION = re.compile("^(?:\s|\*)*@(\w*)\s+((?:\w|:)*)", re.MULTILINE)
-RE_HEX_NUMBER = re.compile("([0-9A-Fa-fxX]+)")
+RE_BLOCK_COMMENT_ANNOTATION = re.compile("^(?:\s|\*)*@(\w*)\s+((?:[\w:\.])*)", re.MULTILINE)
+RE_HEX_NUMBER = re.compile("([\.\-0-9A-Za-z]+)")
 
 
 class JEnum:
-    def __init__(self, name):
+    def __init__(self, package, name):
+        self.package = package
         self.name = name
         self.values = []
 
+class Enum:
+    def __init__(self, package, name, text, imports):
+        self.text = text
+        self.parsed = False
+        self.imports = imports
+        self.jenum = JEnum(package, name)
 
-class Converter:
-    # Only addition is supported for now, but that covers all existing properties except
-    # OBD diagnostics, which use bitwise shifts
-    def calculateValue(self, expression, default_value):
+    def parse(self, enums):
+        if self.parsed:
+            return
+        for dep in self.imports:
+            enums[dep].parse(enums)
+        print("Parsing " + self.jenum.name)
+        matches = RE_COMMENT.findall(self.text)
+        defaultValue = 0
+        for match in matches:
+            value = dict()
+            value['name'] = match[1]
+            value['value'] = self.calculateValue(match[2], defaultValue, enums)
+            defaultValue = value['value'] + 1
+            if self.jenum.name == "VehicleProperty":
+                block_comment = match[0]
+                self.parseBlockComment(value, block_comment)
+            self.jenum.values.append(value)
+        self.parsed = True
+        self.text = None
+
+    def get_value(self, value_name):
+        for value in self.jenum.values:
+            if value['name'] == value_name:
+                return value['value']
+        raise Exception("Cannot decode value: " + self.jenum.package + " : " + value_name)
+
+    def calculateValue(self, expression, default_value, enums):
         numbers = RE_HEX_NUMBER.findall(expression)
         if len(numbers) == 0:
             return default_value
@@ -44,7 +77,13 @@
         if numbers[0].lower().startswith("0x"):
             base = 16
         for number in numbers:
-            result += int(number, base)
+            if '.' in number:
+                package, val_name = number.split('.')
+                for dep in self.imports:
+                    if package in dep:
+                        result += enums[dep].get_value(val_name)
+            else:
+                result += int(number, base)
         return result
 
     def parseBlockComment(self, value, blockComment):
@@ -54,30 +93,22 @@
             break
         annots_res = RE_BLOCK_COMMENT_ANNOTATION.findall(blockComment)
         for annot in annots_res:
-            value[annot[0]] = annot[1]
+            value[annot[0]] = annot[1].replace(".", ":")
 
-    def parseEnumContents(self, enum: JEnum, enumValue):
-        matches = RE_COMMENT.findall(enumValue)
-        defaultValue = 0
-        for match in matches:
-            value = dict()
-            value['name'] = match[1]
-            value['value'] = self.calculateValue(match[2], defaultValue)
-            defaultValue = value['value'] + 1
-            if enum.name == "VehicleProperty":
-                block_comment = match[0]
-                self.parseBlockComment(value, block_comment)
-            enum.values.append(value)
-
+class Converter:
+    # Only addition is supported for now, but that covers all existing properties except
+    # OBD diagnostics, which use bitwise shifts
     def convert(self, input):
         text = Path(input).read_text()
         matches = RE_ENUM.findall(text)
-        jenums = []
+        package = RE_PACKAGE.findall(text)[0]
+        imports = RE_IMPORT.findall(text)
+        enums = []
         for match in matches:
-            enum = JEnum(match[0])
-            self.parseEnumContents(enum, match[1])
-            jenums.append(enum)
-        return jenums
+            enum = Enum(package, match[0], match[1], imports)
+            enums.append(enum)
+        return enums
+
 
 def main():
     if (len(sys.argv) != 3):
@@ -85,10 +116,18 @@
         sys.exit(1)
     aidl_path = sys.argv[1]
     out_path = sys.argv[2]
-    result = []
+    enums_dict = dict()
     for file in os.listdir(aidl_path):
-        result.extend(Converter().convert(os.path.join(aidl_path, file)))
-    json_result = json.dumps(result, default=vars, indent=2)
+        enums = Converter().convert(os.path.join(aidl_path, file))
+        for enum in enums:
+            enums_dict[enum.jenum.package + "." + enum.jenum.name] = enum
+
+    result = []
+    for enum_name, enum in enums_dict.items():
+        enum.parse(enums_dict)
+        result.append(enum.jenum.__dict__)
+
+    json_result = json.dumps(result, default=None, indent=2)
     with open(out_path, 'w') as f:
         f.write(json_result)
 
diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/LinearFakeValueGenerator.h b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/LinearFakeValueGenerator.h
index d2b701d..2378676 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/LinearFakeValueGenerator.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/LinearFakeValueGenerator.h
@@ -57,7 +57,7 @@
         float dispersion;    //  Defines minimum and maximum value based on initial value.
         float increment;     //  Value that we will be added to currentValue with each timer tick.
         int64_t interval;
-        long lastEventTimestamp;
+        int64_t lastEventTimestamp;
     };
 
     GeneratorCfg mGenCfg;
diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/LinearFakeValueGenerator.cpp b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/LinearFakeValueGenerator.cpp
index 9133144..fe08dcf 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/LinearFakeValueGenerator.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/LinearFakeValueGenerator.cpp
@@ -86,7 +86,7 @@
     if (mGenCfg.lastEventTimestamp == 0) {
         mGenCfg.lastEventTimestamp = elapsedRealtimeNano();
     } else {
-        long nextEventTime = mGenCfg.lastEventTimestamp + mGenCfg.interval;
+        int64_t nextEventTime = mGenCfg.lastEventTimestamp + mGenCfg.interval;
         // Prevent overflow.
         assert(nextEventTime > mGenCfg.lastEventTimestamp);
         mGenCfg.lastEventTimestamp = nextEventTime;
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 c3ebd3b..af1bb1d 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -99,12 +99,17 @@
     const std::shared_ptr<VehiclePropValuePool> mValuePool;
     const std::shared_ptr<VehiclePropertyStore> mServerSidePropStore;
 
+    const std::string mDefaultConfigDir;
+    const std::string mOverrideConfigDir;
+
     ValueResultType getValue(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
 
     VhalResult<void> setValue(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
 
+    bool UseOverrideConfigDir();
+
   private:
     // Expose private methods to unit test.
     friend class FakeVehicleHardwareTestHelper;
@@ -156,8 +161,6 @@
                                   aidl::android::hardware::automotive::vehicle::SetValueRequest>
             mPendingSetValueRequests;
 
-    const std::string mDefaultConfigDir;
-    const std::string mOverrideConfigDir;
     const bool mForceOverride;
     bool mAddExtraTestVendorConfigs;
 
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 3f5e4c4..250a226 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -39,7 +39,6 @@
 #include <dirent.h>
 #include <inttypes.h>
 #include <sys/types.h>
-#include <fstream>
 #include <regex>
 #include <unordered_set>
 #include <vector>
@@ -205,9 +204,10 @@
 
         // Create a separate instance for each individual zone
         VehiclePropValue prop = {
+                .timestamp = elapsedRealtimeNano(),
                 .areaId = curArea,
                 .prop = propId,
-                .timestamp = elapsedRealtimeNano(),
+                .value = {},
         };
 
         if (config.initialAreaValues.empty()) {
@@ -240,6 +240,8 @@
                                          std::string overrideConfigDir, bool forceOverride)
     : mValuePool(std::make_unique<VehiclePropValuePool>()),
       mServerSidePropStore(new VehiclePropertyStore(mValuePool)),
+      mDefaultConfigDir(defaultConfigDir),
+      mOverrideConfigDir(overrideConfigDir),
       mFakeObd2Frame(new obd2frame::FakeObd2Frame(mServerSidePropStore)),
       mFakeUserHal(new FakeUserHal(mValuePool)),
       mRecurrentTimer(new RecurrentTimer()),
@@ -247,8 +249,6 @@
               [this](const VehiclePropValue& value) { eventFromVehicleBus(value); })),
       mPendingGetValueRequests(this),
       mPendingSetValueRequests(this),
-      mDefaultConfigDir(defaultConfigDir),
-      mOverrideConfigDir(overrideConfigDir),
       mForceOverride(forceOverride) {
     init();
 }
@@ -259,11 +259,15 @@
     mGeneratorHub.reset();
 }
 
+bool FakeVehicleHardware::UseOverrideConfigDir() {
+    return mForceOverride ||
+           android::base::GetBoolProperty(OVERRIDE_PROPERTY, /*default_value=*/false);
+}
+
 std::unordered_map<int32_t, ConfigDeclaration> FakeVehicleHardware::loadConfigDeclarations() {
     std::unordered_map<int32_t, ConfigDeclaration> configsByPropId;
     loadPropConfigsFromDir(mDefaultConfigDir, &configsByPropId);
-    if (mForceOverride ||
-        android::base::GetBoolProperty(OVERRIDE_PROPERTY, /*default_value=*/false)) {
+    if (UseOverrideConfigDir()) {
         loadPropConfigsFromDir(mOverrideConfigDir, &configsByPropId);
     }
     return configsByPropId;
@@ -938,7 +942,7 @@
                    << StringPrintf("failed to get special value: %d, error: %s", value.prop,
                                    getErrorMsg(result).c_str());
         } else {
-            return std::move(result);
+            return result;
         }
     }
 
@@ -953,7 +957,7 @@
         }
     }
 
-    return std::move(readResult);
+    return readResult;
 }
 
 DumpResult FakeVehicleHardware::dump(const std::vector<std::string>& options) {
@@ -990,9 +994,11 @@
     } else if (EqualsIgnoreCase(option, "--genTestVendorConfigs")) {
         mAddExtraTestVendorConfigs = true;
         result.refreshPropertyConfigs = true;
+        result.buffer = "successfully generated vendor configs";
     } else if (EqualsIgnoreCase(option, "--restoreVendorConfigs")) {
         mAddExtraTestVendorConfigs = false;
         result.refreshPropertyConfigs = true;
+        result.buffer = "successfully restored vendor configs";
     } else {
         result.buffer = StringPrintf("Invalid option: %s\n", option.c_str());
     }
@@ -1328,9 +1334,9 @@
 VehiclePropValue FakeVehicleHardware::createHwInputKeyProp(VehicleHwKeyInputAction action,
                                                            int32_t keyCode, int32_t targetDisplay) {
     VehiclePropValue value = {
-            .prop = toInt(VehicleProperty::HW_KEY_INPUT),
-            .areaId = 0,
             .timestamp = elapsedRealtimeNano(),
+            .areaId = 0,
+            .prop = toInt(VehicleProperty::HW_KEY_INPUT),
             .status = VehiclePropertyStatus::AVAILABLE,
             .value.int32Values = {toInt(action), keyCode, targetDisplay},
     };
@@ -1340,9 +1346,9 @@
 VehiclePropValue FakeVehicleHardware::createHwKeyInputV2Prop(int32_t area, int32_t targetDisplay,
                                                              int32_t keyCode, int32_t action,
                                                              int32_t repeatCount) {
-    VehiclePropValue value = {.prop = toInt(VehicleProperty::HW_KEY_INPUT_V2),
+    VehiclePropValue value = {.timestamp = elapsedRealtimeNano(),
                               .areaId = area,
-                              .timestamp = elapsedRealtimeNano(),
+                              .prop = toInt(VehicleProperty::HW_KEY_INPUT_V2),
                               .status = VehiclePropertyStatus::AVAILABLE,
                               .value.int32Values = {targetDisplay, keyCode, action, repeatCount},
                               .value.int64Values = {elapsedRealtimeNano()}};
@@ -1380,9 +1386,9 @@
         floatValues.push_back(size[i]);
     }
 
-    VehiclePropValue value = {.prop = toInt(VehicleProperty::HW_MOTION_INPUT),
+    VehiclePropValue value = {.timestamp = elapsedRealtimeNano(),
                               .areaId = area,
-                              .timestamp = elapsedRealtimeNano(),
+                              .prop = toInt(VehicleProperty::HW_MOTION_INPUT),
                               .status = VehiclePropertyStatus::AVAILABLE,
                               .value.int32Values = intValues,
                               .value.floatValues = floatValues,
@@ -1451,8 +1457,9 @@
 
 std::string FakeVehicleHardware::dumpOnePropertyById(int32_t propId, int32_t areaId) {
     VehiclePropValue value = {
-            .prop = propId,
             .areaId = areaId,
+            .prop = propId,
+            .value = {},
     };
     bool isSpecialValue = false;
     auto result = maybeGetSpecialValue(value, &isSpecialValue);
@@ -1523,12 +1530,12 @@
     while (*index < options.size()) {
         std::string option = options[*index];
         if (SET_PROP_OPTIONS.find(option) != SET_PROP_OPTIONS.end()) {
-            return std::move(values);
+            return values;
         }
         values.push_back(option);
         (*index)++;
     }
-    return std::move(values);
+    return values;
 }
 
 Result<VehiclePropValue> FakeVehicleHardware::parsePropOptions(
@@ -1808,6 +1815,7 @@
 
 void FakeVehicleHardware::registerOnPropertySetErrorEvent(
         std::unique_ptr<const PropertySetErrorCallback> callback) {
+    // In FakeVehicleHardware, we will never use mOnPropertySetErrorCallback.
     if (mOnPropertySetErrorCallback != nullptr) {
         ALOGE("registerOnPropertySetErrorEvent must only be called once");
         return;
@@ -1836,8 +1844,9 @@
         // Refresh the property value. In real implementation, this should poll the latest value
         // from vehicle bus. Here, we are just refreshing the existing value with a new timestamp.
         auto result = getValue(VehiclePropValue{
-                .prop = propId,
                 .areaId = areaId,
+                .prop = propId,
+                .value = {},
         });
         if (!result.ok()) {
             // Failed to read current value, skip refreshing.
diff --git a/automotive/vehicle/aidl/impl/grpc/Android.bp b/automotive/vehicle/aidl/impl/grpc/Android.bp
index 06c9600..e5106f8 100644
--- a/automotive/vehicle/aidl/impl/grpc/Android.bp
+++ b/automotive/vehicle/aidl/impl/grpc/Android.bp
@@ -22,9 +22,11 @@
         "aprotoc",
         "protoc-gen-grpc-cpp-plugin",
     ],
-    cmd: "$(location aprotoc) -I$$(dirname $(in)) -Ihardware/interfaces/automotive/vehicle/aidl/impl/proto -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+    cmd: "$(location aprotoc) -I$$(dirname $(location proto/VehicleServer.proto)) -Ihardware/interfaces/automotive/vehicle/aidl/impl/proto -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(location proto/VehicleServer.proto) --grpc_out=$(genDir) --cpp_out=$(genDir)",
     srcs: [
         "proto/VehicleServer.proto",
+        ":libprotobuf-internal-protos",
+        ":VehicleHalProtoFiles",
     ],
     out: [
         "VehicleServer.pb.h",
@@ -39,9 +41,11 @@
         "aprotoc",
         "protoc-gen-grpc-cpp-plugin",
     ],
-    cmd: "$(location aprotoc) -I$$(dirname $(in)) -Ihardware/interfaces/automotive/vehicle/aidl/impl/proto -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+    cmd: "$(location aprotoc) -I$$(dirname $(location proto/VehicleServer.proto)) -Ihardware/interfaces/automotive/vehicle/aidl/impl/proto -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(location proto/VehicleServer.proto) --grpc_out=$(genDir) --cpp_out=$(genDir)",
     srcs: [
         "proto/VehicleServer.proto",
+        ":libprotobuf-internal-protos",
+        ":VehicleHalProtoFiles",
     ],
     out: [
         "VehicleServer.pb.cc",
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
index e740da7..ddd620e 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
@@ -82,6 +82,10 @@
 
     bool waitForConnected(std::chrono::milliseconds waitTime);
 
+  protected:
+    std::shared_mutex mCallbackMutex;
+    std::unique_ptr<const PropertyChangeCallback> mOnPropChange;
+
   private:
     void ValuePollingLoop();
 
@@ -90,8 +94,6 @@
     std::unique_ptr<proto::VehicleServer::Stub> mGrpcStub;
     std::thread mValuePollingThread;
 
-    std::shared_mutex mCallbackMutex;
-    std::unique_ptr<const PropertyChangeCallback> mOnPropChange;
     std::unique_ptr<const PropertySetErrorCallback> mOnSetErr;
 
     std::mutex mShutdownMutex;
diff --git a/automotive/vehicle/aidl/impl/grpc/OWNERS b/automotive/vehicle/aidl/impl/grpc/OWNERS
deleted file mode 100644
index 7a96f23..0000000
--- a/automotive/vehicle/aidl/impl/grpc/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-shanyu@google.com
-chenhaosjtuacm@google.com
-egranata@google.com
diff --git a/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
index 2e7298f..b3f4a0f 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
@@ -107,12 +107,18 @@
     // Gets the callback to be called when the request for this client has finished.
     std::shared_ptr<const IVehicleHardware::GetValuesCallback> getResultCallback();
 
-    // Marshals the updated values into largeParcelable and sents it through {@code onPropertyEvent}
+    // Marshals the updated values into largeParcelable and sends it through {@code onPropertyEvent}
     // callback.
     static void sendUpdatedValues(
             CallbackType callback,
             std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
                     updatedValues);
+    // Marshals the set property error events into largeParcelable and sends it through
+    // {@code onPropertySetError} callback.
+    static void sendPropertySetErrors(
+            CallbackType callback,
+            std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropError>&&
+                    vehiclePropErrors);
 
   protected:
     // Gets the callback to be called when the request for this client has timeout.
diff --git a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
index 2c2cf1a..74ad7ea 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
@@ -249,10 +249,14 @@
             const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
 
     static void onPropertyChangeEvent(
-            std::weak_ptr<SubscriptionManager> subscriptionManager,
+            const std::weak_ptr<SubscriptionManager>& subscriptionManager,
             const std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&
                     updatedValues);
 
+    static void onPropertySetErrorEvent(
+            const std::weak_ptr<SubscriptionManager>& subscriptionManager,
+            const std::vector<SetValueErrorEvent>& errorEvents);
+
     static void checkHealth(IVehicleHardware* hardware,
                             std::weak_ptr<SubscriptionManager> subscriptionManager);
 
diff --git a/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h b/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h
index 14799d9..301d56c 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h
@@ -99,6 +99,12 @@
             const std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&
                     updatedValues);
 
+    // For a list of set property error events, returns a map that maps clients subscribing to the
+    // properties to a list of errors for each client.
+    std::unordered_map<CallbackType,
+                       std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropError>>
+    getSubscribedClientsForErrorEvents(const std::vector<SetValueErrorEvent>& errorEvents);
+
     // Checks whether the sample rate is valid.
     static bool checkSampleRateHz(float sampleRateHz);
 
diff --git a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
index 81d231c..fb23a25 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
@@ -38,6 +38,8 @@
 using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
 using ::aidl::android::hardware::automotive::vehicle::SetValueResults;
 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropError;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValues;
 using ::android::base::Result;
@@ -300,7 +302,34 @@
     if (ScopedAStatus callbackStatus =
                 callback->onPropertyEvent(vehiclePropValues, sharedMemoryFileCount);
         !callbackStatus.isOk()) {
-        ALOGE("subscribe: failed to call UpdateValues callback, client ID: %p, error: %s, "
+        ALOGE("subscribe: failed to call onPropertyEvent callback, client ID: %p, error: %s, "
+              "exception: %d, service specific error: %d",
+              callback->asBinder().get(), callbackStatus.getMessage(),
+              callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError());
+    }
+}
+
+void SubscriptionClient::sendPropertySetErrors(std::shared_ptr<IVehicleCallback> callback,
+                                               std::vector<VehiclePropError>&& vehiclePropErrors) {
+    if (vehiclePropErrors.empty()) {
+        return;
+    }
+
+    VehiclePropErrors vehiclePropErrorsLargeParcelable;
+    ScopedAStatus status = vectorToStableLargeParcelable(std::move(vehiclePropErrors),
+                                                         &vehiclePropErrorsLargeParcelable);
+    if (!status.isOk()) {
+        int statusCode = status.getServiceSpecificError();
+        ALOGE("subscribe: failed to marshal result into large parcelable, error: "
+              "%s, code: %d",
+              status.getMessage(), statusCode);
+        return;
+    }
+
+    if (ScopedAStatus callbackStatus =
+                callback->onPropertySetError(vehiclePropErrorsLargeParcelable);
+        !callbackStatus.isOk()) {
+        ALOGE("subscribe: failed to call onPropertySetError callback, client ID: %p, error: %s, "
               "exception: %d, service specific error: %d",
               callback->asBinder().get(), callbackStatus.getMessage(),
               callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError());
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index 98cfc39..0d5c070 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -144,6 +144,11 @@
                     [subscriptionManagerCopy](std::vector<VehiclePropValue> updatedValues) {
                         onPropertyChangeEvent(subscriptionManagerCopy, updatedValues);
                     }));
+    mVehicleHardware->registerOnPropertySetErrorEvent(
+            std::make_unique<IVehicleHardware::PropertySetErrorCallback>(
+                    [subscriptionManagerCopy](std::vector<SetValueErrorEvent> errorEvents) {
+                        onPropertySetErrorEvent(subscriptionManagerCopy, errorEvents);
+                    }));
 
     // Register heartbeat event.
     mRecurrentAction = std::make_shared<std::function<void()>>(
@@ -177,7 +182,7 @@
 }
 
 void DefaultVehicleHal::onPropertyChangeEvent(
-        std::weak_ptr<SubscriptionManager> subscriptionManager,
+        const std::weak_ptr<SubscriptionManager>& subscriptionManager,
         const std::vector<VehiclePropValue>& updatedValues) {
     auto manager = subscriptionManager.lock();
     if (manager == nullptr) {
@@ -194,6 +199,20 @@
     }
 }
 
+void DefaultVehicleHal::onPropertySetErrorEvent(
+        const std::weak_ptr<SubscriptionManager>& subscriptionManager,
+        const std::vector<SetValueErrorEvent>& errorEvents) {
+    auto manager = subscriptionManager.lock();
+    if (manager == nullptr) {
+        ALOGW("the SubscriptionManager is destroyed, DefaultVehicleHal is ending");
+        return;
+    }
+    auto vehiclePropErrorsByClient = manager->getSubscribedClientsForErrorEvents(errorEvents);
+    for (auto& [callback, vehiclePropErrors] : vehiclePropErrorsByClient) {
+        SubscriptionClient::sendPropertySetErrors(callback, std::move(vehiclePropErrors));
+    }
+}
+
 template <class T>
 std::shared_ptr<T> DefaultVehicleHal::getOrCreateClient(
         std::unordered_map<const AIBinder*, std::shared_ptr<T>>* clients,
@@ -692,15 +711,19 @@
         // Create a new SubscriptionClient if there isn't an existing one.
         mSubscriptionClients->maybeAddClient(callback);
 
-        // Since we have already check the sample rates, the following functions must succeed.
         if (!onChangeSubscriptions.empty()) {
-            return toScopedAStatus(mSubscriptionManager->subscribe(callback, onChangeSubscriptions,
-                                                                   /*isContinuousProperty=*/false));
+            auto result = mSubscriptionManager->subscribe(callback, onChangeSubscriptions,
+                                                          /*isContinuousProperty=*/false);
+            if (!result.ok()) {
+                return toScopedAStatus(result);
+            }
         }
         if (!continuousSubscriptions.empty()) {
-            return toScopedAStatus(mSubscriptionManager->subscribe(callback,
-                                                                   continuousSubscriptions,
-                                                                   /*isContinuousProperty=*/true));
+            auto result = mSubscriptionManager->subscribe(callback, continuousSubscriptions,
+                                                          /*isContinuousProperty=*/true);
+            if (!result.ok()) {
+                return toScopedAStatus(result);
+            }
         }
     }
     return ScopedAStatus::ok();
diff --git a/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp b/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
index bba730f..1f2690e 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
@@ -36,6 +36,7 @@
 using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
 using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropError;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 using ::android::base::Error;
 using ::android::base::Result;
@@ -269,6 +270,32 @@
     return clients;
 }
 
+std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<VehiclePropError>>
+SubscriptionManager::getSubscribedClientsForErrorEvents(
+        const std::vector<SetValueErrorEvent>& errorEvents) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<VehiclePropError>> clients;
+
+    for (const auto& errorEvent : errorEvents) {
+        PropIdAreaId propIdAreaId{
+                .propId = errorEvent.propId,
+                .areaId = errorEvent.areaId,
+        };
+        if (mClientsByPropIdArea.find(propIdAreaId) == mClientsByPropIdArea.end()) {
+            continue;
+        }
+
+        for (const auto& [_, client] : mClientsByPropIdArea[propIdAreaId]) {
+            clients[client].push_back({
+                    .propId = errorEvent.propId,
+                    .areaId = errorEvent.areaId,
+                    .errorCode = errorEvent.errorCode,
+            });
+        }
+    }
+    return clients;
+}
+
 bool SubscriptionManager::isEmpty() {
     std::scoped_lock<std::mutex> lockGuard(mLock);
     return mSubscribedPropsByClient.empty() && mClientsByPropIdArea.empty();
diff --git a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
index 05e569a..96b71f0 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
@@ -62,6 +62,7 @@
 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaWindow;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropError;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors;
 using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
@@ -1653,6 +1654,63 @@
     ASSERT_EQ(msg.find("Vehicle HAL State: "), std::string::npos);
 }
 
+TEST_F(DefaultVehicleHalTest, testOnPropertySetErrorEvent) {
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = GLOBAL_ON_CHANGE_PROP,
+                    .areaIds = {0},
+            },
+            {
+                    .propId = GLOBAL_CONTINUOUS_PROP,
+                    .areaIds = {0},
+                    .sampleRate = 1,
+            },
+    };
+    auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+    ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+    std::vector<SetValueErrorEvent> errorEvents = {
+            {
+                    .propId = GLOBAL_ON_CHANGE_PROP,
+                    .areaId = 0,
+                    .errorCode = StatusCode::INTERNAL_ERROR,
+            },
+            {
+                    .propId = GLOBAL_ON_CHANGE_PROP,
+                    .areaId = 0,
+                    .errorCode = StatusCode::ACCESS_DENIED,
+            },
+            {
+                    .propId = GLOBAL_CONTINUOUS_PROP,
+                    .areaId = 0,
+                    .errorCode = StatusCode::INVALID_ARG,
+            },
+    };
+    std::vector<VehiclePropError> expectedResults = {
+            {
+                    .propId = GLOBAL_ON_CHANGE_PROP,
+                    .areaId = 0,
+                    .errorCode = StatusCode::INTERNAL_ERROR,
+            },
+            {
+                    .propId = GLOBAL_ON_CHANGE_PROP,
+                    .areaId = 0,
+                    .errorCode = StatusCode::ACCESS_DENIED,
+            },
+            {
+                    .propId = GLOBAL_CONTINUOUS_PROP,
+                    .areaId = 0,
+                    .errorCode = StatusCode::INVALID_ARG,
+            },
+    };
+    getHardware()->sendOnPropertySetErrorEvent(errorEvents);
+
+    ASSERT_EQ(getCallback()->countOnPropertySetErrorResults(), 1u);
+    auto maybeVehiclePropErrors = getCallback()->nextOnPropertySetErrorResults();
+    ASSERT_TRUE(maybeVehiclePropErrors.has_value());
+    const auto& vehiclePropErrors = maybeVehiclePropErrors.value();
+    ASSERT_THAT(vehiclePropErrors.payloads, UnorderedElementsAreArray(expectedResults));
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
index f51ce5c..54fede1 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
@@ -81,8 +81,14 @@
     return result;
 }
 
-ScopedAStatus MockVehicleCallback::onPropertySetError(const VehiclePropErrors&) {
-    return ScopedAStatus::ok();
+ScopedAStatus MockVehicleCallback::onPropertySetError(const VehiclePropErrors& results) {
+    ScopedAStatus result;
+    {
+        std::scoped_lock<std::mutex> lockGuard(mLock);
+        result = storeResults(results, &mOnPropertySetErrorResults);
+    }
+    mCond.notify_all();
+    return result;
 }
 
 std::optional<GetValueResults> MockVehicleCallback::nextGetValueResults() {
@@ -105,6 +111,16 @@
     return mOnPropertyEventResults.size();
 }
 
+std::optional<VehiclePropErrors> MockVehicleCallback::nextOnPropertySetErrorResults() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return pop(mOnPropertySetErrorResults);
+}
+
+size_t MockVehicleCallback::countOnPropertySetErrorResults() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return mOnPropertySetErrorResults.size();
+}
+
 bool MockVehicleCallback::waitForSetValueResults(size_t size, size_t timeoutInNano) {
     std::unique_lock lk(mLock);
     return mCond.wait_for(lk, std::chrono::nanoseconds(timeoutInNano), [this, size] {
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
index f17b273..1545eae 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
@@ -63,6 +63,9 @@
     nextSetValueResults();
     std::optional<aidl::android::hardware::automotive::vehicle::VehiclePropValues>
     nextOnPropertyEventResults();
+    size_t countOnPropertySetErrorResults();
+    std::optional<aidl::android::hardware::automotive::vehicle::VehiclePropErrors>
+    nextOnPropertySetErrorResults();
     size_t countOnPropertyEventResults();
     bool waitForSetValueResults(size_t size, size_t timeoutInNano);
     bool waitForGetValueResults(size_t size, size_t timeoutInNano);
@@ -77,6 +80,8 @@
     std::list<aidl::android::hardware::automotive::vehicle::VehiclePropValues>
             mOnPropertyEventResults GUARDED_BY(mLock);
     int32_t mSharedMemoryFileCount GUARDED_BY(mLock);
+    std::list<aidl::android::hardware::automotive::vehicle::VehiclePropErrors>
+            mOnPropertySetErrorResults GUARDED_BY(mLock);
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
index 4df4e1a..ba0d33d 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
@@ -131,8 +131,9 @@
 }
 
 void MockVehicleHardware::registerOnPropertySetErrorEvent(
-        std::unique_ptr<const PropertySetErrorCallback>) {
-    // TODO(b/200737967): mock this.
+        std::unique_ptr<const PropertySetErrorCallback> callback) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    mPropertySetErrorCallback = std::move(callback);
 }
 
 void MockVehicleHardware::setPropertyConfigs(const std::vector<VehiclePropConfig>& configs) {
@@ -254,6 +255,12 @@
         std::list<std::vector<SetValueRequest>>* storedRequests,
         std::list<std::vector<SetValueResult>>* storedResponses) const;
 
+void MockVehicleHardware::sendOnPropertySetErrorEvent(
+        const std::vector<SetValueErrorEvent>& errorEvents) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    (*mPropertySetErrorCallback)(errorEvents);
+}
+
 }  // 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 743841c..46b30b9 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
@@ -85,6 +85,7 @@
                    aidl::android::hardware::automotive::vehicle::StatusCode status);
     void setSleepTime(int64_t timeInNano);
     void setDumpResult(DumpResult result);
+    void sendOnPropertySetErrorEvent(const std::vector<SetValueErrorEvent>& errorEvents);
 
   private:
     mutable std::mutex mLock;
@@ -104,6 +105,7 @@
             mStatusByFunctions GUARDED_BY(mLock);
     int64_t mSleepTime GUARDED_BY(mLock) = 0;
     std::unique_ptr<const PropertyChangeCallback> mPropertyChangeCallback GUARDED_BY(mLock);
+    std::unique_ptr<const PropertySetErrorCallback> mPropertySetErrorCallback GUARDED_BY(mLock);
     std::function<aidl::android::hardware::automotive::vehicle::StatusCode(
             std::shared_ptr<const GetValuesCallback>,
             const std::vector<aidl::android::hardware::automotive::vehicle::GetValueRequest>&)>
diff --git a/automotive/vehicle/aidl_property/OWNERS b/automotive/vehicle/aidl_property/OWNERS
deleted file mode 100644
index 73e45ca..0000000
--- a/automotive/vehicle/aidl_property/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-tylertrephan@google.com
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 d9c6de7..717f561 100644
--- a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -4625,11 +4625,11 @@
      *
      * Commands to activate and suspend LCA.
      *
-     * When the command ACTIVATE from LaneCenteringAssistCommmand is sent,
+     * When the command ACTIVATE from LaneCenteringAssistCommand is sent,
      * LANE_CENTERING_ASSIST_STATE must be set to LaneCenteringAssistState#ACTIVATION_REQUESTED.
      * When the ACTIVATE command succeeds, LANE_CENTERING_ASSIST_STATE must be set to
      * LaneCenteringAssistState#ACTIVATED. When the command DEACTIVATE from
-     * LaneCenteringAssistCommmand succeeds, LANE_CENTERING_ASSIST_STATE must be set to
+     * LaneCenteringAssistCommand succeeds, LANE_CENTERING_ASSIST_STATE must be set to
      * LaneCenteringAssistState#ENABLED.
      *
      * For the global area ID (0), the VehicleAreaConfig#supportedEnumValues must be defined unless
@@ -4645,7 +4645,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
-     * @data_enum LaneCenteringAssistCommmand
+     * @data_enum LaneCenteringAssistCommand
      */
     LANE_CENTERING_ASSIST_COMMAND =
             0x100B + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
diff --git a/automotive/vehicle/proto/Android.bp b/automotive/vehicle/proto/Android.bp
index 683f128..e7dabcf 100644
--- a/automotive/vehicle/proto/Android.bp
+++ b/automotive/vehicle/proto/Android.bp
@@ -27,6 +27,7 @@
     visibility: [
         "//hardware/interfaces/automotive/vehicle:__subpackages__",
         "//device/generic/car/emulator:__subpackages__",
+        "//system/software_defined_vehicle/core_services:__subpackages__",
     ],
     vendor: true,
     host_supported: true,
diff --git a/automotive/vehicle/vts/OWNERS b/automotive/vehicle/vts/OWNERS
index c93a843..0f88eec 100644
--- a/automotive/vehicle/vts/OWNERS
+++ b/automotive/vehicle/vts/OWNERS
@@ -1,3 +1,3 @@
 # Bug component: 533426
 shanyu@google.com
-kwangsudo@google.com
+tylertrephan@google.com
diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
index 90ec8f2..54076c8 100644
--- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
+++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
@@ -31,6 +31,9 @@
 
 namespace aidl::android::hardware::biometrics::fingerprint {
 
+FakeFingerprintEngine::FakeFingerprintEngine()
+    : mRandom(std::mt19937::default_seed), mWorkMode(WorkMode::kIdle) {}
+
 void FakeFingerprintEngine::generateChallengeImpl(ISessionCallback* cb) {
     BEGIN_OP(0);
     std::uniform_int_distribution<int64_t> dist;
@@ -48,7 +51,7 @@
 void FakeFingerprintEngine::enrollImpl(ISessionCallback* cb,
                                        const keymaster::HardwareAuthToken& hat,
                                        const std::future<void>& cancel) {
-    BEGIN_OP(getLatency(FingerprintHalProperties::operation_enroll_latency()));
+    BEGIN_OP(0);
 
     // Do proper HAT verification in the real implementation.
     if (hat.mac.empty()) {
@@ -57,13 +60,77 @@
         return;
     }
 
+    updateContext(WorkMode::kEnroll, cb, const_cast<std::future<void>&>(cancel), 0, hat);
+}
+
+void FakeFingerprintEngine::authenticateImpl(ISessionCallback* cb, int64_t operationId,
+                                             const std::future<void>& cancel) {
+    BEGIN_OP(0);
+    updateContext(WorkMode::kAuthenticate, cb, const_cast<std::future<void>&>(cancel), operationId,
+                  keymaster::HardwareAuthToken());
+}
+
+void FakeFingerprintEngine::detectInteractionImpl(ISessionCallback* cb,
+                                                  const std::future<void>& cancel) {
+    BEGIN_OP(0);
+
+    auto detectInteractionSupported =
+            FingerprintHalProperties::detect_interaction().value_or(false);
+    if (!detectInteractionSupported) {
+        LOG(ERROR) << "Detect interaction is not supported";
+        cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
+        return;
+    }
+
+    updateContext(WorkMode::kDetectInteract, cb, const_cast<std::future<void>&>(cancel), 0,
+                  keymaster::HardwareAuthToken());
+}
+
+void FakeFingerprintEngine::updateContext(WorkMode mode, ISessionCallback* cb,
+                                          std::future<void>& cancel, int64_t operationId,
+                                          const keymaster::HardwareAuthToken& hat) {
+    mCancel = std::move(cancel);
+    mWorkMode = mode;
+    mCb = cb;
+    mOperationId = operationId;
+    mHat = hat;
+}
+
+void FakeFingerprintEngine::fingerDownAction() {
+    bool isTerminal = false;
+    LOG(INFO) << __func__;
+    switch (mWorkMode) {
+        case WorkMode::kAuthenticate:
+            isTerminal = onAuthenticateFingerDown(mCb, mOperationId, mCancel);
+            break;
+        case WorkMode::kEnroll:
+            isTerminal = onEnrollFingerDown(mCb, mHat, mCancel);
+            break;
+        case WorkMode::kDetectInteract:
+            isTerminal = onDetectInteractFingerDown(mCb, mCancel);
+            break;
+        default:
+            LOG(WARNING) << "unexpected mode: on fingerDownAction(), " << (int)mWorkMode;
+            break;
+    }
+
+    if (isTerminal) {
+        mWorkMode = WorkMode::kIdle;
+    }
+}
+
+bool FakeFingerprintEngine::onEnrollFingerDown(ISessionCallback* cb,
+                                               const keymaster::HardwareAuthToken&,
+                                               const std::future<void>& cancel) {
+    BEGIN_OP(getLatency(FingerprintHalProperties::operation_enroll_latency()));
+
     // Force error-out
     auto err = FingerprintHalProperties::operation_enroll_error().value_or(0);
     if (err != 0) {
         LOG(ERROR) << "Fail: operation_enroll_error";
         auto ec = convertError(err);
         cb->onError(ec.first, ec.second);
-        return;
+        return true;
     }
 
     // Format is "<id>:<progress_ms-[acquiredInfo..]>,...:<result>
@@ -72,7 +139,7 @@
     if (parts.size() != 3) {
         LOG(ERROR) << "Fail: invalid next_enrollment:" << nextEnroll;
         cb->onError(Error::VENDOR, 0 /* vendorError */);
-        return;
+        return true;
     }
     auto enrollmentId = std::stoi(parts[0]);
     auto progress = parseEnrollmentCapture(parts[1]);
@@ -88,7 +155,7 @@
             if (shouldCancel(cancel)) {
                 LOG(ERROR) << "Fail: cancel";
                 cb->onError(Error::CANCELED, 0 /* vendorCode */);
-                return;
+                return true;
             }
             auto ac = convertAcquiredInfo(acquired[j]);
             cb->onAcquired(ac.first, ac.second);
@@ -114,10 +181,13 @@
             cb->onEnrollmentProgress(enrollmentId, left);
         }
     }
+
+    return true;
 }
 
-void FakeFingerprintEngine::authenticateImpl(ISessionCallback* cb, int64_t /* operationId */,
-                                             const std::future<void>& cancel) {
+bool FakeFingerprintEngine::onAuthenticateFingerDown(ISessionCallback* cb,
+                                                     int64_t /* operationId */,
+                                                     const std::future<void>& cancel) {
     BEGIN_OP(getLatency(FingerprintHalProperties::operation_authenticate_latency()));
 
     int64_t now = Util::getSystemNanoTime();
@@ -129,19 +199,12 @@
     if (N == 0) {
         LOG(ERROR) << "Fail to parse authentiate acquired info: " + acquired;
         cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
-        return;
+        return true;
     }
 
     // got lockout?
-    FakeLockoutTracker::LockoutMode lockoutMode = mLockoutTracker.getMode();
-    if (lockoutMode == FakeLockoutTracker::LockoutMode::kPermanent) {
-        LOG(ERROR) << "Fail: lockout permanent";
-        cb->onLockoutPermanent();
-        return;
-    } else if (lockoutMode == FakeLockoutTracker::LockoutMode::kTimed) {
-        int64_t timeLeft = mLockoutTracker.getLockoutTimeLeft();
-        LOG(ERROR) << "Fail: lockout timed " << timeLeft;
-        cb->onLockoutTimed(timeLeft);
+    if (checkSensorLockout(cb)) {
+        return FakeLockoutTracker::LockoutMode::kPermanent == mLockoutTracker.getMode();
     }
 
     int i = 0;
@@ -150,7 +213,7 @@
             LOG(ERROR) << "Fail: operation_authenticate_fails";
             mLockoutTracker.addFailedAttempt();
             cb->onAuthenticationFailed();
-            return;
+            return false;
         }
 
         auto err = FingerprintHalProperties::operation_authenticate_error().value_or(0);
@@ -158,20 +221,21 @@
             LOG(ERROR) << "Fail: operation_authenticate_error";
             auto ec = convertError(err);
             cb->onError(ec.first, ec.second);
-            return;
+            return true; /* simply terminating current operation for any user inserted error,
+                            revisit if tests need*/
         }
 
         if (FingerprintHalProperties::lockout().value_or(false)) {
             LOG(ERROR) << "Fail: lockout";
             cb->onLockoutPermanent();
             cb->onError(Error::HW_UNAVAILABLE, 0 /* vendorError */);
-            return;
+            return true;
         }
 
         if (shouldCancel(cancel)) {
             LOG(ERROR) << "Fail: cancel";
             cb->onError(Error::CANCELED, 0 /* vendorCode */);
-            return;
+            return true;
         }
 
         if (i < N) {
@@ -189,29 +253,23 @@
     if (id > 0 && isEnrolled) {
         cb->onAuthenticationSucceeded(id, {} /* hat */);
         mLockoutTracker.reset();
-        return;
+        return true;
     } else {
         LOG(ERROR) << "Fail: fingerprint not enrolled";
         cb->onAuthenticationFailed();
         mLockoutTracker.addFailedAttempt();
+        checkSensorLockout(cb);
+        return false;
     }
 }
 
-void FakeFingerprintEngine::detectInteractionImpl(ISessionCallback* cb,
-                                                  const std::future<void>& cancel) {
+bool FakeFingerprintEngine::onDetectInteractFingerDown(ISessionCallback* cb,
+                                                       const std::future<void>& cancel) {
     BEGIN_OP(getLatency(FingerprintHalProperties::operation_detect_interaction_latency()));
 
     int64_t duration =
             FingerprintHalProperties::operation_detect_interaction_duration().value_or(10);
 
-    auto detectInteractionSupported =
-            FingerprintHalProperties::detect_interaction().value_or(false);
-    if (!detectInteractionSupported) {
-        LOG(ERROR) << "Detect interaction is not supported";
-        cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
-        return;
-    }
-
     auto acquired = FingerprintHalProperties::operation_detect_interaction_acquired().value_or("1");
     auto acquiredInfos = parseIntSequence(acquired);
     int N = acquiredInfos.size();
@@ -220,7 +278,7 @@
     if (N == 0) {
         LOG(ERROR) << "Fail to parse detect interaction acquired info: " + acquired;
         cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
-        return;
+        return true;
     }
 
     int i = 0;
@@ -230,13 +288,13 @@
             LOG(ERROR) << "Fail: operation_detect_interaction_error";
             auto ec = convertError(err);
             cb->onError(ec.first, ec.second);
-            return;
+            return true;
         }
 
         if (shouldCancel(cancel)) {
             LOG(ERROR) << "Fail: cancel";
             cb->onError(Error::CANCELED, 0 /* vendorCode */);
-            return;
+            return true;
         }
 
         if (i < N) {
@@ -253,21 +311,18 @@
     if (id <= 0 || !isEnrolled) {
         LOG(ERROR) << "Fail: not enrolled";
         cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
-        return;
+        return true;
     }
 
     cb->onInteractionDetected();
+
+    return true;
 }
 
 void FakeFingerprintEngine::enumerateEnrollmentsImpl(ISessionCallback* cb) {
     BEGIN_OP(0);
 
     std::vector<int32_t> ids;
-    // There are some enrollment sync issue with framework, which results in
-    //  a single template removal during the very firt sync command after reboot.
-    //  This is a workaround for now. TODO(b/243129174)
-    ids.push_back(-1);
-
     for (auto& enrollment : FingerprintHalProperties::enrollments()) {
         auto id = enrollment.value_or(0);
         if (id > 0) {
@@ -330,6 +385,11 @@
         cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
         return;
     }
+    clearLockout(cb);
+    isLockoutTimerAborted = true;
+}
+
+void FakeFingerprintEngine::clearLockout(ISessionCallback* cb) {
     FingerprintHalProperties::lockout(false);
     cb->onLockoutCleared();
     mLockoutTracker.reset();
@@ -339,6 +399,7 @@
                                                             int32_t /*y*/, float /*minor*/,
                                                             float /*major*/) {
     BEGIN_OP(0);
+    fingerDownAction();
     return ndk::ScopedAStatus::ok();
 }
 
@@ -369,7 +430,8 @@
         if (dim.size() >= 4) {
             d = dim[3];
         }
-        if (isValidStr) out = {0, x, y, r, d};
+        if (isValidStr)
+            out = {.sensorLocationX = x, .sensorLocationY = y, .sensorRadius = r, .display = d};
 
         return isValidStr;
     }
@@ -385,8 +447,7 @@
 }
 
 SensorLocation FakeFingerprintEngine::defaultSensorLocation() {
-    return {0 /* displayId (not used) */, 0 /* sensorLocationX */, 0 /* sensorLocationY */,
-            0 /* sensorRadius */, "" /* display */};
+    return SensorLocation();
 }
 
 std::vector<int32_t> FakeFingerprintEngine::parseIntSequence(const std::string& str,
@@ -513,4 +574,39 @@
     return dist(mRandom);
 }
 
+bool FakeFingerprintEngine::checkSensorLockout(ISessionCallback* cb) {
+    FakeLockoutTracker::LockoutMode lockoutMode = mLockoutTracker.getMode();
+    if (lockoutMode == FakeLockoutTracker::LockoutMode::kPermanent) {
+        LOG(ERROR) << "Fail: lockout permanent";
+        cb->onLockoutPermanent();
+        isLockoutTimerAborted = true;
+        return true;
+    } else if (lockoutMode == FakeLockoutTracker::LockoutMode::kTimed) {
+        int64_t timeLeft = mLockoutTracker.getLockoutTimeLeft();
+        LOG(ERROR) << "Fail: lockout timed " << timeLeft;
+        cb->onLockoutTimed(timeLeft);
+        if (isLockoutTimerSupported && !isLockoutTimerStarted) startLockoutTimer(timeLeft, cb);
+        return true;
+    }
+    return false;
+}
+
+void FakeFingerprintEngine::startLockoutTimer(int64_t timeout, ISessionCallback* cb) {
+    BEGIN_OP(0);
+    std::function<void(ISessionCallback*)> action =
+            std::bind(&FakeFingerprintEngine::lockoutTimerExpired, this, std::placeholders::_1);
+    std::thread([timeout, action, cb]() {
+        std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
+        action(cb);
+    }).detach();
+
+    isLockoutTimerStarted = true;
+}
+void FakeFingerprintEngine::lockoutTimerExpired(ISessionCallback* cb) {
+    if (!isLockoutTimerAborted) {
+        clearLockout(cb);
+    }
+    isLockoutTimerStarted = false;
+    isLockoutTimerAborted = false;
+}
 }  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngineSide.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngineSide.cpp
index 9f736e7..a78cdcd 100644
--- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngineSide.cpp
+++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngineSide.cpp
@@ -27,11 +27,13 @@
 
 namespace aidl::android::hardware::biometrics::fingerprint {
 
-SensorLocation FakeFingerprintEngineSide::defaultSensorLocation() {
-    SensorLocation location;
+FakeFingerprintEngineSide::FakeFingerprintEngineSide() : FakeFingerprintEngine() {
+    isLockoutTimerSupported = true;
+}
 
-    return {0 /* displayId (not used) */, defaultSensorLocationX /* sensorLocationX */,
-            defaultSensorLocationY /* sensorLocationY */, defaultSensorRadius /* sensorRadius */,
-            "" /* display */};
+SensorLocation FakeFingerprintEngineSide::defaultSensorLocation() {
+    return SensorLocation{.sensorLocationX = defaultSensorLocationX,
+                          .sensorLocationY = defaultSensorLocationY,
+                          .sensorRadius = defaultSensorRadius};
 }
 }  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngineUdfps.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngineUdfps.cpp
index 3cdfc70..68b0f0d 100644
--- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngineUdfps.cpp
+++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngineUdfps.cpp
@@ -31,12 +31,12 @@
 namespace aidl::android::hardware::biometrics::fingerprint {
 
 FakeFingerprintEngineUdfps::FakeFingerprintEngineUdfps()
-    : FakeFingerprintEngine(), mWorkMode(WorkMode::kIdle), mPointerDownTime(0), mUiReadyTime(0) {}
+    : FakeFingerprintEngine(), mPointerDownTime(0), mUiReadyTime(0) {}
 
 SensorLocation FakeFingerprintEngineUdfps::defaultSensorLocation() {
-    return {0 /* displayId (not used) */, defaultSensorLocationX /* sensorLocationX */,
-            defaultSensorLocationY /* sensorLocationY */, defaultSensorRadius /* sensorRadius */,
-            "" /* display */};
+    return SensorLocation{.sensorLocationX = defaultSensorLocationX,
+                          .sensorLocationY = defaultSensorLocationY,
+                          .sensorRadius = defaultSensorRadius};
 }
 
 ndk::ScopedAStatus FakeFingerprintEngineUdfps::onPointerDownImpl(int32_t /*pointerId*/,
@@ -70,68 +70,17 @@
 }
 
 void FakeFingerprintEngineUdfps::fingerDownAction() {
-    switch (mWorkMode) {
-        case WorkMode::kAuthenticate:
-            onAuthenticateFingerDown();
-            break;
-        case WorkMode::kEnroll:
-            onEnrollFingerDown();
-            break;
-        case WorkMode::kDetectInteract:
-            onDetectInteractFingerDown();
-            break;
-        default:
-            LOG(WARNING) << "unexpected call: onUiReady()";
-            break;
-    }
-
+    FakeFingerprintEngine::fingerDownAction();
     mUiReadyTime = 0;
     mPointerDownTime = 0;
 }
 
-void FakeFingerprintEngineUdfps::onAuthenticateFingerDown() {
-    FakeFingerprintEngine::authenticateImpl(mCb, mOperationId, mCancelVec[0]);
-}
-
-void FakeFingerprintEngineUdfps::onEnrollFingerDown() {
-    // Any use case to emulate display touch for each capture during enrollment?
-    FakeFingerprintEngine::enrollImpl(mCb, mHat, mCancelVec[0]);
-}
-
-void FakeFingerprintEngineUdfps::onDetectInteractFingerDown() {
-    FakeFingerprintEngine::detectInteractionImpl(mCb, mCancelVec[0]);
-}
-
-void FakeFingerprintEngineUdfps::enrollImpl(ISessionCallback* cb,
-                                            const keymaster::HardwareAuthToken& hat,
-                                            const std::future<void>& cancel) {
-    updateContext(WorkMode::kEnroll, cb, const_cast<std::future<void>&>(cancel), 0, hat);
-}
-
-void FakeFingerprintEngineUdfps::authenticateImpl(ISessionCallback* cb, int64_t operationId,
-                                                  const std::future<void>& cancel) {
-    updateContext(WorkMode::kAuthenticate, cb, const_cast<std::future<void>&>(cancel), operationId,
-                  keymaster::HardwareAuthToken());
-}
-
-void FakeFingerprintEngineUdfps::detectInteractionImpl(ISessionCallback* cb,
-                                                       const std::future<void>& cancel) {
-    updateContext(WorkMode::kDetectInteract, cb, const_cast<std::future<void>&>(cancel), 0,
-                  keymaster::HardwareAuthToken());
-}
-
 void FakeFingerprintEngineUdfps::updateContext(WorkMode mode, ISessionCallback* cb,
                                                std::future<void>& cancel, int64_t operationId,
                                                const keymaster::HardwareAuthToken& hat) {
+    FakeFingerprintEngine::updateContext(mode, cb, cancel, operationId, hat);
     mPointerDownTime = 0;
     mUiReadyTime = 0;
-    mCancelVec.clear();
-
-    mCancelVec.push_back(std::move(cancel));
-    mWorkMode = mode;
-    mCb = cb;
-    mOperationId = operationId;
-    mHat = hat;
 }
 
 }  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp b/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp
index 5996406..b0163ee 100644
--- a/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp
+++ b/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp
@@ -67,9 +67,13 @@
     int64_t res = 0;
 
     if (mLockoutTimedStart > 0) {
+        int32_t lockoutTimedDuration =
+                FingerprintHalProperties::lockout_timed_duration().value_or(10 * 100);
         auto now = Util::getSystemNanoTime();
-        auto left = now - mLockoutTimedStart;
-        res = (left > 0) ? (left / 1000000LL) : 0;
+        auto elapsed = (now - mLockoutTimedStart) / 1000000LL;
+        res = lockoutTimedDuration - elapsed;
+        LOG(INFO) << "xxxxxx: elapsed=" << elapsed << " now = " << now
+                  << " mLockoutTimedStart=" << mLockoutTimedStart << " res=" << res;
     }
 
     return res;
diff --git a/biometrics/fingerprint/aidl/default/Fingerprint.cpp b/biometrics/fingerprint/aidl/default/Fingerprint.cpp
index f00a49d..79b563e 100644
--- a/biometrics/fingerprint/aidl/default/Fingerprint.cpp
+++ b/biometrics/fingerprint/aidl/default/Fingerprint.cpp
@@ -17,6 +17,7 @@
 #include "Fingerprint.h"
 #include "Session.h"
 
+#include <android-base/properties.h>
 #include <fingerprint.sysprop.h>
 
 #include <android-base/file.h>
@@ -59,6 +60,7 @@
                              << sensorTypeProp;
     }
     LOG(INFO) << "sensorTypeProp:" << sensorTypeProp;
+    LOG(INFO) << "ro.product.name=" << ::android::base::GetProperty("ro.product.name", "UNKNOWN");
 }
 
 ndk::ScopedAStatus Fingerprint::getSensorProps(std::vector<SensorProps>* out) {
@@ -105,16 +107,16 @@
 
     mSession->linkToDeath(cb->asBinder().get());
 
-    LOG(INFO) << "createSession: sensorId:" << sensorId << " userId:" << userId;
+    LOG(INFO) << __func__ << ": sensorId:" << sensorId << " userId:" << userId;
     return ndk::ScopedAStatus::ok();
 }
 
 binder_status_t Fingerprint::dump(int fd, const char** /*args*/, uint32_t numArgs) {
     if (fd < 0) {
-        LOG(ERROR) << "Fingerprint::dump fd invalid: " << fd;
+        LOG(ERROR) << __func__ << "fd invalid: " << fd;
         return STATUS_BAD_VALUE;
     } else {
-        LOG(INFO) << "Fingerprint::dump fd:" << fd << "numArgs:" << numArgs;
+        LOG(INFO) << __func__ << " fd:" << fd << "numArgs:" << numArgs;
     }
 
     dprintf(fd, "----- FingerprintVirtualHal::dump -----\n");
@@ -131,11 +133,11 @@
 
 binder_status_t Fingerprint::handleShellCommand(int in, int out, int err, const char** args,
                                                 uint32_t numArgs) {
-    LOG(INFO) << "Fingerprint::handleShellCommand in:" << in << " out:" << out << " err:" << err
+    LOG(INFO) << __func__ << " in:" << in << " out:" << out << " err:" << err
               << " numArgs:" << numArgs;
 
     if (numArgs == 0) {
-        LOG(INFO) << "Fingerprint::handleShellCommand: available commands";
+        LOG(INFO) << __func__ << ": available commands";
         onHelp(out);
         return STATUS_OK;
     }
@@ -163,7 +165,7 @@
 }
 
 void Fingerprint::resetConfigToDefault() {
-    LOG(INFO) << "reset virtual HAL configuration to default";
+    LOG(INFO) << __func__ << ": reset virtual HAL configuration to default";
 #define RESET_CONFIG_O(__NAME__) \
     if (FingerprintHalProperties::__NAME__()) FingerprintHalProperties::__NAME__(std::nullopt)
 #define RESET_CONFIG_V(__NAME__)                       \
diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
index 1279cd9..2450115 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
@@ -38,7 +38,7 @@
 // A fake engine that is backed by system properties instead of hardware.
 class FakeFingerprintEngine {
   public:
-    FakeFingerprintEngine() : mRandom(std::mt19937::default_seed) {}
+    FakeFingerprintEngine();
     virtual ~FakeFingerprintEngine() {}
 
     void generateChallengeImpl(ISessionCallback* cb);
@@ -66,6 +66,8 @@
 
     virtual SensorLocation defaultSensorLocation();
 
+    virtual void fingerDownAction();
+
     std::vector<int32_t> parseIntSequence(const std::string& str, const std::string& sep = ",");
 
     std::vector<std::vector<int32_t>> parseEnrollmentCapture(const std::string& str);
@@ -74,15 +76,35 @@
 
     std::mt19937 mRandom;
 
+    enum class WorkMode : int8_t { kIdle = 0, kAuthenticate, kEnroll, kDetectInteract };
+
+    WorkMode getWorkMode() { return mWorkMode; }
+
     virtual std::string toString() const {
         std::ostringstream os;
         os << "----- FakeFingerprintEngine:: -----" << std::endl;
+        os << "mWorkMode:" << (int)mWorkMode;
         os << "acquiredVendorInfoBase:" << FINGERPRINT_ACQUIRED_VENDOR_BASE;
         os << ", errorVendorBase:" << FINGERPRINT_ERROR_VENDOR_BASE << std::endl;
         os << mLockoutTracker.toString();
         return os.str();
     }
 
+  protected:
+    virtual void updateContext(WorkMode mode, ISessionCallback* cb, std::future<void>& cancel,
+                               int64_t operationId, const keymaster::HardwareAuthToken& hat);
+
+    bool onEnrollFingerDown(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat,
+                            const std::future<void>& cancel);
+    bool onAuthenticateFingerDown(ISessionCallback* cb, int64_t, const std::future<void>& cancel);
+    bool onDetectInteractFingerDown(ISessionCallback* cb, const std::future<void>& cancel);
+
+    WorkMode mWorkMode;
+    ISessionCallback* mCb;
+    keymaster::HardwareAuthToken mHat;
+    std::future<void> mCancel;
+    int64_t mOperationId;
+
   private:
     static constexpr int32_t FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;
     static constexpr int32_t FINGERPRINT_ERROR_VENDOR_BASE = 1000;
@@ -91,8 +113,21 @@
     bool parseEnrollmentCaptureSingle(const std::string& str,
                                       std::vector<std::vector<int32_t>>& res);
     int32_t getRandomInRange(int32_t bound1, int32_t bound2);
+    bool checkSensorLockout(ISessionCallback*);
+    void clearLockout(ISessionCallback* cb);
 
     FakeLockoutTracker mLockoutTracker;
+
+  protected:
+    // lockout timer
+    void lockoutTimerExpired(ISessionCallback* cb);
+    bool isLockoutTimerSupported;
+    bool isLockoutTimerStarted;
+    bool isLockoutTimerAborted;
+
+  public:
+    void startLockoutTimer(int64_t timeout, ISessionCallback* cb);
+    bool getLockoutTimerStarted() { return isLockoutTimerStarted; }
 };
 
 }  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineSide.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineSide.h
index c2fc005..67a3ebc 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineSide.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineSide.h
@@ -28,7 +28,7 @@
     static constexpr int32_t defaultSensorLocationY = 600;
     static constexpr int32_t defaultSensorRadius = 150;
 
-    FakeFingerprintEngineSide() : FakeFingerprintEngine() {}
+    FakeFingerprintEngineSide();
     ~FakeFingerprintEngineSide() {}
 
     virtual SensorLocation defaultSensorLocation() override;
diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineUdfps.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineUdfps.h
index c5e93e7..2270eca 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineUdfps.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineUdfps.h
@@ -42,39 +42,20 @@
 
     SensorLocation defaultSensorLocation() override;
 
-    void enrollImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat,
-                    const std::future<void>& cancel);
-    void authenticateImpl(ISessionCallback* cb, int64_t operationId,
-                          const std::future<void>& cancel);
-    void detectInteractionImpl(ISessionCallback* cb, const std::future<void>& cancel);
-
-    enum class WorkMode : int8_t { kIdle = 0, kAuthenticate, kEnroll, kDetectInteract };
-
-    WorkMode getWorkMode() { return mWorkMode; }
+    void updateContext(WorkMode mode, ISessionCallback* cb, std::future<void>& cancel,
+                       int64_t operationId, const keymaster::HardwareAuthToken& hat);
+    void fingerDownAction();
 
     std::string toString() const {
         std::ostringstream os;
         os << FakeFingerprintEngine::toString();
         os << "----- FakeFingerprintEngineUdfps -----" << std::endl;
-        os << "mWorkMode:" << (int)mWorkMode;
         os << ", mUiReadyTime:" << mUiReadyTime;
         os << ", mPointerDownTime:" << mPointerDownTime << std::endl;
         return os.str();
     }
 
   private:
-    void onAuthenticateFingerDown();
-    void onEnrollFingerDown();
-    void onDetectInteractFingerDown();
-    void fingerDownAction();
-    void updateContext(WorkMode mode, ISessionCallback* cb, std::future<void>& cancel,
-                       int64_t operationId, const keymaster::HardwareAuthToken& hat);
-
-    WorkMode mWorkMode;
-    ISessionCallback* mCb;
-    keymaster::HardwareAuthToken mHat;
-    std::vector<std::future<void>> mCancelVec;
-    int64_t mOperationId;
     int64_t mPointerDownTime;
     int64_t mUiReadyTime;
 };
diff --git a/biometrics/fingerprint/aidl/default/include/Fingerprint.h b/biometrics/fingerprint/aidl/default/include/Fingerprint.h
index fc4fb8d..2bd66d4 100644
--- a/biometrics/fingerprint/aidl/default/include/Fingerprint.h
+++ b/biometrics/fingerprint/aidl/default/include/Fingerprint.h
@@ -43,6 +43,7 @@
   private:
     void resetConfigToDefault();
     void onHelp(int);
+    void onSimFingerDown();
 
     std::unique_ptr<FakeFingerprintEngine> mEngine;
     WorkerThread mWorker;
diff --git a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
index a200b39..fe405f4 100644
--- a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
+++ b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
@@ -93,9 +93,13 @@
         return ndk::ScopedAStatus::ok();
     };
     ndk::ScopedAStatus onLockoutTimed(int64_t /* timeout */) override {
+        mLockoutTimed = true;
         return ndk::ScopedAStatus::ok();
     }
-    ndk::ScopedAStatus onLockoutCleared() override { return ndk::ScopedAStatus::ok(); }
+    ndk::ScopedAStatus onLockoutCleared() override {
+        mLockoutCleared = true;
+        return ndk::ScopedAStatus::ok();
+    }
     ndk::ScopedAStatus onSessionClosed() override { return ndk::ScopedAStatus::ok(); }
 
     Error mError = Error::UNKNOWN;
@@ -110,6 +114,8 @@
     bool mAuthenticateFailed = false;
     bool mAuthenticatorIdInvalidated = false;
     bool mLockoutPermanent = false;
+    bool mLockoutTimed = false;
+    bool mLockoutCleared = false;
     int mInteractionDetectedCount = 0;
     int32_t mLastAcquiredInfo = -1;
     int32_t mLastAcquiredVendorCode = -1;
@@ -132,6 +138,8 @@
         FingerprintHalProperties::operation_enroll_latency({});
         FingerprintHalProperties::operation_authenticate_latency({});
         FingerprintHalProperties::operation_detect_interaction_latency({});
+        FingerprintHalProperties::operation_authenticate_fails(false);
+        FingerprintHalProperties::operation_detect_interaction_latency({});
     }
 
     FakeFingerprintEngine mEngine;
@@ -178,11 +186,14 @@
     FingerprintHalProperties::next_enrollment("4:0,0:true");
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mEngine.enrollImpl(mCallback.get(), hat, mCancel.get_future());
+    ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kEnroll);
+    mEngine.fingerDownAction();
     ASSERT_FALSE(FingerprintHalProperties::next_enrollment().has_value());
     ASSERT_EQ(1, FingerprintHalProperties::enrollments().size());
     ASSERT_EQ(4, FingerprintHalProperties::enrollments()[0].value());
     ASSERT_EQ(4, mCallback->mLastEnrolled);
     ASSERT_EQ(1, mCallback->mLastAcquiredInfo);
+    ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kIdle);
 }
 
 TEST_F(FakeFingerprintEngineTest, EnrollCancel) {
@@ -192,6 +203,7 @@
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mCancel.set_value();
     mEngine.enrollImpl(mCallback.get(), hat, mCancel.get_future());
+    mEngine.fingerDownAction();
     ASSERT_EQ(Error::CANCELED, mCallback->mError);
     ASSERT_EQ(-1, mCallback->mLastEnrolled);
     ASSERT_EQ(0, FingerprintHalProperties::enrollments().size());
@@ -204,6 +216,7 @@
     FingerprintHalProperties::next_enrollment(next);
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mEngine.enrollImpl(mCallback.get(), hat, mCancel.get_future());
+    mEngine.fingerDownAction();
     ASSERT_EQ(Error::UNABLE_TO_PROCESS, mCallback->mError);
     ASSERT_EQ(-1, mCallback->mLastEnrolled);
     ASSERT_EQ(0, FingerprintHalProperties::enrollments().size());
@@ -216,6 +229,7 @@
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     int32_t prevCnt = mCallback->mLastAcquiredCount;
     mEngine.enrollImpl(mCallback.get(), hat, mCancel.get_future());
+    mEngine.fingerDownAction();
     ASSERT_FALSE(FingerprintHalProperties::next_enrollment().has_value());
     ASSERT_EQ(1, FingerprintHalProperties::enrollments().size());
     ASSERT_EQ(4, FingerprintHalProperties::enrollments()[0].value());
@@ -229,9 +243,12 @@
     FingerprintHalProperties::enrollments({1, 2});
     FingerprintHalProperties::enrollment_hit(2);
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
+    ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kAuthenticate);
+    mEngine.fingerDownAction();
     ASSERT_FALSE(mCallback->mAuthenticateFailed);
     ASSERT_EQ(2, mCallback->mLastAuthenticated);
     ASSERT_EQ(1, mCallback->mLastAcquiredInfo);
+    ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kIdle);
 }
 
 TEST_F(FakeFingerprintEngineTest, AuthenticateCancel) {
@@ -239,6 +256,7 @@
     FingerprintHalProperties::enrollment_hit(2);
     mCancel.set_value();
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
+    mEngine.fingerDownAction();
     ASSERT_EQ(Error::CANCELED, mCallback->mError);
     ASSERT_EQ(-1, mCallback->mLastAuthenticated);
 }
@@ -247,6 +265,7 @@
     FingerprintHalProperties::enrollments({1, 2});
     FingerprintHalProperties::enrollment_hit({});
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
+    mEngine.fingerDownAction();
     ASSERT_TRUE(mCallback->mAuthenticateFailed);
 }
 
@@ -254,7 +273,9 @@
     FingerprintHalProperties::enrollments({1, 2});
     FingerprintHalProperties::enrollment_hit(3);
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
+    mEngine.fingerDownAction();
     ASSERT_TRUE(mCallback->mAuthenticateFailed);
+    ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kAuthenticate);
 }
 
 TEST_F(FakeFingerprintEngineTest, AuthenticateLockout) {
@@ -262,6 +283,7 @@
     FingerprintHalProperties::enrollment_hit(2);
     FingerprintHalProperties::lockout(true);
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
+    mEngine.fingerDownAction();
     ASSERT_TRUE(mCallback->mLockoutPermanent);
     ASSERT_NE(mCallback->mError, Error::UNKNOWN);
 }
@@ -269,6 +291,7 @@
 TEST_F(FakeFingerprintEngineTest, AuthenticateError8) {
     FingerprintHalProperties::operation_authenticate_error(8);
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
+    mEngine.fingerDownAction();
     ASSERT_EQ(mCallback->mError, (Error)8);
     ASSERT_EQ(mCallback->mErrorVendorCode, 0);
 }
@@ -276,10 +299,19 @@
 TEST_F(FakeFingerprintEngineTest, AuthenticateError9) {
     FingerprintHalProperties::operation_authenticate_error(1009);
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
+    mEngine.fingerDownAction();
     ASSERT_EQ(mCallback->mError, (Error)7);
     ASSERT_EQ(mCallback->mErrorVendorCode, 9);
 }
 
+TEST_F(FakeFingerprintEngineTest, AuthenticateFails) {
+    FingerprintHalProperties::operation_authenticate_fails(true);
+    mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
+    mEngine.fingerDownAction();
+    ASSERT_TRUE(mCallback->mAuthenticateFailed);
+    ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kAuthenticate);
+}
+
 TEST_F(FakeFingerprintEngineTest, AuthenticateAcquired) {
     FingerprintHalProperties::lockout(false);
     FingerprintHalProperties::enrollments({1, 2});
@@ -287,6 +319,7 @@
     FingerprintHalProperties::operation_authenticate_acquired("4,1009");
     int32_t prevCount = mCallback->mLastAcquiredCount;
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
+    mEngine.fingerDownAction();
     ASSERT_FALSE(mCallback->mAuthenticateFailed);
     ASSERT_EQ(2, mCallback->mLastAuthenticated);
     ASSERT_EQ(prevCount + 2, mCallback->mLastAcquiredCount);
@@ -300,8 +333,11 @@
     FingerprintHalProperties::enrollment_hit(2);
     FingerprintHalProperties::operation_detect_interaction_acquired("");
     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
+    ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kDetectInteract);
+    mEngine.fingerDownAction();
     ASSERT_EQ(1, mCallback->mInteractionDetectedCount);
     ASSERT_EQ(1, mCallback->mLastAcquiredInfo);
+    ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kIdle);
 }
 
 TEST_F(FakeFingerprintEngineTest, InteractionDetectCancel) {
@@ -310,6 +346,7 @@
     FingerprintHalProperties::enrollment_hit(2);
     mCancel.set_value();
     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
+    mEngine.fingerDownAction();
     ASSERT_EQ(Error::CANCELED, mCallback->mError);
     ASSERT_EQ(0, mCallback->mInteractionDetectedCount);
 }
@@ -319,6 +356,7 @@
     FingerprintHalProperties::enrollments({1, 2});
     FingerprintHalProperties::enrollment_hit({});
     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
+    mEngine.fingerDownAction();
     ASSERT_EQ(0, mCallback->mInteractionDetectedCount);
 }
 
@@ -326,6 +364,7 @@
     FingerprintHalProperties::enrollments({1, 2});
     FingerprintHalProperties::enrollment_hit(25);
     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
+    mEngine.fingerDownAction();
     ASSERT_EQ(0, mCallback->mInteractionDetectedCount);
 }
 
@@ -333,6 +372,7 @@
     FingerprintHalProperties::detect_interaction(true);
     FingerprintHalProperties::operation_detect_interaction_error(8);
     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
+    mEngine.fingerDownAction();
     ASSERT_EQ(0, mCallback->mInteractionDetectedCount);
     ASSERT_EQ(mCallback->mError, (Error)8);
     ASSERT_EQ(mCallback->mErrorVendorCode, 0);
@@ -345,6 +385,7 @@
     FingerprintHalProperties::operation_detect_interaction_acquired("4,1013");
     int32_t prevCount = mCallback->mLastAcquiredCount;
     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
+    mEngine.fingerDownAction();
     ASSERT_EQ(1, mCallback->mInteractionDetectedCount);
     ASSERT_EQ(prevCount + 2, mCallback->mLastAcquiredCount);
     ASSERT_EQ(7, mCallback->mLastAcquiredInfo);
@@ -354,9 +395,7 @@
 TEST_F(FakeFingerprintEngineTest, EnumerateEnrolled) {
     FingerprintHalProperties::enrollments({2, 4, 8});
     mEngine.enumerateEnrollmentsImpl(mCallback.get());
-    ASSERT_EQ(
-            4,
-            mCallback->mLastEnrollmentEnumerated.size());  // Due to workaround. TODO (b/243129174)
+    ASSERT_EQ(3, mCallback->mLastEnrollmentEnumerated.size());
     for (auto id : FingerprintHalProperties::enrollments()) {
         ASSERT_TRUE(std::find(mCallback->mLastEnrollmentEnumerated.begin(),
                               mCallback->mLastEnrollmentEnumerated.end(),
@@ -464,9 +503,15 @@
                 FingerprintHalProperties::operation_detect_interaction_latency()));
     }
     ASSERT_TRUE(latencySet.size() > 95);
-    FingerprintHalProperties::operation_detect_interaction_latency({});
 }
 
+TEST_F(FakeFingerprintEngineTest, lockoutTimer) {
+    mEngine.startLockoutTimer(200, mCallback.get());
+    ASSERT_TRUE(mEngine.getLockoutTimerStarted());
+    std::this_thread::sleep_for(std::chrono::milliseconds(210));
+    ASSERT_FALSE(mEngine.getLockoutTimerStarted());
+    ASSERT_TRUE(mCallback->mLockoutCleared);
+}
 }  // namespace aidl::android::hardware::biometrics::fingerprint
 
 int main(int argc, char** argv) {
diff --git a/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp
index 1b071ee..93c6f84 100644
--- a/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp
+++ b/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp
@@ -65,11 +65,11 @@
     ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kTimed);
     // time left
     int N = 5;
-    int64_t prevTimeLeft = INT_MIN;
+    int64_t prevTimeLeft = INT_MAX;
     for (int i = 0; i < N; i++) {
         SLEEP_MS(LOCKOUT_TIMED_DURATION / N + 1);
         int64_t currTimeLeft = mLockoutTracker.getLockoutTimeLeft();
-        ASSERT_TRUE(currTimeLeft > prevTimeLeft);
+        ASSERT_TRUE(currTimeLeft < prevTimeLeft);
         prevTimeLeft = currTimeLeft;
     }
     ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
diff --git a/bluetooth/aidl/default/BluetoothHci.cpp b/bluetooth/aidl/default/BluetoothHci.cpp
index 9862e9e..a247cb0 100644
--- a/bluetooth/aidl/default/BluetoothHci.cpp
+++ b/bluetooth/aidl/default/BluetoothHci.cpp
@@ -320,6 +320,7 @@
   {
     std::lock_guard<std::mutex> guard(mStateMutex);
     mState = HalState::READY;
+    mH4 = nullptr;
   }
   return ndk::ScopedAStatus::ok();
 }
@@ -346,13 +347,16 @@
 
 ndk::ScopedAStatus BluetoothHci::send(PacketType type,
     const std::vector<uint8_t>& v) {
-  if (mH4 == nullptr) {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-  }
   if (v.empty()) {
     ALOGE("Packet is empty, no data was found to be sent");
     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
   }
+
+  std::lock_guard<std::mutex> guard(mStateMutex);
+  if (mH4 == nullptr) {
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+  }
+
   mH4->Send(type, v);
   return ndk::ScopedAStatus::ok();
 }
diff --git a/bluetooth/aidl/default/net_bluetooth_mgmt.cpp b/bluetooth/aidl/default/net_bluetooth_mgmt.cpp
index 937cd57..0699781 100644
--- a/bluetooth/aidl/default/net_bluetooth_mgmt.cpp
+++ b/bluetooth/aidl/default/net_bluetooth_mgmt.cpp
@@ -162,9 +162,9 @@
           (struct mgmt_ev_read_index_list*)ev.data;
 
       for (int i = 0; i < data->num_controllers; i++) {
-        if (data->index[i] == hci_interface) {
-          ALOGI("hci interface %d found", hci_interface);
-          ret = 0;
+        if (data->index[i] >= hci_interface) {
+          ALOGI("hci interface %d found", data->index[i]);
+          ret = data->index[i];
           goto end;
         }
       }
@@ -253,8 +253,9 @@
   rfkill(1);
 
   // Wait for the HCI interface to complete initialization or to come online.
-  if (waitHciDev(hci_interface)) {
-    ALOGE("hci interface %d not found", hci_interface);
+  hci_interface = waitHciDev(hci_interface);
+  if (hci_interface < 0) {
+    ALOGE("hci interface not found");
     return -1;
   }
 
diff --git a/bluetooth/audio/aidl/Android.bp b/bluetooth/audio/aidl/Android.bp
index 1028fae..feed6f5 100644
--- a/bluetooth/audio/aidl/Android.bp
+++ b/bluetooth/audio/aidl/Android.bp
@@ -27,10 +27,12 @@
     host_supported: true,
     srcs: ["android/hardware/bluetooth/audio/*.aidl"],
     stability: "vintf",
+    defaults: [
+        "latest_android_hardware_audio_common_import_interface",
+    ],
     imports: [
         "android.hardware.common-V2",
         "android.hardware.common.fmq-V1",
-        "android.hardware.audio.common-V2",
     ],
     backend: {
         cpp: {
@@ -75,6 +77,23 @@
         },
 
     ],
-    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"
+
+cc_defaults {
+    name: "latest_android_hardware_bluetooth_audio_ndk_shared",
+    shared_libs: [
+        latest_android_hardware_bluetooth_audio + "-ndk",
+    ],
+}
+
+cc_defaults {
+    name: "latest_android_hardware_bluetooth_audio_ndk_static",
+    static_libs: [
+        latest_android_hardware_bluetooth_audio + "-ndk",
+    ],
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpConfiguration.aidl
new file mode 100644
index 0000000..9e67b15
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpConfiguration.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable A2dpConfiguration {
+  int remoteSeid;
+  android.hardware.bluetooth.audio.CodecId id;
+  android.hardware.bluetooth.audio.CodecParameters parameters;
+  byte[] configuration;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpConfigurationHint.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpConfigurationHint.aidl
new file mode 100644
index 0000000..0a5b489
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpConfigurationHint.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable A2dpConfigurationHint {
+  byte[6] bdAddr;
+  android.hardware.bluetooth.audio.AudioContext audioContext;
+  @nullable android.hardware.bluetooth.audio.CodecId codecId;
+  @nullable android.hardware.bluetooth.audio.CodecParameters codecParameters;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpRemoteCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpRemoteCapabilities.aidl
new file mode 100644
index 0000000..9c1e971
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpRemoteCapabilities.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable A2dpRemoteCapabilities {
+  int seid;
+  android.hardware.bluetooth.audio.CodecId id;
+  byte[] capabilities;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpStatus.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpStatus.aidl
new file mode 100644
index 0000000..ac22e25
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpStatus.aidl
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum A2dpStatus {
+  OK = 0,
+  BAD_LENGTH = 0x11u8,
+  BAD_PAYLOAD_FORMAT = 0x18u8,
+  INVALID_CODEC_TYPE = 0xC1u8,
+  NOT_SUPPORTED_CODEC_TYPE = 0xC2u8,
+  INVALID_SAMPLING_FREQUENCY = 0xC3u8,
+  NOT_SUPPORTED_SAMPLING_FREQUENCY = 0xC4u8,
+  INVALID_CHANNEL_MODE = 0xC5u8,
+  NOT_SUPPORTED_CHANNEL_MODE = 0xC6u8,
+  INVALID_SUBBANDS = 0xC7u8,
+  NOT_SUPPORTED_SUBBANDS = 0xC8u8,
+  INVALID_ALLOCATION_METHOD = 0xC9u8,
+  NOT_SUPPORTED_ALLOCATION_METHOD = 0xCAu8,
+  INVALID_MINIMUM_BITPOOL_VALUE = 0xCBu8,
+  NOT_SUPPORTED_MINIMUM_BITPOOL_VALUE = 0xCCu8,
+  INVALID_MAXIMUM_BITPOOL_VALUE = 0xCDu8,
+  NOT_SUPPORTED_MAXIMUM_BITPOOL_VALUE = 0xCEu8,
+  NOT_SUPPORTED_VBR = 0xD3u8,
+  NOT_SUPPORTED_BIT_RATE = 0xD5u8,
+  INVALID_OBJECT_TYPE = 0xD6u8,
+  NOT_SUPPORTED_OBJECT_TYPE = 0xD7u8,
+  INVALID_CHANNELS = 0xD8u8,
+  NOT_SUPPORTED_CHANNELS = 0xD9u8,
+  INVALID_BLOCK_LENGTH = 0xDDu8,
+  INVALID_CODEC_PARAMETER = 0xE2u8,
+  NOT_SUPPORTED_CODEC_PARAMETER = 0xE3u8,
+  INVALID_DRC = 0xE4u8,
+  NOT_SUPPORTED_DRC = 0xE5u8,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpStreamConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpStreamConfiguration.aidl
new file mode 100644
index 0000000..ff5a1bc
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpStreamConfiguration.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable A2dpStreamConfiguration {
+  int peerMtu;
+  @nullable byte[1] cpHeaderScmst;
+  android.hardware.bluetooth.audio.CodecId codecId;
+  byte[] configuration;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacObjectType.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacObjectType.aidl
index 2148244..418dd7a 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacObjectType.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacObjectType.aidl
@@ -34,8 +34,8 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="byte") @VintfStability
 enum AacObjectType {
-  MPEG2_LC = 0,
-  MPEG4_LC = 1,
-  MPEG4_LTP = 2,
-  MPEG4_SCALABLE = 3,
+  MPEG2_LC,
+  MPEG4_LC,
+  MPEG4_LTP,
+  MPEG4_SCALABLE,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxAdaptiveChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxAdaptiveChannelMode.aidl
index 0499b70..675f9f2 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxAdaptiveChannelMode.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxAdaptiveChannelMode.aidl
@@ -38,5 +38,5 @@
   MONO = 1,
   DUAL_MONO = 2,
   TWS_STEREO = 4,
-  UNKNOWN = 255,
+  UNKNOWN = 0xFF,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxAdaptiveInputMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxAdaptiveInputMode.aidl
index f702939..a18303e 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxAdaptiveInputMode.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxAdaptiveInputMode.aidl
@@ -34,6 +34,6 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="int") @VintfStability
 enum AptxAdaptiveInputMode {
-  STEREO = 0,
-  DUAL_MONO = 1,
+  STEREO = 0x00,
+  DUAL_MONO = 0x01,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxMode.aidl
index d5dd9d9..dd8cf08 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxMode.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxMode.aidl
@@ -34,8 +34,8 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="int") @VintfStability
 enum AptxMode {
-  UNKNOWN = 0,
-  HIGH_QUALITY = 4096,
-  LOW_LATENCY = 8192,
-  ULTRA_LOW_LATENCY = 16384,
+  UNKNOWN = 0x00,
+  HIGH_QUALITY = 0x1000,
+  LOW_LATENCY = 0x2000,
+  ULTRA_LOW_LATENCY = 0x4000,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioConfiguration.aidl
index 3abfb31..2c40267 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioConfiguration.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioConfiguration.aidl
@@ -38,4 +38,6 @@
   android.hardware.bluetooth.audio.CodecConfiguration a2dpConfig;
   android.hardware.bluetooth.audio.LeAudioConfiguration leAudioConfig;
   android.hardware.bluetooth.audio.LeAudioBroadcastConfiguration leAudioBroadcastConfig;
+  android.hardware.bluetooth.audio.HfpConfiguration hfpConfig;
+  android.hardware.bluetooth.audio.A2dpStreamConfiguration a2dp;
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioContext.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioContext.aidl
new file mode 100644
index 0000000..5aafeb7
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioContext.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable AudioContext {
+  int bitmask;
+  const int UNSPECIFIED = 0x0001;
+  const int CONVERSATIONAL = 0x0002;
+  const int MEDIA = 0x0004;
+  const int GAME = 0x0008;
+  const int INSTRUCTIONAL = 0x0010;
+  const int VOICE_ASSISTANTS = 0x0020;
+  const int LIVE_AUDIO = 0x0040;
+  const int SOUND_EFFECTS = 0x0080;
+  const int NOTIFICATIONS = 0x0100;
+  const int RINGTONE_ALERTS = 0x0200;
+  const int ALERTS = 0x0400;
+  const int EMERGENCY_ALARM = 0x0800;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioLocation.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioLocation.aidl
index 319a5e2..941344c 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioLocation.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioLocation.aidl
@@ -35,6 +35,6 @@
 @Backing(type="int") @VintfStability
 enum AudioLocation {
   UNKNOWN = 1,
-  FRONT_LEFT = 2,
-  FRONT_RIGHT = 4,
+  FRONT_LEFT = (1 << 1) /* 2 */,
+  FRONT_RIGHT = (1 << 2) /* 4 */,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ChannelMode.aidl
index feacb80..2bb5cd8 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ChannelMode.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ChannelMode.aidl
@@ -34,8 +34,8 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="byte") @VintfStability
 enum ChannelMode {
-  UNKNOWN = 0,
-  MONO = 1,
-  STEREO = 2,
-  DUALMONO = 3,
+  UNKNOWN,
+  MONO,
+  STEREO,
+  DUALMONO,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecId.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecId.aidl
new file mode 100644
index 0000000..f3b4102
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecId.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+union CodecId {
+  android.hardware.bluetooth.audio.CodecId.A2dp a2dp = android.hardware.bluetooth.audio.CodecId.A2dp.SBC;
+  android.hardware.bluetooth.audio.CodecId.Core core;
+  android.hardware.bluetooth.audio.CodecId.Vendor vendor;
+  enum A2dp {
+    SBC = 0,
+    AAC = 2,
+  }
+  enum Core {
+    CVSD = 2,
+    MSBC = 5,
+    LC3 = 6,
+  }
+  parcelable Vendor {
+    int id;
+    int codecId;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecInfo.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecInfo.aidl
new file mode 100644
index 0000000..2727d6e
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecInfo.aidl
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable CodecInfo {
+  android.hardware.bluetooth.audio.CodecId id;
+  String name;
+  android.hardware.bluetooth.audio.CodecInfo.Transport transport;
+  parcelable A2dp {
+    byte[] capabilities;
+    android.hardware.bluetooth.audio.ChannelMode[] channelMode;
+    int[] samplingFrequencyHz;
+    int[] bitdepth;
+    boolean lossless;
+  }
+  parcelable Hfp {
+    int inputDataPath = 1;
+    int outputDataPath = 1;
+    boolean useControllerCodec = true;
+  }
+  parcelable LeAudio {
+    android.hardware.bluetooth.audio.ChannelMode[] channelMode;
+    int[] samplingFrequencyHz;
+    int[] frameDurationUs;
+    int[] bitdepth;
+    @nullable android.hardware.bluetooth.audio.ConfigurationFlags flags;
+  }
+  union Transport {
+    android.hardware.bluetooth.audio.CodecInfo.LeAudio leAudio;
+    android.hardware.bluetooth.audio.CodecInfo.A2dp a2dp;
+    android.hardware.bluetooth.audio.CodecInfo.Hfp hfp;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecParameters.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecParameters.aidl
new file mode 100644
index 0000000..60cf82a
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecParameters.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable CodecParameters {
+  android.hardware.bluetooth.audio.ChannelMode channelMode;
+  int samplingFrequencyHz;
+  int bitdepth;
+  int minBitrate;
+  int maxBitrate;
+  boolean lowLatency;
+  boolean lossless;
+  byte[] vendorSpecificParameters;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecSpecificCapabilitiesLtv.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecSpecificCapabilitiesLtv.aidl
new file mode 100644
index 0000000..1049d98
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecSpecificCapabilitiesLtv.aidl
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+union CodecSpecificCapabilitiesLtv {
+  android.hardware.bluetooth.audio.CodecSpecificCapabilitiesLtv.SupportedSamplingFrequencies supportedSamplingFrequencies;
+  android.hardware.bluetooth.audio.CodecSpecificCapabilitiesLtv.SupportedFrameDurations supportedFrameDurations;
+  android.hardware.bluetooth.audio.CodecSpecificCapabilitiesLtv.SupportedAudioChannelCounts supportedAudioChannelCounts;
+  android.hardware.bluetooth.audio.CodecSpecificCapabilitiesLtv.SupportedOctetsPerCodecFrame supportedOctetsPerCodecFrame;
+  android.hardware.bluetooth.audio.CodecSpecificCapabilitiesLtv.SupportedMaxCodecFramesPerSDU supportedMaxCodecFramesPerSDU;
+  parcelable SupportedSamplingFrequencies {
+    int bitmask;
+    const int HZ8000 = 0x0001;
+    const int HZ11025 = 0x0002;
+    const int HZ16000 = 0x0004;
+    const int HZ22050 = 0x0008;
+    const int HZ24000 = 0x0010;
+    const int HZ32000 = 0x0020;
+    const int HZ44100 = 0x0040;
+    const int HZ48000 = 0x0080;
+    const int HZ88200 = 0x0100;
+    const int HZ96000 = 0x0200;
+    const int HZ176400 = 0x0400;
+    const int HZ192000 = 0x0800;
+    const int HZ384000 = 0x1000;
+  }
+  parcelable SupportedFrameDurations {
+    int bitmask;
+    const int US7500 = 0x01;
+    const int US10000 = 0x02;
+    const int US7500PREFERRED = 0x10;
+    const int US10000PREFERRED = 0x20;
+  }
+  parcelable SupportedAudioChannelCounts {
+    int bitmask;
+    const int ONE = 0x01;
+    const int TWO = 0x02;
+    const int THREE = 0x04;
+    const int FOUR = 0x08;
+    const int FIVE = 0x10;
+    const int SIX = 0x20;
+    const int SEVEN = 0x40;
+    const int EIGHT = 0x80;
+  }
+  parcelable SupportedOctetsPerCodecFrame {
+    int minimum;
+    int maximum;
+  }
+  parcelable SupportedMaxCodecFramesPerSDU {
+    int value;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl
new file mode 100644
index 0000000..943d396
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+union CodecSpecificConfigurationLtv {
+  android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv.CodecFrameBlocksPerSDU codecFrameBlocksPerSDU;
+  android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv.SamplingFrequency samplingFrequency;
+  android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv.FrameDuration frameDuration;
+  android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv.AudioChannelAllocation audioChannelAllocation;
+  android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv.OctetsPerCodecFrame octetsPerCodecFrame;
+  @Backing(type="byte")
+  enum SamplingFrequency {
+    HZ8000 = 0x01,
+    HZ11025 = 0x02,
+    HZ16000 = 0x03,
+    HZ22050 = 0x04,
+    HZ24000 = 0x05,
+    HZ32000 = 0x06,
+    HZ44100 = 0x07,
+    HZ48000 = 0x08,
+    HZ88200 = 0x09,
+    HZ96000 = 0x0A,
+    HZ176400 = 0x0B,
+    HZ192000 = 0x0C,
+    HZ384000 = 0x0D,
+  }
+  @Backing(type="byte")
+  enum FrameDuration {
+    US7500 = 0x00,
+    US10000 = 0x01,
+  }
+  parcelable AudioChannelAllocation {
+    int bitmask;
+    const int NOT_ALLOWED = 0x00000000;
+    const int FRONT_LEFT = 0x00000001;
+    const int FRONT_RIGHT = 0x00000002;
+    const int FRONT_CENTER = 0x00000004;
+    const int LOW_FREQUENCY_EFFECTS_1 = 0x00000008;
+    const int BACK_LEFT = 0x00000010;
+    const int BACK_RIGHT = 0x00000020;
+    const int FRONT_LEFT_OF_CENTER = 0x00000040;
+    const int FRONT_RIGHT_OF_CENTER = 0x00000080;
+    const int BACK_CENTER = 0x00000100;
+    const int LOW_FREQUENCY_EFFECTS_2 = 0x00000200;
+    const int SIDE_LEFT = 0x00000400;
+    const int SIDE_RIGHT = 0x00000800;
+    const int TOP_FRONT_LEFT = 0x00001000;
+    const int TOP_FRONT_RIGHT = 0x00002000;
+    const int TOP_FRONT_CENTER = 0x00004000;
+    const int TOP_CENTER = 0x00008000;
+    const int TOP_BACK_LEFT = 0x00010000;
+    const int TOP_BACK_RIGHT = 0x00020000;
+    const int TOP_SIDE_LEFT = 0x00040000;
+    const int TOP_SIDE_RIGHT = 0x00080000;
+    const int TOP_BACK_CENTER = 0x00100000;
+    const int BOTTOM_FRONT_CENTER = 0x00200000;
+    const int BOTTOM_FRONT_LEFT = 0x00400000;
+    const int BOTTOM_FRONT_RIGHT = 0x00800000;
+    const int FRONT_LEFT_WIDE = 0x01000000;
+    const int FRONT_RIGHT_WIDE = 0x02000000;
+    const int LEFT_SURROUND = 0x04000000;
+    const int RIGHT_SURROUND = 0x08000000;
+  }
+  parcelable OctetsPerCodecFrame {
+    int value;
+  }
+  parcelable CodecFrameBlocksPerSDU {
+    int value;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl
index 3e204f9..d4f205e 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl
@@ -34,16 +34,16 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="int") @VintfStability
 enum CodecType {
-  UNKNOWN = 0,
-  SBC = 1,
-  AAC = 2,
-  APTX = 3,
-  APTX_HD = 4,
-  LDAC = 5,
-  LC3 = 6,
-  VENDOR = 7,
-  APTX_ADAPTIVE = 8,
-  OPUS = 9,
-  APTX_ADAPTIVE_LE = 10,
-  APTX_ADAPTIVE_LEX = 11,
+  UNKNOWN,
+  SBC,
+  AAC,
+  APTX,
+  APTX_HD,
+  LDAC,
+  LC3,
+  VENDOR,
+  APTX_ADAPTIVE,
+  OPUS,
+  APTX_ADAPTIVE_LE,
+  APTX_ADAPTIVE_LEX,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ConfigurationFlags.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ConfigurationFlags.aidl
new file mode 100644
index 0000000..baf0a4e
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ConfigurationFlags.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable ConfigurationFlags {
+  int bitmask;
+  const int NONE = 0x0000;
+  const int LOSSLESS = 0x0001;
+  const int LOW_LATENCY = 0x0002;
+  const int ALLOW_ASYMMETRIC_CONFIGURATIONS = 0x0003;
+  const int SPATIAL_AUDIO = 0x0004;
+  const int PROVIDE_ASE_METADATA = 0x0005;
+  const int MONO_MIC_CONFIGURATION = 0x0006;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/HfpConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/HfpConfiguration.aidl
new file mode 100644
index 0000000..490a05d
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/HfpConfiguration.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable HfpConfiguration {
+  android.hardware.bluetooth.audio.CodecId codecId;
+  int connectionHandle;
+  boolean nrec;
+  boolean controllerCodec;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
index 267af0f..87401ff 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
@@ -40,4 +40,158 @@
   void streamSuspended(in android.hardware.bluetooth.audio.BluetoothAudioStatus status);
   void updateAudioConfiguration(in android.hardware.bluetooth.audio.AudioConfiguration audioConfig);
   void setLowLatencyModeAllowed(in boolean allowed);
+  android.hardware.bluetooth.audio.A2dpStatus parseA2dpConfiguration(in android.hardware.bluetooth.audio.CodecId codecId, in byte[] configuration, out android.hardware.bluetooth.audio.CodecParameters codecParameters);
+  @nullable android.hardware.bluetooth.audio.A2dpConfiguration getA2dpConfiguration(in List<android.hardware.bluetooth.audio.A2dpRemoteCapabilities> remoteA2dpCapabilities, in android.hardware.bluetooth.audio.A2dpConfigurationHint hint);
+  void setCodecPriority(in android.hardware.bluetooth.audio.CodecId codecId, int priority);
+  List<android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioAseConfigurationSetting> getLeAudioAseConfiguration(in @nullable List<android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioDeviceCapabilities> remoteSinkAudioCapabilities, in @nullable List<android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioDeviceCapabilities> remoteSourceAudioCapabilities, in List<android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioConfigurationRequirement> requirements);
+  android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioAseQosConfigurationPair getLeAudioAseQosConfiguration(in android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioAseQosConfigurationRequirement qosRequirement);
+  android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioDataPathConfigurationPair getLeAudioAseDatapathConfiguration(in @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.StreamConfig sinkConfig, in @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.StreamConfig sourceConfig);
+  void onSinkAseMetadataChanged(in android.hardware.bluetooth.audio.IBluetoothAudioProvider.AseState state, int cigId, int cisId, in @nullable android.hardware.bluetooth.audio.MetadataLtv[] metadata);
+  void onSourceAseMetadataChanged(in android.hardware.bluetooth.audio.IBluetoothAudioProvider.AseState state, int cigId, int cisId, in @nullable android.hardware.bluetooth.audio.MetadataLtv[] metadata);
+  android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioBroadcastConfigurationSetting getLeAudioBroadcastConfiguration(in @nullable List<android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioDeviceCapabilities> remoteSinkAudioCapabilities, in android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioBroadcastConfigurationRequirement requirement);
+  android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioDataPathConfiguration getLeAudioBroadcastDatapathConfiguration(in android.hardware.bluetooth.audio.AudioContext context, in android.hardware.bluetooth.audio.LeAudioBroadcastConfiguration.BroadcastStreamMap[] streamMap);
+  @VintfStability
+  parcelable LeAudioDeviceCapabilities {
+    android.hardware.bluetooth.audio.CodecId codecId;
+    android.hardware.bluetooth.audio.CodecSpecificCapabilitiesLtv[] codecSpecificCapabilities;
+    @nullable byte[] vendorCodecSpecificCapabilities;
+    @nullable android.hardware.bluetooth.audio.MetadataLtv[] metadata;
+  }
+  @VintfStability
+  parcelable LeAudioDataPathConfiguration {
+    int dataPathId;
+    android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioDataPathConfiguration.DataPathConfiguration dataPathConfiguration;
+    android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioDataPathConfiguration.IsoDataPathConfiguration isoDataPathConfiguration;
+    @VintfStability
+    parcelable IsoDataPathConfiguration {
+      android.hardware.bluetooth.audio.CodecId codecId;
+      boolean isTransparent;
+      int controllerDelayUs;
+      @nullable byte[] configuration;
+    }
+    @VintfStability
+    parcelable DataPathConfiguration {
+      @nullable byte[] configuration;
+    }
+  }
+  @VintfStability
+  parcelable LeAudioAseQosConfiguration {
+    int sduIntervalUs;
+    android.hardware.bluetooth.audio.IBluetoothAudioProvider.Framing framing;
+    android.hardware.bluetooth.audio.Phy[] phy;
+    int maxTransportLatencyMs;
+    int maxSdu;
+    int retransmissionNum;
+  }
+  @Backing(type="byte") @VintfStability
+  enum Packing {
+    SEQUENTIAL = 0x00,
+    INTERLEAVED = 0x01,
+  }
+  @Backing(type="byte") @VintfStability
+  enum Framing {
+    UNFRAMED = 0x00,
+    FRAMED = 0x01,
+  }
+  @VintfStability
+  parcelable LeAudioAseConfigurationSetting {
+    android.hardware.bluetooth.audio.AudioContext audioContext;
+    android.hardware.bluetooth.audio.IBluetoothAudioProvider.Packing packing;
+    @nullable List<android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioAseConfigurationSetting.AseDirectionConfiguration> sinkAseConfiguration;
+    @nullable List<android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioAseConfigurationSetting.AseDirectionConfiguration> sourceAseConfiguration;
+    @nullable android.hardware.bluetooth.audio.ConfigurationFlags flags;
+    @VintfStability
+    parcelable AseDirectionConfiguration {
+      android.hardware.bluetooth.audio.LeAudioAseConfiguration aseConfiguration;
+      @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioAseQosConfiguration qosConfiguration;
+      @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioDataPathConfiguration dataPathConfiguration;
+    }
+  }
+  @VintfStability
+  parcelable LeAudioConfigurationRequirement {
+    android.hardware.bluetooth.audio.AudioContext audioContext;
+    @nullable List<android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioConfigurationRequirement.AseDirectionRequirement> sinkAseRequirement;
+    @nullable List<android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioConfigurationRequirement.AseDirectionRequirement> sourceAseRequirement;
+    @nullable android.hardware.bluetooth.audio.ConfigurationFlags flags;
+    @VintfStability
+    parcelable AseDirectionRequirement {
+      android.hardware.bluetooth.audio.LeAudioAseConfiguration aseConfiguration;
+    }
+  }
+  @VintfStability
+  parcelable LeAudioAseQosConfigurationRequirement {
+    android.hardware.bluetooth.audio.AudioContext contextType;
+    @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioAseQosConfigurationRequirement.AseQosDirectionRequirement sinkAseQosRequirement;
+    @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioAseQosConfigurationRequirement.AseQosDirectionRequirement sourceAseQosRequirement;
+    @nullable android.hardware.bluetooth.audio.ConfigurationFlags flags;
+    @VintfStability
+    parcelable AseQosDirectionRequirement {
+      android.hardware.bluetooth.audio.IBluetoothAudioProvider.Framing framing;
+      android.hardware.bluetooth.audio.Phy[] preferredPhy;
+      int preferredRetransmissionNum;
+      int maxTransportLatencyMs;
+      int presentationDelayMinUs;
+      int presentationDelayMaxUs;
+      int preferredPresentationDelayMinUs;
+      int preferredPresentationDelayMaxUs;
+      android.hardware.bluetooth.audio.LeAudioAseConfiguration aseConfiguration;
+    }
+  }
+  @VintfStability
+  parcelable LeAudioAseQosConfigurationPair {
+    @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioAseQosConfiguration sinkQosConfiguration;
+    @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioAseQosConfiguration sourceQosConfiguration;
+  }
+  parcelable LeAudioDataPathConfigurationPair {
+    @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioDataPathConfiguration inputConfig;
+    @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioDataPathConfiguration outputConfig;
+  }
+  parcelable StreamConfig {
+    android.hardware.bluetooth.audio.AudioContext context;
+    android.hardware.bluetooth.audio.LeAudioConfiguration.StreamMap[] streamMap;
+  }
+  @Backing(type="byte") @VintfStability
+  enum AseState {
+    ENABLING = 0x00,
+    STREAMING = 0x01,
+    DISABLING = 0x02,
+  }
+  @Backing(type="byte") @VintfStability
+  enum BroadcastQuality {
+    STANDARD,
+    HIGH,
+  }
+  @VintfStability
+  parcelable LeAudioBroadcastSubgroupConfigurationRequirement {
+    android.hardware.bluetooth.audio.AudioContext context;
+    android.hardware.bluetooth.audio.IBluetoothAudioProvider.BroadcastQuality quality;
+    int bisNumPerSubgroup;
+  }
+  @VintfStability
+  parcelable LeAudioBroadcastConfigurationRequirement {
+    List<android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioBroadcastSubgroupConfigurationRequirement> subgroupConfigurationRequirements;
+  }
+  @VintfStability
+  parcelable LeAudioSubgroupBisConfiguration {
+    int numBis;
+    android.hardware.bluetooth.audio.LeAudioBisConfiguration bisConfiguration;
+  }
+  @VintfStability
+  parcelable LeAudioBroadcastSubgroupConfiguration {
+    List<android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioSubgroupBisConfiguration> bisConfigurations;
+    @nullable byte[] vendorCodecConfiguration;
+  }
+  @VintfStability
+  parcelable LeAudioBroadcastConfigurationSetting {
+    int sduIntervalUs;
+    int numBis;
+    int maxSduOctets;
+    int maxTransportLatencyMs;
+    int retransmitionNum;
+    android.hardware.bluetooth.audio.Phy[] phy;
+    android.hardware.bluetooth.audio.IBluetoothAudioProvider.Packing packing;
+    android.hardware.bluetooth.audio.IBluetoothAudioProvider.Framing framing;
+    @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioDataPathConfiguration dataPathConfiguration;
+    List<android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioBroadcastSubgroupConfiguration> subgroupsConfigurations;
+  }
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl
index 5e33deb..edb79a3 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl
@@ -36,4 +36,11 @@
 interface IBluetoothAudioProviderFactory {
   android.hardware.bluetooth.audio.AudioCapabilities[] getProviderCapabilities(in android.hardware.bluetooth.audio.SessionType sessionType);
   android.hardware.bluetooth.audio.IBluetoothAudioProvider openProvider(in android.hardware.bluetooth.audio.SessionType sessionType);
+  @nullable android.hardware.bluetooth.audio.IBluetoothAudioProviderFactory.ProviderInfo getProviderInfo(in android.hardware.bluetooth.audio.SessionType sessionType);
+  @VintfStability
+  parcelable ProviderInfo {
+    String name;
+    android.hardware.bluetooth.audio.CodecInfo[] codecInfos;
+    boolean supportsMultidirectionalCapabilities;
+  }
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacChannelMode.aidl
index 88d6faf..3d80c4b 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacChannelMode.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacChannelMode.aidl
@@ -34,8 +34,8 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="byte") @VintfStability
 enum LdacChannelMode {
-  UNKNOWN = 0,
-  STEREO = 1,
-  DUAL = 2,
-  MONO = 3,
+  UNKNOWN,
+  STEREO,
+  DUAL,
+  MONO,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacQualityIndex.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacQualityIndex.aidl
index 35e4358..a332dc5 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacQualityIndex.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacQualityIndex.aidl
@@ -34,8 +34,8 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="byte") @VintfStability
 enum LdacQualityIndex {
-  HIGH = 0,
-  MID = 1,
-  LOW = 2,
-  ABR = 3,
+  HIGH,
+  MID,
+  LOW,
+  ABR,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioAseConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioAseConfiguration.aidl
new file mode 100644
index 0000000..bffc88b
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioAseConfiguration.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable LeAudioAseConfiguration {
+  android.hardware.bluetooth.audio.LeAudioAseConfiguration.TargetLatency targetLatency;
+  android.hardware.bluetooth.audio.Phy targetPhy;
+  @nullable android.hardware.bluetooth.audio.CodecId codecId;
+  android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv[] codecConfiguration;
+  @nullable byte[] vendorCodecConfiguration;
+  @nullable android.hardware.bluetooth.audio.MetadataLtv[] metadata;
+  @Backing(type="byte") @VintfStability
+  enum TargetLatency {
+    UNDEFINED = 0x00,
+    LOWER = 0x01,
+    BALANCED_LATENCY_RELIABILITY = 0x02,
+    HIGHER_RELIABILITY = 0x03,
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioBisConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioBisConfiguration.aidl
new file mode 100644
index 0000000..b09d34f
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioBisConfiguration.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable LeAudioBisConfiguration {
+  android.hardware.bluetooth.audio.CodecId codecId;
+  android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv[] codecConfiguration;
+  byte[] vendorCodecConfiguration;
+  @nullable android.hardware.bluetooth.audio.MetadataLtv[] metadata;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioBroadcastConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioBroadcastConfiguration.aidl
index 2945710..efd3b02 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioBroadcastConfiguration.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioBroadcastConfiguration.aidl
@@ -42,5 +42,7 @@
     int audioChannelAllocation;
     android.hardware.bluetooth.audio.LeAudioCodecConfiguration leAudioCodecConfig;
     char pcmStreamId;
+    @nullable android.hardware.bluetooth.audio.LeAudioBisConfiguration bisConfiguration;
+    @nullable android.hardware.bluetooth.audio.ConfigurationFlags flags;
   }
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl
index 2d9ebae..25a9797 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl
@@ -44,5 +44,16 @@
     char streamHandle;
     int audioChannelAllocation;
     boolean isStreamActive;
+    @nullable android.hardware.bluetooth.audio.LeAudioAseConfiguration aseConfiguration;
+    @nullable android.hardware.bluetooth.audio.ConfigurationFlags flags;
+    @nullable android.hardware.bluetooth.audio.LeAudioConfiguration.StreamMap.BluetoothDeviceAddress bluetoothDeviceAddress;
+    parcelable BluetoothDeviceAddress {
+      byte[6] deviceAddress;
+      android.hardware.bluetooth.audio.LeAudioConfiguration.StreamMap.BluetoothDeviceAddress.DeviceAddressType deviceAddressType;
+      enum DeviceAddressType {
+        BLE_ADDRESS_PUBLIC = 0x00,
+        BLE_ADDRESS_RANDOM = 0x01,
+      }
+    }
   }
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/MetadataLtv.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/MetadataLtv.aidl
new file mode 100644
index 0000000..5e8a2ae
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/MetadataLtv.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+union MetadataLtv {
+  android.hardware.bluetooth.audio.MetadataLtv.PreferredAudioContexts preferredAudioContexts;
+  android.hardware.bluetooth.audio.MetadataLtv.StreamingAudioContexts streamingAudioContexts;
+  android.hardware.bluetooth.audio.MetadataLtv.VendorSpecific vendorSpecific;
+  parcelable PreferredAudioContexts {
+    android.hardware.bluetooth.audio.AudioContext values;
+  }
+  parcelable StreamingAudioContexts {
+    android.hardware.bluetooth.audio.AudioContext values;
+  }
+  parcelable VendorSpecific {
+    int companyId;
+    byte[] opaqueValue;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/Phy.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/Phy.aidl
new file mode 100644
index 0000000..bfeabcd
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/Phy.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum Phy {
+  UNDEFINED = 0x00,
+  ONE_M = 0x01,
+  TWO_M = 0x02,
+  CODED = 0x03,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcAllocMethod.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcAllocMethod.aidl
index 091f6d7..9cf65d5 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcAllocMethod.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcAllocMethod.aidl
@@ -34,6 +34,6 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="byte") @VintfStability
 enum SbcAllocMethod {
-  ALLOC_MD_S = 0,
-  ALLOC_MD_L = 1,
+  ALLOC_MD_S,
+  ALLOC_MD_L,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcChannelMode.aidl
index 6441a99..7779aa0 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcChannelMode.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcChannelMode.aidl
@@ -34,9 +34,9 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="byte") @VintfStability
 enum SbcChannelMode {
-  UNKNOWN = 0,
-  JOINT_STEREO = 1,
-  STEREO = 2,
-  DUAL = 3,
-  MONO = 4,
+  UNKNOWN,
+  JOINT_STEREO,
+  STEREO,
+  DUAL,
+  MONO,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SessionType.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SessionType.aidl
index 33a3187..71cca53 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SessionType.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SessionType.aidl
@@ -34,16 +34,19 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="byte") @VintfStability
 enum SessionType {
-  UNKNOWN = 0,
-  A2DP_SOFTWARE_ENCODING_DATAPATH = 1,
-  A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH = 2,
-  HEARING_AID_SOFTWARE_ENCODING_DATAPATH = 3,
-  LE_AUDIO_SOFTWARE_ENCODING_DATAPATH = 4,
-  LE_AUDIO_SOFTWARE_DECODING_DATAPATH = 5,
-  LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH = 6,
-  LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH = 7,
-  LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH = 8,
-  LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH = 9,
-  A2DP_SOFTWARE_DECODING_DATAPATH = 10,
-  A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH = 11,
+  UNKNOWN,
+  A2DP_SOFTWARE_ENCODING_DATAPATH,
+  A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+  HEARING_AID_SOFTWARE_ENCODING_DATAPATH,
+  LE_AUDIO_SOFTWARE_ENCODING_DATAPATH,
+  LE_AUDIO_SOFTWARE_DECODING_DATAPATH,
+  LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+  LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+  LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH,
+  LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+  A2DP_SOFTWARE_DECODING_DATAPATH,
+  A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+  HFP_SOFTWARE_ENCODING_DATAPATH,
+  HFP_SOFTWARE_DECODING_DATAPATH,
+  HFP_HARDWARE_OFFLOAD_DATAPATH,
 }
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpConfiguration.aidl
new file mode 100644
index 0000000..a7fd9ff
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpConfiguration.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.CodecId;
+import android.hardware.bluetooth.audio.CodecParameters;
+
+/**
+ * A2DP Service Configuration
+ */
+@VintfStability
+parcelable A2dpConfiguration {
+    /**
+     * Remote Stream Endpoint Identifier
+     */
+    int remoteSeid;
+
+    /**
+     * Codec Selection and configuration, in a generic way with `parameters`
+     * and as defined by A2DP for codec interoperability requirements, with
+     * `configuration`. Using `id.a2dp`, the format is given by the `Codec
+     * Specific Information Elements` [A2DP - 4.3-6.2], and using `id.vendor`,
+     * by `Vendor Specific Value` [A2DP - 4.7.2].
+     * In any case, this byte array is limited by the framework to 128 Bytes.
+     */
+    CodecId id;
+    CodecParameters parameters;
+    byte[] configuration;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpConfigurationHint.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpConfigurationHint.aidl
new file mode 100644
index 0000000..f707a8a
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpConfigurationHint.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.AudioContext;
+import android.hardware.bluetooth.audio.CodecId;
+import android.hardware.bluetooth.audio.CodecParameters;
+
+/**
+ * A2DP Configuration Hints
+ */
+@VintfStability
+parcelable A2dpConfigurationHint {
+    /**
+     * Bluetooth Device Address, intended to be used for interoperabilities.
+     */
+    byte[6] bdAddr;
+
+    /**
+     * Audio configuration hints:
+     * - The starting audio context of the session
+     * - An optional preference of codec and / or parameters
+     */
+
+    AudioContext audioContext;
+    @nullable CodecId codecId;
+    @nullable CodecParameters codecParameters;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpRemoteCapabilities.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpRemoteCapabilities.aidl
new file mode 100644
index 0000000..87277f1
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpRemoteCapabilities.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.CodecId;
+
+/**
+ * A2DP Remote Capabilites
+ */
+@VintfStability
+parcelable A2dpRemoteCapabilities {
+    /**
+     * Remote Stream Endpoint identifier
+     */
+    int seid;
+
+    /**
+     * Codec Identifier and `capabilities` as defined by A2DP for codec
+     * interoperability requirements. Using `id.a2dp`, the format is given
+     * by the `Codec Specific Information Elements` [A2DP - 4.3-6.2], and
+     * using `id.vendor`, by `Vendor Specific Value` [A2DP - 4.7.2].
+     */
+    CodecId id;
+    byte[] capabilities;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpStatus.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpStatus.aidl
new file mode 100644
index 0000000..8eba3c9
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpStatus.aidl
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+@VintfStability
+@Backing(type="byte")
+enum A2dpStatus {
+
+    OK = 0,
+
+    /**
+     * Error codes defined by AVDTP [AVDTP - 8.20.6.2]
+     */
+
+    BAD_LENGTH = 0x11u8,
+    BAD_PAYLOAD_FORMAT = 0x18u8,
+
+    /**
+     * Error codecs defined by A2DP for AVDTP Interoperability [A2DP - 5.1.3]
+     */
+
+    INVALID_CODEC_TYPE = 0xC1u8,
+    NOT_SUPPORTED_CODEC_TYPE = 0xC2u8,
+    INVALID_SAMPLING_FREQUENCY = 0xC3u8,
+    NOT_SUPPORTED_SAMPLING_FREQUENCY = 0xC4u8,
+    INVALID_CHANNEL_MODE = 0xC5u8,
+    NOT_SUPPORTED_CHANNEL_MODE = 0xC6u8,
+    INVALID_SUBBANDS = 0xC7u8,
+    NOT_SUPPORTED_SUBBANDS = 0xC8u8,
+    INVALID_ALLOCATION_METHOD = 0xC9u8,
+    NOT_SUPPORTED_ALLOCATION_METHOD = 0xCAu8,
+    INVALID_MINIMUM_BITPOOL_VALUE = 0xCBu8,
+    NOT_SUPPORTED_MINIMUM_BITPOOL_VALUE = 0xCCu8,
+    INVALID_MAXIMUM_BITPOOL_VALUE = 0xCDu8,
+    NOT_SUPPORTED_MAXIMUM_BITPOOL_VALUE = 0xCEu8,
+    NOT_SUPPORTED_VBR = 0xD3u8,
+    NOT_SUPPORTED_BIT_RATE = 0xD5u8,
+    INVALID_OBJECT_TYPE = 0xD6u8,
+    NOT_SUPPORTED_OBJECT_TYPE = 0xD7u8,
+    INVALID_CHANNELS = 0xD8u8,
+    NOT_SUPPORTED_CHANNELS = 0xD9u8,
+    INVALID_BLOCK_LENGTH = 0xDDu8,
+    INVALID_CODEC_PARAMETER = 0xE2u8,
+    NOT_SUPPORTED_CODEC_PARAMETER = 0xE3u8,
+    INVALID_DRC = 0xE4u8,
+    NOT_SUPPORTED_DRC = 0xE5u8,
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpStreamConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpStreamConfiguration.aidl
new file mode 100644
index 0000000..2a0c4d8
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpStreamConfiguration.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.CodecId;
+
+@VintfStability
+parcelable A2dpStreamConfiguration {
+    /**
+     * Peer MTU (16 bits)
+     */
+    int peerMtu;
+
+    /**
+     * Optional SCMS-T Content Protection header
+     * that precedes audio content when enabled [A2DP - 3.2.1-2].
+     * The content protection byte is defined by [Assigned Number - 6.3.2].
+     */
+    @nullable byte[1] cpHeaderScmst;
+
+    /**
+     * Codec Identifier and `configuration` as defined by A2DP for codec
+     * interoperability requirements. Using `codecId.a2dp`, the format is given
+     * by the `Codec Specific Information Elements` [A2DP - 4.3-6.2], and
+     * using `codecId.vendor`, by `Vendor Specific Value` [A2DP - 4.7.2].
+     */
+    CodecId codecId;
+    byte[] configuration;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioConfiguration.aidl
index a06337e..5317dfb 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioConfiguration.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioConfiguration.aidl
@@ -16,7 +16,9 @@
 
 package android.hardware.bluetooth.audio;
 
+import android.hardware.bluetooth.audio.A2dpStreamConfiguration;
 import android.hardware.bluetooth.audio.CodecConfiguration;
+import android.hardware.bluetooth.audio.HfpConfiguration;
 import android.hardware.bluetooth.audio.LeAudioBroadcastConfiguration;
 import android.hardware.bluetooth.audio.LeAudioConfiguration;
 import android.hardware.bluetooth.audio.PcmConfiguration;
@@ -30,4 +32,6 @@
     CodecConfiguration a2dpConfig;
     LeAudioConfiguration leAudioConfig;
     LeAudioBroadcastConfiguration leAudioBroadcastConfig;
+    HfpConfiguration hfpConfig;
+    A2dpStreamConfiguration a2dp;
 }
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioContext.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioContext.aidl
new file mode 100644
index 0000000..306e897
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioContext.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+/**
+ * Context of the audio configuration.
+ * Defined by PACS (Le Audio) and used either by A2DP or LE Audio.
+ * The `bitmask` is any combination of BT Sig standardized values
+ * [Assigned Numbers - 6.12.3], defined in this scope.
+ */
+@VintfStability
+parcelable AudioContext {
+    const int UNSPECIFIED = 0x0001;
+    const int CONVERSATIONAL = 0x0002;
+    const int MEDIA = 0x0004;
+    const int GAME = 0x0008;
+    const int INSTRUCTIONAL = 0x0010;
+    const int VOICE_ASSISTANTS = 0x0020;
+    const int LIVE_AUDIO = 0x0040;
+    const int SOUND_EFFECTS = 0x0080;
+    const int NOTIFICATIONS = 0x0100;
+    const int RINGTONE_ALERTS = 0x0200;
+    const int ALERTS = 0x0400;
+    const int EMERGENCY_ALARM = 0x0800;
+
+    int bitmask;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecId.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecId.aidl
new file mode 100644
index 0000000..896a712
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecId.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+@VintfStability
+union CodecId {
+    /**
+     * Codec Identifier defined for A2DP
+     * The values are assigned by BT Sig [Assigned Numbers - 6.5.1]
+     */
+    enum A2dp { SBC = 0, AAC = 2 }
+
+    /**
+     * Codec Identifier defined for the Bluetooth Core Specification
+     * The values are assigned by BT Sig [Assigned Numbers - 2.11]
+     */
+    enum Core { CVSD = 2, MSBC = 5, LC3 = 6 }
+
+    /**
+     * Vendor Codec:
+     * id       16 bits - Assigned by BT Sig
+     * codecId  16 bits - Assigned by the vendor
+     */
+    parcelable Vendor {
+        int id;
+        int codecId;
+    }
+
+    /**
+     * Standard (A2DP or Core numbering space) or vendor
+     */
+    A2dp a2dp = A2dp.SBC;
+    Core core;
+    Vendor vendor;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecInfo.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecInfo.aidl
new file mode 100644
index 0000000..33f0c04
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecInfo.aidl
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.ChannelMode;
+import android.hardware.bluetooth.audio.CodecId;
+import android.hardware.bluetooth.audio.ConfigurationFlags;
+
+/**
+ * General information about a Codec
+ */
+@VintfStability
+parcelable CodecInfo {
+    /**
+     * Codec identifier and human readable name
+     */
+    CodecId id;
+    String name;
+
+    /**
+     * A2DP Context
+     */
+    parcelable A2dp {
+        /**
+         * The capabilities as defined by A2DP for codec interoperability
+         * requirements. With `id.a2dp`, the format is given by the `Codec
+         * Specific Information Elements` [A2DP - 4.3-6.2], and with `id.vendor`,
+         * by `Vendor Specific Value` [A2DP - 4.7.2].
+         */
+        byte[] capabilities;
+
+        /**
+         * PCM characteristics:
+         * - Mono, Dual-Mono or Stereo
+         * - Supported sampling frequencies, in Hz.
+         * - Fixed point resolution, basically 16, 24 or 32 bits by samples.
+         *   The value 32 should be used for floating point representation.
+         *
+         * When the bitdepth is not an encoding/decoding parameter (don't take part
+         * in the interoperability), the `bitdepth` list shall have a single element
+         * indicating the bitdepth selected for the platform.
+         */
+        ChannelMode[] channelMode;
+        int[] samplingFrequencyHz;
+        int[] bitdepth;
+
+        /**
+         * Lossless capable characteristic
+         */
+        boolean lossless;
+    }
+
+    /**
+     * HFP Context
+     */
+    parcelable Hfp {
+        /**
+         * Vendor-specific identifiers of stream data paths, set in the
+         * HCI Command Enhanced Setup Synchronous Connection [Core - 4.E.7.1.45],
+         * in the command parameters respectively `Input_Data_Path` and
+         * `Output_Data_Path`. The value range from 0x01 to 0xFE.
+         * The stack operates as a pass-through; the client SHALL NOT
+         * interpret the values.
+         */
+        int inputDataPath = 1;
+        int outputDataPath = 1;
+
+        /**
+         * Whether the audio stream is encoded and decoded in the controller or
+         * locally; enable the controller transparent mode when the audio
+         * stream is locally processed.
+         */
+        boolean useControllerCodec = true;
+    }
+
+    /**
+     * LE Audio Context
+     */
+    parcelable LeAudio {
+        /**
+         * Channel configuration: Mono, Dual-Mono or Stereo
+         */
+        ChannelMode[] channelMode;
+
+        /**
+         * Supported sampling frequencies, in Hz.
+         */
+        int[] samplingFrequencyHz;
+
+        /*
+         * FrameDuration in microseconds.
+         */
+        int[] frameDurationUs;
+
+        /**
+         * - Fixed point resolution, basically 16, 24 or 32 bits by samples.
+         *   The value 32 should be used for floating point representation.
+         *
+         * When the bitdepth is not an encoding/decoding parameter (don't take
+         * part in the interoperability), the `bitdepth` list shall have a
+         * single element indicating the bitdepth selected for the platform.
+         */
+        int[] bitdepth;
+
+        /**
+         * Additional configuration flags
+         */
+        @nullable ConfigurationFlags flags;
+    }
+
+    /**
+     * Specific informations,
+     * depending on transport.
+     */
+    union Transport {
+        LeAudio leAudio;
+        A2dp a2dp;
+        Hfp hfp;
+    }
+
+    Transport transport;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecParameters.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecParameters.aidl
new file mode 100644
index 0000000..b6f8a94
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecParameters.aidl
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.ChannelMode;
+
+/**
+ * Used to exchange generic codec parameters between the stack and the provider.
+ */
+@VintfStability
+parcelable CodecParameters {
+    /**
+     * PCM related parameters:
+     * - Mono, Dual-Mono or Stereo
+     * - Sampling frequencies, in Hz.
+     * - Fixed point resolution, basically 16, 24 or 32 bits by samples.
+     *   The value 32 should be used for floating point representation..
+     */
+    ChannelMode channelMode;
+    int samplingFrequencyHz;
+    int bitdepth;
+
+    /**
+     * Encoding parameters:
+     *
+     * - Bitrate limits on a frame basis, defined in bits per second.
+     *   The encoder bitrate mode can be encoded following this rule:
+     *     . minBitrate equals to maxBitrate for constant bitrate
+     *     . minBitrate set to 0, for VBR with peak bitrate at maxBitratre value.
+     *     . minBitrate greater than 0, for ABR, the bitrate of the stream varies
+     *       between minBitrate to maxBitrate according to link quality.
+     *   The 0 value for both means "undefined" or "don't care".
+     *
+     * - Low-latency configuration privileged
+     * - Lossless effort indication. The 'False' value can be used as "don't care"
+     */
+    int minBitrate;
+    int maxBitrate;
+
+    boolean lowLatency;
+    boolean lossless;
+
+    /**
+     * Vendor specific parameters, inserted in the Vendor Specific HCI Command
+     * `Start A2DP Offload` as it is. The stack operates as a pass-through;
+     * the data SHALL NOT be inspected nor written by the client.
+     * The size is limited to 128 bytes by the client; a larger size is
+     * interpreted as a zero-sized buffer.
+     */
+    byte[] vendorSpecificParameters;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecSpecificCapabilitiesLtv.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecSpecificCapabilitiesLtv.aidl
new file mode 100644
index 0000000..ceb90ba
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecSpecificCapabilitiesLtv.aidl
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+/**
+ * Used to exchange generic remote device codec specific capabilities between
+ * the stack and the provider. As defined in Bluetooth Assigned Numbers,
+ * Sec. 6.12.4.
+ */
+@VintfStability
+union CodecSpecificCapabilitiesLtv {
+    parcelable SupportedSamplingFrequencies {
+        const int HZ8000 = 0x0001;
+        const int HZ11025 = 0x0002;
+        const int HZ16000 = 0x0004;
+        const int HZ22050 = 0x0008;
+        const int HZ24000 = 0x0010;
+        const int HZ32000 = 0x0020;
+        const int HZ44100 = 0x0040;
+        const int HZ48000 = 0x0080;
+        const int HZ88200 = 0x0100;
+        const int HZ96000 = 0x0200;
+        const int HZ176400 = 0x0400;
+        const int HZ192000 = 0x0800;
+        const int HZ384000 = 0x1000;
+
+        /* 16 bits wide bit mask */
+        int bitmask;
+    }
+    parcelable SupportedFrameDurations {
+        const int US7500 = 0x01;
+        const int US10000 = 0x02;
+        // Bits 2-3 are RFU
+        const int US7500PREFERRED = 0x10;
+        const int US10000PREFERRED = 0x20;
+
+        /* 8 bit wide bit mask */
+        int bitmask;
+    }
+    parcelable SupportedAudioChannelCounts {
+        const int ONE = 0x01;
+        const int TWO = 0x02;
+        const int THREE = 0x04;
+        const int FOUR = 0x08;
+        const int FIVE = 0x10;
+        const int SIX = 0x20;
+        const int SEVEN = 0x40;
+        const int EIGHT = 0x80;
+
+        /* 8 bit wide bit mask */
+        int bitmask;
+    }
+    parcelable SupportedOctetsPerCodecFrame {
+        int minimum;
+        int maximum;
+    }
+    parcelable SupportedMaxCodecFramesPerSDU {
+        int value;
+    }
+
+    SupportedSamplingFrequencies supportedSamplingFrequencies;
+    SupportedFrameDurations supportedFrameDurations;
+    SupportedAudioChannelCounts supportedAudioChannelCounts;
+    SupportedOctetsPerCodecFrame supportedOctetsPerCodecFrame;
+    SupportedMaxCodecFramesPerSDU supportedMaxCodecFramesPerSDU;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl
new file mode 100644
index 0000000..c099ebe
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+/**
+ * Used to exchange generic remote device configuration between the stack and
+ * the provider. As defined in Bluetooth Assigned Numbers, Sec. 6.12.5.
+ */
+@VintfStability
+union CodecSpecificConfigurationLtv {
+    @Backing(type="byte")
+    enum SamplingFrequency {
+        HZ8000 = 0x01,
+        HZ11025 = 0x02,
+        HZ16000 = 0x03,
+        HZ22050 = 0x04,
+        HZ24000 = 0x05,
+        HZ32000 = 0x06,
+        HZ44100 = 0x07,
+        HZ48000 = 0x08,
+        HZ88200 = 0x09,
+        HZ96000 = 0x0A,
+        HZ176400 = 0x0B,
+        HZ192000 = 0x0C,
+        HZ384000 = 0x0D,
+    }
+
+    @Backing(type="byte")
+    enum FrameDuration {
+        US7500 = 0x00,
+        US10000 = 0x01,
+    }
+
+    parcelable AudioChannelAllocation {
+        const int NOT_ALLOWED = 0x00000000;
+        const int FRONT_LEFT = 0x00000001;
+        const int FRONT_RIGHT = 0x00000002;
+        const int FRONT_CENTER = 0x00000004;
+        const int LOW_FREQUENCY_EFFECTS_1 = 0x00000008;
+        const int BACK_LEFT = 0x00000010;
+        const int BACK_RIGHT = 0x00000020;
+        const int FRONT_LEFT_OF_CENTER = 0x00000040;
+        const int FRONT_RIGHT_OF_CENTER = 0x00000080;
+        const int BACK_CENTER = 0x00000100;
+        const int LOW_FREQUENCY_EFFECTS_2 = 0x00000200;
+        const int SIDE_LEFT = 0x00000400;
+        const int SIDE_RIGHT = 0x00000800;
+        const int TOP_FRONT_LEFT = 0x00001000;
+        const int TOP_FRONT_RIGHT = 0x00002000;
+        const int TOP_FRONT_CENTER = 0x00004000;
+        const int TOP_CENTER = 0x00008000;
+        const int TOP_BACK_LEFT = 0x00010000;
+        const int TOP_BACK_RIGHT = 0x00020000;
+        const int TOP_SIDE_LEFT = 0x00040000;
+        const int TOP_SIDE_RIGHT = 0x00080000;
+        const int TOP_BACK_CENTER = 0x00100000;
+        const int BOTTOM_FRONT_CENTER = 0x00200000;
+        const int BOTTOM_FRONT_LEFT = 0x00400000;
+        const int BOTTOM_FRONT_RIGHT = 0x00800000;
+        const int FRONT_LEFT_WIDE = 0x01000000;
+        const int FRONT_RIGHT_WIDE = 0x02000000;
+        const int LEFT_SURROUND = 0x04000000;
+        const int RIGHT_SURROUND = 0x08000000;
+
+        // Bit mask of Audio Locations
+        int bitmask;
+    }
+
+    parcelable OctetsPerCodecFrame {
+        int value;
+    }
+
+    parcelable CodecFrameBlocksPerSDU {
+        int value;
+    }
+
+    CodecFrameBlocksPerSDU codecFrameBlocksPerSDU;
+    SamplingFrequency samplingFrequency;
+    FrameDuration frameDuration;
+    AudioChannelAllocation audioChannelAllocation;
+    OctetsPerCodecFrame octetsPerCodecFrame;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/ConfigurationFlags.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/ConfigurationFlags.aidl
new file mode 100644
index 0000000..57c8be5
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/ConfigurationFlags.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+/**
+ * Coding fetures
+ */
+@VintfStability
+parcelable ConfigurationFlags {
+    const int NONE = 0x0000;
+    /*
+     * Set for the lossless configurations
+     */
+    const int LOSSLESS = 0x0001;
+    /*
+     * Set for the low latency configurations
+     */
+    const int LOW_LATENCY = 0x0002;
+    /*
+     * When set, asymmetric configuration for SINK and SOURCE can be used.
+     * e.g. in GAMING mode stream for 32kHz and back channel for 16 kHz
+     */
+    const int ALLOW_ASYMMETRIC_CONFIGURATIONS = 0x0003;
+    /*
+     * Set for the spatial audio configurations
+     */
+    const int SPATIAL_AUDIO = 0x0004;
+    /*
+     * When set, BluetoothAudioProvider requests to receive ASE metadata.
+     * In such case onSinkAseMetadataChanged() and onSourceAseMetadataChanged
+     * will be called.
+     */
+    const int PROVIDE_ASE_METADATA = 0x0005;
+    /*
+     * Set for mono microphone configurations
+     */
+    const int MONO_MIC_CONFIGURATION = 0x0006;
+
+    int bitmask;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/HfpConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/HfpConfiguration.aidl
new file mode 100644
index 0000000..9494bb9
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/HfpConfiguration.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.CodecId;
+
+@VintfStability
+parcelable HfpConfiguration {
+    /**
+     * Codec identifier.
+     */
+    CodecId codecId;
+
+    /**
+     * The connection handle used for SCO connection.
+     * Range: 0x0000 to 0x0EFF.
+     */
+    int connectionHandle;
+
+    /**
+     *  Echo canceling and noise reduction functions resident in the AG.
+     */
+    boolean nrec;
+
+    /**
+     *  Indicate whether the codec is encoded and decoded in the controller.
+     *  If the codec is inside the DSP, then it would be transparent mode.
+     */
+    boolean controllerCodec;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
index d5c051e..8c6fe69 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
@@ -16,10 +16,26 @@
 
 package android.hardware.bluetooth.audio;
 
+import android.hardware.bluetooth.audio.A2dpConfiguration;
+import android.hardware.bluetooth.audio.A2dpConfigurationHint;
+import android.hardware.bluetooth.audio.A2dpRemoteCapabilities;
+import android.hardware.bluetooth.audio.A2dpStatus;
 import android.hardware.bluetooth.audio.AudioConfiguration;
+import android.hardware.bluetooth.audio.AudioContext;
 import android.hardware.bluetooth.audio.BluetoothAudioStatus;
+import android.hardware.bluetooth.audio.CodecId;
+import android.hardware.bluetooth.audio.CodecParameters;
+import android.hardware.bluetooth.audio.CodecSpecificCapabilitiesLtv;
+import android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv;
+import android.hardware.bluetooth.audio.ConfigurationFlags;
 import android.hardware.bluetooth.audio.IBluetoothAudioPort;
 import android.hardware.bluetooth.audio.LatencyMode;
+import android.hardware.bluetooth.audio.LeAudioAseConfiguration;
+import android.hardware.bluetooth.audio.LeAudioBisConfiguration;
+import android.hardware.bluetooth.audio.LeAudioBroadcastConfiguration.BroadcastStreamMap;
+import android.hardware.bluetooth.audio.LeAudioConfiguration.StreamMap;
+import android.hardware.bluetooth.audio.MetadataLtv;
+import android.hardware.bluetooth.audio.Phy;
 import android.hardware.common.fmq.MQDescriptor;
 import android.hardware.common.fmq.SynchronizedReadWrite;
 
@@ -59,9 +75,8 @@
      *    audioConfig.pcmConfig parameter. Invalid if streaming is offloaded
      *    from/to hardware or on failure
      */
-    MQDescriptor<byte, SynchronizedReadWrite> startSession(
-            in IBluetoothAudioPort hostIf, in AudioConfiguration audioConfig,
-            in LatencyMode[] supportedLatencyModes);
+    MQDescriptor<byte, SynchronizedReadWrite> startSession(in IBluetoothAudioPort hostIf,
+            in AudioConfiguration audioConfig, in LatencyMode[] supportedLatencyModes);
     /**
      * Callback for IBluetoothAudioPort.startStream()
      *
@@ -93,4 +108,624 @@
      * mode, the API will be called with supported is false.
      */
     void setLowLatencyModeAllowed(in boolean allowed);
+
+    /**
+     * Validate and parse an A2DP Configuration,
+     * shall be used with A2DP session types
+     *
+     * @param codecId Identify the codec
+     * @param The configuration as defined by the A2DP's `Codec Specific
+     *        Information Elements`, or `Vendor Specific Value` when CodecId
+     *        format is set to `VENDOR`.
+     * @param codecParameters result of parsing, when the validation succeeded.
+     * @return A2DP Status of the parsing
+     */
+    A2dpStatus parseA2dpConfiguration(
+            in CodecId codecId, in byte[] configuration, out CodecParameters codecParameters);
+
+    /**
+     * Return a configuration, from a list of remote Capabilites,
+     * shall be used with A2DP session types
+     *
+     * @param remoteCapabilities The capabilities of the remote device
+     * @param hint Hint on selection (audio context and/or codec)
+     * @return The requested configuration. A null value value is returned
+     *         when no suitable configuration has been found.
+     */
+    @nullable A2dpConfiguration getA2dpConfiguration(
+            in List<A2dpRemoteCapabilities> remoteA2dpCapabilities, in A2dpConfigurationHint hint);
+
+    /**
+     * Set specific codec priority
+     *
+     *  It should be assumed that the external module will start with all its
+     *  integrated codecs priority 0 by default.
+     *
+     * @param codecId:  codecId
+     * @param priority: 0 for no priority, -1 for codec disabled,
+     *                  from 1 to N, where 1 is highest.
+     */
+    void setCodecPriority(in CodecId codecId, int priority);
+
+    /**
+     * LE Audio device Capabilities - as defined in Bluetooth Published Audio
+     * Capabilities Service specification, v1.0.1, Sec. 3.1: "Sink PAC", and
+     * Sec. 3.3: "Source PAC".
+     */
+    @VintfStability
+    parcelable LeAudioDeviceCapabilities {
+        /**
+         * Codec Identifier
+         */
+        CodecId codecId;
+        /**
+         * Codec capabilities, packed as LTV.
+         */
+        CodecSpecificCapabilitiesLtv[] codecSpecificCapabilities;
+        /**
+         * Vendor codec specific capabilities.
+         *
+         * This will not be parsed by the BT stack, but passed to the vendor
+         * module who can interpret this and based on that select the proper
+         * vendor specific codec configuration.
+         */
+        @nullable byte[] vendorCodecSpecificCapabilities;
+        /**
+         * Audio capabilities metadata, packed as LTV.
+         */
+        @nullable MetadataLtv[] metadata;
+    }
+
+    @VintfStability
+    parcelable LeAudioDataPathConfiguration {
+        /**
+         * Vendor specific data path identifier
+         */
+        int dataPathId;
+
+        /**
+         * Used in the HCI_LE_Setup_ISO_Data_Path (0x006E).
+         * As defined in Bluetooth Core Specification Version
+         * 5.3, Vol 4, Part E, Sec. 7.8.109: "LE Setup ISO Data Path command".
+         */
+        @VintfStability
+        parcelable IsoDataPathConfiguration {
+            /**
+             * Codec ID - Valid Codec Identifier matching the selected codec
+             */
+            CodecId codecId;
+            /**
+             * Whether the transparent air mode should be set as a coding format
+             * in the HCI_LE_Setup_ISO_Data_Path command, indicating that the
+             * codec is not in the controller.
+             *
+             * If set to true, 0x03 (transparent air mode) will be used as a
+             * Codec_ID coding format and the `byte[] configuration` field shall
+             * remain empty. Otherwise the Codec_ID field will be set to
+             * according to BT specification (0xFF coding format, company ID,
+             * codec ID for vendor codecs, or according to Codec_ID identifiers
+             * defined in the Assigned Numbers for the non-vendor codecs).
+             */
+            boolean isTransparent;
+            /**
+             * Controller delay (in microseconds)
+             */
+            int controllerDelayUs;
+            /**
+             * Codec specific LE Audio ISO data path configuration
+             * must be null when codec ID is 0x03 transparent
+             */
+            @nullable byte[] configuration;
+        }
+
+        /**
+         * Used in HCI_Configure_Data_Path (0x0083)
+         * As defined in Bluetooth Core Specification Version
+         * 5.3, Vol 4, Part E, Sec. 7.3.101: "Configure Data Path command".
+         */
+        @VintfStability
+        parcelable DataPathConfiguration {
+            /**
+             * Vendor specific data path configuration
+             */
+            @nullable byte[] configuration;
+        }
+        /**
+         * Data path configuration
+         */
+        DataPathConfiguration dataPathConfiguration;
+        /**
+         * ISO data path configuration
+         */
+        IsoDataPathConfiguration isoDataPathConfiguration;
+    }
+
+    /* All the LeAudioAseQosConfiguration parameters are defined by the
+     * Bluetooth Audio Stream Control Service specification v.1.0, Sec. 5: "ASE
+     * Control Operations".
+     */
+    @VintfStability
+    parcelable LeAudioAseQosConfiguration {
+        /**
+         * SDU Interval (in microseconds) used in Set CIG Parameters command and
+         * Configure QoS.
+         */
+        int sduIntervalUs;
+        /**
+         * Framing used in Set CIG Parameters command and Configure QoS
+         */
+        Framing framing;
+        /**
+         * Phy used in Set CIG Parameters command and Configure QoS
+         */
+        Phy[] phy;
+        /**
+         * Max transport latency (in milliseconds) used in Set CIG Parameters
+         * command and Configure QoS.
+         */
+        int maxTransportLatencyMs;
+        /**
+         * Max SDU used in Set CIG Parameters command and Configure QoS
+         */
+        int maxSdu;
+        /**
+         * Retransmission number used in Set CIG Parameters command and
+         * Configure QoS
+         */
+        int retransmissionNum;
+    }
+
+    /**
+     * Connected Isochronous Channel arrangement within the Connected
+     * Isochronous Group. As defined in Bluetooth Core Specification Version
+     * 5.3, Vol 4, Part E, Sec. 7.8.97.
+     */
+    @VintfStability
+    @Backing(type="byte")
+    enum Packing {
+        SEQUENTIAL = 0x00,
+        INTERLEAVED = 0x01,
+    }
+
+    /**
+     * Isochronous Data PDU framing parameter. As defined in Bluetooth Core
+     * Specification Version 5.3, Vol 4, Part E, Sec. 7.8.97.
+     */
+    @VintfStability
+    @Backing(type="byte")
+    enum Framing {
+        UNFRAMED = 0x00,
+        FRAMED = 0x01,
+    }
+
+    @VintfStability
+    parcelable LeAudioAseConfigurationSetting {
+        /**
+         * Audio Context that this configuration apply to
+         */
+        AudioContext audioContext;
+        /**
+         * Sequential or interleave packing used in Set CIG Parameters command
+         */
+        Packing packing;
+
+        @VintfStability
+        parcelable AseDirectionConfiguration {
+            /**
+             * ASE configuration
+             */
+            LeAudioAseConfiguration aseConfiguration;
+            /**
+             * QoS Configuration
+             */
+            @nullable LeAudioAseQosConfiguration qosConfiguration;
+            /**
+             * Data path configuration
+             * If not provided, getLeAudioAseDatapathConfiguration() will be
+             * called during the configuration, increasing the stream
+             * establishment time (not recommended).
+             */
+            @nullable LeAudioDataPathConfiguration dataPathConfiguration;
+        }
+        /**
+         * Sink ASEs configuration
+         */
+        @nullable List<AseDirectionConfiguration> sinkAseConfiguration;
+        /**
+         * Source ASEs configuration
+         */
+        @nullable List<AseDirectionConfiguration> sourceAseConfiguration;
+        /**
+         * Additional flags, used for configurations with special features
+         */
+        @nullable ConfigurationFlags flags;
+    }
+
+    /**
+     * ASE configuration requirements set by the BT stack.
+     */
+    @VintfStability
+    parcelable LeAudioConfigurationRequirement {
+        /**
+         * Audio Contect that this requirements apply to
+         */
+        AudioContext audioContext;
+
+        @VintfStability
+        parcelable AseDirectionRequirement {
+            /**
+             * Optional ASE configurations requirements
+             *
+             * Note that the Host can set as many or as little parameters in
+             * the `aseConfiguration.codecConfiguration` field as needed, to
+             * closely or loosely specify the requirements. If any parameter
+             * is not specified, the offloader can choose it freely. The
+             * offloader should put all the specified parameters into the
+             * `aseConfiguration.codecConfiguration` field of the returned
+             * configuration to let the BT stack verify if the requirements
+             * were met. The mandatory requirement set by the BT stack will be
+             * the Audio Location.
+             */
+            LeAudioAseConfiguration aseConfiguration;
+        }
+        /**
+         * Sink ASEs configuration setting
+         */
+        @nullable List<AseDirectionRequirement> sinkAseRequirement;
+        /**
+         * Source ASEs configuration setting
+         */
+        @nullable List<AseDirectionRequirement> sourceAseRequirement;
+        /**
+         * Additional flags, used to request configurations with special
+         * features
+         */
+        @nullable ConfigurationFlags flags;
+    }
+
+    /**
+     * Method that returns a proposed ASE configuration settings for each
+     * requested audio context type
+     *
+     * Note: _ENCODING session provides SINK ASE configuration
+     *       and _DECODING session provides SOURCE ASE configuration unless
+     *       BluetoothAudioProvider sets supportsMultidirectionalCapabilities to
+     *       true in ProviderInfo.
+     *       If supportsMultidirectionalCapabilities is set to true then the
+     *       BluetoothStack expects to get configuration list for SINK and SOURCE
+     *       on either _ENCODING or _DECODING session.
+     *
+     * @param remoteSinkAudioCapabilities List of remote sink capabilities
+     *        supported by an active group devices.
+     * @param remoteSourceAudioCapabilities List of remote source capabilities
+     *        supported by an active group devices.
+     * @param requirements ASE configuration requirements
+     *
+     * @return List<LeAudioAseConfigurationSetting>
+     */
+    List<LeAudioAseConfigurationSetting> getLeAudioAseConfiguration(
+            in @nullable List<LeAudioDeviceCapabilities> remoteSinkAudioCapabilities,
+            in @nullable List<LeAudioDeviceCapabilities> remoteSourceAudioCapabilities,
+            in List<LeAudioConfigurationRequirement> requirements);
+
+    @VintfStability
+    parcelable LeAudioAseQosConfigurationRequirement {
+        /**
+         * Audio Contect Type that this requirements apply to
+         */
+        AudioContext contextType;
+
+        /**
+         * QoS preferences received in Codec Configured ASE state. As defined in
+         * bluetooth service specification: Audio Stream Control Service" V1.0,
+         * Sec. 4.1 Audio Stream Endpoints, Table 4.3:"Additional_ASE_Parameters
+         * format when ASE_State = 0x01 (Codec Configured)".
+         */
+        @VintfStability
+        parcelable AseQosDirectionRequirement {
+            /**
+             * Support for unframed Isochronous Adaptation Layer PDUs.
+             * When set to FRAMED, the unframed PDUs are not supported.
+             */
+            Framing framing;
+            /**
+             * Preferred value for the PHY parameter to be written by the client
+             * for this ASE in the Config QoS operation
+             */
+            Phy[] preferredPhy;
+            /**
+             * Preferred value for the Retransmission Number parameter to be
+             * written by the client for this ASE in the Config QoS operation.
+             */
+            int preferredRetransmissionNum;
+            /**
+             * Preferred value for the Max Transport Latency parameter to be
+             * written by the client for this ASE in the Config QoS operation.
+             */
+            int maxTransportLatencyMs;
+            /**
+             * Minimum server supported Presentation Delay (in microseconds) for
+             * an ASE.
+             */
+            int presentationDelayMinUs;
+            /**
+             * Maximum server supported Presentation Delay (in microseconds) for
+             * an ASE.
+             */
+            int presentationDelayMaxUs;
+            /**
+             * Preferred minimum Presentation Delay (in microseconds) for an
+             * ASE.
+             */
+            int preferredPresentationDelayMinUs;
+            /**
+             * Preferred maximum Presentation Delay (in microseconds) for an
+             * ASE.
+             */
+            int preferredPresentationDelayMaxUs;
+
+            /**
+             * ASE configuration
+             */
+            LeAudioAseConfiguration aseConfiguration;
+        }
+        /**
+         * Sink ASEs configuration setting
+         */
+        @nullable AseQosDirectionRequirement sinkAseQosRequirement;
+        /**
+         * Source ASEs configuration setting
+         */
+        @nullable AseQosDirectionRequirement sourceAseQosRequirement;
+        /**
+         * Additional configuration flags requirements
+         */
+        @nullable ConfigurationFlags flags;
+    }
+
+    /**
+     * A directional pair for QoS configuration. Either one or both directions
+     * can be set, depending on the audio context and the requirements provided
+     * to getLeAudioAseQosConfiguration().
+     */
+    @VintfStability
+    parcelable LeAudioAseQosConfigurationPair {
+        @nullable LeAudioAseQosConfiguration sinkQosConfiguration;
+        @nullable LeAudioAseQosConfiguration sourceQosConfiguration;
+    }
+
+    /**
+     * Method that returns an ASE QoS configuration settings for the given ASE
+     * configuration,taking an ASE preferenced QoS parameters. It should be used
+     * to negotiaite the QoS parameters, when the initialy received QoS
+     * parameters are not within the boundaries received from the remote device
+     * after configuring the ASEs.
+     *
+     * @param qosRequirement ASE QoS configurations requirements
+     *
+     * @return LeAudioAseQosConfigurationPair
+     */
+    LeAudioAseQosConfigurationPair getLeAudioAseQosConfiguration(
+            in LeAudioAseQosConfigurationRequirement qosRequirement);
+
+    /**
+     * Audio data path configuration.
+     */
+    parcelable LeAudioDataPathConfigurationPair {
+        /* Host to Controller data path */
+        @nullable LeAudioDataPathConfiguration inputConfig;
+        /* Controller to Host data path */
+        @nullable LeAudioDataPathConfiguration outputConfig;
+    }
+
+    /**
+     * Stream Configuration
+     */
+    parcelable StreamConfig {
+        /**
+         * Streaming Audio Context.
+         * This can serve as a hint for selecting the proper configuration by
+         * the offloader.
+         */
+        AudioContext context;
+        /**
+         * Stream configuration, including connection handles and audio channel
+         * allocations.
+         */
+        StreamMap[] streamMap;
+    }
+
+    /**
+     * Used to get a data path configuration which dynamically depends on CIS
+     * connection handles in StreamMap. This is used if non-dynamic data path
+     * was not provided in LeAudioAseConfigurationSetting. Calling this during
+     * the unicast audio stream establishment might slightly delay the stream
+     * start.
+     *
+     * @param sinkConfig - remote sink device stream configuration
+     * @param sourceConfig - remote source device stream configuration
+     *
+     * @return LeAudioDataPathConfigurationPair
+     */
+    LeAudioDataPathConfigurationPair getLeAudioAseDatapathConfiguration(
+            in @nullable StreamConfig sinkConfig,
+            in @nullable StreamConfig sourceConfig);
+
+    /*
+     * Audio Stream Endpoint state used to report Metadata changes on the remote
+     * device audio endpoints.
+     */
+    @VintfStability
+    @Backing(type="byte")
+    enum AseState {
+        ENABLING = 0x00,
+        STREAMING = 0x01,
+        DISABLING = 0x02,
+    }
+
+    /**
+     * Used to report metadata changes to the provider. This allows for a
+     * pseudo communication channel between the remote device and the provider,
+     * using the vendor specific metadata of the changing ASE state.
+     * It is used only when ASE is using configurations marked with the
+     * `PROVIDE_ASE_METADATA` flag.
+     */
+    void onSinkAseMetadataChanged(
+            in AseState state, int cigId, int cisId, in @nullable MetadataLtv[] metadata);
+    void onSourceAseMetadataChanged(
+            in AseState state, int cigId, int cisId, in @nullable MetadataLtv[] metadata);
+
+    /**
+     * Broadcast quality index
+     */
+    @VintfStability
+    @Backing(type="byte")
+    enum BroadcastQuality {
+        STANDARD,
+        HIGH,
+    }
+
+    /**
+     * It is used in LeAudioBroadcastConfigurationRequirement
+     */
+    @VintfStability
+    parcelable LeAudioBroadcastSubgroupConfigurationRequirement {
+        /**
+         * Streaming Audio Context for the given subgroup.
+         * This can serve as a hint for selecting the proper configuration by
+         * the offloader.
+         */
+        AudioContext context;
+        /**
+         * Streaming Broadcast Audio Quality
+         */
+        BroadcastQuality quality;
+        /**
+         * Number of BISes for the given subgroup
+         */
+        int bisNumPerSubgroup;
+    }
+
+    /**
+     * It is used in getLeAudioBroadcastConfiguration method
+     * If any group id is provided, the Provider should check Pacs capabilities
+     * of the group(s) and provide Broadcast configuration supported by the
+     * group.
+     */
+    @VintfStability
+    parcelable LeAudioBroadcastConfigurationRequirement {
+        List<LeAudioBroadcastSubgroupConfigurationRequirement> subgroupConfigurationRequirements;
+    }
+
+    /**
+     * Subgroup BIS configuration
+     *
+     */
+    @VintfStability
+    parcelable LeAudioSubgroupBisConfiguration {
+        /**
+         * The number of BISes with the given configuration
+         */
+        int numBis;
+        /**
+         * LE Audio BIS configuration for the `numBis` number of BISes
+         */
+        LeAudioBisConfiguration bisConfiguration;
+    }
+
+    /**
+     * Subgroup configuration with a list of BIS configurations
+     *
+     */
+    @VintfStability
+    parcelable LeAudioBroadcastSubgroupConfiguration {
+        List<LeAudioSubgroupBisConfiguration> bisConfigurations;
+
+        /**
+         * Vendor specific codec configuration for all the BISes inside this
+         * subgroup. Only the vendor specific part is needed, since the BT stack
+         * can derive the common subgroup configuration by intersecting the LTV
+         * formatted configuration of every BIS inside the subgroup.
+         * This will not be parsed by the BT stack but will be set as the codec
+         * specific configuration for the ongoing audio stream at the subgroup
+         * level of the audio announcement,The remote device will receive this
+         * information when being configured for receiveing a brodcast audio
+         * stream.
+         */
+        @nullable byte[] vendorCodecConfiguration;
+    }
+
+    /**
+     * LeAudioBroadcastConfigurationSetting is a result of
+     * getLeAudioBroadcastConfiguration. It is used in HCI_LE_Create_BIG command
+     * and for creating the Broadcast Announcements.
+     *
+     */
+    @VintfStability
+    parcelable LeAudioBroadcastConfigurationSetting {
+        /**
+         * SDU Interval (in microseconds) used in LE Create BIG command
+         */
+        int sduIntervalUs;
+        /**
+         * Total number of BISes in the BIG
+         */
+        int numBis;
+        /**
+         *  Maximum size of an SDU in octets
+         */
+        int maxSduOctets;
+        /**
+         * Maximum transport latency (in milliseconds)
+         */
+        int maxTransportLatencyMs;
+        /**
+         * The number of times every PDU should be retransmitted
+         */
+        int retransmitionNum;
+        /**
+         * A list of PHYs used for transmission of PDUs of BISes in the BIG.
+         */
+        Phy[] phy;
+        /**
+         * The preferred method of arranging subevents of multiple BISes
+         */
+        Packing packing;
+        /**
+         * format for sending BIS Data PDUs
+         */
+        Framing framing;
+
+        /**
+         * Data path configuration
+         * If not provided, getLeAudioBroadcastDatapathConfiguration() will be
+         * called during the configuration, increasing the stream establishment
+         * time (not recommended).
+         */
+        @nullable LeAudioDataPathConfiguration dataPathConfiguration;
+
+        /**
+         * A list of subgroup configurations in the broadcast.
+         */
+        List<LeAudioBroadcastSubgroupConfiguration> subgroupsConfigurations;
+    }
+
+    /**
+     * Get Broadcast configuration. Output of this function will be used
+     * in HCI_LE_Create_BIG  (0x0068) command and also to create BIG INFO
+     *
+     */
+    LeAudioBroadcastConfigurationSetting getLeAudioBroadcastConfiguration(
+            in @nullable List<LeAudioDeviceCapabilities> remoteSinkAudioCapabilities,
+            in LeAudioBroadcastConfigurationRequirement requirement);
+
+    /**
+     * Used to get a data path configuration which dynamically depends on BIS
+     * handles in BroadcastStreamMap. This is used if non-dynamic data path was
+     * not provided in LeAudioBroadcastConfigurationSetting. Calling this during
+     * the broadcast audio stream establishment might slightly delay the stream
+     * start.
+     */
+    LeAudioDataPathConfiguration getLeAudioBroadcastDatapathConfiguration(
+            in AudioContext context, in BroadcastStreamMap[] streamMap);
 }
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl
index 3cde22c..ea9c4e1 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl
@@ -17,8 +17,10 @@
 package android.hardware.bluetooth.audio;
 
 import android.hardware.bluetooth.audio.AudioCapabilities;
+import android.hardware.bluetooth.audio.CodecInfo;
 import android.hardware.bluetooth.audio.IBluetoothAudioProvider;
 import android.hardware.bluetooth.audio.SessionType;
+
 /**
  * This factory allows a HAL implementation to be split into multiple
  * independent providers.
@@ -62,4 +64,38 @@
      * @return provider The provider of the specified session type
      */
     IBluetoothAudioProvider openProvider(in SessionType sessionType);
+
+    /**
+     * General information relative to a provider
+     * - An optional name
+     * - A list of codec information
+     * - supportsMultidirectionalCapabilities if is set to false it means each
+     * session i.e. _ENCODING and _DECODING is responsible to provide
+     * configuration for a single direction:
+     *    _ENCODING for SINK ASE
+     *    _DECODING for SOURCE ASE
+     *
+     * If supportsMultidirectionalCapabilities is set to true, then either
+     * _ENCODING or _DECODING session can provide the configurations for either
+     * direction.
+     */
+    @VintfStability
+    parcelable ProviderInfo {
+        String name;
+        CodecInfo[] codecInfos;
+        boolean supportsMultidirectionalCapabilities;
+    }
+
+    /**
+     * Get general information relative to a provider.
+     *
+     * This can be called at any time, or just once during the BT stack
+     * initialization.
+     *
+     * @param sessionType Hardware Offload provider (*_HARDWARE_OFFLOAD_*)
+     * @return General information relative to the provider.
+     *         The `null` value can be returned when the provider is not
+     *         available
+     */
+    @nullable ProviderInfo getProviderInfo(in SessionType sessionType);
 }
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioAseConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioAseConfiguration.aidl
new file mode 100644
index 0000000..9fb2ecf
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioAseConfiguration.aidl
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.CodecId;
+import android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv;
+import android.hardware.bluetooth.audio.MetadataLtv;
+import android.hardware.bluetooth.audio.Phy;
+
+/**
+ * All the LeAudioAseConfiguration parameters are defined by the Bluetooth Audio
+ * Stream Control Service specification v.1.0, Sec. 5: "ASE Control Operations".
+ */
+@VintfStability
+parcelable LeAudioAseConfiguration {
+    @VintfStability
+    @Backing(type="byte")
+    enum TargetLatency {
+        UNDEFINED = 0x00,
+        LOWER = 0x01,
+        BALANCED_LATENCY_RELIABILITY = 0x02,
+        HIGHER_RELIABILITY = 0x03,
+    }
+
+    /**
+     * Target latency used in Configure Codec command - Can be UNDEFINED when
+     * used inside the AseDirectionRequirement, but shall not be UNDEFINED when
+     * used inside LeAudioAseConfigurationSetting.
+     */
+    TargetLatency targetLatency;
+
+    /**
+     * Target PHY used in Configure Codec command - Can be UNDEFINED when used
+     * inside the AseDirectionRequirement, but shall not be UNDEFINED when used
+     * inside LeAudioAseConfigurationSetting.
+     */
+    Phy targetPhy;
+
+    /**
+     * Codec ID - Can be Null when used inside the AseDirectionRequirement, but
+     * shall not be Null when used inside LeAudioAseConfigurationSetting.
+     */
+    @nullable CodecId codecId;
+
+    /**
+     * Codec configuration for ASE represented in the LTV types defined by
+     * Bluetooth SIG. Regardless of vendor specific configuration being used or
+     * not, this shall contain Bluetooth LTV types describing the common stream
+     * parameters, at least CodecSpecificConfigurationLtv.SamplingFrequency and
+     * CodecSpecificConfigurationLtv.AudioChannelAllocation. In addition, it
+     * should match aseConfiguration provided in LeAudioConfigurationRequirement
+     * as this will also be used to verify the requirements on the known LTV
+     * types.
+     */
+    CodecSpecificConfigurationLtv[] codecConfiguration;
+
+    /**
+     * Vendor specific codec configuration for ASE.
+     *
+     * This will not be parsed by the BT stack but will be written to the remote
+     * device as the codec specific configuration as part of the codec configure
+     * control point operation. If this is populated, only the
+     * `vendorCodecConfiguration` will be used for the ASE configuration,
+     * otherwise `codecConfiguration` will be used. The BT stack will not merge
+     * it with the codecConfiguration for any purpose.
+     */
+    @nullable byte[] vendorCodecConfiguration;
+
+    /**
+     * Metadata, packed as LTV - used to enable ASE. This is optional
+     */
+    @nullable MetadataLtv[] metadata;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioBisConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioBisConfiguration.aidl
new file mode 100644
index 0000000..4d6cfde
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioBisConfiguration.aidl
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.CodecId;
+import android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv;
+import android.hardware.bluetooth.audio.MetadataLtv;
+
+/**
+ * LE Audio BIS configuration. This will be part of the streaming broadcast
+ * audio announcement advertised by the BT stack during the broadcast audio
+ * stream to inform the remote devices about the broadcast audio configuration.
+ * It will also be passed back to the vendor module as part of the currently
+ * active LeAudioBroadcastConfiguration for the encoder setup.
+ * As defined in Bluetooth Basic Audio Profile Specification, v.1.0.1,
+ * Sec. 3.7.2.2, Table 3.15, Level 3.
+ */
+@VintfStability
+parcelable LeAudioBisConfiguration {
+    /**
+     * Codec ID
+     */
+    CodecId codecId;
+
+    /**
+     * Codec configuration for BIS or group of BISes represented in the LTV
+     * types defined by Bluetooht SIG. Regardless of vendor specific
+     * configuration being used or not, this shall contain Bluetooth LTV types
+     * describing the common stream parameters, at least
+     * CodecSpecificConfigurationLtv.SamplingFrequency and
+     * CodecSpecificConfigurationLtv.AudioChannelAllocation.
+     * This will also be used to verify the requirements on the known LTV types.
+     */
+    CodecSpecificConfigurationLtv[] codecConfiguration;
+
+    /**
+     * Vendor specific codec configuration.
+     * This will not be parsed by the BT stack but will be set as the codec
+     * specific configuration for the ongoing audio stream, encoded by the
+     * vendor module. The remote device will receive this information when being
+     * configured for receiveing a brodcast audio stream. If this is populated,
+     * only the `vendorCodecConfiguration` will be used when configuring the
+     * remote device, otherwise `codecConfiguration` will be used.
+     */
+    byte[] vendorCodecConfiguration;
+
+    /**
+     * Metadata for the particular BIS or group of BISes. This is optional.
+     */
+    @nullable MetadataLtv[] metadata;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioBroadcastConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioBroadcastConfiguration.aidl
index 16503fb..da90373 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioBroadcastConfiguration.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioBroadcastConfiguration.aidl
@@ -17,6 +17,8 @@
 package android.hardware.bluetooth.audio;
 
 import android.hardware.bluetooth.audio.CodecType;
+import android.hardware.bluetooth.audio.ConfigurationFlags;
+import android.hardware.bluetooth.audio.LeAudioBisConfiguration;
 import android.hardware.bluetooth.audio.LeAudioCodecConfiguration;
 
 @VintfStability
@@ -39,6 +41,15 @@
          * Pcm stream id to identify the source for given streamHandle.
          */
         char pcmStreamId;
+        /*
+         * LE Audio BIS configuration
+         */
+        @nullable LeAudioBisConfiguration bisConfiguration;
+        /*
+         * Additional flags, used to request configurations with special
+         * features
+         */
+        @nullable ConfigurationFlags flags;
     }
     CodecType codecType;
     BroadcastStreamMap[] streamMap;
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl
index 7302aea..db753ad 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl
@@ -17,6 +17,8 @@
 package android.hardware.bluetooth.audio;
 
 import android.hardware.bluetooth.audio.CodecType;
+import android.hardware.bluetooth.audio.ConfigurationFlags;
+import android.hardware.bluetooth.audio.LeAudioAseConfiguration;
 import android.hardware.bluetooth.audio.LeAudioCodecConfiguration;
 
 @VintfStability
@@ -29,16 +31,40 @@
          */
         char streamHandle;
         /*
-         * Audio channel allocation is  a bit field, each enabled bit means that given audio
-         * direction, i.e. "left", or "right" is used. Ordering of audio channels comes from the
-         * least significant bit to the most significant bit. The valus follows the Bluetooth SIG
-         * Audio Location assigned number.
+         * Audio channel allocation is a bit field, each enabled bit means that
+         * given audio direction, i.e. "left", or "right" is used. Ordering of
+         * audio channels comes from the least significant bit to the most
+         * significant bit. The valus follows the Bluetooth SIG Audio Location
+         * assigned number.
          */
         int audioChannelAllocation;
         /*
          * The stream handle status
          */
         boolean isStreamActive;
+        /*
+         * LE Audio device ASE configuration
+         */
+        @nullable LeAudioAseConfiguration aseConfiguration;
+        /*
+         * Additional flags, used for configurations with special features
+         */
+        @nullable ConfigurationFlags flags;
+        parcelable BluetoothDeviceAddress {
+            enum DeviceAddressType {
+                BLE_ADDRESS_PUBLIC = 0x00,
+                BLE_ADDRESS_RANDOM = 0x01,
+            }
+            /**
+             * Peer device address. It should be non zero when isStreamActive is true
+             */
+            byte[6] deviceAddress;
+            /**
+             * Peer device address type.
+             */
+            DeviceAddressType deviceAddressType;
+        }
+        @nullable BluetoothDeviceAddress bluetoothDeviceAddress;
     }
     CodecType codecType;
     StreamMap[] streamMap;
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/MetadataLtv.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/MetadataLtv.aidl
new file mode 100644
index 0000000..b0befc1
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/MetadataLtv.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.AudioContext;
+
+/**
+ * Used to exchange generic metadata between the stack and the provider.
+ * As defined in Bluetooth Assigned Numbers, Sec. 6.12.6.
+ */
+@VintfStability
+union MetadataLtv {
+    parcelable PreferredAudioContexts {
+        AudioContext values;
+    }
+    parcelable StreamingAudioContexts {
+        AudioContext values;
+    }
+    /* This is an opaque container for passing metadata between the provider and
+     * the remote device. It must not be interpreted by the BT stack.
+     */
+    parcelable VendorSpecific {
+        int companyId;
+        byte[] opaqueValue;
+    }
+
+    PreferredAudioContexts preferredAudioContexts;
+    StreamingAudioContexts streamingAudioContexts;
+    VendorSpecific vendorSpecific;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/Phy.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/Phy.aidl
new file mode 100644
index 0000000..cbffdd5
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/Phy.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+/**
+ * Used to exchange generic Phy parameter between the stack and the provider.
+ */
+@VintfStability
+@Backing(type="byte")
+enum Phy {
+    UNDEFINED = 0x00,
+    ONE_M = 0x01,
+    TWO_M = 0x02,
+    CODED = 0x03,
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SessionType.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SessionType.aidl
index 7acb5c6..35292a1 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SessionType.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SessionType.aidl
@@ -70,4 +70,17 @@
      * The decoding of AVDTP media is done by HW and there is control only
      */
     A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+    /**
+     * Used when audio is encoded by Bluetooth Stack and is streaming to HFP device.
+     */
+    HFP_SOFTWARE_ENCODING_DATAPATH,
+    /**
+     * Used when audio is decoded by Bluetooth Stack and is streaming to HFP device.
+     */
+    HFP_SOFTWARE_DECODING_DATAPATH,
+    /**
+     * Used when encoded and decoded by hardware offload and is streamed to HFP device.
+     * This is a control path only.
+     */
+    HFP_HARDWARE_OFFLOAD_DATAPATH,
 }
diff --git a/bluetooth/audio/aidl/default/A2dpBits.h b/bluetooth/audio/aidl/default/A2dpBits.h
new file mode 100644
index 0000000..fb7587c
--- /dev/null
+++ b/bluetooth/audio/aidl/default/A2dpBits.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace aidl::android::hardware::bluetooth::audio {
+
+class A2dpBits {
+  const uint8_t* cdata_;
+  uint8_t* data_;
+
+ public:
+  A2dpBits(const std::vector<uint8_t>& vector)
+      : cdata_(vector.data()), data_(nullptr) {}
+
+  A2dpBits(std::vector<uint8_t>& vector)
+      : cdata_(vector.data()), data_(vector.data()) {}
+
+  struct Range {
+    const int first, len;
+    constexpr Range(int first, int last)
+        : first(first), len(last - first + 1) {}
+    constexpr Range(int index) : first(index), len(1) {}
+  };
+
+  constexpr bool get(int bit) const {
+    return (cdata_[bit >> 3] >> (7 - (bit & 7))) & 1;
+  }
+
+  constexpr unsigned get(const Range& range) const {
+    unsigned v(0);
+    for (int i = 0; i < range.len; i++)
+      v |= get(range.first + i) << ((range.len - 1) - i);
+    return v;
+  }
+
+  constexpr void set(int bit, int value = 1) {
+    uint8_t m = 1 << (7 - (bit & 7));
+    if (value)
+      data_[bit >> 3] |= m;
+    else
+      data_[bit >> 3] &= ~m;
+  }
+
+  constexpr void set(const Range& range, int value) {
+    for (int i = 0; i < range.len; i++)
+      set(range.first + i, (value >> ((range.len - 1) - i)) & 1);
+  }
+
+  constexpr int find_active_bit(const Range& range) const {
+    unsigned v = get(range);
+    int i = 0;
+    for (; i < range.len && ((v >> i) & 1) == 0; i++)
+      ;
+    return i < range.len && (v ^ (1 << i)) == 0
+               ? range.first + (range.len - 1) - i
+               : -1;
+  }
+};
+
+}  // namespace aidl::android::hardware::bluetooth::audio
diff --git a/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.cpp
index 2d0d8c9..ba7a89d 100644
--- a/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.cpp
@@ -22,6 +22,10 @@
 #include <BluetoothAudioSessionReport.h>
 #include <android-base/logging.h>
 
+#include "A2dpOffloadCodecAac.h"
+#include "A2dpOffloadCodecFactory.h"
+#include "A2dpOffloadCodecSbc.h"
+
 namespace aidl {
 namespace android {
 namespace hardware {
@@ -48,19 +52,44 @@
     const std::shared_ptr<IBluetoothAudioPort>& host_if,
     const AudioConfiguration& audio_config,
     const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return) {
-  if (audio_config.getTag() != AudioConfiguration::a2dpConfig) {
+  if (audio_config.getTag() == AudioConfiguration::Tag::a2dp) {
+    auto a2dp_config = audio_config.get<AudioConfiguration::Tag::a2dp>();
+    A2dpStatus a2dp_status = A2dpStatus::NOT_SUPPORTED_CODEC_TYPE;
+
+    if (a2dp_config.codecId ==
+        A2dpOffloadCodecSbc::GetInstance()->GetCodecId()) {
+      SbcParameters sbc_parameters;
+      a2dp_status = A2dpOffloadCodecSbc::GetInstance()->ParseConfiguration(
+          a2dp_config.configuration, &sbc_parameters);
+
+    } else if (a2dp_config.codecId ==
+               A2dpOffloadCodecAac::GetInstance()->GetCodecId()) {
+      AacParameters aac_parameters;
+      a2dp_status = A2dpOffloadCodecAac::GetInstance()->ParseConfiguration(
+          a2dp_config.configuration, &aac_parameters);
+    }
+    if (a2dp_status != A2dpStatus::OK) {
+      LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+                   << audio_config.toString();
+      *_aidl_return = DataMQDesc();
+      return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+  } else if (audio_config.getTag() == AudioConfiguration::Tag::a2dpConfig) {
+    if (!BluetoothAudioCodecs::IsOffloadCodecConfigurationValid(
+            session_type_,
+            audio_config.get<AudioConfiguration::a2dpConfig>())) {
+      LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+                   << audio_config.toString();
+      *_aidl_return = DataMQDesc();
+      return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+  } else {
     LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
                  << audio_config.toString();
     *_aidl_return = DataMQDesc();
     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
   }
-  if (!BluetoothAudioCodecs::IsOffloadCodecConfigurationValid(
-          session_type_, audio_config.get<AudioConfiguration::a2dpConfig>())) {
-    LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
-                 << audio_config.toString();
-    *_aidl_return = DataMQDesc();
-    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
-  }
+
   return BluetoothAudioProvider::startSession(
       host_if, audio_config, latency_modes, _aidl_return);
 }
@@ -73,6 +102,36 @@
   return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus A2dpOffloadAudioProvider::parseA2dpConfiguration(
+    const CodecId& codec_id, const std::vector<uint8_t>& configuration,
+    CodecParameters* codec_parameters, A2dpStatus* _aidl_return) {
+  auto codec = A2dpOffloadCodecFactory::GetInstance()->GetCodec(codec_id);
+  if (!codec) {
+    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+              << " - CodecId=" << codec_id.toString() << " is not found";
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+
+  *_aidl_return = codec->ParseConfiguration(configuration, codec_parameters);
+
+  return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus A2dpOffloadAudioProvider::getA2dpConfiguration(
+    const std::vector<A2dpRemoteCapabilities>& remote_a2dp_capabilities,
+    const A2dpConfigurationHint& hint,
+    std::optional<audio::A2dpConfiguration>* _aidl_return) {
+  *_aidl_return = std::nullopt;
+  A2dpConfiguration avdtp_configuration;
+
+  if (A2dpOffloadCodecFactory::GetInstance()->GetConfiguration(
+          remote_a2dp_capabilities, hint, &avdtp_configuration))
+    *_aidl_return =
+        std::make_optional<A2dpConfiguration>(std::move(avdtp_configuration));
+
+  return ndk::ScopedAStatus::ok();
+}
+
 }  // namespace audio
 }  // namespace bluetooth
 }  // namespace hardware
diff --git a/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.h b/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.h
index e6f188b..7cc6dee 100644
--- a/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.h
+++ b/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.h
@@ -34,7 +34,16 @@
       const std::shared_ptr<IBluetoothAudioPort>& host_if,
       const AudioConfiguration& audio_config,
       const std::vector<LatencyMode>& latency_modes,
-      DataMQDesc* _aidl_return);
+      DataMQDesc* _aidl_return) override;
+
+  ndk::ScopedAStatus parseA2dpConfiguration(
+      const CodecId& codec_id, const std::vector<uint8_t>& configuration,
+      CodecParameters* codec_parameters, A2dpStatus* _aidl_return) override;
+
+  ndk::ScopedAStatus getA2dpConfiguration(
+      const std::vector<A2dpRemoteCapabilities>& remote_a2dp_capabilities,
+      const A2dpConfigurationHint& hint,
+      std::optional<audio::A2dpConfiguration>* _aidl_return) override;
 
  private:
   ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
diff --git a/bluetooth/audio/aidl/default/A2dpOffloadCodec.h b/bluetooth/audio/aidl/default/A2dpOffloadCodec.h
new file mode 100644
index 0000000..7ed5872
--- /dev/null
+++ b/bluetooth/audio/aidl/default/A2dpOffloadCodec.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/bluetooth/audio/A2dpStatus.h>
+#include <aidl/android/hardware/bluetooth/audio/ChannelMode.h>
+#include <aidl/android/hardware/bluetooth/audio/CodecParameters.h>
+
+#include "BluetoothAudioProviderFactory.h"
+
+namespace aidl::android::hardware::bluetooth::audio {
+
+class A2dpOffloadCodec {
+ protected:
+  A2dpOffloadCodec(const CodecInfo& info) : info(info) {}
+  virtual ~A2dpOffloadCodec() {}
+
+ public:
+  const CodecInfo& info;
+
+  const CodecId& GetCodecId() const { return info.id; }
+
+  virtual A2dpStatus ParseConfiguration(
+      const std::vector<uint8_t>& configuration,
+      CodecParameters* codec_parameters) const = 0;
+
+  virtual bool BuildConfiguration(
+      const std::vector<uint8_t>& remote_capabilities,
+      const std::optional<CodecParameters>& hint,
+      std::vector<uint8_t>* configuration) const = 0;
+};
+
+}  // namespace aidl::android::hardware::bluetooth::audio
diff --git a/bluetooth/audio/aidl/default/A2dpOffloadCodecAac.cpp b/bluetooth/audio/aidl/default/A2dpOffloadCodecAac.cpp
new file mode 100644
index 0000000..0f5533a
--- /dev/null
+++ b/bluetooth/audio/aidl/default/A2dpOffloadCodecAac.cpp
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "A2dpOffloadCodecAac.h"
+
+#include "A2dpBits.h"
+
+namespace aidl::android::hardware::bluetooth::audio {
+
+/**
+ * AAC Local Capabilities
+ */
+
+enum : bool {
+  kEnableObjectTypeMpeg2AacLc = true,
+  kEnableObjectTypeMpeg4AacLc = true,
+};
+
+enum : bool {
+  kEnableSamplingFrequency44100 = true,
+  kEnableSamplingFrequency48000 = true,
+  kEnableSamplingFrequency88200 = false,
+  kEnableSamplingFrequency96000 = false,
+};
+
+enum : bool {
+  kEnableChannels1 = true,
+  kEnableChannels2 = true,
+};
+
+enum : bool {
+  kEnableVbrSupported = true,
+};
+
+enum : int {
+  kBitdepth = 24,
+};
+
+/**
+ * AAC Signaling format [A2DP - 4.5]
+ */
+
+// clang-format off
+
+constexpr A2dpBits::Range kObjectType        (  0,  6 );
+constexpr A2dpBits::Range kDrcEnable         (  7     );
+constexpr A2dpBits::Range kSamplingFrequency (  8, 19 );
+constexpr A2dpBits::Range kChannels          ( 20, 23 );
+constexpr A2dpBits::Range kVbrSupported      ( 24     );
+constexpr A2dpBits::Range kBitrate           ( 25, 47 );
+constexpr size_t kCapabilitiesSize = 48/8;
+
+// clang-format on
+
+enum {
+  kObjectTypeMpeg2AacLc = kObjectType.first,
+  kObjectTypeMpeg4AacLc,
+  kObjectTypeMpeg4AacLtp,
+  kObjectTypeMpeg4AacScalable,
+  kObjectTypeMpeg4AacHeV1,
+  kObjectTypeMpeg4AacHeV2,
+  kObjectTypeMpeg4AacEldV2
+};
+
+enum {
+  kSamplingFrequency8000 = kSamplingFrequency.first,
+  kSamplingFrequency11025,
+  kSamplingFrequency12000,
+  kSamplingFrequency16000,
+  kSamplingFrequency22050,
+  kSamplingFrequency24000,
+  kSamplingFrequency32000,
+  kSamplingFrequency44100,
+  kSamplingFrequency48000,
+  kSamplingFrequency64000,
+  kSamplingFrequency88200,
+  kSamplingFrequency96000
+};
+
+enum { kChannels1 = kChannels.first, kChannels2, kChannels51, kChannels71 };
+
+/**
+ * AAC Conversion functions
+ */
+
+static AacParameters::ObjectType GetObjectTypeEnum(int object_type) {
+  switch (object_type) {
+    case kObjectTypeMpeg2AacLc:
+      return AacParameters::ObjectType::MPEG2_AAC_LC;
+    case kObjectTypeMpeg4AacLc:
+    default:
+      return AacParameters::ObjectType::MPEG4_AAC_LC;
+  }
+}
+
+static int GetSamplingFrequencyBit(int32_t sampling_frequency) {
+  switch (sampling_frequency) {
+    case 8000:
+      return kSamplingFrequency8000;
+    case 11025:
+      return kSamplingFrequency11025;
+    case 12000:
+      return kSamplingFrequency12000;
+    case 16000:
+      return kSamplingFrequency16000;
+    case 22050:
+      return kSamplingFrequency22050;
+    case 24000:
+      return kSamplingFrequency24000;
+    case 32000:
+      return kSamplingFrequency32000;
+    case 44100:
+      return kSamplingFrequency44100;
+    case 48000:
+      return kSamplingFrequency48000;
+    case 64000:
+      return kSamplingFrequency64000;
+    case 88200:
+      return kSamplingFrequency88200;
+    case 96000:
+      return kSamplingFrequency96000;
+    default:
+      return -1;
+  }
+}
+
+static int32_t GetSamplingFrequencyValue(int sampling_frequency) {
+  switch (sampling_frequency) {
+    case kSamplingFrequency8000:
+      return 8000;
+    case kSamplingFrequency11025:
+      return 11025;
+    case kSamplingFrequency12000:
+      return 12000;
+    case kSamplingFrequency16000:
+      return 16000;
+    case kSamplingFrequency22050:
+      return 22050;
+    case kSamplingFrequency24000:
+      return 24000;
+    case kSamplingFrequency32000:
+      return 32000;
+    case kSamplingFrequency44100:
+      return 44100;
+    case kSamplingFrequency48000:
+      return 48000;
+    case kSamplingFrequency64000:
+      return 64000;
+    case kSamplingFrequency88200:
+      return 88200;
+    case kSamplingFrequency96000:
+      return 96000;
+    default:
+      return 0;
+  }
+}
+
+static int GetChannelsBit(ChannelMode channel_mode) {
+  switch (channel_mode) {
+    case ChannelMode::MONO:
+      return kChannels1;
+    case ChannelMode::STEREO:
+      return kChannels2;
+    default:
+      return -1;
+  }
+}
+
+static ChannelMode GetChannelModeEnum(int channel_mode) {
+  switch (channel_mode) {
+    case kChannels1:
+      return ChannelMode::MONO;
+    case kChannels2:
+      return ChannelMode::STEREO;
+    default:
+      return ChannelMode::UNKNOWN;
+  }
+}
+
+/**
+ * AAC Class implementation
+ */
+
+const A2dpOffloadCodecAac* A2dpOffloadCodecAac::GetInstance() {
+  static A2dpOffloadCodecAac instance;
+  return &instance;
+}
+
+A2dpOffloadCodecAac::A2dpOffloadCodecAac()
+    : A2dpOffloadCodec(info_),
+      info_({.id = CodecId(CodecId::A2dp::AAC), .name = "AAC"}) {
+  info_.transport.set<CodecInfo::Transport::Tag::a2dp>();
+  auto& a2dp_info = info_.transport.get<CodecInfo::Transport::Tag::a2dp>();
+
+  /* --- Setup Capabilities --- */
+
+  a2dp_info.capabilities.resize(kCapabilitiesSize);
+  std::fill(begin(a2dp_info.capabilities), end(a2dp_info.capabilities), 0);
+
+  auto capabilities = A2dpBits(a2dp_info.capabilities);
+
+  capabilities.set(kObjectTypeMpeg2AacLc, kEnableObjectTypeMpeg2AacLc);
+  capabilities.set(kObjectTypeMpeg4AacLc, kEnableObjectTypeMpeg4AacLc);
+
+  capabilities.set(kSamplingFrequency44100, kEnableSamplingFrequency44100);
+  capabilities.set(kSamplingFrequency48000, kEnableSamplingFrequency48000);
+  capabilities.set(kSamplingFrequency88200, kEnableSamplingFrequency88200);
+  capabilities.set(kSamplingFrequency96000, kEnableSamplingFrequency96000);
+
+  capabilities.set(kChannels1, kEnableChannels1);
+  capabilities.set(kChannels2, kEnableChannels2);
+
+  capabilities.set(kVbrSupported, kEnableVbrSupported);
+
+  /* --- Setup Sampling Frequencies --- */
+
+  auto& sampling_frequency = a2dp_info.samplingFrequencyHz;
+
+  for (auto v : {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
+                 64000, 88200, 96000})
+    if (capabilities.get(GetSamplingFrequencyBit(int32_t(v))))
+      sampling_frequency.push_back(v);
+
+  /* --- Setup Channel Modes --- */
+
+  auto& channel_modes = a2dp_info.channelMode;
+
+  for (auto v : {ChannelMode::MONO, ChannelMode::STEREO})
+    if (capabilities.get(GetChannelsBit(v))) channel_modes.push_back(v);
+
+  /* --- Setup Bitdepth --- */
+
+  a2dp_info.bitdepth.push_back(kBitdepth);
+}
+
+A2dpStatus A2dpOffloadCodecAac::ParseConfiguration(
+    const std::vector<uint8_t>& configuration,
+    CodecParameters* codec_parameters, AacParameters* aac_parameters) const {
+  auto& a2dp_info = info.transport.get<CodecInfo::Transport::Tag::a2dp>();
+
+  if (configuration.size() != a2dp_info.capabilities.size())
+    return A2dpStatus::BAD_LENGTH;
+
+  auto config = A2dpBits(configuration);
+  auto lcaps = A2dpBits(a2dp_info.capabilities);
+
+  /* --- Check Object Type --- */
+
+  int object_type = config.find_active_bit(kObjectType);
+  if (object_type < 0) return A2dpStatus::INVALID_OBJECT_TYPE;
+  if (!lcaps.get(object_type)) return A2dpStatus::NOT_SUPPORTED_OBJECT_TYPE;
+
+  /* --- Check Sampling Frequency --- */
+
+  int sampling_frequency = config.find_active_bit(kSamplingFrequency);
+  if (sampling_frequency < 0) return A2dpStatus::INVALID_SAMPLING_FREQUENCY;
+  if (!lcaps.get(sampling_frequency))
+    return A2dpStatus::NOT_SUPPORTED_SAMPLING_FREQUENCY;
+
+  /* --- Check Channels --- */
+
+  int channels = config.find_active_bit(kChannels);
+  if (channels < 0) return A2dpStatus::INVALID_CHANNELS;
+  if (!lcaps.get(channels)) return A2dpStatus::NOT_SUPPORTED_CHANNELS;
+
+  /* --- Check Bitrate --- */
+
+  bool vbr = config.get(kVbrSupported);
+  if (vbr && !lcaps.get(kVbrSupported)) return A2dpStatus::NOT_SUPPORTED_VBR;
+
+  int bitrate = config.get(kBitrate);
+  if (vbr && lcaps.get(kBitrate) && bitrate > lcaps.get(kBitrate))
+    return A2dpStatus::NOT_SUPPORTED_BIT_RATE;
+
+  /* --- Return --- */
+
+  codec_parameters->channelMode = GetChannelModeEnum(channels);
+  codec_parameters->samplingFrequencyHz =
+      GetSamplingFrequencyValue(sampling_frequency);
+  codec_parameters->bitdepth = kBitdepth;
+
+  codec_parameters->minBitrate = vbr ? 0 : bitrate;
+  codec_parameters->maxBitrate = bitrate;
+
+  if (aac_parameters)
+    aac_parameters->object_type = GetObjectTypeEnum(object_type);
+
+  return A2dpStatus::OK;
+}
+
+bool A2dpOffloadCodecAac::BuildConfiguration(
+    const std::vector<uint8_t>& remote_capabilities,
+    const std::optional<CodecParameters>& hint,
+    std::vector<uint8_t>* configuration) const {
+  auto& a2dp_info = info_.transport.get<CodecInfo::Transport::Tag::a2dp>();
+
+  if (remote_capabilities.size() != a2dp_info.capabilities.size()) return false;
+
+  auto lcaps = A2dpBits(a2dp_info.capabilities);
+  auto rcaps = A2dpBits(remote_capabilities);
+
+  configuration->resize(a2dp_info.capabilities.size());
+  std::fill(begin(*configuration), end(*configuration), 0);
+  auto config = A2dpBits(*configuration);
+
+  /* --- Select Object Type --- */
+
+  if (lcaps.get(kObjectTypeMpeg2AacLc) && rcaps.get(kObjectTypeMpeg2AacLc))
+    config.set(kObjectTypeMpeg2AacLc);
+  else if (lcaps.get(kObjectTypeMpeg4AacLc) && rcaps.get(kObjectTypeMpeg4AacLc))
+    config.set(kObjectTypeMpeg4AacLc);
+  else
+    return false;
+
+  /* --- Select Sampling Frequency --- */
+
+  auto sf_hint = hint ? GetSamplingFrequencyBit(hint->samplingFrequencyHz) : -1;
+
+  if (sf_hint >= 0 && lcaps.get(sf_hint) && rcaps.get(sf_hint))
+    config.set(sf_hint);
+  else if (lcaps.get(kSamplingFrequency96000) &&
+           rcaps.get(kSamplingFrequency96000))
+    config.set(kSamplingFrequency96000);
+  else if (lcaps.get(kSamplingFrequency88200) &&
+           rcaps.get(kSamplingFrequency88200))
+    config.set(kSamplingFrequency88200);
+  else if (lcaps.get(kSamplingFrequency48000) &&
+           rcaps.get(kSamplingFrequency48000))
+    config.set(kSamplingFrequency48000);
+  else if (lcaps.get(kSamplingFrequency44100) &&
+           rcaps.get(kSamplingFrequency44100))
+    config.set(kSamplingFrequency44100);
+  else
+    return false;
+
+  /* --- Select Channels --- */
+
+  auto ch_hint = hint ? GetChannelsBit(hint->channelMode) : -1;
+
+  if (ch_hint >= 0 && lcaps.get(ch_hint) && rcaps.get(ch_hint))
+    config.set(ch_hint);
+  else if (lcaps.get(kChannels2) && rcaps.get(kChannels2))
+    config.set(kChannels2);
+  else if (lcaps.get(kChannels1) && rcaps.get(kChannels1))
+    config.set(kChannels1);
+  else
+    return false;
+
+  /* --- Select Bitrate --- */
+
+  if (!hint || hint->minBitrate == 0)
+    config.set(kVbrSupported,
+               lcaps.get(kVbrSupported) && rcaps.get(kVbrSupported));
+
+  int32_t bitrate = lcaps.get(kBitrate);
+  if (hint && hint->maxBitrate > 0 && bitrate)
+    bitrate = std::min(hint->maxBitrate, bitrate);
+  else if (hint && hint->maxBitrate > 0)
+    bitrate = hint->maxBitrate;
+  config.set(kBitrate, bitrate);
+
+  return true;
+}
+
+}  // namespace aidl::android::hardware::bluetooth::audio
diff --git a/bluetooth/audio/aidl/default/A2dpOffloadCodecAac.h b/bluetooth/audio/aidl/default/A2dpOffloadCodecAac.h
new file mode 100644
index 0000000..eefa89b
--- /dev/null
+++ b/bluetooth/audio/aidl/default/A2dpOffloadCodecAac.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "A2dpOffloadCodec.h"
+
+namespace aidl::android::hardware::bluetooth::audio {
+
+struct AacParameters : public CodecParameters {
+  enum class ObjectType { MPEG2_AAC_LC, MPEG4_AAC_LC };
+
+  ObjectType object_type;
+};
+
+class A2dpOffloadCodecAac : public A2dpOffloadCodec {
+  CodecInfo info_;
+
+  A2dpOffloadCodecAac();
+
+  A2dpStatus ParseConfiguration(const std::vector<uint8_t>& configuration,
+                                CodecParameters* codec_parameters,
+                                AacParameters* aac_parameters) const;
+
+ public:
+  static const A2dpOffloadCodecAac* GetInstance();
+
+  A2dpStatus ParseConfiguration(
+      const std::vector<uint8_t>& configuration,
+      CodecParameters* codec_parameters) const override {
+    return ParseConfiguration(configuration, codec_parameters, nullptr);
+  }
+
+  A2dpStatus ParseConfiguration(const std::vector<uint8_t>& configuration,
+                                AacParameters* aac_parameters) const {
+    return ParseConfiguration(configuration, aac_parameters, aac_parameters);
+  }
+
+  bool BuildConfiguration(const std::vector<uint8_t>& remote_capabilities,
+                          const std::optional<CodecParameters>& hint,
+                          std::vector<uint8_t>* configuration) const override;
+};
+
+}  // namespace aidl::android::hardware::bluetooth::audio
diff --git a/bluetooth/audio/aidl/default/A2dpOffloadCodecFactory.cpp b/bluetooth/audio/aidl/default/A2dpOffloadCodecFactory.cpp
new file mode 100644
index 0000000..73d8fb1
--- /dev/null
+++ b/bluetooth/audio/aidl/default/A2dpOffloadCodecFactory.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "A2dpOffloadCodecFactory.h"
+
+#include <algorithm>
+#include <cassert>
+
+#include "A2dpOffloadCodecAac.h"
+#include "A2dpOffloadCodecSbc.h"
+
+namespace aidl::android::hardware::bluetooth::audio {
+
+/**
+ * Local Capabilities Configuration
+ */
+
+enum : bool {
+  kEnableAac = true,
+  kEnableSbc = true,
+};
+
+/**
+ * Class implementation
+ */
+
+const A2dpOffloadCodecFactory* A2dpOffloadCodecFactory::GetInstance() {
+  static A2dpOffloadCodecFactory instance;
+  return &instance;
+}
+
+A2dpOffloadCodecFactory::A2dpOffloadCodecFactory()
+    : name("Offload"), codecs(ranked_codecs_) {
+  ranked_codecs_.reserve(kEnableAac + kEnableSbc);
+
+  if (kEnableAac) ranked_codecs_.push_back(A2dpOffloadCodecAac::GetInstance());
+  if (kEnableSbc) ranked_codecs_.push_back(A2dpOffloadCodecSbc::GetInstance());
+}
+
+const A2dpOffloadCodec* A2dpOffloadCodecFactory::GetCodec(CodecId id) const {
+  auto codec = std::find_if(begin(ranked_codecs_), end(ranked_codecs_),
+                            [&](auto c) { return id == c->info.id; });
+
+  return codec != end(ranked_codecs_) ? *codec : nullptr;
+}
+
+bool A2dpOffloadCodecFactory::GetConfiguration(
+    const std::vector<A2dpRemoteCapabilities>& remote_capabilities,
+    const A2dpConfigurationHint& hint, A2dpConfiguration* configuration) const {
+  decltype(ranked_codecs_) codecs;
+
+  codecs.reserve(ranked_codecs_.size());
+
+  auto hinted_codec =
+      std::find_if(begin(ranked_codecs_), end(ranked_codecs_),
+                   [&](auto c) { return hint.codecId == c->info.id; });
+
+  if (hinted_codec != end(ranked_codecs_)) codecs.push_back(*hinted_codec);
+
+  std::copy_if(begin(ranked_codecs_), end(ranked_codecs_),
+               std::back_inserter(codecs),
+               [&](auto c) { return c != *hinted_codec; });
+
+  for (auto codec : codecs) {
+    auto rc =
+        std::find_if(begin(remote_capabilities), end(remote_capabilities),
+                     [&](auto& rc__) { return codec->info.id == rc__.id; });
+
+    if ((rc == end(remote_capabilities)) ||
+        !codec->BuildConfiguration(rc->capabilities, hint.codecParameters,
+                                   &configuration->configuration))
+      continue;
+
+    configuration->id = codec->info.id;
+    A2dpStatus status = codec->ParseConfiguration(configuration->configuration,
+                                                  &configuration->parameters);
+    assert(status == A2dpStatus::OK);
+
+    configuration->remoteSeid = rc->seid;
+
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace aidl::android::hardware::bluetooth::audio
diff --git a/bluetooth/audio/aidl/default/A2dpOffloadCodecFactory.h b/bluetooth/audio/aidl/default/A2dpOffloadCodecFactory.h
new file mode 100644
index 0000000..3fb5b1d
--- /dev/null
+++ b/bluetooth/audio/aidl/default/A2dpOffloadCodecFactory.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "A2dpOffloadCodec.h"
+
+namespace aidl::android::hardware::bluetooth::audio {
+
+class A2dpOffloadCodecFactory {
+  std::vector<const A2dpOffloadCodec*> ranked_codecs_;
+
+  A2dpOffloadCodecFactory();
+
+ public:
+  const std::string name;
+  const std::vector<const A2dpOffloadCodec*>& codecs;
+
+  static const A2dpOffloadCodecFactory* GetInstance();
+
+  const A2dpOffloadCodec* GetCodec(CodecId id) const;
+
+  bool GetConfiguration(const std::vector<A2dpRemoteCapabilities>&,
+                        const A2dpConfigurationHint& hint,
+                        A2dpConfiguration* configuration) const;
+};
+
+}  // namespace aidl::android::hardware::bluetooth::audio
diff --git a/bluetooth/audio/aidl/default/A2dpOffloadCodecSbc.cpp b/bluetooth/audio/aidl/default/A2dpOffloadCodecSbc.cpp
new file mode 100644
index 0000000..36d8f72
--- /dev/null
+++ b/bluetooth/audio/aidl/default/A2dpOffloadCodecSbc.cpp
@@ -0,0 +1,510 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "A2dpOffloadCodecSbc.h"
+
+#include <algorithm>
+
+#include "A2dpBits.h"
+
+namespace aidl::android::hardware::bluetooth::audio {
+
+/**
+ * SBC Local Capabilities
+ */
+
+enum : bool {
+  kEnableSamplingFrequency44100 = true,
+  kEnableSamplingFrequency48000 = true,
+};
+
+enum : bool {
+  kEnableChannelModeMono = true,
+  kEnableChannelModeDualChannel = true,
+  kEnableChannelModeStereo = true,
+  kEnableChannelModeJointStereo = true,
+};
+
+enum : bool {
+  kEnableBlockLength4 = true,
+  kEnableBlockLength8 = true,
+  kEnableBlockLength12 = true,
+  kEnableBlockLength16 = true,
+};
+
+enum : bool {
+  kEnableSubbands4 = true,
+  kEnableSubbands8 = true,
+};
+
+enum : bool {
+  kEnableAllocationMethodSnr = true,
+  kEnableAllocationMethodLoudness = true,
+};
+
+enum : uint8_t {
+  kDefaultMinimumBitpool = 2,
+  kDefaultMaximumBitpool = 250,
+};
+
+enum : int {
+  kBitdepth = 16,
+};
+
+/**
+ * SBC Signaling format [A2DP - 4.3]
+ */
+
+// clang-format off
+
+constexpr A2dpBits::Range kSamplingFrequency (  0,  3 );
+constexpr A2dpBits::Range kChannelMode       (  4,  7 );
+constexpr A2dpBits::Range kBlockLength       (  8, 11 );
+constexpr A2dpBits::Range kSubbands          ( 12, 13 );
+constexpr A2dpBits::Range kAllocationMethod  ( 14, 15 );
+constexpr A2dpBits::Range kMinimumBitpool    ( 16, 23 );
+constexpr A2dpBits::Range kMaximumBitpool    ( 24, 31 );
+constexpr size_t kCapabilitiesSize = 32/8;
+
+// clang-format on
+
+enum {
+  kSamplingFrequency16000 = kSamplingFrequency.first,
+  kSamplingFrequency32000,
+  kSamplingFrequency44100,
+  kSamplingFrequency48000
+};
+
+enum {
+  kChannelModeMono = kChannelMode.first,
+  kChannelModeDualChannel,
+  kChannelModeStereo,
+  kChannelModeJointStereo
+};
+
+enum {
+  kBlockLength4 = kBlockLength.first,
+  kBlockLength8,
+  kBlockLength12,
+  kBlockLength16
+};
+
+enum { kSubbands8 = kSubbands.first, kSubbands4 };
+
+enum {
+  kAllocationMethodSnr = kAllocationMethod.first,
+  kAllocationMethodLoudness
+};
+
+/**
+ * SBC Conversion functions
+ */
+
+static int GetSamplingFrequencyBit(int32_t sampling_frequency) {
+  switch (sampling_frequency) {
+    case 16000:
+      return kSamplingFrequency16000;
+    case 32000:
+      return kSamplingFrequency32000;
+    case 44100:
+      return kSamplingFrequency44100;
+    case 48000:
+      return kSamplingFrequency48000;
+    default:
+      return -1;
+  }
+}
+
+static int32_t GetSamplingFrequencyValue(int sampling_frequency) {
+  switch (sampling_frequency) {
+    case kSamplingFrequency16000:
+      return 16000;
+    case kSamplingFrequency32000:
+      return 32000;
+    case kSamplingFrequency44100:
+      return 44100;
+    case kSamplingFrequency48000:
+      return 48000;
+    default:
+      return 0;
+  }
+}
+
+static int GetChannelModeBit(ChannelMode channel_mode) {
+  switch (channel_mode) {
+    case ChannelMode::STEREO:
+      return kChannelModeJointStereo | kChannelModeStereo;
+    case ChannelMode::DUALMONO:
+      return kChannelModeDualChannel;
+    case ChannelMode::MONO:
+      return kChannelModeMono;
+    default:
+      return -1;
+  }
+}
+
+static ChannelMode GetChannelModeEnum(int channel_mode) {
+  switch (channel_mode) {
+    case kChannelModeMono:
+      return ChannelMode::MONO;
+    case kChannelModeDualChannel:
+      return ChannelMode::DUALMONO;
+    case kChannelModeStereo:
+    case kChannelModeJointStereo:
+      return ChannelMode::STEREO;
+    default:
+      return ChannelMode::UNKNOWN;
+  }
+}
+
+static int32_t GetBlockLengthValue(int block_length) {
+  switch (block_length) {
+    case kBlockLength4:
+      return 4;
+    case kBlockLength8:
+      return 8;
+    case kBlockLength12:
+      return 12;
+    case kBlockLength16:
+      return 16;
+    default:
+      return 0;
+  }
+}
+
+static int32_t GetSubbandsValue(int subbands) {
+  switch (subbands) {
+    case kSubbands4:
+      return 4;
+    case kSubbands8:
+      return 8;
+    default:
+      return 0;
+  }
+}
+
+static SbcParameters::AllocationMethod GetAllocationMethodEnum(
+    int allocation_method) {
+  switch (allocation_method) {
+    case kAllocationMethodSnr:
+      return SbcParameters::AllocationMethod::SNR;
+    case kAllocationMethodLoudness:
+    default:
+      return SbcParameters::AllocationMethod::LOUDNESS;
+  }
+}
+
+static int32_t GetSamplingFrequencyValue(const A2dpBits& configuration) {
+  return GetSamplingFrequencyValue(
+      configuration.find_active_bit(kSamplingFrequency));
+}
+
+static int32_t GetBlockLengthValue(const A2dpBits& configuration) {
+  return GetBlockLengthValue(configuration.find_active_bit(kBlockLength));
+}
+
+static int32_t GetSubbandsValue(const A2dpBits& configuration) {
+  return GetSubbandsValue(configuration.find_active_bit(kSubbands));
+}
+
+static int GetFrameSize(const A2dpBits& configuration, int bitpool) {
+  const int kSbcHeaderSize = 4;
+  int subbands = GetSubbandsValue(configuration);
+  int blocks = GetBlockLengthValue(configuration);
+
+  unsigned bits =
+      ((4 * subbands) << !configuration.get(kChannelModeMono)) +
+      ((blocks * bitpool) << configuration.get(kChannelModeDualChannel)) +
+      ((configuration.get(kChannelModeJointStereo) ? subbands : 0));
+
+  return kSbcHeaderSize + ((bits + 7) >> 3);
+}
+
+static int GetBitrate(const A2dpBits& configuration, int bitpool) {
+  int sampling_frequency = GetSamplingFrequencyValue(configuration);
+  int subbands = GetSubbandsValue(configuration);
+  int blocks = GetBlockLengthValue(configuration);
+  int bits = 8 * GetFrameSize(configuration, bitpool);
+
+  return (bits * sampling_frequency) / (blocks * subbands);
+}
+
+static uint8_t GetBitpool(const A2dpBits& configuration, int bitrate) {
+  int bitpool = 0;
+
+  for (int i = 128; i; i >>= 1)
+    if (bitrate > GetBitrate(configuration, bitpool + i)) {
+      bitpool += i;
+    }
+
+  return std::clamp(bitpool, 2, 250);
+}
+
+/**
+ * SBC Class implementation
+ */
+
+const A2dpOffloadCodecSbc* A2dpOffloadCodecSbc::GetInstance() {
+  static A2dpOffloadCodecSbc instance;
+  return &instance;
+}
+
+A2dpOffloadCodecSbc::A2dpOffloadCodecSbc()
+    : A2dpOffloadCodec(info_),
+      info_({.id = CodecId(CodecId::A2dp::SBC), .name = "SBC"}) {
+  info_.transport.set<CodecInfo::Transport::Tag::a2dp>();
+  auto& a2dp_info = info_.transport.get<CodecInfo::Transport::Tag::a2dp>();
+
+  /* --- Setup Capabilities --- */
+
+  a2dp_info.capabilities.resize(kCapabilitiesSize);
+  std::fill(begin(a2dp_info.capabilities), end(a2dp_info.capabilities), 0);
+
+  auto capabilities = A2dpBits(a2dp_info.capabilities);
+
+  capabilities.set(kSamplingFrequency44100, kEnableSamplingFrequency44100);
+  capabilities.set(kSamplingFrequency48000, kEnableSamplingFrequency48000);
+
+  capabilities.set(kChannelModeMono, kEnableChannelModeMono);
+  capabilities.set(kChannelModeDualChannel, kEnableChannelModeDualChannel);
+  capabilities.set(kChannelModeStereo, kEnableChannelModeStereo);
+  capabilities.set(kChannelModeJointStereo, kEnableChannelModeJointStereo);
+
+  capabilities.set(kBlockLength4, kEnableBlockLength4);
+  capabilities.set(kBlockLength8, kEnableBlockLength8);
+  capabilities.set(kBlockLength12, kEnableBlockLength12);
+  capabilities.set(kBlockLength16, kEnableBlockLength16);
+
+  capabilities.set(kSubbands4, kEnableSubbands4);
+  capabilities.set(kSubbands8, kEnableSubbands8);
+
+  capabilities.set(kSubbands4, kEnableSubbands4);
+  capabilities.set(kSubbands8, kEnableSubbands8);
+
+  capabilities.set(kAllocationMethodSnr, kEnableAllocationMethodSnr);
+  capabilities.set(kAllocationMethodLoudness, kEnableAllocationMethodLoudness);
+
+  capabilities.set(kMinimumBitpool, kDefaultMinimumBitpool);
+  capabilities.set(kMaximumBitpool, kDefaultMaximumBitpool);
+
+  /* --- Setup Sampling Frequencies --- */
+
+  auto& sampling_frequency = a2dp_info.samplingFrequencyHz;
+
+  for (auto v : {16000, 32000, 44100, 48000})
+    if (capabilities.get(GetSamplingFrequencyBit(int32_t(v))))
+      sampling_frequency.push_back(v);
+
+  /* --- Setup Channel Modes --- */
+
+  auto& channel_modes = a2dp_info.channelMode;
+
+  for (auto v : {ChannelMode::MONO, ChannelMode::DUALMONO, ChannelMode::STEREO})
+    if (capabilities.get(GetChannelModeBit(v))) channel_modes.push_back(v);
+
+  /* --- Setup Bitdepth --- */
+
+  a2dp_info.bitdepth.push_back(kBitdepth);
+}
+
+A2dpStatus A2dpOffloadCodecSbc::ParseConfiguration(
+    const std::vector<uint8_t>& configuration,
+    CodecParameters* codec_parameters, SbcParameters* sbc_parameters) const {
+  auto& a2dp_info = info.transport.get<CodecInfo::Transport::Tag::a2dp>();
+
+  if (configuration.size() != a2dp_info.capabilities.size())
+    return A2dpStatus::BAD_LENGTH;
+
+  auto config = A2dpBits(configuration);
+  auto lcaps = A2dpBits(a2dp_info.capabilities);
+
+  /* --- Check Sampling Frequency --- */
+
+  int sampling_frequency = config.find_active_bit(kSamplingFrequency);
+  if (sampling_frequency < 0) return A2dpStatus::INVALID_SAMPLING_FREQUENCY;
+  if (!lcaps.get(sampling_frequency))
+    return A2dpStatus::NOT_SUPPORTED_SAMPLING_FREQUENCY;
+
+  /* --- Check Channel Mode --- */
+
+  int channel_mode = config.find_active_bit(kChannelMode);
+  if (channel_mode < 0) return A2dpStatus::INVALID_CHANNEL_MODE;
+  if (!lcaps.get(channel_mode)) return A2dpStatus::NOT_SUPPORTED_CHANNEL_MODE;
+
+  /* --- Check Block Length --- */
+
+  int block_length = config.find_active_bit(kBlockLength);
+  if (block_length < 0) return A2dpStatus::INVALID_BLOCK_LENGTH;
+
+  /* --- Check Subbands --- */
+
+  int subbands = config.find_active_bit(kSubbands);
+  if (subbands < 0) return A2dpStatus::INVALID_SUBBANDS;
+  if (!lcaps.get(subbands)) return A2dpStatus::NOT_SUPPORTED_SUBBANDS;
+
+  /* --- Check Allocation Method --- */
+
+  int allocation_method = config.find_active_bit(kAllocationMethod);
+  if (allocation_method < 0) return A2dpStatus::INVALID_ALLOCATION_METHOD;
+  if (!lcaps.get(allocation_method))
+    return A2dpStatus::NOT_SUPPORTED_ALLOCATION_METHOD;
+
+  /* --- Check Bitpool --- */
+
+  uint8_t min_bitpool = config.get(kMinimumBitpool);
+  if (min_bitpool < 2 || min_bitpool > 250)
+    return A2dpStatus::INVALID_MINIMUM_BITPOOL_VALUE;
+  if (min_bitpool < lcaps.get(kMinimumBitpool))
+    return A2dpStatus::NOT_SUPPORTED_MINIMUM_BITPOOL_VALUE;
+
+  uint8_t max_bitpool = config.get(kMaximumBitpool);
+  if (max_bitpool < 2 || max_bitpool > 250)
+    return A2dpStatus::INVALID_MAXIMUM_BITPOOL_VALUE;
+  if (max_bitpool > lcaps.get(kMaximumBitpool))
+    return A2dpStatus::NOT_SUPPORTED_MAXIMUM_BITPOOL_VALUE;
+
+  /* --- Return --- */
+
+  codec_parameters->channelMode = GetChannelModeEnum(channel_mode);
+  codec_parameters->samplingFrequencyHz =
+      GetSamplingFrequencyValue(sampling_frequency);
+  codec_parameters->bitdepth = kBitdepth;
+
+  codec_parameters->minBitrate = GetBitrate(config, min_bitpool);
+  codec_parameters->maxBitrate = GetBitrate(config, max_bitpool);
+
+  if (sbc_parameters) {
+    sbc_parameters->block_length = GetBlockLengthValue(block_length);
+    sbc_parameters->subbands = GetSubbandsValue(subbands);
+    sbc_parameters->allocation_method =
+        GetAllocationMethodEnum(allocation_method);
+    sbc_parameters->min_bitpool = min_bitpool;
+    sbc_parameters->max_bitpool = max_bitpool;
+  }
+
+  return A2dpStatus::OK;
+}
+
+bool A2dpOffloadCodecSbc::BuildConfiguration(
+    const std::vector<uint8_t>& remote_capabilities,
+    const std::optional<CodecParameters>& hint,
+    std::vector<uint8_t>* configuration) const {
+  auto& a2dp_info = info.transport.get<CodecInfo::Transport::Tag::a2dp>();
+
+  if (remote_capabilities.size() != a2dp_info.capabilities.size()) return false;
+
+  auto lcaps = A2dpBits(a2dp_info.capabilities);
+  auto rcaps = A2dpBits(remote_capabilities);
+
+  configuration->resize(a2dp_info.capabilities.size());
+  std::fill(begin(*configuration), end(*configuration), 0);
+  auto config = A2dpBits(*configuration);
+
+  /* --- Select Sampling Frequency --- */
+
+  auto sf_hint = hint ? GetSamplingFrequencyBit(hint->samplingFrequencyHz) : -1;
+
+  if (sf_hint >= 0 && lcaps.get(sf_hint) && rcaps.get(sf_hint))
+    config.set(sf_hint);
+  else if (lcaps.get(kSamplingFrequency44100) &&
+           rcaps.get(kSamplingFrequency44100))
+    config.set(kSamplingFrequency44100);
+  else if (lcaps.get(kSamplingFrequency48000) &&
+           rcaps.get(kSamplingFrequency48000))
+    config.set(kSamplingFrequency48000);
+  else
+    return false;
+
+  /* --- Select Channel Mode --- */
+
+  auto cm_hint = hint ? GetChannelModeBit(hint->channelMode) : -1;
+
+  if (cm_hint >= 0 && lcaps.get(cm_hint) && rcaps.get(cm_hint))
+    config.set(cm_hint);
+  else if (lcaps.get(kChannelModeJointStereo) &&
+           rcaps.get(kChannelModeJointStereo))
+    config.set(kChannelModeJointStereo);
+  else if (lcaps.get(kChannelModeStereo) && rcaps.get(kChannelModeStereo))
+    config.set(kChannelModeStereo);
+  else if (lcaps.get(kChannelModeDualChannel) &&
+           rcaps.get(kChannelModeDualChannel))
+    config.set(kChannelModeDualChannel);
+  else if (lcaps.get(kChannelModeMono) && rcaps.get(kChannelModeMono))
+    config.set(kChannelModeMono);
+  else
+    return false;
+
+  /* --- Select Block Length --- */
+
+  if (lcaps.get(kBlockLength16) && rcaps.get(kBlockLength16))
+    config.set(kBlockLength16);
+  else if (lcaps.get(kBlockLength12) && rcaps.get(kBlockLength12))
+    config.set(kBlockLength12);
+  else if (lcaps.get(kBlockLength8) && rcaps.get(kBlockLength8))
+    config.set(kBlockLength8);
+  else if (lcaps.get(kBlockLength4) && rcaps.get(kBlockLength4))
+    config.set(kBlockLength4);
+  else
+    return false;
+
+  /* --- Select Subbands --- */
+
+  if (lcaps.get(kSubbands8) && rcaps.get(kSubbands8))
+    config.set(kSubbands8);
+  else if (lcaps.get(kSubbands4) && rcaps.get(kSubbands4))
+    config.set(kSubbands4);
+  else
+    return false;
+
+  /* --- Select Allocation method --- */
+
+  if (lcaps.get(kAllocationMethodLoudness) &&
+      rcaps.get(kAllocationMethodLoudness))
+    config.set(kAllocationMethodLoudness);
+  else if (lcaps.get(kAllocationMethodSnr) && rcaps.get(kAllocationMethodSnr))
+    config.set(kAllocationMethodSnr);
+  else
+    return false;
+
+  /* --- Select Bitpool --- */
+
+  uint8_t min_bitpool = rcaps.get(kMinimumBitpool);
+  uint8_t max_bitpool = rcaps.get(kMaximumBitpool);
+
+  if (min_bitpool < 2 || min_bitpool > 250 || max_bitpool < 2 ||
+      max_bitpool > 250 || min_bitpool > max_bitpool) {
+    min_bitpool = 2;
+    max_bitpool = 250;
+  }
+
+  min_bitpool = std::max(min_bitpool, uint8_t(lcaps.get(kMinimumBitpool)));
+  max_bitpool = std::max(max_bitpool, uint8_t(lcaps.get(kMaximumBitpool)));
+
+  if (hint) {
+    min_bitpool =
+        std::max(min_bitpool, GetBitpool(*configuration, hint->minBitrate));
+    if (hint->maxBitrate && hint->maxBitrate >= hint->minBitrate)
+      max_bitpool =
+          std::min(max_bitpool, GetBitpool(*configuration, hint->maxBitrate));
+  }
+
+  config.set(kMinimumBitpool, min_bitpool);
+  config.set(kMaximumBitpool, max_bitpool);
+
+  return true;
+}
+
+}  // namespace aidl::android::hardware::bluetooth::audio
diff --git a/bluetooth/audio/aidl/default/A2dpOffloadCodecSbc.h b/bluetooth/audio/aidl/default/A2dpOffloadCodecSbc.h
new file mode 100644
index 0000000..c380850
--- /dev/null
+++ b/bluetooth/audio/aidl/default/A2dpOffloadCodecSbc.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "A2dpOffloadCodec.h"
+
+namespace aidl::android::hardware::bluetooth::audio {
+
+struct SbcParameters : public CodecParameters {
+  enum class AllocationMethod { SNR, LOUDNESS };
+
+  AllocationMethod allocation_method;
+  int block_length;
+  int subbands;
+  int min_bitpool;
+  int max_bitpool;
+};
+
+class A2dpOffloadCodecSbc : public A2dpOffloadCodec {
+  CodecInfo info_;
+
+  A2dpOffloadCodecSbc();
+
+  A2dpStatus ParseConfiguration(const std::vector<uint8_t>& configuration,
+                                CodecParameters* codec_parameters,
+                                SbcParameters* sbc_parameters) const;
+
+ public:
+  static const A2dpOffloadCodecSbc* GetInstance();
+
+  A2dpStatus ParseConfiguration(
+      const std::vector<uint8_t>& configuration,
+      CodecParameters* codec_parameters) const override {
+    return ParseConfiguration(configuration, codec_parameters, nullptr);
+  }
+
+  A2dpStatus ParseConfiguration(const std::vector<uint8_t>& configuration,
+                                SbcParameters* sbc_parameters) const {
+    return ParseConfiguration(configuration, sbc_parameters, sbc_parameters);
+  }
+
+  bool BuildConfiguration(const std::vector<uint8_t>& remote_capabilities,
+                          const std::optional<CodecParameters>& hint,
+                          std::vector<uint8_t>* configuration) const override;
+};
+
+}  // namespace aidl::android::hardware::bluetooth::audio
diff --git a/bluetooth/audio/aidl/default/Android.bp b/bluetooth/audio/aidl/default/Android.bp
index e4c2844..69db1b3 100644
--- a/bluetooth/audio/aidl/default/Android.bp
+++ b/bluetooth/audio/aidl/default/Android.bp
@@ -11,12 +11,20 @@
     name: "android.hardware.bluetooth.audio-impl",
     vendor: true,
     vintf_fragments: ["bluetooth_audio.xml"],
+    defaults: [
+        "latest_android_hardware_bluetooth_audio_ndk_shared",
+    ],
     srcs: [
         "BluetoothAudioProvider.cpp",
         "BluetoothAudioProviderFactory.cpp",
         "A2dpOffloadAudioProvider.cpp",
+        "A2dpOffloadCodecAac.cpp",
+        "A2dpOffloadCodecFactory.cpp",
+        "A2dpOffloadCodecSbc.cpp",
         "A2dpSoftwareAudioProvider.cpp",
         "HearingAidAudioProvider.cpp",
+        "HfpOffloadAudioProvider.cpp",
+        "HfpSoftwareAudioProvider.cpp",
         "LeAudioOffloadAudioProvider.cpp",
         "LeAudioSoftwareAudioProvider.cpp",
         "service.cpp",
@@ -29,7 +37,6 @@
         "libcutils",
         "libfmq",
         "liblog",
-        "android.hardware.bluetooth.audio-V3-ndk",
         "libbluetooth_audio_session_aidl",
     ],
 }
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp b/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp
index 9c72e19..8d03fae 100644
--- a/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp
@@ -21,6 +21,8 @@
 #include <BluetoothAudioSessionReport.h>
 #include <android-base/logging.h>
 
+#include "A2dpOffloadCodecFactory.h"
+
 namespace aidl {
 namespace android {
 namespace hardware {
@@ -164,8 +166,146 @@
   return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus BluetoothAudioProvider::parseA2dpConfiguration(
+    [[maybe_unused]] const CodecId& codec_id,
+    [[maybe_unused]] const std::vector<uint8_t>& configuration,
+    [[maybe_unused]] CodecParameters* codec_parameters,
+    [[maybe_unused]] A2dpStatus* _aidl_return) {
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+            << " is illegal";
+  return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+}
+
+ndk::ScopedAStatus BluetoothAudioProvider::getA2dpConfiguration(
+    [[maybe_unused]] const std::vector<A2dpRemoteCapabilities>&
+        remote_a2dp_capabilities,
+    [[maybe_unused]] const A2dpConfigurationHint& hint,
+    [[maybe_unused]] std::optional<audio::A2dpConfiguration>* _aidl_return) {
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+            << " is illegal";
+
+  return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+}
+
+ndk::ScopedAStatus BluetoothAudioProvider::setCodecPriority(
+    const ::aidl::android::hardware::bluetooth::audio::CodecId& in_codecId,
+    int32_t in_priority) {
+  /* TODO: Implement */
+  (void)in_codecId;
+  (void)in_priority;
+  return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
+ndk::ScopedAStatus BluetoothAudioProvider::getLeAudioAseConfiguration(
+    const std::optional<std::vector<std::optional<
+        ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+            LeAudioDeviceCapabilities>>>& in_remoteSinkAudioCapabilities,
+    const std::optional<std::vector<std::optional<
+        ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+            LeAudioDeviceCapabilities>>>& in_remoteSourceAudioCapabilities,
+    const std::vector<
+        ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+            LeAudioConfigurationRequirement>& in_requirements,
+    std::vector<::aidl::android::hardware::bluetooth::audio::
+                    IBluetoothAudioProvider::LeAudioAseConfigurationSetting>*
+        _aidl_return) {
+  /* TODO: Implement */
+  (void)in_remoteSinkAudioCapabilities;
+  (void)in_remoteSourceAudioCapabilities;
+  (void)in_requirements;
+  (void)_aidl_return;
+  return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
+ndk::ScopedAStatus BluetoothAudioProvider::getLeAudioAseQosConfiguration(
+    const ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+        LeAudioAseQosConfigurationRequirement& in_qosRequirement,
+    ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+        LeAudioAseQosConfigurationPair* _aidl_return) {
+  /* TODO: Implement */
+  (void)in_qosRequirement;
+  (void)_aidl_return;
+  return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
+ndk::ScopedAStatus BluetoothAudioProvider::getLeAudioAseDatapathConfiguration(
+    const std::optional<::aidl::android::hardware::bluetooth::audio::
+                            IBluetoothAudioProvider::StreamConfig>&
+        in_sinkConfig,
+    const std::optional<::aidl::android::hardware::bluetooth::audio::
+                            IBluetoothAudioProvider::StreamConfig>&
+        in_sourceConfig,
+    ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+        LeAudioDataPathConfigurationPair* _aidl_return) {
+  /* TODO: Implement */
+  (void)in_sinkConfig;
+  (void)in_sourceConfig;
+  (void)_aidl_return;
+  return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus BluetoothAudioProvider::onSinkAseMetadataChanged(
+    ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+        AseState in_state,
+    int32_t cigId, int32_t cisId,
+    const std::optional<std::vector<std::optional<
+        ::aidl::android::hardware::bluetooth::audio::MetadataLtv>>>&
+        in_metadata) {
+  /* TODO: Implement */
+  (void)in_state;
+  (void)cigId;
+  (void)cisId;
+  (void)in_metadata;
+  return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
+ndk::ScopedAStatus BluetoothAudioProvider::onSourceAseMetadataChanged(
+    ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+        AseState in_state,
+    int32_t cigId, int32_t cisId,
+    const std::optional<std::vector<std::optional<
+        ::aidl::android::hardware::bluetooth::audio::MetadataLtv>>>&
+        in_metadata) {
+  /* TODO: Implement */
+  (void)in_state;
+  (void)cigId;
+  (void)cisId;
+  (void)in_metadata;
+  return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
+ndk::ScopedAStatus BluetoothAudioProvider::getLeAudioBroadcastConfiguration(
+    const std::optional<std::vector<std::optional<
+        ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+            LeAudioDeviceCapabilities>>>& in_remoteSinkAudioCapabilities,
+    const ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+        LeAudioBroadcastConfigurationRequirement& in_requirement,
+    ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+        LeAudioBroadcastConfigurationSetting* _aidl_return) {
+  /* TODO: Implement */
+  (void)in_remoteSinkAudioCapabilities;
+  (void)in_requirement;
+  (void)_aidl_return;
+  return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
+ndk::ScopedAStatus
+BluetoothAudioProvider::getLeAudioBroadcastDatapathConfiguration(
+    const ::aidl::android::hardware::bluetooth::audio::AudioContext& in_context,
+    const std::vector<::aidl::android::hardware::bluetooth::audio::
+                          LeAudioBroadcastConfiguration::BroadcastStreamMap>&
+        in_streamMap,
+    ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+        LeAudioDataPathConfiguration* _aidl_return) {
+  /* TODO: Implement */
+  (void)in_context;
+  (void)in_streamMap;
+  (void)_aidl_return;
+  return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
 }  // namespace audio
 }  // namespace bluetooth
 }  // namespace hardware
 }  // namespace android
-}  // namespace aidl
\ No newline at end of file
+}  // namespace aidl
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProvider.h b/bluetooth/audio/aidl/default/BluetoothAudioProvider.h
index b6e07a1..2c21440 100644
--- a/bluetooth/audio/aidl/default/BluetoothAudioProvider.h
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProvider.h
@@ -41,14 +41,83 @@
   ndk::ScopedAStatus startSession(
       const std::shared_ptr<IBluetoothAudioPort>& host_if,
       const AudioConfiguration& audio_config,
-      const std::vector<LatencyMode>& latency_modes,
-      DataMQDesc* _aidl_return);
+      const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return);
   ndk::ScopedAStatus endSession();
   ndk::ScopedAStatus streamStarted(BluetoothAudioStatus status);
   ndk::ScopedAStatus streamSuspended(BluetoothAudioStatus status);
   ndk::ScopedAStatus updateAudioConfiguration(
       const AudioConfiguration& audio_config);
   ndk::ScopedAStatus setLowLatencyModeAllowed(bool allowed);
+  ndk::ScopedAStatus setCodecPriority(
+      const ::aidl::android::hardware::bluetooth::audio::CodecId& in_codecId,
+      int32_t in_priority) override;
+  ndk::ScopedAStatus getLeAudioAseConfiguration(
+      const std::optional<std::vector<std::optional<
+          ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+              LeAudioDeviceCapabilities>>>& in_remoteSinkAudioCapabilities,
+      const std::optional<std::vector<std::optional<
+          ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+              LeAudioDeviceCapabilities>>>& in_remoteSourceAudioCapabilities,
+      const std::vector<
+          ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+              LeAudioConfigurationRequirement>& in_requirements,
+      std::vector<::aidl::android::hardware::bluetooth::audio::
+                      IBluetoothAudioProvider::LeAudioAseConfigurationSetting>*
+          _aidl_return) override;
+  ndk::ScopedAStatus getLeAudioAseQosConfiguration(
+      const ::aidl::android::hardware::bluetooth::audio::
+          IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
+              in_qosRequirement,
+      ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+          LeAudioAseQosConfigurationPair* _aidl_return) override;
+  ndk::ScopedAStatus getLeAudioAseDatapathConfiguration(
+      const std::optional<::aidl::android::hardware::bluetooth::audio::
+                              IBluetoothAudioProvider::StreamConfig>&
+          in_sinkConfig,
+      const std::optional<::aidl::android::hardware::bluetooth::audio::
+                              IBluetoothAudioProvider::StreamConfig>&
+          in_sourceConfig,
+      ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+          LeAudioDataPathConfigurationPair* _aidl_return) override;
+  ndk::ScopedAStatus onSinkAseMetadataChanged(
+      ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+          AseState in_state,
+      int32_t cigId, int32_t cisId,
+      const std::optional<std::vector<std::optional<
+          ::aidl::android::hardware::bluetooth::audio::MetadataLtv>>>&
+          in_metadata) override;
+  ndk::ScopedAStatus onSourceAseMetadataChanged(
+      ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+          AseState in_state,
+      int32_t cigId, int32_t cisId,
+      const std::optional<std::vector<std::optional<
+          ::aidl::android::hardware::bluetooth::audio::MetadataLtv>>>&
+          in_metadata) override;
+  ndk::ScopedAStatus getLeAudioBroadcastConfiguration(
+      const std::optional<std::vector<std::optional<
+          ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+              LeAudioDeviceCapabilities>>>& in_remoteSinkAudioCapabilities,
+      const ::aidl::android::hardware::bluetooth::audio::
+          IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement&
+              in_requirement,
+      ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+          LeAudioBroadcastConfigurationSetting* _aidl_return) override;
+  ndk::ScopedAStatus getLeAudioBroadcastDatapathConfiguration(
+      const ::aidl::android::hardware::bluetooth::audio::AudioContext&
+          in_context,
+      const std::vector<::aidl::android::hardware::bluetooth::audio::
+                            LeAudioBroadcastConfiguration::BroadcastStreamMap>&
+          in_streamMap,
+      ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+          LeAudioDataPathConfiguration* _aidl_return) override;
+
+  ndk::ScopedAStatus parseA2dpConfiguration(
+      const CodecId& codec_id, const std::vector<uint8_t>& configuration,
+      CodecParameters* codec_parameters, A2dpStatus* _aidl_return);
+  ndk::ScopedAStatus getA2dpConfiguration(
+      const std::vector<A2dpRemoteCapabilities>& remote_a2dp_capabilities,
+      const A2dpConfigurationHint& hint,
+      std::optional<audio::A2dpConfiguration>* _aidl_return);
 
   virtual bool isValid(const SessionType& sessionType) = 0;
 
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
index 91731d4..e55a434 100644
--- a/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
@@ -22,9 +22,12 @@
 #include <android-base/logging.h>
 
 #include "A2dpOffloadAudioProvider.h"
+#include "A2dpOffloadCodecFactory.h"
 #include "A2dpSoftwareAudioProvider.h"
 #include "BluetoothAudioProvider.h"
 #include "HearingAidAudioProvider.h"
+#include "HfpOffloadAudioProvider.h"
+#include "HfpSoftwareAudioProvider.h"
 #include "LeAudioOffloadAudioProvider.h"
 #include "LeAudioSoftwareAudioProvider.h"
 
@@ -34,6 +37,9 @@
 namespace bluetooth {
 namespace audio {
 
+static const std::string kLeAudioOffloadProviderName =
+    "LE_AUDIO_OFFLOAD_HARDWARE_OFFLOAD_PROVIDER";
+
 BluetoothAudioProviderFactory::BluetoothAudioProviderFactory() {}
 
 ndk::ScopedAStatus BluetoothAudioProviderFactory::openProvider(
@@ -78,6 +84,15 @@
     case SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH:
       provider = ndk::SharedRefBase::make<A2dpOffloadDecodingAudioProvider>();
       break;
+    case SessionType::HFP_SOFTWARE_ENCODING_DATAPATH:
+      provider = ndk::SharedRefBase::make<HfpSoftwareOutputAudioProvider>();
+      break;
+    case SessionType::HFP_SOFTWARE_DECODING_DATAPATH:
+      provider = ndk::SharedRefBase::make<HfpSoftwareInputAudioProvider>();
+      break;
+    case SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH:
+      provider = ndk::SharedRefBase::make<HfpOffloadAudioProvider>();
+      break;
     default:
       provider = nullptr;
       break;
@@ -135,8 +150,43 @@
   return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus BluetoothAudioProviderFactory::getProviderInfo(
+    SessionType session_type, std::optional<ProviderInfo>* _aidl_return) {
+  *_aidl_return = std::nullopt;
+
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type);
+
+  if (session_type == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+      session_type == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+    auto& provider_info = _aidl_return->emplace();
+
+    provider_info.name = A2dpOffloadCodecFactory::GetInstance()->name;
+    for (auto codec : A2dpOffloadCodecFactory::GetInstance()->codecs)
+      provider_info.codecInfos.push_back(codec->info);
+  }
+
+  if (session_type ==
+          SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+      session_type ==
+          SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH ||
+      session_type ==
+          SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+    std::vector<CodecInfo> db_codec_info =
+        BluetoothAudioCodecs::GetLeAudioOffloadCodecInfo(session_type);
+    if (!db_codec_info.empty()) {
+      auto& provider_info = _aidl_return->emplace();
+      provider_info.name = kLeAudioOffloadProviderName;
+      provider_info.codecInfos = db_codec_info;
+      *_aidl_return = provider_info;
+      return ndk::ScopedAStatus::ok();
+    }
+  }
+
+  return ndk::ScopedAStatus::ok();
+}
+
 }  // namespace audio
 }  // namespace bluetooth
 }  // namespace hardware
 }  // namespace android
-}  // namespace aidl
\ No newline at end of file
+}  // namespace aidl
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.h b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.h
index b38cfd2..1afae64 100644
--- a/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.h
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.h
@@ -35,6 +35,10 @@
   ndk::ScopedAStatus getProviderCapabilities(
       const SessionType session_type,
       std::vector<AudioCapabilities>* _aidl_return) override;
+
+  ndk::ScopedAStatus getProviderInfo(
+      SessionType in_sessionType,
+      std::optional<ProviderInfo>* _aidl_return) override;
 };
 
 }  // namespace audio
diff --git a/bluetooth/audio/aidl/default/HfpOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/HfpOffloadAudioProvider.cpp
new file mode 100644
index 0000000..7196bb6
--- /dev/null
+++ b/bluetooth/audio/aidl/default/HfpOffloadAudioProvider.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BTAudioProviderHfpHW"
+
+#include "HfpOffloadAudioProvider.h"
+
+#include <BluetoothAudioCodecs.h>
+#include <BluetoothAudioSessionReport.h>
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+HfpOffloadAudioProvider::HfpOffloadAudioProvider() {
+  session_type_ = SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH;
+}
+
+bool HfpOffloadAudioProvider::isValid(const SessionType& session_type) {
+  return (session_type == session_type_);
+}
+
+ndk::ScopedAStatus HfpOffloadAudioProvider::startSession(
+    const std::shared_ptr<IBluetoothAudioPort>& host_if,
+    const AudioConfiguration& audio_config,
+    const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return) {
+  if (audio_config.getTag() != AudioConfiguration::hfpConfig) {
+    LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+                 << audio_config.toString();
+    *_aidl_return = DataMQDesc();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+  return BluetoothAudioProvider::startSession(host_if, audio_config,
+                                              latency_modes, _aidl_return);
+}
+
+ndk::ScopedAStatus HfpOffloadAudioProvider::onSessionReady(
+    DataMQDesc* _aidl_return) {
+  *_aidl_return = DataMQDesc();
+  BluetoothAudioSessionReport::OnSessionStarted(
+      session_type_, stack_iface_, nullptr, *audio_config_, latency_modes_);
+  return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/aidl/default/HfpOffloadAudioProvider.h b/bluetooth/audio/aidl/default/HfpOffloadAudioProvider.h
new file mode 100644
index 0000000..5526b46
--- /dev/null
+++ b/bluetooth/audio/aidl/default/HfpOffloadAudioProvider.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "BluetoothAudioProvider.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class HfpOffloadAudioProvider : public BluetoothAudioProvider {
+ public:
+  HfpOffloadAudioProvider();
+
+  bool isValid(const SessionType& sessionType) override;
+
+  ndk::ScopedAStatus startSession(
+      const std::shared_ptr<IBluetoothAudioPort>& host_if,
+      const AudioConfiguration& audio_config,
+      const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return);
+
+ private:
+  ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/aidl/default/HfpSoftwareAudioProvider.cpp b/bluetooth/audio/aidl/default/HfpSoftwareAudioProvider.cpp
new file mode 100644
index 0000000..0f96046
--- /dev/null
+++ b/bluetooth/audio/aidl/default/HfpSoftwareAudioProvider.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BTAudioProviderHfpSW"
+
+#include "HfpSoftwareAudioProvider.h"
+
+#include <BluetoothAudioCodecs.h>
+#include <BluetoothAudioSessionReport.h>
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+static constexpr uint32_t kBufferCount = 2;  // two frame buffer
+
+HfpSoftwareOutputAudioProvider::HfpSoftwareOutputAudioProvider()
+    : HfpSoftwareAudioProvider() {
+  session_type_ = SessionType::HFP_SOFTWARE_ENCODING_DATAPATH;
+}
+
+HfpSoftwareInputAudioProvider::HfpSoftwareInputAudioProvider()
+    : HfpSoftwareAudioProvider() {
+  session_type_ = SessionType::HFP_SOFTWARE_DECODING_DATAPATH;
+}
+
+HfpSoftwareAudioProvider::HfpSoftwareAudioProvider()
+    : BluetoothAudioProvider(), data_mq_(nullptr) {
+}
+
+bool HfpSoftwareAudioProvider::isValid(const SessionType& sessionType) {
+  return (sessionType == session_type_);
+}
+
+ndk::ScopedAStatus HfpSoftwareAudioProvider::startSession(
+    const std::shared_ptr<IBluetoothAudioPort>& host_if,
+    const AudioConfiguration& audio_config,
+    const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return) {
+  if (audio_config.getTag() != AudioConfiguration::pcmConfig) {
+    LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+                 << audio_config.toString();
+    *_aidl_return = DataMQDesc();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+  const PcmConfiguration& pcm_config =
+      audio_config.get<AudioConfiguration::pcmConfig>();
+  if (!BluetoothAudioCodecs::IsSoftwarePcmConfigurationValid(pcm_config)) {
+    LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
+                 << pcm_config.toString();
+    *_aidl_return = DataMQDesc();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+
+  bool isValidConfig = true;
+
+  if (pcm_config.bitsPerSample != 16) {
+    isValidConfig = false;
+  }
+
+  if (pcm_config.sampleRateHz != 8000 && pcm_config.sampleRateHz != 16000 &&
+      pcm_config.sampleRateHz != 32000) {
+    isValidConfig = false;
+  }
+
+  if (pcm_config.channelMode != ChannelMode::MONO) {
+    isValidConfig = false;
+  }
+
+  if (pcm_config.dataIntervalUs != 7500) {
+    isValidConfig = false;
+  }
+
+  int bytes_per_sample = pcm_config.bitsPerSample / 8;
+
+  uint32_t data_mq_size = kBufferCount * bytes_per_sample *
+                          (pcm_config.sampleRateHz / 1000) *
+                          pcm_config.dataIntervalUs / 1000;
+  if (!isValidConfig) {
+    LOG(ERROR) << __func__ << "Unexpected audio buffer size: " << data_mq_size
+               << ", SampleRateHz: " << pcm_config.sampleRateHz
+               << ", ChannelMode: " << toString(pcm_config.channelMode)
+               << ", BitsPerSample: "
+               << static_cast<int>(pcm_config.bitsPerSample)
+               << ", BytesPerSample: " << bytes_per_sample
+               << ", DataIntervalUs: " << pcm_config.dataIntervalUs
+               << ", SessionType: " << toString(session_type_);
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+
+  LOG(INFO) << __func__ << " - size of audio buffer " << data_mq_size
+            << " byte(s)";
+
+  std::unique_ptr<DataMQ> temp_data_mq(
+      new DataMQ(data_mq_size, /* EventFlag */ true));
+  if (temp_data_mq == nullptr || !temp_data_mq->isValid()) {
+    ALOGE_IF(!temp_data_mq, "failed to allocate data MQ");
+    ALOGE_IF(temp_data_mq && !temp_data_mq->isValid(), "data MQ is invalid");
+    *_aidl_return = DataMQDesc();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+  data_mq_ = std::move(temp_data_mq);
+
+  return BluetoothAudioProvider::startSession(host_if, audio_config,
+                                              latency_modes, _aidl_return);
+}
+
+ndk::ScopedAStatus HfpSoftwareAudioProvider::onSessionReady(
+    DataMQDesc* _aidl_return) {
+  if (data_mq_ == nullptr || !data_mq_->isValid()) {
+    *_aidl_return = DataMQDesc();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+  *_aidl_return = data_mq_->dupeDesc();
+  auto desc = data_mq_->dupeDesc();
+  BluetoothAudioSessionReport::OnSessionStarted(
+      session_type_, stack_iface_, &desc, *audio_config_, latency_modes_);
+  return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/aidl/default/HfpSoftwareAudioProvider.h b/bluetooth/audio/aidl/default/HfpSoftwareAudioProvider.h
new file mode 100644
index 0000000..ef51065
--- /dev/null
+++ b/bluetooth/audio/aidl/default/HfpSoftwareAudioProvider.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "BluetoothAudioProvider.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class HfpSoftwareAudioProvider : public BluetoothAudioProvider {
+ public:
+  HfpSoftwareAudioProvider();
+
+  bool isValid(const SessionType& sessionType) override;
+
+  ndk::ScopedAStatus startSession(
+      const std::shared_ptr<IBluetoothAudioPort>& host_if,
+      const AudioConfiguration& audio_config,
+      const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return);
+
+ private:
+  // audio data queue for software encoding
+  std::unique_ptr<DataMQ> data_mq_;
+
+  ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
+};
+
+class HfpSoftwareOutputAudioProvider : public HfpSoftwareAudioProvider {
+ public:
+  HfpSoftwareOutputAudioProvider();
+};
+
+class HfpSoftwareInputAudioProvider : public HfpSoftwareAudioProvider {
+ public:
+  HfpSoftwareInputAudioProvider();
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
index 7f610ef..cff3b25 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
@@ -28,6 +28,73 @@
 namespace bluetooth {
 namespace audio {
 
+constexpr uint8_t kLeAudioDirectionSink = 0x01;
+constexpr uint8_t kLeAudioDirectionSource = 0x02;
+
+const std::map<CodecSpecificConfigurationLtv::SamplingFrequency, uint32_t>
+    freq_to_support_bitmask_map = {
+        {CodecSpecificConfigurationLtv::SamplingFrequency::HZ8000,
+         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ8000},
+        {CodecSpecificConfigurationLtv::SamplingFrequency::HZ11025,
+         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ11025},
+        {CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ16000},
+        {CodecSpecificConfigurationLtv::SamplingFrequency::HZ22050,
+         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ22050},
+        {CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000,
+         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ24000},
+        {CodecSpecificConfigurationLtv::SamplingFrequency::HZ32000,
+         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ32000},
+        {CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000,
+         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ48000},
+        {CodecSpecificConfigurationLtv::SamplingFrequency::HZ88200,
+         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ88200},
+        {CodecSpecificConfigurationLtv::SamplingFrequency::HZ96000,
+         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ96000},
+        {CodecSpecificConfigurationLtv::SamplingFrequency::HZ176400,
+         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ176400},
+        {CodecSpecificConfigurationLtv::SamplingFrequency::HZ192000,
+         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ192000},
+        {CodecSpecificConfigurationLtv::SamplingFrequency::HZ384000,
+         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ384000},
+};
+
+// Helper map from capability's tag to configuration's tag
+std::map<CodecSpecificCapabilitiesLtv::Tag, CodecSpecificConfigurationLtv::Tag>
+    cap_to_cfg_tag_map = {
+        {CodecSpecificCapabilitiesLtv::Tag::supportedSamplingFrequencies,
+         CodecSpecificConfigurationLtv::Tag::samplingFrequency},
+        {CodecSpecificCapabilitiesLtv::Tag::supportedMaxCodecFramesPerSDU,
+         CodecSpecificConfigurationLtv::Tag::codecFrameBlocksPerSDU},
+        {CodecSpecificCapabilitiesLtv::Tag::supportedFrameDurations,
+         CodecSpecificConfigurationLtv::Tag::frameDuration},
+        {CodecSpecificCapabilitiesLtv::Tag::supportedAudioChannelCounts,
+         CodecSpecificConfigurationLtv::Tag::audioChannelAllocation},
+        {CodecSpecificCapabilitiesLtv::Tag::supportedOctetsPerCodecFrame,
+         CodecSpecificConfigurationLtv::Tag::octetsPerCodecFrame},
+};
+
+const std::map<CodecSpecificConfigurationLtv::FrameDuration, uint32_t>
+    fduration_to_support_fduration_map = {
+        {CodecSpecificConfigurationLtv::FrameDuration::US7500,
+         CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US7500},
+        {CodecSpecificConfigurationLtv::FrameDuration::US10000,
+         CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US10000},
+};
+
+std::map<int32_t, CodecSpecificConfigurationLtv::SamplingFrequency>
+    sampling_freq_map = {
+        {16000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000},
+        {48000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000},
+        {96000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ96000},
+};
+
+std::map<int32_t, CodecSpecificConfigurationLtv::FrameDuration>
+    frame_duration_map = {
+        {7500, CodecSpecificConfigurationLtv::FrameDuration::US7500},
+        {10000, CodecSpecificConfigurationLtv::FrameDuration::US10000},
+};
+
 LeAudioOffloadOutputAudioProvider::LeAudioOffloadOutputAudioProvider()
     : LeAudioOffloadAudioProvider() {
   session_type_ = SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
@@ -70,8 +137,8 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
   }
 
-  return BluetoothAudioProvider::startSession(
-      host_if, audio_config, latency_modes, _aidl_return);
+  return BluetoothAudioProvider::startSession(host_if, audio_config,
+                                              latency_modes, _aidl_return);
 }
 
 ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSessionReady(
@@ -81,6 +148,644 @@
   *_aidl_return = DataMQDesc();
   return ndk::ScopedAStatus::ok();
 }
+ndk::ScopedAStatus LeAudioOffloadAudioProvider::setCodecPriority(
+    const CodecId& in_codecId, int32_t in_priority) {
+  codec_priority_map_[in_codecId] = in_priority;
+  return ndk::ScopedAStatus::ok();
+};
+
+bool LeAudioOffloadAudioProvider::isMatchedValidCodec(CodecId cfg_codec,
+                                                      CodecId req_codec) {
+  auto priority = codec_priority_map_.find(cfg_codec);
+  if (priority != codec_priority_map_.end() && priority->second == -1)
+    return false;
+  return cfg_codec == req_codec;
+}
+
+bool LeAudioOffloadAudioProvider::isCapabilitiesMatchedContext(
+    AudioContext setting_context,
+    const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities) {
+  // If has no metadata, assume match
+  if (!capabilities.metadata.has_value()) return true;
+
+  for (auto metadata : capabilities.metadata.value()) {
+    if (!metadata.has_value()) continue;
+    if (metadata.value().getTag() == MetadataLtv::Tag::preferredAudioContexts) {
+      // Check all pref audio context to see if anything matched
+      auto& context = metadata.value()
+                          .get<MetadataLtv::Tag::preferredAudioContexts>()
+                          .values;
+      if (setting_context.bitmask & context.bitmask) return true;
+    }
+  }
+
+  return false;
+}
+
+bool LeAudioOffloadAudioProvider::isMatchedSamplingFreq(
+    CodecSpecificConfigurationLtv::SamplingFrequency& cfg_freq,
+    CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies&
+        capability_freq) {
+  for (auto [freq, bitmask] : freq_to_support_bitmask_map)
+    if (cfg_freq == freq) return (capability_freq.bitmask & bitmask);
+  return false;
+}
+
+bool LeAudioOffloadAudioProvider::isMatchedFrameDuration(
+    CodecSpecificConfigurationLtv::FrameDuration& cfg_fduration,
+    CodecSpecificCapabilitiesLtv::SupportedFrameDurations&
+        capability_fduration) {
+  for (auto [fduration, bitmask] : fduration_to_support_fduration_map)
+    if (cfg_fduration == fduration)
+      return (capability_fduration.bitmask & bitmask);
+  return false;
+}
+
+bool LeAudioOffloadAudioProvider::isMatchedAudioChannel(
+    CodecSpecificConfigurationLtv::AudioChannelAllocation&
+    /*cfg_channel*/,
+    CodecSpecificCapabilitiesLtv::SupportedAudioChannelCounts&
+    /*capability_channel*/) {
+  bool isMatched = true;
+  // TODO: how to match?
+  return isMatched;
+}
+
+bool LeAudioOffloadAudioProvider::isMatchedCodecFramesPerSDU(
+    CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU& cfg_frame_sdu,
+    CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU&
+        capability_frame_sdu) {
+  return cfg_frame_sdu.value <= capability_frame_sdu.value;
+}
+
+bool LeAudioOffloadAudioProvider::isMatchedOctetsPerCodecFrame(
+    CodecSpecificConfigurationLtv::OctetsPerCodecFrame& cfg_octets,
+    CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame&
+        capability_octets) {
+  return cfg_octets.value >= capability_octets.minimum &&
+         cfg_octets.value <= capability_octets.maximum;
+}
+
+bool LeAudioOffloadAudioProvider::isCapabilitiesMatchedCodecConfiguration(
+    std::vector<CodecSpecificConfigurationLtv>& codec_cfg,
+    std::vector<CodecSpecificCapabilitiesLtv> codec_capabilities) {
+  // Convert all codec_cfg into a map of tags -> correct data
+  std::map<CodecSpecificConfigurationLtv::Tag, CodecSpecificConfigurationLtv>
+      cfg_tag_map;
+  for (auto codec_cfg_data : codec_cfg)
+    cfg_tag_map[codec_cfg_data.getTag()] = codec_cfg_data;
+
+  for (auto& codec_capability : codec_capabilities) {
+    auto cfg = cfg_tag_map.find(cap_to_cfg_tag_map[codec_capability.getTag()]);
+    // Cannot find tag for the capability:
+    if (cfg == cfg_tag_map.end()) return false;
+
+    // Matching logic for sampling frequency
+    if (codec_capability.getTag() ==
+        CodecSpecificCapabilitiesLtv::Tag::supportedSamplingFrequencies) {
+      if (!isMatchedSamplingFreq(
+              cfg->second
+                  .get<CodecSpecificConfigurationLtv::Tag::samplingFrequency>(),
+              codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+                                       supportedSamplingFrequencies>()))
+        return false;
+    } else if (codec_capability.getTag() ==
+               CodecSpecificCapabilitiesLtv::Tag::supportedFrameDurations) {
+      if (!isMatchedFrameDuration(
+              cfg->second
+                  .get<CodecSpecificConfigurationLtv::Tag::frameDuration>(),
+              codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+                                       supportedFrameDurations>()))
+        return false;
+    } else if (codec_capability.getTag() ==
+               CodecSpecificCapabilitiesLtv::Tag::supportedAudioChannelCounts) {
+      if (!isMatchedAudioChannel(
+              cfg->second.get<
+                  CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>(),
+              codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+                                       supportedAudioChannelCounts>()))
+        return false;
+    } else if (codec_capability.getTag() == CodecSpecificCapabilitiesLtv::Tag::
+                                                supportedMaxCodecFramesPerSDU) {
+      if (!isMatchedCodecFramesPerSDU(
+              cfg->second.get<
+                  CodecSpecificConfigurationLtv::Tag::codecFrameBlocksPerSDU>(),
+              codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+                                       supportedMaxCodecFramesPerSDU>()))
+        return false;
+    } else if (codec_capability.getTag() == CodecSpecificCapabilitiesLtv::Tag::
+                                                supportedOctetsPerCodecFrame) {
+      if (!isMatchedOctetsPerCodecFrame(
+              cfg->second.get<
+                  CodecSpecificConfigurationLtv::Tag::octetsPerCodecFrame>(),
+              codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+                                       supportedOctetsPerCodecFrame>()))
+        return false;
+    }
+  }
+
+  return true;
+}
+
+bool LeAudioOffloadAudioProvider::isMatchedAseConfiguration(
+    LeAudioAseConfiguration setting_cfg,
+    LeAudioAseConfiguration requirement_cfg) {
+  // Check matching for codec configuration <=> requirement ASE codec
+  // Also match if no CodecId requirement
+  if (requirement_cfg.codecId.has_value()) {
+    if (!setting_cfg.codecId.has_value()) return false;
+    if (!isMatchedValidCodec(setting_cfg.codecId.value(),
+                             requirement_cfg.codecId.value()))
+      return false;
+  }
+
+  if (setting_cfg.targetLatency != requirement_cfg.targetLatency) return false;
+  // Ignore PHY requirement
+
+  // Check all codec configuration
+  std::map<CodecSpecificConfigurationLtv::Tag, CodecSpecificConfigurationLtv>
+      cfg_tag_map;
+  for (auto cfg : setting_cfg.codecConfiguration)
+    cfg_tag_map[cfg.getTag()] = cfg;
+
+  for (auto requirement_cfg : requirement_cfg.codecConfiguration) {
+    // Directly compare CodecSpecificConfigurationLtv
+    auto cfg = cfg_tag_map.find(requirement_cfg.getTag());
+    if (cfg == cfg_tag_map.end()) return false;
+
+    if (cfg->second != requirement_cfg) return false;
+  }
+  // Ignore vendor configuration and metadata requirement
+
+  return true;
+}
+
+bool LeAudioOffloadAudioProvider::isMatchedBISConfiguration(
+    LeAudioBisConfiguration bis_cfg,
+    const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities) {
+  if (!isMatchedValidCodec(bis_cfg.codecId, capabilities.codecId)) return false;
+  if (!isCapabilitiesMatchedCodecConfiguration(
+          bis_cfg.codecConfiguration, capabilities.codecSpecificCapabilities))
+    return false;
+  return true;
+}
+
+void LeAudioOffloadAudioProvider::filterCapabilitiesAseDirectionConfiguration(
+    std::vector<std::optional<AseDirectionConfiguration>>&
+        direction_configurations,
+    const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities,
+    std::vector<std::optional<AseDirectionConfiguration>>&
+        valid_direction_configurations) {
+  for (auto direction_configuration : direction_configurations) {
+    if (!direction_configuration.has_value()) continue;
+    if (!direction_configuration.value().aseConfiguration.codecId.has_value())
+      continue;
+    if (!isMatchedValidCodec(
+            direction_configuration.value().aseConfiguration.codecId.value(),
+            capabilities.codecId))
+      continue;
+    // Check matching for codec configuration <=> codec capabilities
+    if (!isCapabilitiesMatchedCodecConfiguration(
+            direction_configuration.value().aseConfiguration.codecConfiguration,
+            capabilities.codecSpecificCapabilities))
+      continue;
+    valid_direction_configurations.push_back(direction_configuration);
+  }
+}
+
+void LeAudioOffloadAudioProvider::filterRequirementAseDirectionConfiguration(
+    std::vector<std::optional<AseDirectionConfiguration>>&
+        direction_configurations,
+    const std::optional<std::vector<std::optional<AseDirectionRequirement>>>&
+        requirements,
+    std::vector<std::optional<AseDirectionConfiguration>>&
+        valid_direction_configurations) {
+  for (auto direction_configuration : direction_configurations) {
+    if (!requirements.has_value()) {
+      // If there's no requirement, all are valid
+      valid_direction_configurations.push_back(direction_configuration);
+      continue;
+    }
+    if (!direction_configuration.has_value()) continue;
+
+    for (auto& requirement : requirements.value()) {
+      if (!requirement.has_value()) continue;
+      if (!isMatchedAseConfiguration(
+              direction_configuration.value().aseConfiguration,
+              requirement.value().aseConfiguration))
+        continue;
+      // Valid if match any requirement.
+      valid_direction_configurations.push_back(direction_configuration);
+      break;
+    }
+  }
+}
+
+/* Get a new LeAudioAseConfigurationSetting by matching a setting with a
+ * capabilities. The new setting will have a filtered list of
+ * AseDirectionConfiguration that matched the capabilities */
+std::optional<LeAudioAseConfigurationSetting>
+LeAudioOffloadAudioProvider::getCapabilitiesMatchedAseConfigurationSettings(
+    IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
+    const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities,
+    uint8_t direction) {
+  // Try to match context in metadata.
+  if (!isCapabilitiesMatchedContext(setting.audioContext, capabilities))
+    return std::nullopt;
+
+  // Get a list of all matched AseDirectionConfiguration
+  // for the input direction
+  std::vector<std::optional<AseDirectionConfiguration>>*
+      direction_configuration = nullptr;
+  if (direction == kLeAudioDirectionSink) {
+    if (!setting.sinkAseConfiguration.has_value()) return std::nullopt;
+    direction_configuration = &setting.sinkAseConfiguration.value();
+  } else {
+    if (!setting.sourceAseConfiguration.has_value()) return std::nullopt;
+    direction_configuration = &setting.sourceAseConfiguration.value();
+  }
+  std::vector<std::optional<AseDirectionConfiguration>>
+      valid_direction_configuration;
+  filterCapabilitiesAseDirectionConfiguration(
+      *direction_configuration, capabilities, valid_direction_configuration);
+  if (valid_direction_configuration.empty()) return std::nullopt;
+
+  // Create a new LeAudioAseConfigurationSetting and return
+  LeAudioAseConfigurationSetting filtered_setting;
+  filtered_setting.audioContext = setting.audioContext;
+  filtered_setting.packing = setting.packing;
+  if (direction == kLeAudioDirectionSink) {
+    filtered_setting.sinkAseConfiguration = valid_direction_configuration;
+  } else {
+    filtered_setting.sourceAseConfiguration = valid_direction_configuration;
+  }
+  filtered_setting.flags = setting.flags;
+
+  return filtered_setting;
+}
+
+/* Get a new LeAudioAseConfigurationSetting by matching a setting with a
+ * requirement. The new setting will have a filtered list of
+ * AseDirectionConfiguration that matched the requirement */
+std::optional<LeAudioAseConfigurationSetting>
+LeAudioOffloadAudioProvider::getRequirementMatchedAseConfigurationSettings(
+    IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
+    const IBluetoothAudioProvider::LeAudioConfigurationRequirement&
+        requirement) {
+  // Try to match context in metadata.
+  if (setting.audioContext != requirement.audioContext) return std::nullopt;
+
+  // Check requirement for the correct direction
+  const std::optional<std::vector<std::optional<AseDirectionRequirement>>>*
+      direction_requirement;
+  std::vector<std::optional<AseDirectionConfiguration>>*
+      direction_configuration;
+  if (setting.sinkAseConfiguration.has_value()) {
+    direction_configuration = &setting.sinkAseConfiguration.value();
+    direction_requirement = &requirement.sinkAseRequirement;
+  } else {
+    direction_configuration = &setting.sourceAseConfiguration.value();
+    direction_requirement = &requirement.sourceAseRequirement;
+  }
+
+  std::vector<std::optional<AseDirectionConfiguration>>
+      valid_direction_configuration;
+  filterRequirementAseDirectionConfiguration(*direction_configuration,
+                                             *direction_requirement,
+                                             valid_direction_configuration);
+  if (valid_direction_configuration.empty()) return std::nullopt;
+
+  // Create a new LeAudioAseConfigurationSetting and return
+  LeAudioAseConfigurationSetting filtered_setting;
+  filtered_setting.audioContext = setting.audioContext;
+  filtered_setting.packing = setting.packing;
+  if (setting.sinkAseConfiguration.has_value())
+    filtered_setting.sinkAseConfiguration = valid_direction_configuration;
+  else
+    filtered_setting.sourceAseConfiguration = valid_direction_configuration;
+  filtered_setting.flags = setting.flags;
+
+  return filtered_setting;
+}
+
+ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseConfiguration(
+    const std::optional<std::vector<
+        std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
+        in_remoteSinkAudioCapabilities,
+    const std::optional<std::vector<
+        std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
+        in_remoteSourceAudioCapabilities,
+    const std::vector<IBluetoothAudioProvider::LeAudioConfigurationRequirement>&
+        in_requirements,
+    std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>*
+        _aidl_return) {
+  // Get all configuration settings
+  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
+      ase_configuration_settings =
+          BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings();
+
+  // Currently won't handle case where both sink and source capabilities
+  // are passed in. Only handle one of them.
+  const std::optional<std::vector<
+      std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>*
+      in_remoteAudioCapabilities;
+  uint8_t direction = 0;
+  if (in_remoteSinkAudioCapabilities.has_value()) {
+    direction = kLeAudioDirectionSink;
+    in_remoteAudioCapabilities = &in_remoteSinkAudioCapabilities;
+  } else {
+    direction = kLeAudioDirectionSource;
+    in_remoteAudioCapabilities = &in_remoteSourceAudioCapabilities;
+  }
+
+  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
+      capability_matched_ase_configuration_settings;
+  // Matching with remote capabilities
+  for (auto& setting : ase_configuration_settings) {
+    for (auto& capability : in_remoteAudioCapabilities->value()) {
+      if (!capability.has_value()) continue;
+      auto filtered_ase_configuration_setting =
+          getCapabilitiesMatchedAseConfigurationSettings(
+              setting, capability.value(), direction);
+      if (filtered_ase_configuration_setting.has_value()) {
+        capability_matched_ase_configuration_settings.push_back(
+            filtered_ase_configuration_setting.value());
+      }
+    }
+  }
+
+  // Matching with requirements
+  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting> result;
+  for (auto& setting : capability_matched_ase_configuration_settings) {
+    for (auto& requirement : in_requirements) {
+      auto filtered_ase_configuration_setting =
+          getRequirementMatchedAseConfigurationSettings(setting, requirement);
+      if (filtered_ase_configuration_setting.has_value()) {
+        result.push_back(filtered_ase_configuration_setting.value());
+      }
+    }
+  }
+
+  *_aidl_return = result;
+  return ndk::ScopedAStatus::ok();
+};
+
+bool LeAudioOffloadAudioProvider::isMatchedQosRequirement(
+    LeAudioAseQosConfiguration setting_qos,
+    AseQosDirectionRequirement requirement_qos) {
+  if (setting_qos.retransmissionNum !=
+      requirement_qos.preferredRetransmissionNum)
+    return false;
+  if (setting_qos.maxTransportLatencyMs > requirement_qos.maxTransportLatencyMs)
+    return false;
+  // Ignore other parameters, as they are not populated in the setting_qos
+  return true;
+}
+
+ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseQosConfiguration(
+    const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
+        in_qosRequirement,
+    IBluetoothAudioProvider::LeAudioAseQosConfigurationPair* _aidl_return) {
+  IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
+  // Get all configuration settings
+  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
+      ase_configuration_settings =
+          BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings();
+
+  // Direction QoS matching
+  // Only handle one direction input case
+  uint8_t direction = 0;
+  std::optional<AseQosDirectionRequirement> direction_qos_requirement =
+      std::nullopt;
+  if (in_qosRequirement.sinkAseQosRequirement.has_value()) {
+    direction_qos_requirement = in_qosRequirement.sinkAseQosRequirement.value();
+    direction = kLeAudioDirectionSink;
+  } else if (in_qosRequirement.sourceAseQosRequirement.has_value()) {
+    direction_qos_requirement =
+        in_qosRequirement.sourceAseQosRequirement.value();
+    direction = kLeAudioDirectionSource;
+  }
+
+  for (auto& setting : ase_configuration_settings) {
+    // Context matching
+    if (setting.audioContext != in_qosRequirement.contextType) continue;
+
+    // Match configuration flags
+    // Currently configuration flags are not populated, ignore.
+
+    // Get a list of all matched AseDirectionConfiguration
+    // for the input direction
+    std::vector<std::optional<AseDirectionConfiguration>>*
+        direction_configuration = nullptr;
+    if (direction == kLeAudioDirectionSink) {
+      if (!setting.sinkAseConfiguration.has_value()) continue;
+      direction_configuration = &setting.sinkAseConfiguration.value();
+    } else {
+      if (!setting.sourceAseConfiguration.has_value()) continue;
+      direction_configuration = &setting.sourceAseConfiguration.value();
+    }
+
+    for (auto cfg : *direction_configuration) {
+      if (!cfg.has_value()) continue;
+      // If no requirement, return the first QoS
+      if (!direction_qos_requirement.has_value()) {
+        result.sinkQosConfiguration = cfg.value().qosConfiguration;
+        result.sourceQosConfiguration = cfg.value().qosConfiguration;
+        *_aidl_return = result;
+        return ndk::ScopedAStatus::ok();
+      }
+
+      // If has requirement, return the first matched QoS
+      // Try to match the ASE configuration
+      // and QoS with requirement
+      if (!cfg.value().qosConfiguration.has_value()) continue;
+      if (isMatchedAseConfiguration(
+              cfg.value().aseConfiguration,
+              direction_qos_requirement.value().aseConfiguration) &&
+          isMatchedQosRequirement(cfg.value().qosConfiguration.value(),
+                                  direction_qos_requirement.value())) {
+        if (direction == kLeAudioDirectionSink)
+          result.sinkQosConfiguration = cfg.value().qosConfiguration;
+        else
+          result.sourceQosConfiguration = cfg.value().qosConfiguration;
+        *_aidl_return = result;
+        return ndk::ScopedAStatus::ok();
+      }
+    }
+  }
+
+  // No match, return empty QoS
+  *_aidl_return = result;
+  return ndk::ScopedAStatus::ok();
+};
+
+ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSinkAseMetadataChanged(
+    IBluetoothAudioProvider::AseState in_state, int32_t /*in_cigId*/,
+    int32_t /*in_cisId*/,
+    const std::optional<std::vector<std::optional<MetadataLtv>>>& in_metadata) {
+  (void)in_state;
+  (void)in_metadata;
+  return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
+ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSourceAseMetadataChanged(
+    IBluetoothAudioProvider::AseState in_state, int32_t /*in_cigId*/,
+    int32_t /*in_cisId*/,
+    const std::optional<std::vector<std::optional<MetadataLtv>>>& in_metadata) {
+  (void)in_state;
+  (void)in_metadata;
+  return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
+void LeAudioOffloadAudioProvider::getBroadcastSettings() {
+  if (!broadcast_settings.empty()) return;
+
+  LOG(INFO) << __func__ << ": Loading broadcast settings from provider info";
+
+  std::vector<CodecInfo> db_codec_info =
+      BluetoothAudioCodecs::GetLeAudioOffloadCodecInfo(
+          SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
+  broadcast_settings.clear();
+  CodecSpecificConfigurationLtv::AudioChannelAllocation default_allocation;
+  default_allocation.bitmask =
+      CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_CENTER;
+
+  for (auto& codec_info : db_codec_info) {
+    if (codec_info.transport.getTag() != CodecInfo::Transport::leAudio)
+      continue;
+    auto& transport = codec_info.transport.get<CodecInfo::Transport::leAudio>();
+    LeAudioBroadcastConfigurationSetting setting;
+    // Default setting
+    setting.numBis = 1;
+    setting.phy = {Phy::TWO_M};
+    // Populate BIS configuration info using codec_info
+    LeAudioBisConfiguration bis_cfg;
+    bis_cfg.codecId = codec_info.id;
+
+    CodecSpecificConfigurationLtv::OctetsPerCodecFrame octets;
+    octets.value = transport.bitdepth[0];
+
+    bis_cfg.codecConfiguration = {
+        sampling_freq_map[transport.samplingFrequencyHz[0]], octets,
+        frame_duration_map[transport.frameDurationUs[0]], default_allocation};
+
+    // Add information to structure
+    IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration sub_bis_cfg;
+    sub_bis_cfg.numBis = 1;
+    sub_bis_cfg.bisConfiguration = bis_cfg;
+    IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration sub_cfg;
+    sub_cfg.bisConfigurations = {sub_bis_cfg};
+    setting.subgroupsConfigurations = {sub_cfg};
+
+    broadcast_settings.push_back(setting);
+  }
+
+  LOG(INFO) << __func__
+            << ": Done loading broadcast settings from provider info";
+}
+
+/* Get a new LeAudioAseConfigurationSetting by matching a setting with a
+ * capabilities. The new setting will have a filtered list of
+ * AseDirectionConfiguration that matched the capabilities */
+std::optional<LeAudioBroadcastConfigurationSetting>
+LeAudioOffloadAudioProvider::
+    getCapabilitiesMatchedBroadcastConfigurationSettings(
+        LeAudioBroadcastConfigurationSetting& setting,
+        const IBluetoothAudioProvider::LeAudioDeviceCapabilities&
+            capabilities) {
+  std::vector<IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration>
+      filter_subgroup;
+  for (auto& sub_cfg : setting.subgroupsConfigurations) {
+    std::vector<IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration>
+        filtered_bis_cfg;
+    for (auto& bis_cfg : sub_cfg.bisConfigurations)
+      if (isMatchedBISConfiguration(bis_cfg.bisConfiguration, capabilities)) {
+        filtered_bis_cfg.push_back(bis_cfg);
+      }
+    if (!filtered_bis_cfg.empty()) {
+      IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration
+          subgroup_cfg;
+      subgroup_cfg.bisConfigurations = filtered_bis_cfg;
+      filter_subgroup.push_back(subgroup_cfg);
+    }
+  }
+  if (filter_subgroup.empty()) return std::nullopt;
+
+  // Create a new LeAudioAseConfigurationSetting and return
+  LeAudioBroadcastConfigurationSetting filtered_setting(setting);
+  filtered_setting.subgroupsConfigurations = filter_subgroup;
+
+  return filtered_setting;
+}
+
+ndk::ScopedAStatus
+LeAudioOffloadAudioProvider::getLeAudioBroadcastConfiguration(
+    const std::optional<std::vector<
+        std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
+        in_remoteSinkAudioCapabilities,
+    const IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement&
+        in_requirement,
+    LeAudioBroadcastConfigurationSetting* _aidl_return) {
+  getBroadcastSettings();
+  _aidl_return = nullptr;
+
+  // Match and filter capability
+  std::vector<LeAudioBroadcastConfigurationSetting> filtered_settings;
+  if (!in_remoteSinkAudioCapabilities.has_value()) {
+    LOG(WARNING) << __func__ << ": Empty capability";
+    return ndk::ScopedAStatus::ok();
+  }
+  for (auto& setting : broadcast_settings) {
+    for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
+      if (!capability.has_value()) continue;
+      auto filtered_setting =
+          getCapabilitiesMatchedBroadcastConfigurationSettings(
+              setting, capability.value());
+      if (filtered_setting.has_value())
+        filtered_settings.push_back(filtered_setting.value());
+    }
+  }
+
+  if (filtered_settings.empty()) {
+    LOG(WARNING) << __func__ << ": Cannot match any remote capability";
+    return ndk::ScopedAStatus::ok();
+  }
+
+  // Match and return the first matched requirement
+  if (in_requirement.subgroupConfigurationRequirements.empty()) {
+    LOG(INFO) << __func__ << ": Empty requirement";
+    *_aidl_return = filtered_settings[0];
+    return ndk::ScopedAStatus::ok();
+  }
+
+  for (auto& setting : filtered_settings) {
+    // Further filter out bis configuration
+    LeAudioBroadcastConfigurationSetting filtered_setting(setting);
+    filtered_setting.subgroupsConfigurations.clear();
+    for (auto& sub_cfg : setting.subgroupsConfigurations) {
+      bool isMatched = false;
+      for (auto& sub_req : in_requirement.subgroupConfigurationRequirements) {
+        // Matching number of BIS
+        if (sub_req.bisNumPerSubgroup != sub_cfg.bisConfigurations.size())
+          continue;
+        // Currently will ignore quality and context hint.
+        isMatched = true;
+        break;
+      }
+      if (isMatched)
+        filtered_setting.subgroupsConfigurations.push_back(sub_cfg);
+    }
+    // Return the first match
+    if (!filtered_setting.subgroupsConfigurations.empty()) {
+      LOG(INFO) << __func__ << ": Matched requirement";
+      *_aidl_return = filtered_setting;
+      return ndk::ScopedAStatus::ok();
+    }
+  }
+
+  LOG(WARNING) << __func__ << ": Cannot match any requirement";
+  return ndk::ScopedAStatus::ok();
+};
 
 }  // namespace audio
 }  // namespace bluetooth
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
index 614c794..2785e7f 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
@@ -16,7 +16,12 @@
 
 #pragma once
 
+#include <map>
+
 #include "BluetoothAudioProvider.h"
+#include "aidl/android/hardware/bluetooth/audio/LeAudioAseConfiguration.h"
+#include "aidl/android/hardware/bluetooth/audio/MetadataLtv.h"
+#include "aidl/android/hardware/bluetooth/audio/SessionType.h"
 
 namespace aidl {
 namespace android {
@@ -24,6 +29,19 @@
 namespace bluetooth {
 namespace audio {
 
+using LeAudioAseConfigurationSetting =
+    IBluetoothAudioProvider::LeAudioAseConfigurationSetting;
+using AseDirectionRequirement = IBluetoothAudioProvider::
+    LeAudioConfigurationRequirement::AseDirectionRequirement;
+using AseDirectionConfiguration = IBluetoothAudioProvider::
+    LeAudioAseConfigurationSetting::AseDirectionConfiguration;
+using AseQosDirectionRequirement = IBluetoothAudioProvider::
+    LeAudioAseQosConfigurationRequirement::AseQosDirectionRequirement;
+using LeAudioAseQosConfiguration =
+    IBluetoothAudioProvider::LeAudioAseQosConfiguration;
+using LeAudioBroadcastConfigurationSetting =
+    IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting;
+
 class LeAudioOffloadAudioProvider : public BluetoothAudioProvider {
  public:
   LeAudioOffloadAudioProvider();
@@ -33,11 +51,112 @@
   ndk::ScopedAStatus startSession(
       const std::shared_ptr<IBluetoothAudioPort>& host_if,
       const AudioConfiguration& audio_config,
-      const std::vector<LatencyMode>& latency_modes,
-      DataMQDesc* _aidl_return);
+      const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return);
+  ndk::ScopedAStatus setCodecPriority(const CodecId& in_codecId,
+                                      int32_t in_priority) override;
+  ndk::ScopedAStatus getLeAudioAseConfiguration(
+      const std::optional<std::vector<
+          std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
+          in_remoteSinkAudioCapabilities,
+      const std::optional<std::vector<
+          std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
+          in_remoteSourceAudioCapabilities,
+      const std::vector<
+          IBluetoothAudioProvider::LeAudioConfigurationRequirement>&
+          in_requirements,
+      std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>*
+          _aidl_return) override;
+  ndk::ScopedAStatus getLeAudioAseQosConfiguration(
+      const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
+          in_qosRequirement,
+      IBluetoothAudioProvider::LeAudioAseQosConfigurationPair* _aidl_return)
+      override;
+  ndk::ScopedAStatus onSourceAseMetadataChanged(
+      IBluetoothAudioProvider::AseState in_state, int32_t in_cigId,
+      int32_t in_cisId,
+      const std::optional<std::vector<std::optional<MetadataLtv>>>& in_metadata)
+      override;
+  ndk::ScopedAStatus onSinkAseMetadataChanged(
+      IBluetoothAudioProvider::AseState in_state, int32_t in_cigId,
+      int32_t in_cisId,
+      const std::optional<std::vector<std::optional<MetadataLtv>>>& in_metadata)
+      override;
+  ndk::ScopedAStatus getLeAudioBroadcastConfiguration(
+      const std::optional<std::vector<
+          std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
+          in_remoteSinkAudioCapabilities,
+      const IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement&
+          in_requirement,
+      LeAudioBroadcastConfigurationSetting* _aidl_return) override;
 
  private:
   ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
+  std::map<CodecId, uint32_t> codec_priority_map_;
+  std::vector<LeAudioBroadcastConfigurationSetting> broadcast_settings;
+
+  // Private matching function definitions
+  bool isMatchedValidCodec(CodecId cfg_codec, CodecId req_codec);
+  bool isCapabilitiesMatchedContext(
+      AudioContext setting_context,
+      const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities);
+  bool isMatchedSamplingFreq(
+      CodecSpecificConfigurationLtv::SamplingFrequency& cfg_freq,
+      CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies&
+          capability_freq);
+  bool isMatchedFrameDuration(
+      CodecSpecificConfigurationLtv::FrameDuration& cfg_fduration,
+      CodecSpecificCapabilitiesLtv::SupportedFrameDurations&
+          capability_fduration);
+  bool isMatchedAudioChannel(
+      CodecSpecificConfigurationLtv::AudioChannelAllocation& cfg_channel,
+      CodecSpecificCapabilitiesLtv::SupportedAudioChannelCounts&
+          capability_channel);
+  bool isMatchedCodecFramesPerSDU(
+      CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU& cfg_frame_sdu,
+      CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU&
+          capability_frame_sdu);
+  bool isMatchedOctetsPerCodecFrame(
+      CodecSpecificConfigurationLtv::OctetsPerCodecFrame& cfg_octets,
+      CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame&
+          capability_octets);
+  bool isCapabilitiesMatchedCodecConfiguration(
+      std::vector<CodecSpecificConfigurationLtv>& codec_cfg,
+      std::vector<CodecSpecificCapabilitiesLtv> codec_capabilities);
+  bool isMatchedAseConfiguration(LeAudioAseConfiguration setting_cfg,
+                                 LeAudioAseConfiguration requirement_cfg);
+  bool isMatchedBISConfiguration(
+      LeAudioBisConfiguration bis_cfg,
+      const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities);
+  void filterCapabilitiesAseDirectionConfiguration(
+      std::vector<std::optional<AseDirectionConfiguration>>&
+          direction_configurations,
+      const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities,
+      std::vector<std::optional<AseDirectionConfiguration>>&
+          valid_direction_configurations);
+  void filterRequirementAseDirectionConfiguration(
+      std::vector<std::optional<AseDirectionConfiguration>>&
+          direction_configurations,
+      const std::optional<std::vector<std::optional<AseDirectionRequirement>>>&
+          requirements,
+      std::vector<std::optional<AseDirectionConfiguration>>&
+          valid_direction_configurations);
+  std::optional<LeAudioAseConfigurationSetting>
+  getCapabilitiesMatchedAseConfigurationSettings(
+      IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
+      const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities,
+      uint8_t direction);
+  std::optional<LeAudioAseConfigurationSetting>
+  getRequirementMatchedAseConfigurationSettings(
+      IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
+      const IBluetoothAudioProvider::LeAudioConfigurationRequirement&
+          requirement);
+  bool isMatchedQosRequirement(LeAudioAseQosConfiguration setting_qos,
+                               AseQosDirectionRequirement requirement_qos);
+  std::optional<LeAudioBroadcastConfigurationSetting>
+  getCapabilitiesMatchedBroadcastConfigurationSettings(
+      LeAudioBroadcastConfigurationSetting& setting,
+      const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities);
+  void getBroadcastSettings();
 };
 
 class LeAudioOffloadOutputAudioProvider : public LeAudioOffloadAudioProvider {
diff --git a/bluetooth/audio/aidl/default/bluetooth_audio.xml b/bluetooth/audio/aidl/default/bluetooth_audio.xml
index c0bc55e..3561dd1 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>3</version>
+        <version>4</version>
         <fqname>IBluetoothAudioProviderFactory/default</fqname>
     </hal>
 </manifest>
diff --git a/bluetooth/audio/aidl/vts/Android.bp b/bluetooth/audio/aidl/vts/Android.bp
index fa85fa8..884062a 100644
--- a/bluetooth/audio/aidl/vts/Android.bp
+++ b/bluetooth/audio/aidl/vts/Android.bp
@@ -10,17 +10,17 @@
 cc_test {
     name: "VtsHalBluetoothAudioTargetTest",
     defaults: [
+        "latest_android_hardware_audio_common_ndk_static",
+        "latest_android_hardware_bluetooth_audio_ndk_static",
+        "latest_android_media_audio_common_types_ndk_static",
         "VtsHalTargetTestDefaults",
         "use_libaidlvintf_gtest_helper_static",
     ],
     tidy_timeout_srcs: ["VtsHalBluetoothAudioTargetTest.cpp"],
     srcs: ["VtsHalBluetoothAudioTargetTest.cpp"],
     static_libs: [
-        "android.hardware.audio.common-V2-ndk",
-        "android.hardware.bluetooth.audio-V3-ndk",
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
-        "android.media.audio.common.types-V2-ndk",
     ],
     shared_libs: [
         "libbase",
diff --git a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
index 858fa38..be49a74 100644
--- a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
+++ b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
@@ -33,6 +33,11 @@
 
 using aidl::android::hardware::audio::common::SinkMetadata;
 using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::hardware::bluetooth::audio::A2dpConfiguration;
+using aidl::android::hardware::bluetooth::audio::A2dpConfigurationHint;
+using aidl::android::hardware::bluetooth::audio::A2dpRemoteCapabilities;
+using aidl::android::hardware::bluetooth::audio::A2dpStatus;
+using aidl::android::hardware::bluetooth::audio::A2dpStreamConfiguration;
 using aidl::android::hardware::bluetooth::audio::AacCapabilities;
 using aidl::android::hardware::bluetooth::audio::AacConfiguration;
 using aidl::android::hardware::bluetooth::audio::AptxAdaptiveLeCapabilities;
@@ -41,12 +46,19 @@
 using aidl::android::hardware::bluetooth::audio::AptxConfiguration;
 using aidl::android::hardware::bluetooth::audio::AudioCapabilities;
 using aidl::android::hardware::bluetooth::audio::AudioConfiguration;
+using aidl::android::hardware::bluetooth::audio::AudioContext;
 using aidl::android::hardware::bluetooth::audio::BnBluetoothAudioPort;
 using aidl::android::hardware::bluetooth::audio::BroadcastCapability;
 using aidl::android::hardware::bluetooth::audio::ChannelMode;
 using aidl::android::hardware::bluetooth::audio::CodecCapabilities;
 using aidl::android::hardware::bluetooth::audio::CodecConfiguration;
+using aidl::android::hardware::bluetooth::audio::CodecId;
+using aidl::android::hardware::bluetooth::audio::CodecInfo;
+using aidl::android::hardware::bluetooth::audio::CodecParameters;
+using aidl::android::hardware::bluetooth::audio::CodecSpecificCapabilitiesLtv;
+using aidl::android::hardware::bluetooth::audio::CodecSpecificConfigurationLtv;
 using aidl::android::hardware::bluetooth::audio::CodecType;
+using aidl::android::hardware::bluetooth::audio::HfpConfiguration;
 using aidl::android::hardware::bluetooth::audio::IBluetoothAudioPort;
 using aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider;
 using aidl::android::hardware::bluetooth::audio::IBluetoothAudioProviderFactory;
@@ -55,11 +67,13 @@
 using aidl::android::hardware::bluetooth::audio::Lc3Configuration;
 using aidl::android::hardware::bluetooth::audio::LdacCapabilities;
 using aidl::android::hardware::bluetooth::audio::LdacConfiguration;
+using aidl::android::hardware::bluetooth::audio::LeAudioAseConfiguration;
 using aidl::android::hardware::bluetooth::audio::LeAudioBroadcastConfiguration;
 using aidl::android::hardware::bluetooth::audio::
     LeAudioCodecCapabilitiesSetting;
 using aidl::android::hardware::bluetooth::audio::LeAudioCodecConfiguration;
 using aidl::android::hardware::bluetooth::audio::LeAudioConfiguration;
+using aidl::android::hardware::bluetooth::audio::MetadataLtv;
 using aidl::android::hardware::bluetooth::audio::OpusCapabilities;
 using aidl::android::hardware::bluetooth::audio::OpusConfiguration;
 using aidl::android::hardware::bluetooth::audio::PcmConfiguration;
@@ -83,6 +97,21 @@
 using DataMQ = AidlMessageQueue<MqDataType, MqDataMode>;
 using DataMQDesc = MQDescriptor<MqDataType, MqDataMode>;
 
+using LeAudioAseConfigurationSetting =
+    IBluetoothAudioProvider::LeAudioAseConfigurationSetting;
+using AseDirectionRequirement = IBluetoothAudioProvider::
+    LeAudioConfigurationRequirement::AseDirectionRequirement;
+using AseDirectionConfiguration = IBluetoothAudioProvider::
+    LeAudioAseConfigurationSetting::AseDirectionConfiguration;
+using AseQosDirectionRequirement = IBluetoothAudioProvider::
+    LeAudioAseQosConfigurationRequirement::AseQosDirectionRequirement;
+using LeAudioAseQosConfiguration =
+    IBluetoothAudioProvider::LeAudioAseQosConfiguration;
+using LeAudioDeviceCapabilities =
+    IBluetoothAudioProvider::LeAudioDeviceCapabilities;
+using LeAudioConfigurationRequirement =
+    IBluetoothAudioProvider::LeAudioConfigurationRequirement;
+
 // Constants
 
 static constexpr int32_t a2dp_sample_rates[] = {0, 44100, 48000, 88200, 96000};
@@ -90,6 +119,13 @@
 static constexpr ChannelMode a2dp_channel_modes[] = {
     ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO};
 static std::vector<LatencyMode> latency_modes = {LatencyMode::FREE};
+
+// Some valid configs for HFP PCM configuration (software sessions)
+static constexpr int32_t hfp_sample_rates_[] = {8000, 16000, 32000};
+static constexpr int8_t hfp_bits_per_samples_[] = {16};
+static constexpr ChannelMode hfp_channel_modes_[] = {ChannelMode::MONO};
+static constexpr int32_t hfp_data_interval_us_[] = {7500};
+
 // Helpers
 
 template <typename T>
@@ -181,6 +217,13 @@
 
   virtual void TearDown() override { provider_factory_ = nullptr; }
 
+  void GetProviderInfoHelper(const SessionType& session_type) {
+    temp_provider_info_ = std::nullopt;
+    auto aidl_reval =
+        provider_factory_->getProviderInfo(session_type, &temp_provider_info_);
+    ASSERT_TRUE(aidl_reval.isOk());
+  }
+
   void GetProviderCapabilitiesHelper(const SessionType& session_type) {
     temp_provider_capabilities_.clear();
     auto aidl_retval = provider_factory_->getProviderCapabilities(
@@ -195,7 +238,8 @@
       case SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH:
       case SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH:
       case SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH:
-      case SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH: {
+      case SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH:
+      case SessionType::HFP_SOFTWARE_ENCODING_DATAPATH: {
         // All software paths are mandatory and must have exact 1
         // "PcmParameters"
         ASSERT_EQ(temp_provider_capabilities_.size(), 1);
@@ -256,7 +300,8 @@
                     AudioCapabilities::leAudioCapabilities);
         }
       } break;
-      case SessionType::A2DP_SOFTWARE_DECODING_DATAPATH: {
+      case SessionType::A2DP_SOFTWARE_DECODING_DATAPATH:
+      case SessionType::HFP_SOFTWARE_DECODING_DATAPATH: {
         if (!temp_provider_capabilities_.empty()) {
           ASSERT_EQ(temp_provider_capabilities_.size(), 1);
           ASSERT_EQ(temp_provider_capabilities_[0].getTag(),
@@ -296,7 +341,10 @@
                   LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
           session_type ==
               SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH ||
-          session_type == SessionType::A2DP_SOFTWARE_DECODING_DATAPATH);
+          session_type == SessionType::A2DP_SOFTWARE_DECODING_DATAPATH ||
+          session_type == SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH ||
+          session_type == SessionType::HFP_SOFTWARE_DECODING_DATAPATH ||
+          session_type == SessionType::HFP_SOFTWARE_ENCODING_DATAPATH);
       ASSERT_EQ(audio_provider_, nullptr);
     }
   }
@@ -555,6 +603,8 @@
   std::shared_ptr<IBluetoothAudioProvider> audio_provider_;
   std::shared_ptr<IBluetoothAudioPort> audio_port_;
   std::vector<AudioCapabilities> temp_provider_capabilities_;
+  std::optional<IBluetoothAudioProviderFactory::ProviderInfo>
+      temp_provider_info_;
 
   // temp storage saves the specified codec capability by
   // GetOffloadCodecCapabilityHelper()
@@ -573,6 +623,8 @@
       SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
       SessionType::A2DP_SOFTWARE_DECODING_DATAPATH,
       SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+      SessionType::HFP_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::HFP_SOFTWARE_DECODING_DATAPATH,
   };
 };
 
@@ -598,6 +650,794 @@
 }
 
 /**
+ * Test that getProviderInfo, when implemented,
+ * returns empty information for session types for
+ * software data paths.
+ */
+TEST_P(BluetoothAudioProviderFactoryAidl, getProviderInfo_invalidSessionTypes) {
+  static constexpr SessionType kInvalidSessionTypes[]{
+      SessionType::UNKNOWN,
+      SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH,
+      SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::A2DP_SOFTWARE_DECODING_DATAPATH,
+  };
+
+  for (auto session_type : kInvalidSessionTypes) {
+    std::optional<IBluetoothAudioProviderFactory::ProviderInfo> provider_info =
+        std::nullopt;
+    auto aidl_retval =
+        provider_factory_->getProviderInfo(session_type, &provider_info);
+    if (!aidl_retval.isOk()) {
+      continue;
+    }
+
+    // If getProviderInfo is supported, the provider info
+    // must be empty for software session types.
+    ASSERT_FALSE(provider_info.has_value());
+  }
+}
+
+/**
+ * Test that getProviderInfo, when implemented,
+ * returns valid information for session types for
+ * a2dp hardware data paths.
+ */
+TEST_P(BluetoothAudioProviderFactoryAidl, getProviderInfo_a2dpSessionTypes) {
+  static constexpr SessionType kA2dpSessionTypes[]{
+      SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+      SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+  };
+
+  for (auto session_type : kA2dpSessionTypes) {
+    std::optional<IBluetoothAudioProviderFactory::ProviderInfo> provider_info =
+        std::nullopt;
+    auto aidl_retval =
+        provider_factory_->getProviderInfo(session_type, &provider_info);
+    if (!aidl_retval.isOk() || !provider_info.has_value()) {
+      continue;
+    }
+
+    for (auto const& codec_info : provider_info->codecInfos) {
+      // The codec id must not be core.
+      ASSERT_NE(codec_info.id.getTag(), CodecId::core);
+      // The codec info must contain the information
+      // for a2dp transport.
+      ASSERT_EQ(codec_info.transport.getTag(), CodecInfo::Transport::a2dp);
+    }
+  }
+}
+
+/**
+ * Test that getProviderInfo, when implemented,
+ * returns valid information for session types for
+ * le audio hardware data paths.
+ */
+TEST_P(BluetoothAudioProviderFactoryAidl, getProviderInfo_leAudioSessionTypes) {
+  static constexpr SessionType kLeAudioSessionTypes[]{
+      SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+      SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+  };
+
+  for (auto session_type : kLeAudioSessionTypes) {
+    std::optional<IBluetoothAudioProviderFactory::ProviderInfo> provider_info =
+        std::nullopt;
+    auto aidl_retval =
+        provider_factory_->getProviderInfo(session_type, &provider_info);
+    if (!aidl_retval.isOk() || !provider_info.has_value()) {
+      continue;
+    }
+
+    for (auto const& codec_info : provider_info->codecInfos) {
+      // The codec id must not be a2dp.
+      ASSERT_NE(codec_info.id.getTag(), CodecId::a2dp);
+      // The codec info must contain the information
+      // for le audio transport.
+      // ASSERT_EQ(codec_info.transport.getTag(),
+      // CodecInfo::Transport::le_audio);
+    }
+  }
+}
+
+class BluetoothAudioProviderAidl : public BluetoothAudioProviderFactoryAidl {
+ protected:
+  std::optional<IBluetoothAudioProviderFactory::ProviderInfo>
+      a2dp_encoding_provider_info_{};
+  std::optional<IBluetoothAudioProviderFactory::ProviderInfo>
+      a2dp_decoding_provider_info_{};
+  std::shared_ptr<IBluetoothAudioProvider> a2dp_encoding_provider_{nullptr};
+  std::shared_ptr<IBluetoothAudioProvider> a2dp_decoding_provider_{nullptr};
+
+ public:
+  void SetUp() override {
+    BluetoothAudioProviderFactoryAidl::SetUp();
+    audio_port_ = ndk::SharedRefBase::make<BluetoothAudioPort>();
+
+    (void)provider_factory_->getProviderInfo(
+        SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+        &a2dp_encoding_provider_info_);
+
+    (void)provider_factory_->getProviderInfo(
+        SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+        &a2dp_decoding_provider_info_);
+
+    (void)provider_factory_->openProvider(
+        SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+        &a2dp_encoding_provider_);
+
+    (void)provider_factory_->openProvider(
+        SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+        &a2dp_decoding_provider_);
+  }
+};
+
+/**
+ * Calling parseA2dpConfiguration on a session of a different type than
+ * A2DP_HARDWARE_OFFLOAD_(ENCODING|DECODING)_DATAPATH must fail.
+ */
+TEST_P(BluetoothAudioProviderAidl, parseA2dpConfiguration_invalidSessionType) {
+  static constexpr SessionType kInvalidSessionTypes[] = {
+      SessionType::UNKNOWN,
+      SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH,
+      SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+      SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+      SessionType::A2DP_SOFTWARE_DECODING_DATAPATH,
+  };
+
+  for (auto session_type : kInvalidSessionTypes) {
+    // Open a BluetoothAudioProvider instance of the selected session type.
+    // Skip validation if the provider cannot be opened.
+    std::shared_ptr<IBluetoothAudioProvider> provider{nullptr};
+    (void)provider_factory_->openProvider(session_type, &provider);
+    if (provider == nullptr) {
+      continue;
+    }
+
+    // parseA2dpConfiguration must fail without returning an A2dpStatus.
+    CodecId codec_id(CodecId::A2dp::SBC);
+    CodecParameters codec_parameters;
+    A2dpStatus a2dp_status = A2dpStatus::OK;
+    auto aidl_retval = provider->parseA2dpConfiguration(
+        codec_id, std::vector<uint8_t>{}, &codec_parameters, &a2dp_status);
+    EXPECT_FALSE(aidl_retval.isOk());
+  }
+}
+
+/**
+ * Calling parseA2dpConfiguration with an unknown codec must fail
+ * with the A2dpStatus code INVALID_CODEC_TYPE or NOT_SUPPORTED_CODEC_TYPE.
+ */
+TEST_P(BluetoothAudioProviderAidl,
+       parseA2dpConfiguration_unsupportedCodecType) {
+  CodecId unsupported_core_id(CodecId::Core::CVSD);
+  CodecId unsupported_vendor_id(
+      CodecId::Vendor(0xFCB1, 0x42));  // Google Codec #42
+
+  for (auto& provider : {a2dp_encoding_provider_, a2dp_decoding_provider_}) {
+    if (provider == nullptr) {
+      continue;
+    }
+
+    CodecParameters codec_parameters;
+    A2dpStatus a2dp_status = A2dpStatus::OK;
+    ::ndk::ScopedAStatus aidl_retval;
+
+    // Test with two invalid codec identifiers: vendor or core.
+    aidl_retval = provider->parseA2dpConfiguration(
+        unsupported_core_id, std::vector<uint8_t>{}, &codec_parameters,
+        &a2dp_status);
+    EXPECT_TRUE(!aidl_retval.isOk() ||
+                a2dp_status == A2dpStatus::NOT_SUPPORTED_CODEC_TYPE);
+
+    aidl_retval = provider->parseA2dpConfiguration(
+        unsupported_vendor_id, std::vector<uint8_t>{}, &codec_parameters,
+        &a2dp_status);
+    EXPECT_TRUE(!aidl_retval.isOk() ||
+                a2dp_status == A2dpStatus::NOT_SUPPORTED_CODEC_TYPE);
+  }
+}
+
+/**
+ * Calling parseA2dpConfiguration with a known codec and invalid configuration
+ * must fail with an A2dpStatus code different from INVALID_CODEC_TYPE or
+ * NOT_SUPPORTED_CODEC_TYPE.
+ */
+TEST_P(BluetoothAudioProviderAidl,
+       parseA2dpConfiguration_invalidConfiguration) {
+  for (auto& [provider, provider_info] :
+       {std::pair(a2dp_encoding_provider_, a2dp_encoding_provider_info_),
+        std::pair(a2dp_decoding_provider_, a2dp_decoding_provider_info_)}) {
+    if (provider == nullptr || !provider_info.has_value() ||
+        provider_info->codecInfos.empty()) {
+      continue;
+    }
+
+    CodecParameters codec_parameters;
+    A2dpStatus a2dp_status = A2dpStatus::OK;
+    ::ndk::ScopedAStatus aidl_retval;
+
+    // Test with the first available codec in the provider info for testing.
+    // The test runs with an empty parameters array, anything more specific
+    // would need understanding the codec.
+    aidl_retval = provider->parseA2dpConfiguration(
+        provider_info->codecInfos[0].id, std::vector<uint8_t>{},
+        &codec_parameters, &a2dp_status);
+    ASSERT_TRUE(aidl_retval.isOk());
+    EXPECT_TRUE(a2dp_status != A2dpStatus::OK &&
+                a2dp_status != A2dpStatus::NOT_SUPPORTED_CODEC_TYPE &&
+                a2dp_status != A2dpStatus::INVALID_CODEC_TYPE);
+  }
+}
+
+/**
+ * Calling parseA2dpConfiguration with a known codec and valid parameters
+ * must return with A2dpStatus OK.
+ */
+TEST_P(BluetoothAudioProviderAidl, parseA2dpConfiguration_valid) {
+  for (auto& [provider, provider_info] :
+       {std::pair(a2dp_encoding_provider_, a2dp_encoding_provider_info_),
+        std::pair(a2dp_decoding_provider_, a2dp_decoding_provider_info_)}) {
+    if (provider == nullptr || !provider_info.has_value() ||
+        provider_info->codecInfos.empty()) {
+      continue;
+    }
+
+    CodecParameters codec_parameters;
+    A2dpStatus a2dp_status = A2dpStatus::OK;
+    ::ndk::ScopedAStatus aidl_retval;
+
+    // Test with the first available codec in the provider info for testing.
+    // To get a valid configuration (the capabilities array in the provider
+    // info is not a selection), getA2dpConfiguration is used with the
+    // selected codec parameters as input.
+    auto const& codec_info = provider_info->codecInfos[0];
+    auto transport = codec_info.transport.get<CodecInfo::Transport::a2dp>();
+    A2dpRemoteCapabilities remote_capabilities(/*seid*/ 0, codec_info.id,
+                                               transport.capabilities);
+    std::optional<A2dpConfiguration> configuration;
+    aidl_retval = provider->getA2dpConfiguration(
+        std::vector<A2dpRemoteCapabilities>{remote_capabilities},
+        A2dpConfigurationHint(), &configuration);
+    ASSERT_TRUE(aidl_retval.isOk());
+    ASSERT_TRUE(configuration.has_value());
+
+    aidl_retval = provider->parseA2dpConfiguration(
+        configuration->id, configuration->configuration, &codec_parameters,
+        &a2dp_status);
+    ASSERT_TRUE(aidl_retval.isOk());
+    EXPECT_TRUE(a2dp_status == A2dpStatus::OK);
+    EXPECT_EQ(codec_parameters, configuration->parameters);
+  }
+}
+
+/**
+ * Calling getA2dpConfiguration on a session of a different type than
+ * A2DP_HARDWARE_OFFLOAD_(ENCODING|DECODING)_DATAPATH must fail.
+ */
+TEST_P(BluetoothAudioProviderAidl, getA2dpConfiguration_invalidSessionType) {
+  static constexpr SessionType kInvalidSessionTypes[] = {
+      SessionType::UNKNOWN,
+      SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH,
+      SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+      SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+      SessionType::A2DP_SOFTWARE_DECODING_DATAPATH,
+  };
+
+  for (auto session_type : kInvalidSessionTypes) {
+    // Open a BluetoothAudioProvider instance of the selected session type.
+    // Skip validation if the provider cannot be opened.
+    std::shared_ptr<IBluetoothAudioProvider> provider{nullptr};
+    auto aidl_retval = provider_factory_->openProvider(session_type, &provider);
+    if (provider == nullptr) {
+      continue;
+    }
+
+    // getA2dpConfiguration must fail without returning a configuration.
+    std::optional<A2dpConfiguration> configuration;
+    aidl_retval =
+        provider->getA2dpConfiguration(std::vector<A2dpRemoteCapabilities>{},
+                                       A2dpConfigurationHint(), &configuration);
+    EXPECT_FALSE(aidl_retval.isOk());
+  }
+}
+
+/**
+ * Calling getA2dpConfiguration with empty or unknown remote capabilities
+ * must return an empty configuration.
+ */
+TEST_P(BluetoothAudioProviderAidl,
+       getA2dpConfiguration_unknownRemoteCapabilities) {
+  for (auto& [provider, provider_info] :
+       {std::pair(a2dp_encoding_provider_, a2dp_encoding_provider_info_),
+        std::pair(a2dp_decoding_provider_, a2dp_decoding_provider_info_)}) {
+    if (provider == nullptr || !provider_info.has_value() ||
+        provider_info->codecInfos.empty()) {
+      continue;
+    }
+
+    std::optional<A2dpConfiguration> configuration;
+    ::ndk::ScopedAStatus aidl_retval;
+
+    // Test with empty remote capabilities.
+    aidl_retval =
+        provider->getA2dpConfiguration(std::vector<A2dpRemoteCapabilities>{},
+                                       A2dpConfigurationHint(), &configuration);
+    ASSERT_TRUE(aidl_retval.isOk());
+    EXPECT_FALSE(configuration.has_value());
+
+    // Test with unknown remote capabilities.
+    A2dpRemoteCapabilities unknown_core_remote_capabilities(
+        /*seid*/ 0, CodecId::Core::CVSD, std::vector<uint8_t>{1, 2, 3});
+    A2dpRemoteCapabilities unknown_vendor_remote_capabilities(
+        /*seid*/ 1,
+        /* Google Codec #42 */ CodecId::Vendor(0xFCB1, 0x42),
+        std::vector<uint8_t>{1, 2, 3});
+    aidl_retval = provider->getA2dpConfiguration(
+        std::vector<A2dpRemoteCapabilities>{
+            unknown_core_remote_capabilities,
+            unknown_vendor_remote_capabilities,
+        },
+        A2dpConfigurationHint(), &configuration);
+    ASSERT_TRUE(aidl_retval.isOk());
+    EXPECT_FALSE(configuration.has_value());
+  }
+}
+
+/**
+ * Calling getA2dpConfiguration with invalid remote capabilities
+ * must return an empty configuration.
+ */
+TEST_P(BluetoothAudioProviderAidl,
+       getA2dpConfiguration_invalidRemoteCapabilities) {
+  for (auto& [provider, provider_info] :
+       {std::pair(a2dp_encoding_provider_, a2dp_encoding_provider_info_),
+        std::pair(a2dp_decoding_provider_, a2dp_decoding_provider_info_)}) {
+    if (provider == nullptr || !provider_info.has_value() ||
+        provider_info->codecInfos.empty()) {
+      continue;
+    }
+
+    std::optional<A2dpConfiguration> configuration;
+    ::ndk::ScopedAStatus aidl_retval;
+
+    // Use the first available codec in the provider info for testing.
+    // The capabilities are modified to make them invalid.
+    auto const& codec_info = provider_info->codecInfos[0];
+    auto transport = codec_info.transport.get<CodecInfo::Transport::a2dp>();
+    std::vector<uint8_t> invalid_capabilities = transport.capabilities;
+    invalid_capabilities.push_back(0x42);  // adding bytes should be invalid.
+    aidl_retval = provider->getA2dpConfiguration(
+        std::vector<A2dpRemoteCapabilities>{
+            A2dpRemoteCapabilities(/*seid*/ 0, codec_info.id,
+                                   std::vector<uint8_t>()),
+            A2dpRemoteCapabilities(/*seid*/ 1, codec_info.id,
+                                   invalid_capabilities),
+        },
+        A2dpConfigurationHint(), &configuration);
+    ASSERT_TRUE(aidl_retval.isOk());
+    EXPECT_FALSE(configuration.has_value());
+  }
+}
+
+/**
+ * Calling getA2dpConfiguration with valid remote capabilities
+ * must return a valid configuration. The selected parameters must
+ * be contained in the original capabilities. The returned configuration
+ * must match the returned parameters. The returned SEID must match the
+ * input SEID.
+ */
+TEST_P(BluetoothAudioProviderAidl,
+       getA2dpConfiguration_validRemoteCapabilities) {
+  for (auto& [provider, provider_info] :
+       {std::pair(a2dp_encoding_provider_, a2dp_encoding_provider_info_),
+        std::pair(a2dp_decoding_provider_, a2dp_decoding_provider_info_)}) {
+    if (provider == nullptr || !provider_info.has_value() ||
+        provider_info->codecInfos.empty()) {
+      continue;
+    }
+
+    // Test with all available codecs in the provider info.
+    for (auto const& codec_info : provider_info->codecInfos) {
+      auto a2dp_info = codec_info.transport.get<CodecInfo::Transport::a2dp>();
+      std::optional<A2dpConfiguration> configuration{};
+      ::ndk::ScopedAStatus aidl_retval;
+
+      aidl_retval = provider->getA2dpConfiguration(
+          std::vector<A2dpRemoteCapabilities>{
+              A2dpRemoteCapabilities(/*seid*/ 42, codec_info.id,
+                                     a2dp_info.capabilities),
+          },
+          A2dpConfigurationHint(), &configuration);
+
+      ASSERT_TRUE(aidl_retval.isOk());
+      ASSERT_TRUE(configuration.has_value());
+
+      // Returned configuration must have the same codec id
+      // as the remote capability.
+      EXPECT_EQ(configuration->id, codec_info.id);
+
+      // Returned configuration must have the same SEID
+      // as the remote capability.
+      EXPECT_EQ(configuration->remoteSeid, 42);
+
+      // Returned codec parameters must be in the range of input
+      // parameters.
+      EXPECT_NE(
+          std::find(a2dp_info.channelMode.begin(), a2dp_info.channelMode.end(),
+                    configuration->parameters.channelMode),
+          a2dp_info.channelMode.end());
+      EXPECT_NE(std::find(a2dp_info.samplingFrequencyHz.begin(),
+                          a2dp_info.samplingFrequencyHz.end(),
+                          configuration->parameters.samplingFrequencyHz),
+                a2dp_info.samplingFrequencyHz.end());
+      EXPECT_NE(std::find(a2dp_info.bitdepth.begin(), a2dp_info.bitdepth.end(),
+                          configuration->parameters.bitdepth),
+                a2dp_info.bitdepth.end());
+      EXPECT_EQ(a2dp_info.lossless, configuration->parameters.lossless);
+      EXPECT_TRUE(configuration->parameters.minBitrate <=
+                  configuration->parameters.maxBitrate);
+
+      // Returned configuration must be parsable by parseA2dpParameters
+      // and match the codec parameters.
+      CodecParameters codec_parameters;
+      A2dpStatus a2dp_status = A2dpStatus::OK;
+      aidl_retval = provider->parseA2dpConfiguration(
+          configuration->id, configuration->configuration, &codec_parameters,
+          &a2dp_status);
+      ASSERT_TRUE(aidl_retval.isOk());
+      EXPECT_TRUE(a2dp_status == A2dpStatus::OK);
+      EXPECT_EQ(codec_parameters, configuration->parameters);
+    }
+  }
+}
+
+/**
+ * Calling getA2dpConfiguration with valid remote capabilities
+ * with various hinted codec ids.
+ */
+TEST_P(BluetoothAudioProviderAidl, getA2dpConfiguration_hintCodecId) {
+  for (auto& [provider, provider_info] :
+       {std::pair(a2dp_encoding_provider_, a2dp_encoding_provider_info_),
+        std::pair(a2dp_decoding_provider_, a2dp_decoding_provider_info_)}) {
+    if (provider == nullptr || !provider_info.has_value() ||
+        provider_info->codecInfos.empty()) {
+      continue;
+    }
+
+    // Build the remote capabilities with all supported codecs.
+    std::vector<A2dpRemoteCapabilities> remote_capabilities;
+    for (size_t n = 0; n < provider_info->codecInfos.size(); n++) {
+      auto const& codec_info = provider_info->codecInfos[n];
+      auto a2dp_info = codec_info.transport.get<CodecInfo::Transport::a2dp>();
+      remote_capabilities.push_back(A2dpRemoteCapabilities(
+          /*seid*/ n, codec_info.id, a2dp_info.capabilities));
+    }
+
+    // Test with all supported codec identifiers,
+    for (auto const& codec_info : provider_info->codecInfos) {
+      std::optional<A2dpConfiguration> configuration{};
+      ::ndk::ScopedAStatus aidl_retval;
+
+      A2dpConfigurationHint hint;
+      hint.codecId = codec_info.id;
+
+      aidl_retval = provider->getA2dpConfiguration(remote_capabilities, hint,
+                                                   &configuration);
+
+      ASSERT_TRUE(aidl_retval.isOk());
+      ASSERT_TRUE(configuration.has_value());
+      EXPECT_EQ(configuration->id, codec_info.id);
+    }
+
+    // Test with unknown codec identifiers: either core or vendor.
+    for (auto& codec_id :
+         {CodecId(CodecId::Core::CVSD),
+          CodecId(CodecId::Vendor(0xFCB1, 0x42)) /*Google Codec #42*/}) {
+      std::optional<A2dpConfiguration> configuration{};
+      ::ndk::ScopedAStatus aidl_retval;
+
+      A2dpConfigurationHint hint;
+      hint.codecId = codec_id;
+
+      aidl_retval = provider->getA2dpConfiguration(remote_capabilities, hint,
+                                                   &configuration);
+
+      ASSERT_TRUE(aidl_retval.isOk());
+      ASSERT_TRUE(configuration.has_value());
+      EXPECT_NE(configuration->id, codec_id);
+    }
+  }
+}
+
+/**
+ * Calling getA2dpConfiguration with valid remote capabilities
+ * with various hinted channel modes.
+ */
+TEST_P(BluetoothAudioProviderAidl, getA2dpConfiguration_hintChannelMode) {
+  for (auto& [provider, provider_info] :
+       {std::pair(a2dp_encoding_provider_, a2dp_encoding_provider_info_),
+        std::pair(a2dp_decoding_provider_, a2dp_decoding_provider_info_)}) {
+    if (provider == nullptr || !provider_info.has_value() ||
+        provider_info->codecInfos.empty()) {
+      continue;
+    }
+
+    // Test with all available codecs in the provider info.
+    for (auto const& codec_info : provider_info->codecInfos) {
+      auto a2dp_info = codec_info.transport.get<CodecInfo::Transport::a2dp>();
+      std::optional<A2dpConfiguration> configuration{};
+      ::ndk::ScopedAStatus aidl_retval;
+
+      for (auto& channel_mode :
+           {ChannelMode::STEREO, ChannelMode::MONO, ChannelMode::DUALMONO}) {
+        // Add the hint for the channel mode.
+        A2dpConfigurationHint hint;
+        auto& codec_parameters = hint.codecParameters.emplace();
+        codec_parameters.channelMode = channel_mode;
+
+        aidl_retval = provider->getA2dpConfiguration(
+            std::vector<A2dpRemoteCapabilities>{
+                A2dpRemoteCapabilities(/*seid*/ 42, codec_info.id,
+                                       a2dp_info.capabilities),
+            },
+            hint, &configuration);
+
+        ASSERT_TRUE(aidl_retval.isOk());
+        ASSERT_TRUE(configuration.has_value());
+
+        // The hint must be ignored if the channel mode is not supported
+        // by the codec, and applied otherwise.
+        ASSERT_EQ(configuration->parameters.channelMode == channel_mode,
+                  std::find(a2dp_info.channelMode.begin(),
+                            a2dp_info.channelMode.end(),
+                            channel_mode) != a2dp_info.channelMode.end());
+      }
+    }
+  }
+}
+
+/**
+ * Calling getA2dpConfiguration with valid remote capabilities
+ * with various hinted sampling frequencies.
+ */
+TEST_P(BluetoothAudioProviderAidl,
+       getA2dpConfiguration_hintSamplingFrequencyHz) {
+  for (auto& [provider, provider_info] :
+       {std::pair(a2dp_encoding_provider_, a2dp_encoding_provider_info_),
+        std::pair(a2dp_decoding_provider_, a2dp_decoding_provider_info_)}) {
+    if (provider == nullptr || !provider_info.has_value() ||
+        provider_info->codecInfos.empty()) {
+      continue;
+    }
+
+    // Test with all available codecs in the provider info.
+    for (auto const& codec_info : provider_info->codecInfos) {
+      auto a2dp_info = codec_info.transport.get<CodecInfo::Transport::a2dp>();
+      std::optional<A2dpConfiguration> configuration{};
+      ::ndk::ScopedAStatus aidl_retval;
+
+      for (auto& sampling_frequency_hz : {
+               0,
+               1,
+               8000,
+               16000,
+               24000,
+               32000,
+               44100,
+               48000,
+               88200,
+               96000,
+               176400,
+               192000,
+           }) {
+        // Add the hint for the sampling frequency.
+        A2dpConfigurationHint hint;
+        auto& codec_parameters = hint.codecParameters.emplace();
+        codec_parameters.samplingFrequencyHz = sampling_frequency_hz;
+
+        aidl_retval = provider->getA2dpConfiguration(
+            std::vector<A2dpRemoteCapabilities>{
+                A2dpRemoteCapabilities(/*seid*/ 42, codec_info.id,
+                                       a2dp_info.capabilities),
+            },
+            hint, &configuration);
+
+        ASSERT_TRUE(aidl_retval.isOk());
+        ASSERT_TRUE(configuration.has_value());
+
+        // The hint must be ignored if the sampling frequency is not supported
+        // by the codec, and applied otherwise.
+        ASSERT_EQ(configuration->parameters.samplingFrequencyHz ==
+                      sampling_frequency_hz,
+                  std::find(a2dp_info.samplingFrequencyHz.begin(),
+                            a2dp_info.samplingFrequencyHz.end(),
+                            sampling_frequency_hz) !=
+                      a2dp_info.samplingFrequencyHz.end());
+      }
+    }
+  }
+}
+
+/**
+ * Calling getA2dpConfiguration with valid remote capabilities
+ * with various hinted sampling bit-depths.
+ */
+TEST_P(BluetoothAudioProviderAidl, getA2dpConfiguration_hintBitdepth) {
+  for (auto& [provider, provider_info] :
+       {std::pair(a2dp_encoding_provider_, a2dp_encoding_provider_info_),
+        std::pair(a2dp_decoding_provider_, a2dp_decoding_provider_info_)}) {
+    if (provider == nullptr || !provider_info.has_value() ||
+        provider_info->codecInfos.empty()) {
+      continue;
+    }
+
+    // Test with all available codecs in the provider info.
+    for (auto const& codec_info : provider_info->codecInfos) {
+      auto a2dp_info = codec_info.transport.get<CodecInfo::Transport::a2dp>();
+      std::optional<A2dpConfiguration> configuration{};
+      ::ndk::ScopedAStatus aidl_retval;
+
+      for (auto& bitdepth : {0, 1, 16, 24, 32}) {
+        // Add the hint for the bit depth.
+        A2dpConfigurationHint hint;
+        auto& codec_parameters = hint.codecParameters.emplace();
+        codec_parameters.bitdepth = bitdepth;
+
+        aidl_retval = provider->getA2dpConfiguration(
+            std::vector<A2dpRemoteCapabilities>{
+                A2dpRemoteCapabilities(/*seid*/ 42, codec_info.id,
+                                       a2dp_info.capabilities),
+            },
+            hint, &configuration);
+
+        ASSERT_TRUE(aidl_retval.isOk());
+        ASSERT_TRUE(configuration.has_value());
+
+        // The hint must be ignored if the bitdepth is not supported
+        // by the codec, and applied otherwise.
+        ASSERT_EQ(
+            configuration->parameters.bitdepth == bitdepth,
+            std::find(a2dp_info.bitdepth.begin(), a2dp_info.bitdepth.end(),
+                      bitdepth) != a2dp_info.bitdepth.end());
+      }
+    }
+  }
+}
+
+/**
+ * Calling startSession with an unknown codec id must fail.
+ */
+TEST_P(BluetoothAudioProviderAidl, startSession_unknownCodecId) {
+  for (auto& [provider, provider_info] :
+       {std::pair(a2dp_encoding_provider_, a2dp_encoding_provider_info_),
+        std::pair(a2dp_decoding_provider_, a2dp_decoding_provider_info_)}) {
+    if (provider == nullptr || !provider_info.has_value() ||
+        provider_info->codecInfos.empty()) {
+      continue;
+    }
+
+    for (auto& codec_id :
+         {CodecId(CodecId::Core::CVSD),
+          CodecId(CodecId::Vendor(0xFCB1, 0x42) /*Google Codec #42*/)}) {
+      A2dpStreamConfiguration a2dp_config;
+      DataMQDesc data_mq_desc;
+
+      a2dp_config.codecId = codec_id;
+      a2dp_config.configuration = std::vector<uint8_t>{1, 2, 3};
+
+      auto aidl_retval =
+          provider->startSession(audio_port_, AudioConfiguration(a2dp_config),
+                                 std::vector<LatencyMode>{}, &data_mq_desc);
+
+      EXPECT_FALSE(aidl_retval.isOk());
+    }
+  }
+}
+
+/**
+ * Calling startSession with a known codec and a valid configuration
+ * must succeed.
+ */
+TEST_P(BluetoothAudioProviderAidl, startSession_valid) {
+  for (auto& [provider, provider_info] :
+       {std::pair(a2dp_encoding_provider_, a2dp_encoding_provider_info_),
+        std::pair(a2dp_decoding_provider_, a2dp_decoding_provider_info_)}) {
+    if (provider == nullptr || !provider_info.has_value() ||
+        provider_info->codecInfos.empty()) {
+      continue;
+    }
+
+    // Use the first available codec in the provider info for testing.
+    // To get a valid configuration (the capabilities array in the provider
+    // info is not a selection), getA2dpConfiguration is used with the
+    // selected codec parameters as input.
+    auto const& codec_info = provider_info->codecInfos[0];
+    auto a2dp_info = codec_info.transport.get<CodecInfo::Transport::a2dp>();
+    ::ndk::ScopedAStatus aidl_retval;
+    A2dpRemoteCapabilities remote_capabilities(/*seid*/ 0, codec_info.id,
+                                               a2dp_info.capabilities);
+    std::optional<A2dpConfiguration> configuration;
+    aidl_retval = provider->getA2dpConfiguration(
+        std::vector<A2dpRemoteCapabilities>{remote_capabilities},
+        A2dpConfigurationHint(), &configuration);
+    ASSERT_TRUE(aidl_retval.isOk());
+    ASSERT_TRUE(configuration.has_value());
+
+    // Build the stream configuration.
+    A2dpStreamConfiguration a2dp_config;
+    DataMQDesc data_mq_desc;
+
+    a2dp_config.codecId = codec_info.id;
+    a2dp_config.configuration = configuration->configuration;
+
+    aidl_retval =
+        provider->startSession(audio_port_, AudioConfiguration(a2dp_config),
+                               std::vector<LatencyMode>{}, &data_mq_desc);
+
+    EXPECT_TRUE(aidl_retval.isOk());
+  }
+}
+
+/**
+ * Calling startSession with a known codec but an invalid configuration
+ * must fail.
+ */
+TEST_P(BluetoothAudioProviderAidl, startSession_invalidConfiguration) {
+  for (auto& [provider, provider_info] :
+       {std::pair(a2dp_encoding_provider_, a2dp_encoding_provider_info_),
+        std::pair(a2dp_decoding_provider_, a2dp_decoding_provider_info_)}) {
+    if (provider == nullptr || !provider_info.has_value() ||
+        provider_info->codecInfos.empty()) {
+      continue;
+    }
+
+    // Use the first available codec in the provider info for testing.
+    // To get a valid configuration (the capabilities array in the provider
+    // info is not a selection), getA2dpConfiguration is used with the
+    // selected codec parameters as input.
+    ::ndk::ScopedAStatus aidl_retval;
+    auto const& codec_info = provider_info->codecInfos[0];
+    auto a2dp_info = codec_info.transport.get<CodecInfo::Transport::a2dp>();
+    A2dpRemoteCapabilities remote_capabilities(/*seid*/ 0, codec_info.id,
+                                               a2dp_info.capabilities);
+    std::optional<A2dpConfiguration> configuration;
+    aidl_retval = provider->getA2dpConfiguration(
+        std::vector<A2dpRemoteCapabilities>{remote_capabilities},
+        A2dpConfigurationHint(), &configuration);
+    ASSERT_TRUE(aidl_retval.isOk());
+    ASSERT_TRUE(configuration.has_value());
+
+    // Build the stream configuration but edit the configuration bytes
+    // to make it invalid.
+    A2dpStreamConfiguration a2dp_config;
+    DataMQDesc data_mq_desc;
+
+    a2dp_config.codecId = codec_info.id;
+    a2dp_config.configuration = configuration->configuration;
+    a2dp_config.configuration.push_back(42);
+
+    aidl_retval =
+        provider->startSession(audio_port_, AudioConfiguration(a2dp_config),
+                               std::vector<LatencyMode>{}, &data_mq_desc);
+
+    EXPECT_FALSE(aidl_retval.isOk());
+  }
+}
+
+/**
  * openProvider A2DP_SOFTWARE_ENCODING_DATAPATH
  */
 class BluetoothAudioProviderA2dpEncodingSoftwareAidl
@@ -656,6 +1496,137 @@
 }
 
 /**
+ * openProvider HFP_SOFTWARE_ENCODING_DATAPATH
+ */
+class BluetoothAudioProviderHfpSoftwareEncodingAidl
+    : public BluetoothAudioProviderFactoryAidl {
+ public:
+  virtual void SetUp() override {
+    BluetoothAudioProviderFactoryAidl::SetUp();
+    GetProviderCapabilitiesHelper(SessionType::HFP_SOFTWARE_ENCODING_DATAPATH);
+    OpenProviderHelper(SessionType::HFP_SOFTWARE_ENCODING_DATAPATH);
+    ASSERT_NE(audio_provider_, nullptr);
+  }
+
+  virtual void TearDown() override {
+    audio_port_ = nullptr;
+    audio_provider_ = nullptr;
+    BluetoothAudioProviderFactoryAidl::TearDown();
+  }
+
+  bool OpenSession(int32_t sample_rate, int8_t bits_per_sample,
+                   ChannelMode channel_mode, int32_t data_interval_us) {
+    PcmConfiguration pcm_config{
+        .sampleRateHz = sample_rate,
+        .channelMode = channel_mode,
+        .bitsPerSample = bits_per_sample,
+        .dataIntervalUs = data_interval_us,
+    };
+    // Checking against provider capability from getProviderCapabilities
+    // For HFP software, it's
+    // BluetoothAudioCodecs::GetSoftwarePcmCapabilities();
+    DataMQDesc mq_desc;
+    auto aidl_retval = audio_provider_->startSession(
+        audio_port_, AudioConfiguration(pcm_config), latency_modes, &mq_desc);
+    DataMQ data_mq(mq_desc);
+
+    if (!aidl_retval.isOk()) return false;
+    if (!data_mq.isValid()) return false;
+    return true;
+  }
+};
+
+/**
+ * Test whether we can open a provider of type
+ */
+TEST_P(BluetoothAudioProviderHfpSoftwareEncodingAidl,
+       OpenHfpSoftwareEncodingProvider) {}
+
+/**
+ * Test whether each provider of type
+ * SessionType::HFP_SOFTWARE_ENCODING_DATAPATH can be started and stopped with
+ * different PCM config
+ */
+TEST_P(BluetoothAudioProviderHfpSoftwareEncodingAidl,
+       StartAndEndHfpEncodingSoftwareSessionWithPossiblePcmConfig) {
+  for (auto sample_rate : hfp_sample_rates_) {
+    for (auto bits_per_sample : hfp_bits_per_samples_) {
+      for (auto channel_mode : hfp_channel_modes_) {
+        for (auto data_interval_us : hfp_data_interval_us_) {
+          EXPECT_TRUE(OpenSession(sample_rate, bits_per_sample, channel_mode,
+                                  data_interval_us));
+          EXPECT_TRUE(audio_provider_->endSession().isOk());
+        }
+      }
+    }
+  }
+}
+
+/**
+ * openProvider HFP_SOFTWARE_DECODING_DATAPATH
+ */
+class BluetoothAudioProviderHfpSoftwareDecodingAidl
+    : public BluetoothAudioProviderFactoryAidl {
+ public:
+  virtual void SetUp() override {
+    BluetoothAudioProviderFactoryAidl::SetUp();
+    GetProviderCapabilitiesHelper(SessionType::HFP_SOFTWARE_DECODING_DATAPATH);
+    OpenProviderHelper(SessionType::HFP_SOFTWARE_DECODING_DATAPATH);
+    ASSERT_NE(audio_provider_, nullptr);
+  }
+
+  virtual void TearDown() override {
+    audio_port_ = nullptr;
+    audio_provider_ = nullptr;
+    BluetoothAudioProviderFactoryAidl::TearDown();
+  }
+
+  bool OpenSession(int32_t sample_rate, int8_t bits_per_sample,
+                   ChannelMode channel_mode, int32_t data_interval_us) {
+    PcmConfiguration pcm_config{
+        .sampleRateHz = sample_rate,
+        .channelMode = channel_mode,
+        .bitsPerSample = bits_per_sample,
+        .dataIntervalUs = data_interval_us,
+    };
+    DataMQDesc mq_desc;
+    auto aidl_retval = audio_provider_->startSession(
+        audio_port_, AudioConfiguration(pcm_config), latency_modes, &mq_desc);
+    DataMQ data_mq(mq_desc);
+
+    if (!aidl_retval.isOk()) return false;
+    if (!data_mq.isValid()) return false;
+    return true;
+  }
+};
+
+/**
+ * Test whether we can open a provider of type
+ */
+TEST_P(BluetoothAudioProviderHfpSoftwareDecodingAidl,
+       OpenHfpSoftwareDecodingProvider) {}
+
+/**
+ * Test whether each provider of type
+ * SessionType::HFP_SOFTWARE_DECODING_DATAPATH can be started and stopped with
+ * different PCM config
+ */
+TEST_P(BluetoothAudioProviderHfpSoftwareDecodingAidl,
+       StartAndEndHfpDecodingSoftwareSessionWithPossiblePcmConfig) {
+  for (auto sample_rate : hfp_sample_rates_) {
+    for (auto bits_per_sample : hfp_bits_per_samples_) {
+      for (auto channel_mode : hfp_channel_modes_) {
+        for (auto data_interval_us : hfp_data_interval_us_) {
+          EXPECT_TRUE(OpenSession(sample_rate, bits_per_sample, channel_mode,
+                                  data_interval_us));
+          EXPECT_TRUE(audio_provider_->endSession().isOk());
+        }
+      }
+    }
+  }
+}
+
+/**
  * openProvider A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH
  */
 class BluetoothAudioProviderA2dpEncodingHardwareAidl
@@ -908,6 +1879,62 @@
 }
 
 /**
+ * openProvider HFP_HARDWARE_OFFLOAD_DATAPATH
+ */
+class BluetoothAudioProviderHfpHardwareAidl
+    : public BluetoothAudioProviderFactoryAidl {
+ public:
+  virtual void SetUp() override {
+    BluetoothAudioProviderFactoryAidl::SetUp();
+    OpenProviderHelper(SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH);
+    // Can open or empty capability
+    ASSERT_TRUE(temp_provider_capabilities_.empty() ||
+                audio_provider_ != nullptr);
+  }
+
+  virtual void TearDown() override {
+    audio_port_ = nullptr;
+    audio_provider_ = nullptr;
+    BluetoothAudioProviderFactoryAidl::TearDown();
+  }
+
+  bool OpenSession(CodecId codec_id, int connection_handle, bool nrec,
+                   bool controller_codec) {
+    // Check if can open session with a Hfp configuration
+    HfpConfiguration hfp_configuration{
+        .codecId = codec_id,
+        .connectionHandle = connection_handle,
+        .nrec = nrec,
+        .controllerCodec = controller_codec,
+    };
+    DataMQDesc mq_desc;
+    auto aidl_retval = audio_provider_->startSession(
+        audio_port_, AudioConfiguration(hfp_configuration), latency_modes,
+        &mq_desc);
+
+    // Only check if aidl is ok to start session.
+    return aidl_retval.isOk();
+  }
+};
+
+/**
+ * Test whether we can open a provider of type
+ */
+TEST_P(BluetoothAudioProviderHfpHardwareAidl, OpenHfpHardwareProvider) {}
+
+/**
+ * Test whether each provider of type
+ * SessionType::HFP_SOFTWARE_DECODING_DATAPATH can be started and stopped with
+ * different HFP config
+ */
+TEST_P(BluetoothAudioProviderHfpHardwareAidl,
+       StartAndEndHfpHardwareSessionWithPossiblePcmConfig) {
+  // Try to open with a sample configuration
+  EXPECT_TRUE(OpenSession(CodecId::Core::CVSD, 6, false, true));
+  EXPECT_TRUE(audio_provider_->endSession().isOk());
+}
+
+/**
  * openProvider HEARING_AID_SOFTWARE_ENCODING_DATAPATH
  */
 class BluetoothAudioProviderHearingAidSoftwareAidl
@@ -1128,6 +2155,8 @@
     BluetoothAudioProviderFactoryAidl::SetUp();
     GetProviderCapabilitiesHelper(
         SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
+    GetProviderInfoHelper(
+        SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
     OpenProviderHelper(
         SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
     ASSERT_TRUE(temp_provider_capabilities_.empty() ||
@@ -1154,6 +2183,99 @@
     return false;
   }
 
+  bool IsOffloadOutputProviderInfoSupported() {
+    if (!temp_provider_info_.has_value()) return false;
+    if (temp_provider_info_.value().codecInfos.empty()) return false;
+    // Check if all codec info is of LeAudio type
+    for (auto& codec_info : temp_provider_info_.value().codecInfos) {
+      if (codec_info.transport.getTag() != CodecInfo::Transport::leAudio)
+        return false;
+    }
+    return true;
+  }
+
+  std::vector<Lc3Configuration> GetUnicastLc3SupportedListFromProviderInfo() {
+    std::vector<Lc3Configuration> le_audio_codec_configs;
+    for (auto& codec_info : temp_provider_info_.value().codecInfos) {
+      // Only gets LC3 codec information
+      if (codec_info.id != CodecId::Core::LC3) continue;
+      // Combine those parameters into one list of Lc3Configuration
+      auto& transport =
+          codec_info.transport.get<CodecInfo::Transport::Tag::leAudio>();
+      for (int32_t samplingFrequencyHz : transport.samplingFrequencyHz) {
+        for (int32_t frameDurationUs : transport.frameDurationUs) {
+          for (int32_t octetsPerFrame : transport.bitdepth) {
+            Lc3Configuration lc3_config = {
+                .samplingFrequencyHz = samplingFrequencyHz,
+                .frameDurationUs = frameDurationUs,
+                .octetsPerFrame = octetsPerFrame,
+            };
+            le_audio_codec_configs.push_back(lc3_config);
+          }
+        }
+      }
+    }
+
+    return le_audio_codec_configs;
+  }
+
+  AudioContext GetAudioContext(int32_t bitmask) {
+    AudioContext media_audio_context;
+    media_audio_context.bitmask = bitmask;
+    return media_audio_context;
+  }
+
+  LeAudioDeviceCapabilities GetDefaultRemoteCapability() {
+    // Create a capability
+    LeAudioDeviceCapabilities capability;
+
+    capability.codecId = CodecId::Core::LC3;
+
+    auto pref_context_metadata = MetadataLtv::PreferredAudioContexts();
+    pref_context_metadata.values = GetAudioContext(AudioContext::MEDIA);
+    capability.metadata = {pref_context_metadata};
+
+    auto sampling_rate =
+        CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies();
+    sampling_rate.bitmask =
+        CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ8000;
+    auto frame_duration =
+        CodecSpecificCapabilitiesLtv::SupportedFrameDurations();
+    frame_duration.bitmask =
+        CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US7500;
+    auto octets = CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame();
+    octets.minimum = 0;
+    octets.maximum = 60;
+    auto frames = CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU();
+    frames.value = 2;
+    capability.codecSpecificCapabilities = {sampling_rate, frame_duration,
+                                            octets, frames};
+    return capability;
+  }
+
+  LeAudioConfigurationRequirement GetDefaultRequirement(
+      bool is_source_requriement) {
+    // Create a requirements
+    LeAudioConfigurationRequirement requirement;
+    requirement.audioContext = GetAudioContext(AudioContext::MEDIA);
+
+    auto direction_ase_requriement = AseDirectionRequirement();
+    direction_ase_requriement.aseConfiguration.codecId = CodecId::Core::LC3;
+    direction_ase_requriement.aseConfiguration.targetLatency =
+        LeAudioAseConfiguration::TargetLatency::BALANCED_LATENCY_RELIABILITY;
+
+    // Mismatch sampling frequency
+    direction_ase_requriement.aseConfiguration.codecConfiguration = {
+        CodecSpecificConfigurationLtv::SamplingFrequency::HZ11025,
+        CodecSpecificConfigurationLtv::FrameDuration::US7500,
+    };
+    if (is_source_requriement)
+      requirement.sourceAseRequirement = {direction_ase_requriement};
+    else
+      requirement.sinkAseRequirement = {direction_ase_requriement};
+    return requirement;
+  }
+
   std::vector<Lc3Configuration> GetUnicastLc3SupportedList(bool decoding,
                                                            bool supported) {
     std::vector<Lc3Configuration> le_audio_codec_configs;
@@ -1271,6 +2393,14 @@
   }
 
   LeAudioCodecCapabilitiesSetting temp_le_audio_capabilities_;
+  std::vector<int32_t> all_context_bitmasks = {
+      AudioContext::UNSPECIFIED,   AudioContext::CONVERSATIONAL,
+      AudioContext::MEDIA,         AudioContext::GAME,
+      AudioContext::INSTRUCTIONAL, AudioContext::VOICE_ASSISTANTS,
+      AudioContext::LIVE_AUDIO,    AudioContext::SOUND_EFFECTS,
+      AudioContext::NOTIFICATIONS, AudioContext::RINGTONE_ALERTS,
+      AudioContext::ALERTS,        AudioContext::EMERGENCY_ALARM,
+  };
 };
 
 /**
@@ -1284,6 +2414,135 @@
 /**
  * Test whether each provider of type
  * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
+ * stopped with Unicast hardware encoding config taken from provider info
+ */
+TEST_P(
+    BluetoothAudioProviderLeAudioOutputHardwareAidl,
+    StartAndEndLeAudioOutputSessionWithPossibleUnicastConfigFromProviderInfo) {
+  if (!IsOffloadOutputProviderInfoSupported()) {
+    return;
+  }
+
+  auto lc3_codec_configs = GetUnicastLc3SupportedListFromProviderInfo();
+  LeAudioConfiguration le_audio_config = {
+      .codecType = CodecType::LC3,
+      .peerDelayUs = 0,
+  };
+
+  for (auto& lc3_config : lc3_codec_configs) {
+    le_audio_config.leAudioCodecConfig
+        .set<LeAudioCodecConfiguration::lc3Config>(lc3_config);
+    DataMQDesc mq_desc;
+    auto aidl_retval = audio_provider_->startSession(
+        audio_port_, AudioConfiguration(le_audio_config), latency_modes,
+        &mq_desc);
+
+    ASSERT_TRUE(aidl_retval.isOk());
+    EXPECT_TRUE(audio_provider_->endSession().isOk());
+  }
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+       GetEmptyAseConfigurationEmptyCapability) {
+  std::vector<std::optional<LeAudioDeviceCapabilities>> empty_capability;
+  std::vector<LeAudioConfigurationRequirement> empty_requirement;
+  std::vector<LeAudioAseConfigurationSetting> configurations;
+
+  // Check empty capability for source direction
+  auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      std::nullopt, empty_capability, empty_requirement, &configurations);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_TRUE(configurations.empty());
+
+  // Check empty capability for sink direction
+  aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      empty_capability, std::nullopt, empty_requirement, &configurations);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_TRUE(configurations.empty());
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+       GetEmptyAseConfigurationMismatchedRequirement) {
+  std::vector<std::optional<LeAudioDeviceCapabilities>> capabilities = {
+      GetDefaultRemoteCapability()};
+
+  // Check empty capability for source direction
+  std::vector<LeAudioAseConfigurationSetting> configurations;
+  std::vector<LeAudioConfigurationRequirement> source_requirements = {
+      GetDefaultRequirement(true)};
+  auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      std::nullopt, capabilities, source_requirements, &configurations);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_TRUE(configurations.empty());
+
+  // Check empty capability for sink direction
+  std::vector<LeAudioConfigurationRequirement> sink_requirements = {
+      GetDefaultRequirement(false)};
+  aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      capabilities, std::nullopt, source_requirements, &configurations);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_TRUE(configurations.empty());
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl, GetQoSConfiguration) {
+  IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement requirement;
+  std::vector<IBluetoothAudioProvider::LeAudioAseQosConfiguration>
+      QoSConfigurations;
+  for (auto bitmask : all_context_bitmasks) {
+    requirement.contextType = GetAudioContext(bitmask);
+    IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
+    auto aidl_retval =
+        audio_provider_->getLeAudioAseQosConfiguration(requirement, &result);
+    ASSERT_TRUE(aidl_retval.isOk());
+    if (result.sinkQosConfiguration.has_value())
+      QoSConfigurations.push_back(result.sinkQosConfiguration.value());
+    if (result.sourceQosConfiguration.has_value())
+      QoSConfigurations.push_back(result.sourceQosConfiguration.value());
+  }
+  // QoS Configurations should not be empty, as we searched for all contexts
+  ASSERT_FALSE(QoSConfigurations.empty());
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+       GetDataPathConfiguration) {
+  IBluetoothAudioProvider::StreamConfig sink_requirement;
+  IBluetoothAudioProvider::StreamConfig source_requirement;
+  std::vector<IBluetoothAudioProvider::LeAudioDataPathConfiguration>
+      DataPathConfigurations;
+  bool is_supported = false;
+
+  for (auto bitmask : all_context_bitmasks) {
+    sink_requirement.context = GetAudioContext(bitmask);
+    source_requirement.context = GetAudioContext(bitmask);
+    IBluetoothAudioProvider::LeAudioDataPathConfigurationPair result;
+    auto aidl_retval = audio_provider_->getLeAudioAseDatapathConfiguration(
+        sink_requirement, source_requirement, &result);
+    if (!aidl_retval.isOk()) {
+      // If not OK, then it could be not supported, as it is an optional feature
+      ASSERT_EQ(aidl_retval.getExceptionCode(), EX_UNSUPPORTED_OPERATION);
+    } else {
+      is_supported = true;
+      if (result.inputConfig.has_value())
+        DataPathConfigurations.push_back(result.inputConfig.value());
+      if (result.inputConfig.has_value())
+        DataPathConfigurations.push_back(result.inputConfig.value());
+    }
+  }
+
+  if (is_supported) {
+    // Datapath Configurations should not be empty, as we searched for all
+    // contexts
+    ASSERT_FALSE(DataPathConfigurations.empty());
+  }
+}
+
+/**
+ * Test whether each provider of type
+ * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
  * stopped with Unicast hardware encoding config
  */
 TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
@@ -1437,6 +2696,8 @@
     BluetoothAudioProviderFactoryAidl::SetUp();
     GetProviderCapabilitiesHelper(
         SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH);
+    GetProviderInfoHelper(
+        SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH);
     OpenProviderHelper(
         SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH);
     ASSERT_TRUE(temp_provider_capabilities_.empty() ||
@@ -1466,7 +2727,7 @@
 
 /**
  * Test whether each provider of type
- * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
+ * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH can be started and
  * stopped
  */
 TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
@@ -1474,7 +2735,38 @@
 
 /**
  * Test whether each provider of type
- * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
+ * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH can be started and
+ * stopped with Unicast hardware encoding config taken from provider info
+ */
+TEST_P(
+    BluetoothAudioProviderLeAudioInputHardwareAidl,
+    StartAndEndLeAudioInputSessionWithPossibleUnicastConfigFromProviderInfo) {
+  if (!IsOffloadOutputProviderInfoSupported()) {
+    return;
+  }
+
+  auto lc3_codec_configs = GetUnicastLc3SupportedListFromProviderInfo();
+  LeAudioConfiguration le_audio_config = {
+      .codecType = CodecType::LC3,
+      .peerDelayUs = 0,
+  };
+
+  for (auto& lc3_config : lc3_codec_configs) {
+    le_audio_config.leAudioCodecConfig
+        .set<LeAudioCodecConfiguration::lc3Config>(lc3_config);
+    DataMQDesc mq_desc;
+    auto aidl_retval = audio_provider_->startSession(
+        audio_port_, AudioConfiguration(le_audio_config), latency_modes,
+        &mq_desc);
+
+    ASSERT_TRUE(aidl_retval.isOk());
+    EXPECT_TRUE(audio_provider_->endSession().isOk());
+  }
+}
+
+/**
+ * Test whether each provider of type
+ * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH can be started and
  * stopped with Unicast hardware encoding config
  */
 TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
@@ -1505,7 +2797,7 @@
 
 /**
  * Test whether each provider of type
- * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
+ * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH can be started and
  * stopped with Unicast hardware encoding config
  *
  * Disabled since offload codec checking is not ready
@@ -1623,6 +2915,8 @@
     BluetoothAudioProviderFactoryAidl::SetUp();
     GetProviderCapabilitiesHelper(
         SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
+    GetProviderInfoHelper(
+        SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
     OpenProviderHelper(
         SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
     ASSERT_TRUE(temp_provider_capabilities_.empty() ||
@@ -1649,6 +2943,42 @@
     return false;
   }
 
+  bool IsBroadcastOffloadProviderInfoSupported() {
+    if (!temp_provider_info_.has_value()) return false;
+    if (temp_provider_info_.value().codecInfos.empty()) return false;
+    // Check if all codec info is of LeAudio type
+    for (auto& codec_info : temp_provider_info_.value().codecInfos) {
+      if (codec_info.transport.getTag() != CodecInfo::Transport::leAudio)
+        return false;
+    }
+    return true;
+  }
+
+  std::vector<Lc3Configuration> GetBroadcastLc3SupportedListFromProviderInfo() {
+    std::vector<Lc3Configuration> le_audio_codec_configs;
+    for (auto& codec_info : temp_provider_info_.value().codecInfos) {
+      // Only gets LC3 codec information
+      if (codec_info.id != CodecId::Core::LC3) continue;
+      // Combine those parameters into one list of Lc3Configuration
+      auto& transport =
+          codec_info.transport.get<CodecInfo::Transport::Tag::leAudio>();
+      for (int32_t samplingFrequencyHz : transport.samplingFrequencyHz) {
+        for (int32_t frameDurationUs : transport.frameDurationUs) {
+          for (int32_t octetsPerFrame : transport.bitdepth) {
+            Lc3Configuration lc3_config = {
+                .samplingFrequencyHz = samplingFrequencyHz,
+                .frameDurationUs = frameDurationUs,
+                .octetsPerFrame = octetsPerFrame,
+            };
+            le_audio_codec_configs.push_back(lc3_config);
+          }
+        }
+      }
+    }
+
+    return le_audio_codec_configs;
+  }
+
   std::vector<Lc3Configuration> GetBroadcastLc3SupportedList(bool supported) {
     std::vector<Lc3Configuration> le_audio_codec_configs;
     if (!supported) {
@@ -1710,6 +3040,60 @@
 /**
  * Test whether each provider of type
  * SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be
+ * started and stopped with broadcast hardware encoding config taken from
+ * provider info
+ */
+TEST_P(
+    BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
+    StartAndEndLeAudioBroadcastSessionWithPossibleUnicastConfigFromProviderInfo) {
+  if (!IsBroadcastOffloadProviderInfoSupported()) {
+    return;
+  }
+
+  auto lc3_codec_configs = GetBroadcastLc3SupportedListFromProviderInfo();
+  LeAudioBroadcastConfiguration le_audio_broadcast_config = {
+      .codecType = CodecType::LC3,
+      .streamMap = {},
+  };
+
+  for (auto& lc3_config : lc3_codec_configs) {
+    le_audio_broadcast_config.streamMap.resize(1);
+    le_audio_broadcast_config.streamMap[0]
+        .leAudioCodecConfig.set<LeAudioCodecConfiguration::lc3Config>(
+            lc3_config);
+    le_audio_broadcast_config.streamMap[0].streamHandle = 0x0;
+    le_audio_broadcast_config.streamMap[0].pcmStreamId = 0x0;
+    le_audio_broadcast_config.streamMap[0].audioChannelAllocation = 0x1 << 0;
+
+    DataMQDesc mq_desc;
+    auto aidl_retval = audio_provider_->startSession(
+        audio_port_, AudioConfiguration(le_audio_broadcast_config),
+        latency_modes, &mq_desc);
+
+    ASSERT_TRUE(aidl_retval.isOk());
+    EXPECT_TRUE(audio_provider_->endSession().isOk());
+  }
+}
+
+TEST_P(BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
+       GetEmptyBroadcastConfigurationEmptyCapability) {
+  std::vector<std::optional<LeAudioDeviceCapabilities>> empty_capability;
+  IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement
+      empty_requirement;
+
+  IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting* configuration =
+      new IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting();
+
+  // Check empty capability for source direction
+  auto aidl_retval = audio_provider_->getLeAudioBroadcastConfiguration(
+      empty_capability, empty_requirement, configuration);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+}
+
+/**
+ * Test whether each provider of type
+ * SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be
  * started and stopped with broadcast hardware encoding config
  */
 TEST_P(BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
@@ -2096,6 +3480,12 @@
                              IBluetoothAudioProviderFactory::descriptor)),
                          android::PrintInstanceNameToString);
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BluetoothAudioProviderAidl);
+INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothAudioProviderAidl,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             IBluetoothAudioProviderFactory::descriptor)),
+                         android::PrintInstanceNameToString);
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
     BluetoothAudioProviderA2dpEncodingSoftwareAidl);
 INSTANTIATE_TEST_SUITE_P(PerInstance,
@@ -2184,6 +3574,29 @@
                              IBluetoothAudioProviderFactory::descriptor)),
                          android::PrintInstanceNameToString);
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    BluetoothAudioProviderHfpHardwareAidl);
+INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothAudioProviderHfpHardwareAidl,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             IBluetoothAudioProviderFactory::descriptor)),
+                         android::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    BluetoothAudioProviderHfpSoftwareDecodingAidl);
+INSTANTIATE_TEST_SUITE_P(PerInstance,
+                         BluetoothAudioProviderHfpSoftwareDecodingAidl,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             IBluetoothAudioProviderFactory::descriptor)),
+                         android::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    BluetoothAudioProviderHfpSoftwareEncodingAidl);
+INSTANTIATE_TEST_SUITE_P(PerInstance,
+                         BluetoothAudioProviderHfpSoftwareEncodingAidl,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             IBluetoothAudioProviderFactory::descriptor)),
+                         android::PrintInstanceNameToString);
+
 int main(int argc, char** argv) {
   ::testing::InitGoogleTest(&argc, argv);
   ABinderProcess_setThreadPoolMaxThreadCount(1);
diff --git a/bluetooth/audio/flags/Android.bp b/bluetooth/audio/flags/Android.bp
new file mode 100644
index 0000000..0d18a4d
--- /dev/null
+++ b/bluetooth/audio/flags/Android.bp
@@ -0,0 +1,12 @@
+aconfig_declarations {
+    name: "btaudiohal_flags",
+    package: "com.android.btaudio.hal.flags",
+    srcs: ["btaudiohal.aconfig"],
+}
+
+cc_aconfig_library {
+    name: "btaudiohal_flags_c_lib",
+    aconfig_declarations: "btaudiohal_flags",
+    vendor: true,
+    host_supported: true,
+}
diff --git a/bluetooth/audio/flags/btaudiohal.aconfig b/bluetooth/audio/flags/btaudiohal.aconfig
new file mode 100644
index 0000000..763777e
--- /dev/null
+++ b/bluetooth/audio/flags/btaudiohal.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.btaudio.hal.flags"
+
+flag {
+    name: "dsa_lea"
+    namespace: "pixel_bluetooth"
+    description: "Flag for DSA Over LEA"
+    bug: "270987427"
+}
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index a09e7fe..c0817f5 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -42,12 +42,16 @@
         "aidl_session/BluetoothAudioSession.cpp",
         "aidl_session/HidlToAidlMiddleware.cpp",
         "aidl_session/BluetoothLeAudioCodecsProvider.cpp",
+        "aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp",
     ],
     export_include_dirs: ["aidl_session/"],
     header_libs: [
         "libhardware_headers",
         "libxsdc-utils",
     ],
+    defaults: [
+        "latest_android_hardware_bluetooth_audio_ndk_shared",
+    ],
     shared_libs: [
         "android.hardware.bluetooth.audio@2.0",
         "android.hardware.bluetooth.audio@2.1",
@@ -56,12 +60,25 @@
         "libbinder_ndk",
         "libfmq",
         "liblog",
-        "android.hardware.bluetooth.audio-V3-ndk",
         "libhidlbase",
         "libxml2",
+        "libflatbuffers-cpp",
+        "server_configurable_flags",
+    ],
+    static_libs: [
+        "btaudiohal_flags_c_lib",
     ],
     generated_sources: ["le_audio_codec_capabilities"],
-    generated_headers: ["le_audio_codec_capabilities"],
+    generated_headers: [
+        "le_audio_codec_capabilities",
+        "AIDLLeAudioSetConfigSchemas_h",
+    ],
+    required: [
+        "aidl_audio_set_configurations_bfbs",
+        "aidl_audio_set_configurations_json",
+        "aidl_audio_set_scenarios_bfbs",
+        "aidl_audio_set_scenarios_json",
+    ],
 }
 
 cc_test {
@@ -76,7 +93,7 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.bluetooth.audio-V3-ndk",
+        "android.hardware.bluetooth.audio-V4-ndk",
         "libxml2",
     ],
     test_suites: [
@@ -96,3 +113,81 @@
     api_dir: "le_audio_codec_capabilities/schema",
     root_elements: ["leAudioOffloadSetting"],
 }
+
+genrule {
+    name: "AIDLLeAudioSetConfigSchemas_h",
+    tools: [
+        "flatc",
+    ],
+    cmd: "$(location flatc) -I hardware/interfaces/bluetooth/audio/utils/ -o $(genDir) --cpp $(in) ",
+    srcs: [
+        "le_audio_configuration_set/audio_set_configurations.fbs",
+        "le_audio_configuration_set/audio_set_scenarios.fbs",
+    ],
+    out: [
+        "audio_set_configurations_generated.h",
+        "audio_set_scenarios_generated.h",
+    ],
+}
+
+// Binary generation
+genrule {
+    name: "AIDLLeAudioSetScenariosSchema_bfbs",
+    tools: [
+        "flatc",
+    ],
+    cmd: "$(location flatc) -I hardware/interfaces/bluetooth/audio/utils/ -b --schema -o $(genDir) $(in) ",
+    srcs: [
+        "le_audio_configuration_set/audio_set_scenarios.fbs",
+    ],
+    out: [
+        "audio_set_scenarios.bfbs",
+    ],
+}
+
+genrule {
+    name: "AIDLLeAudioSetConfigsSchema_bfbs",
+    tools: [
+        "flatc",
+    ],
+    cmd: "$(location flatc) -I hardware/interfaces/bluetooth/audio/utils/ -b --schema -o $(genDir) $(in) ",
+    srcs: [
+        "le_audio_configuration_set/audio_set_configurations.fbs",
+    ],
+    out: [
+        "audio_set_configurations.bfbs",
+    ],
+}
+
+// Add to prebuilt etc
+prebuilt_etc {
+    name: "aidl_audio_set_scenarios_bfbs",
+    src: ":AIDLLeAudioSetScenariosSchema_bfbs",
+    filename: "aidl_audio_set_scenarios.bfbs",
+    sub_dir: "aidl/le_audio",
+    vendor: true,
+}
+
+prebuilt_etc {
+    name: "aidl_audio_set_scenarios_json",
+    src: "le_audio_configuration_set/audio_set_scenarios.json",
+    filename: "aidl_audio_set_scenarios.json",
+    sub_dir: "aidl/le_audio",
+    vendor: true,
+}
+
+prebuilt_etc {
+    name: "aidl_audio_set_configurations_bfbs",
+    src: ":AIDLLeAudioSetConfigsSchema_bfbs",
+    filename: "aidl_audio_set_configurations.bfbs",
+    sub_dir: "aidl/le_audio",
+    vendor: true,
+}
+
+prebuilt_etc {
+    name: "aidl_audio_set_configurations_json",
+    src: "le_audio_configuration_set/audio_set_configurations.json",
+    filename: "aidl_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 b4cba49..216e169 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
@@ -32,6 +32,7 @@
 #include <aidl/android/hardware/bluetooth/audio/SbcChannelMode.h>
 #include <android-base/logging.h>
 
+#include "BluetoothLeAudioAseConfigurationSettingProvider.h"
 #include "BluetoothLeAudioCodecsProvider.h"
 
 namespace aidl {
@@ -41,7 +42,7 @@
 namespace audio {
 
 static const PcmCapabilities kDefaultSoftwarePcmCapabilities = {
-    .sampleRateHz = {16000, 24000, 32000, 44100, 48000, 88200, 96000},
+    .sampleRateHz = {8000, 16000, 24000, 32000, 44100, 48000, 88200, 96000},
     .channelMode = {ChannelMode::MONO, ChannelMode::STEREO},
     .bitsPerSample = {16, 24, 32},
     .dataIntervalUs = {},
@@ -97,6 +98,8 @@
     {.codecType = CodecType::OPUS, .capabilities = {}}};
 
 std::vector<LeAudioCodecCapabilitiesSetting> kDefaultOffloadLeAudioCapabilities;
+std::unordered_map<SessionType, std::vector<CodecInfo>>
+    kDefaultOffloadLeAudioCodecInfoMap;
 
 template <class T>
 bool BluetoothAudioCodecs::ContainedInVector(
@@ -411,6 +414,37 @@
   return kDefaultOffloadLeAudioCapabilities;
 }
 
+std::vector<CodecInfo> BluetoothAudioCodecs::GetLeAudioOffloadCodecInfo(
+    const SessionType& session_type) {
+  if (session_type !=
+          SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+      session_type !=
+          SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH &&
+      session_type !=
+          SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+    return std::vector<CodecInfo>();
+  }
+
+  if (kDefaultOffloadLeAudioCodecInfoMap.empty()) {
+    auto le_audio_offload_setting =
+        BluetoothLeAudioCodecsProvider::ParseFromLeAudioOffloadSettingFile();
+    auto kDefaultOffloadLeAudioCodecInfoMap =
+        BluetoothLeAudioCodecsProvider::GetLeAudioCodecInfo(
+            le_audio_offload_setting);
+  }
+  auto codec_info_map_iter =
+      kDefaultOffloadLeAudioCodecInfoMap.find(session_type);
+  if (codec_info_map_iter == kDefaultOffloadLeAudioCodecInfoMap.end())
+    return std::vector<CodecInfo>();
+  return codec_info_map_iter->second;
+}
+
+std::vector<LeAudioAseConfigurationSetting>
+BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings() {
+  return AudioSetConfigurationProviderJson::
+      GetLeAudioAseConfigurationSettings();
+}
+
 }  // namespace audio
 }  // namespace bluetooth
 }  // namespace hardware
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h
index e3d657b..057b9a7 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h
@@ -18,6 +18,8 @@
 
 #include <aidl/android/hardware/bluetooth/audio/CodecCapabilities.h>
 #include <aidl/android/hardware/bluetooth/audio/CodecConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/CodecInfo.h>
+#include <aidl/android/hardware/bluetooth/audio/IBluetoothAudioProvider.h>
 #include <aidl/android/hardware/bluetooth/audio/LeAudioCodecCapabilitiesSetting.h>
 #include <aidl/android/hardware/bluetooth/audio/LeAudioConfiguration.h>
 #include <aidl/android/hardware/bluetooth/audio/OpusConfiguration.h>
@@ -33,6 +35,9 @@
 namespace bluetooth {
 namespace audio {
 
+using LeAudioAseConfigurationSetting =
+    IBluetoothAudioProvider::LeAudioAseConfigurationSetting;
+
 class BluetoothAudioCodecs {
  public:
   static std::vector<PcmCapabilities> GetSoftwarePcmCapabilities();
@@ -46,6 +51,11 @@
 
   static std::vector<LeAudioCodecCapabilitiesSetting>
   GetLeAudioOffloadCodecCapabilities(const SessionType& session_type);
+  static std::vector<CodecInfo> GetLeAudioOffloadCodecInfo(
+      const SessionType& session_type);
+
+  static std::vector<LeAudioAseConfigurationSetting>
+  GetLeAudioAseConfigurationSettings();
 
  private:
   template <typename T>
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
index 0bcafa3..67ba93c 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
@@ -20,6 +20,7 @@
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android/binder_manager.h>
+#include <com_android_btaudio_hal_flags.h>
 #include <hardware/audio.h>
 
 #include "BluetoothAudioSession.h"
@@ -36,6 +37,14 @@
 static constexpr int kWritePollMs = 1;  // polled non-blocking interval
 static constexpr int kReadPollMs = 1;   // polled non-blocking interval
 
+static std::string toString(const std::vector<LatencyMode>& latencies) {
+  std::stringstream latencyModesStr;
+  for (LatencyMode mode : latencies) {
+    latencyModesStr << " " << toString(mode);
+  }
+  return latencyModesStr.str();
+}
+
 BluetoothAudioSession::BluetoothAudioSession(const SessionType& session_type)
     : session_type_(session_type), stack_iface_(nullptr), data_mq_(nullptr) {}
 
@@ -65,6 +74,7 @@
     stack_iface_ = stack_iface;
     latency_modes_ = latency_modes;
     LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+              << " - All LatencyModes=" << toString(latency_modes)
               << ", AudioConfiguration=" << audio_config.toString();
     ReportSessionStatus();
   }
@@ -95,6 +105,8 @@
       case SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
       case SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH:
         return AudioConfiguration(CodecConfiguration{});
+      case SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH:
+        return AudioConfiguration(HfpConfiguration{});
       case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
       case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH:
         return AudioConfiguration(LeAudioConfiguration{});
@@ -154,6 +166,7 @@
        session_type_ ==
            SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
        session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH ||
+       session_type_ == SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH ||
        (data_mq_ != nullptr && data_mq_->isValid()));
   return stack_iface_ != nullptr && is_mq_valid && audio_config_ != nullptr;
 }
@@ -275,6 +288,8 @@
   bool is_software_session =
       (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
        session_type_ == SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH ||
+       session_type_ == SessionType::HFP_SOFTWARE_ENCODING_DATAPATH ||
+       session_type_ == SessionType::HFP_SOFTWARE_DECODING_DATAPATH ||
        session_type_ == SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH ||
        session_type_ == SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH ||
        session_type_ ==
@@ -283,6 +298,8 @@
   bool is_offload_a2dp_session =
       (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
        session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH);
+  bool is_offload_hfp_session =
+      session_type_ == SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH;
   bool is_offload_le_audio_unicast_session =
       (session_type_ ==
            SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
@@ -297,7 +314,11 @@
        audio_config_tag == AudioConfiguration::pcmConfig);
   bool is_a2dp_offload_audio_config =
       (is_offload_a2dp_session &&
-       audio_config_tag == AudioConfiguration::a2dpConfig);
+       (audio_config_tag == AudioConfiguration::a2dp ||
+        audio_config_tag == AudioConfiguration::a2dpConfig));
+  bool is_hfp_offload_audio_config =
+      (is_offload_hfp_session &&
+       audio_config_tag == AudioConfiguration::hfpConfig);
   bool is_le_audio_offload_unicast_audio_config =
       (is_offload_le_audio_unicast_session &&
        audio_config_tag == AudioConfiguration::leAudioConfig);
@@ -305,6 +326,7 @@
       (is_offload_le_audio_broadcast_session &&
        audio_config_tag == AudioConfiguration::leAudioBroadcastConfig);
   if (!is_software_audio_config && !is_a2dp_offload_audio_config &&
+      !is_hfp_offload_audio_config &&
       !is_le_audio_offload_unicast_audio_config &&
       !is_le_audio_offload_broadcast_audio_config) {
     return false;
@@ -439,6 +461,9 @@
 }
 
 void BluetoothAudioSession::ReportLowLatencyModeAllowedChanged(bool allowed) {
+  if (session_type_ != SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+    return;
+  }
   std::lock_guard<std::recursive_mutex> guard(mutex_);
   low_latency_allowed_ = allowed;
   // TODO(b/294498919): Remove this after there is API to update latency mode
@@ -475,14 +500,12 @@
                << " has NO session";
     return false;
   }
-  bool retval = false;
-
   if (!stack_iface_->getPresentationPosition(&presentation_position).isOk()) {
     LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
                  << toString(session_type_) << " failed";
     return false;
   }
-  return retval;
+  return true;
 }
 
 void BluetoothAudioSession::UpdateSourceMetadata(
@@ -588,6 +611,38 @@
                << " has NO session";
     return std::vector<LatencyMode>();
   }
+
+  if (com::android::btaudio::hal::flags::dsa_lea()) {
+    std::vector<LatencyMode> supported_latency_modes;
+    if (session_type_ ==
+        SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+      for (LatencyMode mode : latency_modes_) {
+        if (mode == LatencyMode::LOW_LATENCY) {
+          // LOW_LATENCY is not supported for LE_HARDWARE_OFFLOAD_ENC sessions
+          continue;
+        }
+        supported_latency_modes.push_back(mode);
+      }
+    } else {
+      for (LatencyMode mode : latency_modes_) {
+        if (!low_latency_allowed_ && mode == LatencyMode::LOW_LATENCY) {
+          // ignore LOW_LATENCY mode if Bluetooth stack doesn't allow
+          continue;
+        }
+        if (mode == LatencyMode::DYNAMIC_SPATIAL_AUDIO_SOFTWARE ||
+            mode == LatencyMode::DYNAMIC_SPATIAL_AUDIO_HARDWARE) {
+          // DSA_SW and DSA_HW only supported for LE_HARDWARE_OFFLOAD_ENC
+          // sessions
+          continue;
+        }
+        supported_latency_modes.push_back(mode);
+      }
+    }
+    LOG(DEBUG) << __func__ << " - Supported LatencyMode="
+               << toString(supported_latency_modes);
+    return supported_latency_modes;
+  }
+
   if (low_latency_allowed_) return latency_modes_;
   std::vector<LatencyMode> modes;
   for (LatencyMode mode : latency_modes_) {
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
index 7ae0353..5263222 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
@@ -84,6 +84,8 @@
       case SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
       case SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH:
         return AudioConfiguration(CodecConfiguration{});
+      case SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH:
+        return AudioConfiguration(HfpConfiguration{});
       case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
       case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH:
         return AudioConfiguration(LeAudioConfiguration{});
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp
new file mode 100644
index 0000000..5429a8f
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp
@@ -0,0 +1,760 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define STREAM_TO_UINT8(u8, p) \
+  {                            \
+    (u8) = (uint8_t)(*(p));    \
+    (p) += 1;                  \
+  }
+#define STREAM_TO_UINT16(u16, p)                                  \
+  {                                                               \
+    (u16) = ((uint16_t)(*(p)) + (((uint16_t)(*((p) + 1))) << 8)); \
+    (p) += 2;                                                     \
+  }
+#define STREAM_TO_UINT32(u32, p)                                      \
+  {                                                                   \
+    (u32) = (((uint32_t)(*(p))) + ((((uint32_t)(*((p) + 1)))) << 8) + \
+             ((((uint32_t)(*((p) + 2)))) << 16) +                     \
+             ((((uint32_t)(*((p) + 3)))) << 24));                     \
+    (p) += 4;                                                         \
+  }
+
+#define LOG_TAG "BTAudioAseConfigAidl"
+
+#include "BluetoothLeAudioAseConfigurationSettingProvider.h"
+
+#include <aidl/android/hardware/bluetooth/audio/AudioConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/AudioContext.h>
+#include <aidl/android/hardware/bluetooth/audio/BluetoothAudioStatus.h>
+#include <aidl/android/hardware/bluetooth/audio/CodecId.h>
+#include <aidl/android/hardware/bluetooth/audio/CodecSpecificCapabilitiesLtv.h>
+#include <aidl/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.h>
+#include <aidl/android/hardware/bluetooth/audio/ConfigurationFlags.h>
+#include <aidl/android/hardware/bluetooth/audio/LeAudioAseConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/Phy.h>
+#include <android-base/logging.h>
+
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+/* Internal structure definition */
+std::map<std::string,
+         std::tuple<std::vector<std::optional<AseDirectionConfiguration>>,
+                    std::vector<std::optional<AseDirectionConfiguration>>,
+                    ConfigurationFlags>>
+    configurations_;
+
+std::vector<LeAudioAseConfigurationSetting> ase_configuration_settings_;
+
+constexpr uint8_t kIsoDataPathHci = 0x00;
+constexpr uint8_t kIsoDataPathPlatformDefault = 0x01;
+constexpr uint8_t kIsoDataPathDisabled = 0xFF;
+
+constexpr uint8_t kLeAudioDirectionSink = 0x01;
+constexpr uint8_t kLeAudioDirectionSource = 0x02;
+constexpr uint8_t kLeAudioDirectionBoth =
+    kLeAudioDirectionSink | kLeAudioDirectionSource;
+
+/* Sampling Frequencies */
+constexpr uint8_t kLeAudioSamplingFreq8000Hz = 0x01;
+constexpr uint8_t kLeAudioSamplingFreq11025Hz = 0x02;
+constexpr uint8_t kLeAudioSamplingFreq16000Hz = 0x03;
+constexpr uint8_t kLeAudioSamplingFreq22050Hz = 0x04;
+constexpr uint8_t kLeAudioSamplingFreq24000Hz = 0x05;
+constexpr uint8_t kLeAudioSamplingFreq32000Hz = 0x06;
+constexpr uint8_t kLeAudioSamplingFreq44100Hz = 0x07;
+constexpr uint8_t kLeAudioSamplingFreq48000Hz = 0x08;
+constexpr uint8_t kLeAudioSamplingFreq88200Hz = 0x09;
+constexpr uint8_t kLeAudioSamplingFreq96000Hz = 0x0A;
+constexpr uint8_t kLeAudioSamplingFreq176400Hz = 0x0B;
+constexpr uint8_t kLeAudioSamplingFreq192000Hz = 0x0C;
+constexpr uint8_t kLeAudioSamplingFreq384000Hz = 0x0D;
+
+/* Frame Durations */
+constexpr uint8_t kLeAudioCodecFrameDur7500us = 0x00;
+constexpr uint8_t kLeAudioCodecFrameDur10000us = 0x01;
+
+/* Audio Allocations */
+constexpr uint32_t kLeAudioLocationNotAllowed = 0x00000000;
+constexpr uint32_t kLeAudioLocationFrontLeft = 0x00000001;
+constexpr uint32_t kLeAudioLocationFrontRight = 0x00000002;
+constexpr uint32_t kLeAudioLocationFrontCenter = 0x00000004;
+constexpr uint32_t kLeAudioLocationLowFreqEffects1 = 0x00000008;
+constexpr uint32_t kLeAudioLocationBackLeft = 0x00000010;
+constexpr uint32_t kLeAudioLocationBackRight = 0x00000020;
+constexpr uint32_t kLeAudioLocationFrontLeftOfCenter = 0x00000040;
+constexpr uint32_t kLeAudioLocationFrontRightOfCenter = 0x00000080;
+constexpr uint32_t kLeAudioLocationBackCenter = 0x00000100;
+constexpr uint32_t kLeAudioLocationLowFreqEffects2 = 0x00000200;
+constexpr uint32_t kLeAudioLocationSideLeft = 0x00000400;
+constexpr uint32_t kLeAudioLocationSideRight = 0x00000800;
+constexpr uint32_t kLeAudioLocationTopFrontLeft = 0x00001000;
+constexpr uint32_t kLeAudioLocationTopFrontRight = 0x00002000;
+constexpr uint32_t kLeAudioLocationTopFrontCenter = 0x00004000;
+constexpr uint32_t kLeAudioLocationTopCenter = 0x00008000;
+constexpr uint32_t kLeAudioLocationTopBackLeft = 0x00010000;
+constexpr uint32_t kLeAudioLocationTopBackRight = 0x00020000;
+constexpr uint32_t kLeAudioLocationTopSideLeft = 0x00040000;
+constexpr uint32_t kLeAudioLocationTopSideRight = 0x00080000;
+constexpr uint32_t kLeAudioLocationTopBackCenter = 0x00100000;
+constexpr uint32_t kLeAudioLocationBottomFrontCenter = 0x00200000;
+constexpr uint32_t kLeAudioLocationBottomFrontLeft = 0x00400000;
+constexpr uint32_t kLeAudioLocationBottomFrontRight = 0x00800000;
+constexpr uint32_t kLeAudioLocationFrontLeftWide = 0x01000000;
+constexpr uint32_t kLeAudioLocationFrontRightWide = 0x02000000;
+constexpr uint32_t kLeAudioLocationLeftSurround = 0x04000000;
+constexpr uint32_t kLeAudioLocationRightSurround = 0x08000000;
+
+constexpr uint32_t kLeAudioLocationAnyLeft =
+    kLeAudioLocationFrontLeft | kLeAudioLocationBackLeft |
+    kLeAudioLocationFrontLeftOfCenter | kLeAudioLocationSideLeft |
+    kLeAudioLocationTopFrontLeft | kLeAudioLocationTopBackLeft |
+    kLeAudioLocationTopSideLeft | kLeAudioLocationBottomFrontLeft |
+    kLeAudioLocationFrontLeftWide | kLeAudioLocationLeftSurround;
+
+constexpr uint32_t kLeAudioLocationAnyRight =
+    kLeAudioLocationFrontRight | kLeAudioLocationBackRight |
+    kLeAudioLocationFrontRightOfCenter | kLeAudioLocationSideRight |
+    kLeAudioLocationTopFrontRight | kLeAudioLocationTopBackRight |
+    kLeAudioLocationTopSideRight | kLeAudioLocationBottomFrontRight |
+    kLeAudioLocationFrontRightWide | kLeAudioLocationRightSurround;
+
+constexpr uint32_t kLeAudioLocationStereo =
+    kLeAudioLocationFrontLeft | kLeAudioLocationFrontRight;
+
+/* Octets Per Frame */
+constexpr uint16_t kLeAudioCodecFrameLen30 = 30;
+constexpr uint16_t kLeAudioCodecFrameLen40 = 40;
+constexpr uint16_t kLeAudioCodecFrameLen60 = 60;
+constexpr uint16_t kLeAudioCodecFrameLen80 = 80;
+constexpr uint16_t kLeAudioCodecFrameLen100 = 100;
+constexpr uint16_t kLeAudioCodecFrameLen120 = 120;
+
+/* Helper map for matching various sampling frequency notations */
+const std::map<uint8_t, CodecSpecificConfigurationLtv::SamplingFrequency>
+    sampling_freq_map = {
+        {kLeAudioSamplingFreq8000Hz,
+         CodecSpecificConfigurationLtv::SamplingFrequency::HZ8000},
+        {kLeAudioSamplingFreq16000Hz,
+         CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000},
+        {kLeAudioSamplingFreq24000Hz,
+         CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000},
+        {kLeAudioSamplingFreq32000Hz,
+         CodecSpecificConfigurationLtv::SamplingFrequency::HZ32000},
+        {kLeAudioSamplingFreq44100Hz,
+         CodecSpecificConfigurationLtv::SamplingFrequency::HZ44100},
+        {kLeAudioSamplingFreq48000Hz,
+         CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000}};
+
+/* Helper map for matching various frame durations notations */
+const std::map<uint8_t, CodecSpecificConfigurationLtv::FrameDuration>
+    frame_duration_map = {
+        {kLeAudioCodecFrameDur7500us,
+         CodecSpecificConfigurationLtv::FrameDuration::US7500},
+        {kLeAudioCodecFrameDur10000us,
+         CodecSpecificConfigurationLtv::FrameDuration::US10000}};
+
+/* Helper map for matching various audio channel allocation notations */
+std::map<uint32_t, uint32_t> audio_channel_allocation_map = {
+    {kLeAudioLocationNotAllowed,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::NOT_ALLOWED},
+    {kLeAudioLocationFrontLeft,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT},
+    {kLeAudioLocationFrontRight,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT},
+    {kLeAudioLocationFrontCenter,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_CENTER},
+    {kLeAudioLocationLowFreqEffects1,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::
+         LOW_FREQUENCY_EFFECTS_1},
+    {kLeAudioLocationBackLeft,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::BACK_LEFT},
+    {kLeAudioLocationBackRight,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::BACK_RIGHT},
+    {kLeAudioLocationFrontLeftOfCenter,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::
+         FRONT_LEFT_OF_CENTER},
+    {kLeAudioLocationFrontRightOfCenter,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::
+         FRONT_RIGHT_OF_CENTER},
+    {kLeAudioLocationBackCenter,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::BACK_CENTER},
+    {kLeAudioLocationLowFreqEffects2,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::
+         LOW_FREQUENCY_EFFECTS_2},
+    {kLeAudioLocationSideLeft,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::SIDE_LEFT},
+    {kLeAudioLocationSideRight,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::SIDE_RIGHT},
+    {kLeAudioLocationTopFrontLeft,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_FRONT_LEFT},
+    {kLeAudioLocationTopFrontRight,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_FRONT_RIGHT},
+    {kLeAudioLocationTopFrontCenter,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_FRONT_CENTER},
+    {kLeAudioLocationTopCenter,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_CENTER},
+    {kLeAudioLocationTopBackLeft,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_BACK_LEFT},
+    {kLeAudioLocationTopBackRight,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_BACK_RIGHT},
+    {kLeAudioLocationTopSideLeft,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_SIDE_LEFT},
+    {kLeAudioLocationTopSideRight,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_SIDE_RIGHT},
+    {kLeAudioLocationTopBackCenter,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_BACK_CENTER},
+    {kLeAudioLocationBottomFrontCenter,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::
+         BOTTOM_FRONT_CENTER},
+    {kLeAudioLocationBottomFrontLeft,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::BOTTOM_FRONT_LEFT},
+    {kLeAudioLocationBottomFrontRight,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::BOTTOM_FRONT_RIGHT},
+    {kLeAudioLocationFrontLeftWide,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT_WIDE},
+    {kLeAudioLocationFrontRightWide,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT_WIDE},
+    {kLeAudioLocationLeftSurround,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::LEFT_SURROUND},
+    {kLeAudioLocationRightSurround,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::RIGHT_SURROUND},
+};
+
+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"}};
+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"}};
+
+/* Implementation */
+
+std::vector<LeAudioAseConfigurationSetting>
+AudioSetConfigurationProviderJson::GetLeAudioAseConfigurationSettings() {
+  AudioSetConfigurationProviderJson::LoadAudioSetConfigurationProviderJson();
+  return ase_configuration_settings_;
+}
+
+void AudioSetConfigurationProviderJson::
+    LoadAudioSetConfigurationProviderJson() {
+  if (configurations_.empty() || ase_configuration_settings_.empty()) {
+    ase_configuration_settings_.clear();
+    configurations_.clear();
+    auto loaded = LoadContent(kLeAudioSetConfigs, kLeAudioSetScenarios,
+                              CodecLocation::HOST);
+    if (!loaded)
+      LOG(ERROR) << ": Unable to load le audio set configuration files.";
+  } else
+    LOG(INFO) << ": Reusing loaded le audio set configuration";
+}
+
+const le_audio::CodecSpecificConfiguration*
+AudioSetConfigurationProviderJson::LookupCodecSpecificParam(
+    const flatbuffers::Vector<flatbuffers::Offset<
+        le_audio::CodecSpecificConfiguration>>* flat_codec_specific_params,
+    le_audio::CodecSpecificLtvGenericTypes type) {
+  auto it = std::find_if(
+      flat_codec_specific_params->cbegin(), flat_codec_specific_params->cend(),
+      [&type](const auto& csc) { return (csc->type() == type); });
+  return (it != flat_codec_specific_params->cend()) ? *it : nullptr;
+}
+
+void AudioSetConfigurationProviderJson::populateAudioChannelAllocation(
+    CodecSpecificConfigurationLtv::AudioChannelAllocation&
+        audio_channel_allocation,
+    uint32_t audio_location) {
+  audio_channel_allocation.bitmask = 0;
+  for (auto [allocation, bitmask] : audio_channel_allocation_map) {
+    if (audio_location & allocation)
+      audio_channel_allocation.bitmask |= bitmask;
+  }
+}
+
+void AudioSetConfigurationProviderJson::populateConfigurationData(
+    LeAudioAseConfiguration& ase,
+    const flatbuffers::Vector<
+        flatbuffers::Offset<le_audio::CodecSpecificConfiguration>>*
+        flat_codec_specific_params) {
+  uint8_t sampling_frequency = 0;
+  uint8_t frame_duration = 0;
+  uint32_t audio_channel_allocation = 0;
+  uint16_t octets_per_codec_frame = 0;
+  uint8_t codec_frames_blocks_per_sdu = 0;
+
+  auto param = LookupCodecSpecificParam(
+      flat_codec_specific_params,
+      le_audio::CodecSpecificLtvGenericTypes_SUPPORTED_SAMPLING_FREQUENCY);
+  if (param) {
+    auto ptr = param->compound_value()->value()->data();
+    STREAM_TO_UINT8(sampling_frequency, ptr);
+  }
+
+  param = LookupCodecSpecificParam(
+      flat_codec_specific_params,
+      le_audio::CodecSpecificLtvGenericTypes_SUPPORTED_FRAME_DURATION);
+  if (param) {
+    auto ptr = param->compound_value()->value()->data();
+    STREAM_TO_UINT8(frame_duration, ptr);
+  }
+
+  param = LookupCodecSpecificParam(
+      flat_codec_specific_params,
+      le_audio::
+          CodecSpecificLtvGenericTypes_SUPPORTED_AUDIO_CHANNEL_ALLOCATION);
+  if (param) {
+    auto ptr = param->compound_value()->value()->data();
+    STREAM_TO_UINT32(audio_channel_allocation, ptr);
+  }
+
+  param = LookupCodecSpecificParam(
+      flat_codec_specific_params,
+      le_audio::CodecSpecificLtvGenericTypes_SUPPORTED_OCTETS_PER_CODEC_FRAME);
+  if (param) {
+    auto ptr = param->compound_value()->value()->data();
+    STREAM_TO_UINT16(octets_per_codec_frame, ptr);
+  }
+
+  param = LookupCodecSpecificParam(
+      flat_codec_specific_params,
+      le_audio::
+          CodecSpecificLtvGenericTypes_SUPPORTED_CODEC_FRAME_BLOCKS_PER_SDU);
+  if (param) {
+    auto ptr = param->compound_value()->value()->data();
+    STREAM_TO_UINT8(codec_frames_blocks_per_sdu, ptr);
+  }
+
+  // Make the correct value
+  ase.codecConfiguration = std::vector<CodecSpecificConfigurationLtv>();
+
+  auto sampling_freq_it = sampling_freq_map.find(sampling_frequency);
+  if (sampling_freq_it != sampling_freq_map.end())
+    ase.codecConfiguration.push_back(sampling_freq_it->second);
+  auto frame_duration_it = frame_duration_map.find(frame_duration);
+  if (frame_duration_it != frame_duration_map.end())
+    ase.codecConfiguration.push_back(frame_duration_it->second);
+
+  CodecSpecificConfigurationLtv::AudioChannelAllocation channel_allocation;
+  populateAudioChannelAllocation(channel_allocation, audio_channel_allocation);
+  ase.codecConfiguration.push_back(channel_allocation);
+
+  auto octet_structure = CodecSpecificConfigurationLtv::OctetsPerCodecFrame();
+  octet_structure.value = octets_per_codec_frame;
+  ase.codecConfiguration.push_back(octet_structure);
+
+  auto frame_sdu_structure =
+      CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU();
+  frame_sdu_structure.value = codec_frames_blocks_per_sdu;
+  ase.codecConfiguration.push_back(frame_sdu_structure);
+  // TODO: Channel count
+}
+
+void AudioSetConfigurationProviderJson::populateAseConfiguration(
+    LeAudioAseConfiguration& ase,
+    const le_audio::AudioSetSubConfiguration* flat_subconfig,
+    const le_audio::QosConfiguration* qos_cfg) {
+  // Target latency
+  switch (qos_cfg->target_latency()) {
+    case le_audio::AudioSetConfigurationTargetLatency::
+        AudioSetConfigurationTargetLatency_BALANCED_RELIABILITY:
+      ase.targetLatency =
+          LeAudioAseConfiguration::TargetLatency::BALANCED_LATENCY_RELIABILITY;
+      break;
+    case le_audio::AudioSetConfigurationTargetLatency::
+        AudioSetConfigurationTargetLatency_HIGH_RELIABILITY:
+      ase.targetLatency =
+          LeAudioAseConfiguration::TargetLatency::HIGHER_RELIABILITY;
+      break;
+    case le_audio::AudioSetConfigurationTargetLatency::
+        AudioSetConfigurationTargetLatency_LOW:
+      ase.targetLatency = LeAudioAseConfiguration::TargetLatency::LOWER;
+      break;
+    default:
+      ase.targetLatency = LeAudioAseConfiguration::TargetLatency::UNDEFINED;
+      break;
+  };
+
+  ase.targetPhy = Phy::TWO_M;
+  // Making CodecId
+  if (flat_subconfig->codec_id()->coding_format() ==
+      (uint8_t)CodecId::Core::LC3) {
+    ase.codecId = CodecId::Core::LC3;
+  } else {
+    auto vendorC = CodecId::Vendor();
+    vendorC.codecId = flat_subconfig->codec_id()->vendor_codec_id();
+    vendorC.id = flat_subconfig->codec_id()->vendor_company_id();
+    ase.codecId = vendorC;
+  }
+  // Codec configuration data
+  populateConfigurationData(ase, flat_subconfig->codec_configuration());
+}
+
+void AudioSetConfigurationProviderJson::populateAseQosConfiguration(
+    LeAudioAseQosConfiguration& qos,
+    const le_audio::QosConfiguration* qos_cfg) {
+  qos.maxTransportLatencyMs = qos_cfg->max_transport_latency();
+  qos.retransmissionNum = qos_cfg->retransmission_number();
+}
+
+// Parse into AseDirectionConfiguration
+AseDirectionConfiguration
+AudioSetConfigurationProviderJson::SetConfigurationFromFlatSubconfig(
+    const le_audio::AudioSetSubConfiguration* flat_subconfig,
+    const le_audio::QosConfiguration* qos_cfg, CodecLocation location) {
+  AseDirectionConfiguration direction_conf;
+
+  LeAudioAseConfiguration ase;
+  LeAudioAseQosConfiguration qos;
+  LeAudioDataPathConfiguration path;
+
+  // Translate into LeAudioAseConfiguration
+  populateAseConfiguration(ase, flat_subconfig, qos_cfg);
+
+  // Translate into LeAudioAseQosConfiguration
+  populateAseQosConfiguration(qos, qos_cfg);
+
+  // Translate location to data path id
+  switch (location) {
+    case CodecLocation::ADSP:
+      path.isoDataPathConfiguration.isTransparent = true;
+      path.dataPathId = kIsoDataPathPlatformDefault;
+      break;
+    case CodecLocation::HOST:
+      path.isoDataPathConfiguration.isTransparent = true;
+      path.dataPathId = kIsoDataPathHci;
+      break;
+    case CodecLocation::CONTROLLER:
+      path.isoDataPathConfiguration.isTransparent = false;
+      path.dataPathId = kIsoDataPathPlatformDefault;
+      break;
+  }
+
+  direction_conf.aseConfiguration = ase;
+  direction_conf.qosConfiguration = qos;
+  direction_conf.dataPathConfiguration = path;
+
+  return direction_conf;
+}
+
+// Parse into AseDirectionConfiguration and the ConfigurationFlags
+// and put them in the given list.
+void AudioSetConfigurationProviderJson::processSubconfig(
+    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));
+}
+
+void AudioSetConfigurationProviderJson::PopulateAseConfigurationFromFlat(
+    const le_audio::AudioSetConfiguration* flat_cfg,
+    std::vector<const le_audio::CodecConfiguration*>* codec_cfgs,
+    std::vector<const le_audio::QosConfiguration*>* qos_cfgs,
+    CodecLocation location,
+    std::vector<std::optional<AseDirectionConfiguration>>&
+        sourceAseConfiguration,
+    std::vector<std::optional<AseDirectionConfiguration>>& sinkAseConfiguration,
+    ConfigurationFlags& /*configurationFlags*/) {
+  if (flat_cfg == nullptr) {
+    LOG(ERROR) << "flat_cfg cannot be null";
+    return;
+  }
+  std::string codec_config_key = flat_cfg->codec_config_name()->str();
+  auto* qos_config_key_array = flat_cfg->qos_config_name();
+
+  constexpr std::string_view default_qos = "QoS_Config_Balanced_Reliability";
+
+  std::string qos_sink_key(default_qos);
+  std::string qos_source_key(default_qos);
+
+  /* We expect maximum two QoS settings. First for Sink and second for Source
+   */
+  if (qos_config_key_array->size() > 0) {
+    qos_sink_key = qos_config_key_array->Get(0)->str();
+    if (qos_config_key_array->size() > 1) {
+      qos_source_key = qos_config_key_array->Get(1)->str();
+    } else {
+      qos_source_key = qos_sink_key;
+    }
+  }
+
+  LOG(INFO) << "Audio set config " << flat_cfg->name()->c_str()
+            << ": codec config " << codec_config_key.c_str() << ", qos_sink "
+            << qos_sink_key.c_str() << ", qos_source "
+            << qos_source_key.c_str();
+
+  // Find the first qos config that match the name
+  const le_audio::QosConfiguration* qos_sink_cfg = nullptr;
+  for (auto i = qos_cfgs->begin(); i != qos_cfgs->end(); ++i) {
+    if ((*i)->name()->str() == qos_sink_key) {
+      qos_sink_cfg = *i;
+      break;
+    }
+  }
+
+  const le_audio::QosConfiguration* qos_source_cfg = nullptr;
+  for (auto i = qos_cfgs->begin(); i != qos_cfgs->end(); ++i) {
+    if ((*i)->name()->str() == qos_source_key) {
+      qos_source_cfg = *i;
+      break;
+    }
+  }
+
+  // First codec_cfg with the same name
+  const le_audio::CodecConfiguration* codec_cfg = nullptr;
+  for (auto i = codec_cfgs->begin(); i != codec_cfgs->end(); ++i) {
+    if ((*i)->name()->str() == codec_config_key) {
+      codec_cfg = *i;
+      break;
+    }
+  }
+
+  // Process each subconfig and put it into the correct list
+  if (codec_cfg != nullptr && codec_cfg->subconfigurations()) {
+    /* Load subconfigurations */
+    for (auto subconfig : *codec_cfg->subconfigurations()) {
+      if (subconfig->direction() == kLeAudioDirectionSink) {
+        processSubconfig(subconfig, qos_sink_cfg, sinkAseConfiguration,
+                         location);
+      } else {
+        processSubconfig(subconfig, qos_source_cfg, sourceAseConfiguration,
+                         location);
+      }
+    }
+  } else {
+    if (codec_cfg == nullptr) {
+      LOG(ERROR) << "No codec config matching key " << codec_config_key.c_str()
+                 << " found";
+    } else {
+      LOG(ERROR) << "Configuration '" << flat_cfg->name()->c_str()
+                 << "' has no valid subconfigurations.";
+    }
+  }
+
+  // TODO: Populate information for ConfigurationFlags
+}
+
+bool AudioSetConfigurationProviderJson::LoadConfigurationsFromFiles(
+    const char* schema_file, const char* content_file, CodecLocation location) {
+  flatbuffers::Parser configurations_parser_;
+  std::string configurations_schema_binary_content;
+  bool ok = flatbuffers::LoadFile(schema_file, true,
+                                  &configurations_schema_binary_content);
+  LOG(INFO) << __func__ << ": Loading file " << schema_file;
+  if (!ok) return ok;
+
+  /* Load the binary schema */
+  ok = configurations_parser_.Deserialize(
+      (uint8_t*)configurations_schema_binary_content.c_str(),
+      configurations_schema_binary_content.length());
+  if (!ok) return ok;
+
+  /* Load the content from JSON */
+  std::string configurations_json_content;
+  LOG(INFO) << __func__ << ": Loading file " << content_file;
+  ok = flatbuffers::LoadFile(content_file, false, &configurations_json_content);
+  if (!ok) return ok;
+
+  /* Parse */
+  LOG(INFO) << __func__ << ": Parse JSON content";
+  ok = configurations_parser_.Parse(configurations_json_content.c_str());
+  if (!ok) return ok;
+
+  /* Import from flatbuffers */
+  LOG(INFO) << __func__ << ": Build flat buffer structure";
+  auto configurations_root = le_audio::GetAudioSetConfigurations(
+      configurations_parser_.builder_.GetBufferPointer());
+  if (!configurations_root) return false;
+
+  auto flat_qos_configs = configurations_root->qos_configurations();
+  if ((flat_qos_configs == nullptr) || (flat_qos_configs->size() == 0))
+    return false;
+
+  LOG(DEBUG) << ": Updating " << flat_qos_configs->size()
+             << " qos config entries.";
+  std::vector<const le_audio::QosConfiguration*> qos_cfgs;
+  for (auto const& flat_qos_cfg : *flat_qos_configs) {
+    qos_cfgs.push_back(flat_qos_cfg);
+  }
+
+  auto flat_codec_configs = configurations_root->codec_configurations();
+  if ((flat_codec_configs == nullptr) || (flat_codec_configs->size() == 0))
+    return false;
+
+  LOG(DEBUG) << ": Updating " << flat_codec_configs->size()
+             << " codec config entries.";
+  std::vector<const le_audio::CodecConfiguration*> codec_cfgs;
+  for (auto const& flat_codec_cfg : *flat_codec_configs) {
+    codec_cfgs.push_back(flat_codec_cfg);
+  }
+
+  auto flat_configs = configurations_root->configurations();
+  if ((flat_configs == nullptr) || (flat_configs->size() == 0)) return false;
+
+  LOG(DEBUG) << ": Updating " << flat_configs->size() << " config entries.";
+  for (auto const& flat_cfg : *flat_configs) {
+    // Create 3 vector to use
+    std::vector<std::optional<AseDirectionConfiguration>>
+        sourceAseConfiguration;
+    std::vector<std::optional<AseDirectionConfiguration>> sinkAseConfiguration;
+    ConfigurationFlags configurationFlags;
+    PopulateAseConfigurationFromFlat(flat_cfg, &codec_cfgs, &qos_cfgs, location,
+                                     sourceAseConfiguration,
+                                     sinkAseConfiguration, configurationFlags);
+    if (sourceAseConfiguration.empty() && sinkAseConfiguration.empty())
+      continue;
+    configurations_[flat_cfg->name()->str()] = std::make_tuple(
+        sourceAseConfiguration, sinkAseConfiguration, configurationFlags);
+  }
+
+  return true;
+}
+
+bool AudioSetConfigurationProviderJson::LoadScenariosFromFiles(
+    const char* schema_file, const char* content_file) {
+  flatbuffers::Parser scenarios_parser_;
+  std::string scenarios_schema_binary_content;
+  bool ok = flatbuffers::LoadFile(schema_file, true,
+                                  &scenarios_schema_binary_content);
+  LOG(INFO) << __func__ << ": Loading file " << schema_file;
+  if (!ok) return ok;
+
+  /* Load the binary schema */
+  ok = scenarios_parser_.Deserialize(
+      (uint8_t*)scenarios_schema_binary_content.c_str(),
+      scenarios_schema_binary_content.length());
+  if (!ok) return ok;
+
+  /* Load the content from JSON */
+  LOG(INFO) << __func__ << ": Loading file " << content_file;
+  std::string scenarios_json_content;
+  ok = flatbuffers::LoadFile(content_file, false, &scenarios_json_content);
+  if (!ok) return ok;
+
+  /* Parse */
+  LOG(INFO) << __func__ << ": Parse json content";
+  ok = scenarios_parser_.Parse(scenarios_json_content.c_str());
+  if (!ok) return ok;
+
+  /* Import from flatbuffers */
+  LOG(INFO) << __func__ << ": Build flat buffer structure";
+  auto scenarios_root = le_audio::GetAudioSetScenarios(
+      scenarios_parser_.builder_.GetBufferPointer());
+  if (!scenarios_root) return false;
+
+  auto flat_scenarios = scenarios_root->scenarios();
+  if ((flat_scenarios == nullptr) || (flat_scenarios->size() == 0))
+    return false;
+
+  LOG(INFO) << __func__ << ": Turn flat buffer into structure";
+  AudioContext media_context = AudioContext();
+  media_context.bitmask =
+      (AudioContext::ALERTS | AudioContext::INSTRUCTIONAL |
+       AudioContext::NOTIFICATIONS | AudioContext::EMERGENCY_ALARM |
+       AudioContext::UNSPECIFIED | AudioContext::MEDIA);
+
+  AudioContext conversational_context = AudioContext();
+  conversational_context.bitmask =
+      (AudioContext::RINGTONE_ALERTS | AudioContext::CONVERSATIONAL);
+
+  AudioContext live_context = AudioContext();
+  live_context.bitmask = AudioContext::LIVE_AUDIO;
+
+  AudioContext game_context = AudioContext();
+  game_context.bitmask = AudioContext::GAME;
+
+  AudioContext voice_assistants_context = AudioContext();
+  voice_assistants_context.bitmask = AudioContext::VOICE_ASSISTANTS;
+
+  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;
+    if (scenario_name == "Media")
+      context = AudioContext(media_context);
+    else if (scenario_name == "Conversational")
+      context = AudioContext(conversational_context);
+    else if (scenario_name == "Live")
+      context = AudioContext(live_context);
+    else if (scenario_name == "Game")
+      context = AudioContext(game_context);
+    else if (scenario_name == "VoiceAssistants")
+      context = AudioContext(voice_assistants_context);
+
+    for (auto it = scenario->configurations()->begin();
+         it != scenario->configurations()->end(); ++it) {
+      auto config_name = it->str();
+      auto configuration = configurations_.find(config_name);
+      if (configuration == configurations_.end()) continue;
+      LOG(DEBUG) << "Getting configuration with name: " << config_name;
+      auto [source, sink, flags] = configuration->second;
+      // Each configuration will create a LeAudioAseConfigurationSetting
+      // with the same {context, packing}
+      // and different data
+      LeAudioAseConfigurationSetting setting;
+      setting.audioContext = context;
+      // TODO: Packing
+      setting.sourceAseConfiguration = source;
+      setting.sinkAseConfiguration = sink;
+      setting.flags = flags;
+      // Add to list of setting
+      LOG(DEBUG) << "Pushing configuration to list: " << config_name;
+      ase_configuration_settings_.push_back(setting);
+    }
+  }
+
+  return true;
+}
+
+bool AudioSetConfigurationProviderJson::LoadContent(
+    std::vector<std::pair<const char* /*schema*/, const char* /*content*/>>
+        config_files,
+    std::vector<std::pair<const char* /*schema*/, const char* /*content*/>>
+        scenario_files,
+    CodecLocation location) {
+  for (auto [schema, content] : config_files) {
+    if (!LoadConfigurationsFromFiles(schema, content, location)) return false;
+  }
+
+  for (auto [schema, content] : scenario_files) {
+    if (!LoadScenariosFromFiles(schema, content)) return false;
+  }
+  return true;
+}
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.h b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.h
new file mode 100644
index 0000000..ce91fca
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.h
@@ -0,0 +1,125 @@
+
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/bluetooth/audio/IBluetoothAudioProvider.h>
+
+#include <map>
+#include <mutex>
+#include <optional>
+#include <string>
+#include <string_view>
+#include <tuple>
+
+#include "audio_set_configurations_generated.h"
+#include "audio_set_scenarios_generated.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+using LeAudioAseConfigurationSetting =
+    IBluetoothAudioProvider::LeAudioAseConfigurationSetting;
+using AseDirectionConfiguration = IBluetoothAudioProvider::
+    LeAudioAseConfigurationSetting::AseDirectionConfiguration;
+using LeAudioAseQosConfiguration =
+    IBluetoothAudioProvider::LeAudioAseQosConfiguration;
+using LeAudioDataPathConfiguration =
+    IBluetoothAudioProvider::LeAudioDataPathConfiguration;
+
+enum class CodecLocation {
+  HOST,
+  ADSP,
+  CONTROLLER,
+};
+
+class AudioSetConfigurationProviderJson {
+ public:
+  static std::vector<LeAudioAseConfigurationSetting>
+  GetLeAudioAseConfigurationSettings();
+
+ private:
+  static void LoadAudioSetConfigurationProviderJson();
+
+  static const le_audio::CodecSpecificConfiguration* LookupCodecSpecificParam(
+      const flatbuffers::Vector<flatbuffers::Offset<
+          le_audio::CodecSpecificConfiguration>>* flat_codec_specific_params,
+      le_audio::CodecSpecificLtvGenericTypes type);
+
+  static void populateAudioChannelAllocation(
+      CodecSpecificConfigurationLtv::AudioChannelAllocation&
+          audio_channel_allocation,
+      uint32_t audio_location);
+
+  static void populateConfigurationData(
+      LeAudioAseConfiguration& ase,
+      const flatbuffers::Vector<
+          flatbuffers::Offset<le_audio::CodecSpecificConfiguration>>*
+          flat_codec_specific_params);
+
+  static void populateAseConfiguration(
+      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);
+
+  static AseDirectionConfiguration SetConfigurationFromFlatSubconfig(
+      const le_audio::AudioSetSubConfiguration* flat_subconfig,
+      const le_audio::QosConfiguration* qos_cfg, CodecLocation location);
+
+  static void processSubconfig(
+      const le_audio::AudioSetSubConfiguration* subconfig,
+      const le_audio::QosConfiguration* qos_cfg,
+      std::vector<std::optional<AseDirectionConfiguration>>&
+          directionAseConfiguration,
+      CodecLocation location);
+
+  static void PopulateAseConfigurationFromFlat(
+      const le_audio::AudioSetConfiguration* flat_cfg,
+      std::vector<const le_audio::CodecConfiguration*>* codec_cfgs,
+      std::vector<const le_audio::QosConfiguration*>* qos_cfgs,
+      CodecLocation location,
+      std::vector<std::optional<AseDirectionConfiguration>>&
+          sourceAseConfiguration,
+      std::vector<std::optional<AseDirectionConfiguration>>&
+          sinkAseConfiguration,
+      ConfigurationFlags& configurationFlags);
+
+  static bool LoadConfigurationsFromFiles(const char* schema_file,
+                                          const char* content_file,
+                                          CodecLocation location);
+
+  static bool LoadScenariosFromFiles(const char* schema_file,
+                                     const char* content_file);
+
+  static bool LoadContent(
+      std::vector<std::pair<const char* /*schema*/, const char* /*content*/>>
+          config_files,
+      std::vector<std::pair<const char* /*schema*/, const char* /*content*/>>
+          scenario_files,
+      CodecLocation location);
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
index 26da5fb..b6df67e 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
@@ -14,6 +14,11 @@
  * limitations under the License.
  */
 
+#include <set>
+
+#include "aidl/android/hardware/bluetooth/audio/ChannelMode.h"
+#include "aidl/android/hardware/bluetooth/audio/CodecId.h"
+#include "aidl_android_hardware_bluetooth_audio_setting_enums.h"
 #define LOG_TAG "BTAudioCodecsProviderAidl"
 
 #include "BluetoothLeAudioCodecsProvider.h"
@@ -50,6 +55,123 @@
   return le_audio_offload_setting;
 }
 
+std::unordered_map<SessionType, std::vector<CodecInfo>>
+BluetoothLeAudioCodecsProvider::GetLeAudioCodecInfo(
+    const std::optional<setting::LeAudioOffloadSetting>&
+        le_audio_offload_setting) {
+  // Load from previous storage if present
+  if (!session_codecs_map_.empty()) return session_codecs_map_;
+
+  isInvalidFileContent = true;
+  if (!le_audio_offload_setting.has_value()) return {};
+
+  // Load scenario, configuration, codec configuration and strategy
+  LoadConfigurationToMap(le_audio_offload_setting);
+  if (supported_scenarios_.empty() || configuration_map_.empty() ||
+      codec_configuration_map_.empty() || strategy_configuration_map_.empty())
+    return {};
+
+  // Map each configuration into a CodecInfo
+  std::unordered_map<std::string, CodecInfo> config_codec_info_map_;
+
+  for (auto& p : configuration_map_) {
+    // Initialize new CodecInfo for the config
+    auto config_name = p.first;
+    if (config_codec_info_map_.count(config_name) == 0)
+      config_codec_info_map_[config_name] = CodecInfo();
+
+    // Getting informations from codecConfig and strategyConfig
+    const auto codec_config_name = p.second.getCodecConfiguration();
+    const auto strategy_config_name = p.second.getStrategyConfiguration();
+    const auto codec_configuration_map_iter =
+        codec_configuration_map_.find(codec_config_name);
+    if (codec_configuration_map_iter == codec_configuration_map_.end())
+      continue;
+    const auto strategy_configuration_map_iter =
+        strategy_configuration_map_.find(strategy_config_name);
+    if (strategy_configuration_map_iter == strategy_configuration_map_.end())
+      continue;
+
+    const auto& codec_config = codec_configuration_map_iter->second;
+    const auto codec = codec_config.getCodec();
+    const auto& strategy_config = strategy_configuration_map_iter->second;
+    const auto strategy_config_channel_count =
+        strategy_config.getChannelCount();
+
+    // Initiate information
+    auto& codec_info = config_codec_info_map_[config_name];
+    switch (codec) {
+      case setting::CodecType::LC3:
+        codec_info.name = "LC3";
+        codec_info.id = CodecId::Core::LC3;
+        break;
+      default:
+        codec_info.name = "UNDEFINE";
+        codec_info.id = CodecId::Vendor();
+        break;
+    }
+    codec_info.transport =
+        CodecInfo::Transport::make<CodecInfo::Transport::Tag::leAudio>();
+
+    // Mapping codec configuration information
+    auto& transport =
+        codec_info.transport.get<CodecInfo::Transport::Tag::leAudio>();
+    transport.samplingFrequencyHz.push_back(
+        codec_config.getSamplingFrequency());
+    // Mapping octetsPerCodecFrame to bitdepth for easier comparison.
+    transport.bitdepth.push_back(codec_config.getOctetsPerCodecFrame());
+    transport.frameDurationUs.push_back(codec_config.getFrameDurationUs());
+    switch (strategy_config.getAudioLocation()) {
+      case setting::AudioLocation::MONO:
+        if (strategy_config_channel_count == 1)
+          transport.channelMode.push_back(ChannelMode::MONO);
+        else
+          transport.channelMode.push_back(ChannelMode::DUALMONO);
+        break;
+      case setting::AudioLocation::STEREO:
+        transport.channelMode.push_back(ChannelMode::STEREO);
+        break;
+      default:
+        transport.channelMode.push_back(ChannelMode::UNKNOWN);
+        break;
+    }
+  }
+
+  // Goes through every scenario, deduplicate configuration
+  std::set<std::string> encoding_config, decoding_config, broadcast_config;
+  for (auto& s : supported_scenarios_) {
+    if (s.hasEncode()) encoding_config.insert(s.getEncode());
+    if (s.hasDecode()) decoding_config.insert(s.getDecode());
+    if (s.hasBroadcast()) broadcast_config.insert(s.getBroadcast());
+  }
+
+  // Split by session types and add results
+  const auto encoding_path =
+      SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
+  const auto decoding_path =
+      SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH;
+  const auto broadcast_path =
+      SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
+  session_codecs_map_ =
+      std::unordered_map<SessionType, std::vector<CodecInfo>>();
+  session_codecs_map_[encoding_path] = std::vector<CodecInfo>();
+  session_codecs_map_[decoding_path] = std::vector<CodecInfo>();
+  session_codecs_map_[broadcast_path] = std::vector<CodecInfo>();
+  session_codecs_map_[encoding_path].reserve(encoding_config.size());
+  session_codecs_map_[decoding_path].reserve(decoding_config.size());
+  session_codecs_map_[broadcast_path].reserve(broadcast_config.size());
+  for (auto& c : encoding_config)
+    session_codecs_map_[encoding_path].push_back(config_codec_info_map_[c]);
+  for (auto& c : decoding_config)
+    session_codecs_map_[decoding_path].push_back(config_codec_info_map_[c]);
+  for (auto& c : broadcast_config)
+    session_codecs_map_[broadcast_path].push_back(config_codec_info_map_[c]);
+
+  isInvalidFileContent = session_codecs_map_.empty();
+
+  return session_codecs_map_;
+}
+
 std::vector<LeAudioCodecCapabilitiesSetting>
 BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities(
     const std::optional<setting::LeAudioOffloadSetting>&
@@ -58,6 +180,8 @@
     return leAudioCodecCapabilities;
   }
 
+  isInvalidFileContent = true;
+
   if (!le_audio_offload_setting.has_value()) {
     LOG(ERROR)
         << __func__
@@ -65,40 +189,13 @@
     return {};
   }
 
-  ClearLeAudioCodecCapabilities();
-  isInvalidFileContent = true;
-
-  std::vector<setting::Scenario> supported_scenarios =
-      GetScenarios(le_audio_offload_setting);
-  if (supported_scenarios.empty()) {
-    LOG(ERROR) << __func__ << ": No scenarios in "
-               << kLeAudioCodecCapabilitiesFile;
+  LoadConfigurationToMap(le_audio_offload_setting);
+  if (supported_scenarios_.empty() || configuration_map_.empty() ||
+      codec_configuration_map_.empty() || strategy_configuration_map_.empty())
     return {};
-  }
-
-  UpdateConfigurationsToMap(le_audio_offload_setting);
-  if (configuration_map_.empty()) {
-    LOG(ERROR) << __func__ << ": No configurations in "
-               << kLeAudioCodecCapabilitiesFile;
-    return {};
-  }
-
-  UpdateCodecConfigurationsToMap(le_audio_offload_setting);
-  if (codec_configuration_map_.empty()) {
-    LOG(ERROR) << __func__ << ": No codec configurations in "
-               << kLeAudioCodecCapabilitiesFile;
-    return {};
-  }
-
-  UpdateStrategyConfigurationsToMap(le_audio_offload_setting);
-  if (strategy_configuration_map_.empty()) {
-    LOG(ERROR) << __func__ << ": No strategy configurations in "
-               << kLeAudioCodecCapabilitiesFile;
-    return {};
-  }
 
   leAudioCodecCapabilities =
-      ComposeLeAudioCodecCapabilities(supported_scenarios);
+      ComposeLeAudioCodecCapabilities(supported_scenarios_);
   isInvalidFileContent = leAudioCodecCapabilities.empty();
 
   return leAudioCodecCapabilities;
@@ -109,6 +206,8 @@
   configuration_map_.clear();
   codec_configuration_map_.clear();
   strategy_configuration_map_.clear();
+  session_codecs_map_.clear();
+  supported_scenarios_.clear();
 }
 
 std::vector<setting::Scenario> BluetoothLeAudioCodecsProvider::GetScenarios(
@@ -191,6 +290,40 @@
   }
 }
 
+void BluetoothLeAudioCodecsProvider::LoadConfigurationToMap(
+    const std::optional<setting::LeAudioOffloadSetting>&
+        le_audio_offload_setting) {
+  ClearLeAudioCodecCapabilities();
+
+  supported_scenarios_ = GetScenarios(le_audio_offload_setting);
+  if (supported_scenarios_.empty()) {
+    LOG(ERROR) << __func__ << ": No scenarios in "
+               << kLeAudioCodecCapabilitiesFile;
+    return;
+  }
+
+  UpdateConfigurationsToMap(le_audio_offload_setting);
+  if (configuration_map_.empty()) {
+    LOG(ERROR) << __func__ << ": No configurations in "
+               << kLeAudioCodecCapabilitiesFile;
+    return;
+  }
+
+  UpdateCodecConfigurationsToMap(le_audio_offload_setting);
+  if (codec_configuration_map_.empty()) {
+    LOG(ERROR) << __func__ << ": No codec configurations in "
+               << kLeAudioCodecCapabilitiesFile;
+    return;
+  }
+
+  UpdateStrategyConfigurationsToMap(le_audio_offload_setting);
+  if (strategy_configuration_map_.empty()) {
+    LOG(ERROR) << __func__ << ": No strategy configurations in "
+               << kLeAudioCodecCapabilitiesFile;
+    return;
+  }
+}
+
 std::vector<LeAudioCodecCapabilitiesSetting>
 BluetoothLeAudioCodecsProvider::ComposeLeAudioCodecCapabilities(
     const std::vector<setting::Scenario>& supported_scenarios) {
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
index 654e70c..5bf67e2 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
@@ -22,6 +22,8 @@
 #include <unordered_map>
 #include <vector>
 
+#include "aidl/android/hardware/bluetooth/audio/CodecInfo.h"
+#include "aidl/android/hardware/bluetooth/audio/SessionType.h"
 #include "aidl_android_hardware_bluetooth_audio_setting.h"
 
 namespace aidl {
@@ -39,14 +41,20 @@
       const std::optional<setting::LeAudioOffloadSetting>&
           le_audio_offload_setting);
   static void ClearLeAudioCodecCapabilities();
+  static std::unordered_map<SessionType, std::vector<CodecInfo>>
+  GetLeAudioCodecInfo(const std::optional<setting::LeAudioOffloadSetting>&
+                          le_audio_offload_setting);
 
  private:
+  static inline std::vector<setting::Scenario> supported_scenarios_;
   static inline std::unordered_map<std::string, setting::Configuration>
       configuration_map_;
   static inline std::unordered_map<std::string, setting::CodecConfiguration>
       codec_configuration_map_;
   static inline std::unordered_map<std::string, setting::StrategyConfiguration>
       strategy_configuration_map_;
+  static inline std::unordered_map<SessionType, std::vector<CodecInfo>>
+      session_codecs_map_;
 
   static std::vector<setting::Scenario> GetScenarios(
       const std::optional<setting::LeAudioOffloadSetting>&
@@ -60,6 +68,9 @@
   static void UpdateStrategyConfigurationsToMap(
       const std::optional<setting::LeAudioOffloadSetting>&
           le_audio_offload_setting);
+  static void LoadConfigurationToMap(
+      const std::optional<setting::LeAudioOffloadSetting>&
+          le_audio_offload_setting);
 
   static std::vector<LeAudioCodecCapabilitiesSetting>
   ComposeLeAudioCodecCapabilities(
diff --git a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp
index 3d92ee7..fd12a6e 100644
--- a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp
+++ b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp
@@ -467,6 +467,8 @@
       hidl_audio_config.codecConfig(to_hidl_codec_config_2_0(
           audio_config.get<AudioConfiguration::a2dpConfig>()));
       break;
+    case AudioConfiguration::a2dp:
+      break;
     case AudioConfiguration::leAudioConfig:
       hidl_audio_config.leAudioCodecConfig(to_hidl_leaudio_config_2_1(
           audio_config.get<AudioConfiguration::leAudioConfig>()));
@@ -475,6 +477,8 @@
       hidl_audio_config.leAudioCodecConfig(to_hidl_leaudio_broadcast_config_2_1(
           audio_config.get<AudioConfiguration::leAudioBroadcastConfig>()));
       break;
+    default:
+      LOG(FATAL) << __func__ << ": unexpected AudioConfiguration";
   }
   return hidl_audio_config;
 }
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
new file mode 100644
index 0000000..bde467d
--- /dev/null
+++ b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.fbs
@@ -0,0 +1,91 @@
+/*
+ *  Copyright (c) 2022 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.
+ *
+ */
+namespace aidl.android.hardware.bluetooth.audio.le_audio;
+enum CodecSpecificLtvGenericTypes : byte {
+    SUPPORTED_SAMPLING_FREQUENCY = 0x01,
+    SUPPORTED_FRAME_DURATION = 0x02,
+    SUPPORTED_AUDIO_CHANNEL_ALLOCATION = 0x03,
+    SUPPORTED_OCTETS_PER_CODEC_FRAME = 0x04,
+    SUPPORTED_CODEC_FRAME_BLOCKS_PER_SDU = 0x05,
+}
+/// Note: Holds either a single value (when `value_width == 0`) or multiple
+///       values if `value.length()` is no-remainder divisible by the non-zero
+///       `value_width`.
+/// Note: Consider extending it with `flags` field, to hold additional info like
+///       IsBitfield, IsRange, etc. if we need these type-specific validations.
+table CompoundValue {
+    value: [ubyte] (required);
+    value_width: ubyte = 0;
+}
+table CodecSpecificConfiguration {
+    name: string;
+    type: ubyte (key);
+    compound_value: CompoundValue;
+}
+struct CodecId {
+    coding_format: ubyte;
+    vendor_company_id : ushort;
+    vendor_codec_id : ushort;
+}
+enum AudioSetConfigurationStrategy : byte {
+    MONO_ONE_CIS_PER_DEVICE = 0x00,
+    STEREO_TWO_CISES_PER_DEVICE = 0x01,
+    STEREO_ONE_CIS_PER_DEVICE = 0x02,
+}
+enum AudioSetConfigurationDirection : byte {
+    SINK = 0x01,
+    SOURCE = 0x02,
+}
+enum AudioSetConfigurationTargetLatency : byte {
+    LOW = 0x01,
+    BALANCED_RELIABILITY = 0x02,
+    HIGH_RELIABILITY = 0x03,
+}
+table AudioSetSubConfiguration {
+    device_cnt: ubyte;
+    ase_cnt: ubyte;
+    direction: AudioSetConfigurationDirection = SINK;
+    configuration_strategy: AudioSetConfigurationStrategy;
+    codec_id : CodecId (required);
+    codec_configuration: [CodecSpecificConfiguration] (required);
+}
+table CodecConfiguration {
+    name: string (key, required);
+    subconfigurations: [AudioSetSubConfiguration] (required);
+}
+table QosConfiguration {
+    name: string (key, required);
+    target_latency: AudioSetConfigurationTargetLatency = BALANCED_RELIABILITY;
+    retransmission_number: ubyte;
+    max_transport_latency : ushort;
+}
+/// Each set configration can contain multiple logical subconfigurations, which
+/// all must be configurable with the current set of audio devices. For example,
+/// one can define multiple output stream configurations with different
+/// qualities, or assign different configurations to each stream direction.
+table AudioSetConfiguration {
+    name: string (key, required);
+    codec_config_name: string (required);
+    qos_config_name: [string] (required);
+}
+table AudioSetConfigurations {
+    _comments_: [string];
+    configurations: [AudioSetConfiguration] (required);
+    codec_configurations: [CodecConfiguration] (required);
+    qos_configurations: [QosConfiguration] (required);
+}
+root_type AudioSetConfigurations;
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
new file mode 100644
index 0000000..404a48a
--- /dev/null
+++ b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.json
@@ -0,0 +1,11382 @@
+{
+  "_comments_": [
+    " == Audio Set Configurations == ",
+    " Contains: ",
+    "   1. configurations : ",
+    "        Maps configuration name with codec and qos config to be used",
+    "   2. codec_configurations : ",
+    "        Array of codec specific configurations",
+    "   3. qos_configurations : ",
+    "        Array of QoS specific configurations",
+    "        QoS configuration values are as per BAP spec 1.0",
+    " Example values which can be used as 'codec_configuration.type'",
+    "   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",
+    "     16000Hz = 3",
+    "     22050Hz = 4",
+    "     24000Hz = 5",
+    "     32000Hz = 6",
+    "     44100Hz = 7",
+    "     48000Hz = 8",
+    "     88200Hz = 9",
+    "     96000Hz = 10",
+    "     176400Hz = 11",
+    "     192000Hz = 12",
+    "     384000Hz = 13",
+    "   Frame Durations:",
+    "     7500us = 0",
+    "     10000us = 1"
+  ],
+  "configurations": [
+    {
+      "name": "DualDev_OneChanStereoSnk_16_1_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_16_1_Balanced_Reliability",
+      "codec_config_name": "DualDev_OneChanStereoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_16_1_1",
+      "codec_config_name": "DualDev_OneChanStereoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_1"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_16_1_2",
+      "codec_config_name": "DualDev_OneChanStereoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_2"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_16_2_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_16_2_Balanced_Reliability",
+      "codec_config_name": "DualDev_OneChanStereoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_16_2_1",
+      "codec_config_name": "DualDev_OneChanStereoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_1"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_16_2_2",
+      "codec_config_name": "DualDev_OneChanStereoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_16_1_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_16_1_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_16_1_1",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_1"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_16_1_2",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_16_2_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_16_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_16_2_1",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_1"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_16_2_2",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_2"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_16_1_Low_Latency",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_16_1_Balanced_Reliability",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_16_1_1",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_1"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_16_1_2",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_2"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_16_2_Low_Latency",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_16_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_16_2_1",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_1"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_16_2_2",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_32_1_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_32_1",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_32_1_1",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_32_1",
+      "qos_config_name": [
+        "QoS_Config_32_1_1"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_32_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_32_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_32_2_1",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_32_2",
+      "qos_config_name": [
+        "QoS_Config_32_2_1"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_16_1_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_16_1_1",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_1"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_16_1_2",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_2"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanMonoSnk_16_2_Balanced_Reliability",
+      "codec_config_name": "DualDev_OneChanMonoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_16_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_16_2_1",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_1"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_16_2_2",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_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",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1_1",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_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",
+      "qos_config_name": [
+        "QoS_Config_16_1_2"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_2",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_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",
+      "qos_config_name": [
+        "QoS_Config_16_2_1"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_2",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_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",
+      "qos_config_name": [
+        "QoS_Config_16_1_1"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2_1",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_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",
+      "qos_config_name": [
+        "QoS_Config_16_2_2"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
+      "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1",
+      "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",
+      "qos_config_name": [
+        "QoS_Config_32_2_1"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_Low_Latency",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_2",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_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",
+      "qos_config_name": [
+        "QoS_Config_16_2_1"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_Low_Latency",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_2",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_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",
+      "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",
+      "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",
+      "qos_config_name": [
+        "QoS_Config_16_1_1"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_2",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_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",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_1",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_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",
+      "qos_config_name": [
+        "QoS_Config_16_2_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_1",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_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",
+      "qos_config_name": [
+        "QoS_Config_16_1_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_1",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_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",
+      "qos_config_name": [
+        "QoS_Config_16_2_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_1",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_1"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanMonoSrc_16_2_Balanced_Reliability",
+      "codec_config_name": "DualDev_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSrc_16_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanStereoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_48_4_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSrc_48_4",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_48_3_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSrc_48_3",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_48_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSrc_48_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_48_1_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSrc_48_1",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_32_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSrc_32_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_32_1_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSrc_32_1",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_24_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSrc_24_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_24_1_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSrc_24_1",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_16_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_16_1_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_2",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_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",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_1",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_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",
+      "qos_config_name": [
+        "QoS_Config_16_2_2"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_24_1_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_24_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_24_1_Low_Latency",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_24_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_24_1_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_24_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_24_2_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_24_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_24_2_Balanced_Reliability",
+      "codec_config_name": "DualDev_OneChanStereoSnk_24_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_24_2_2",
+      "codec_config_name": "DualDev_OneChanStereoSnk_24_2",
+      "qos_config_name": [
+        "QoS_Config_24_2_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_24_2_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_24_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_24_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_24_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_24_2_2",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_24_2",
+      "qos_config_name": [
+        "QoS_Config_24_2_2"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_24_2_Low_Latency",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_24_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_24_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_24_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_24_2_2",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_24_2",
+      "qos_config_name": [
+        "QoS_Config_24_2_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_24_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_24_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_24_2_2",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_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",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_1",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_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",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2_1",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2",
+      "qos_config_name": [
+        "QoS_Config_32_2_1"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_32_2_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_32_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_32_1_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_32_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_32_1_Low_Latency",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_32_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_32_2_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_32_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_32_1_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_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",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2_1",
+      "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_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",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_1",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_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",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_1",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_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",
+      "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",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_4_1",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_4",
+      "qos_config_name": [
+        "QoS_Config_48_4_1"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_4_2",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_4",
+      "qos_config_name": [
+        "QoS_Config_48_4_2"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_3_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_3",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_3_High_Reliability",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_3",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_3_2",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_3",
+      "qos_config_name": [
+        "QoS_Config_48_3_2"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_2_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_2_High_Reliability",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_2",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_2_2",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_2",
+      "qos_config_name": [
+        "QoS_Config_48_2_2"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_1_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_1_High_Reliability",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_1",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_1_2",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_1",
+      "qos_config_name": [
+        "QoS_Config_48_1_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_4_High_Reliability",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_4",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_4_1",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_4",
+      "qos_config_name": [
+        "QoS_Config_48_4_1"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_4_2",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_4",
+      "qos_config_name": [
+        "QoS_Config_48_4_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_3_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_3",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_3_High_Reliability",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_3",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_3_2",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_3",
+      "qos_config_name": [
+        "QoS_Config_48_3_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_2_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_2_High_Reliability",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_2",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_2_2",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_2",
+      "qos_config_name": [
+        "QoS_Config_48_2_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_1_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_1_High_Reliability",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_1",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_1_2",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_1",
+      "qos_config_name": [
+        "QoS_Config_48_1_2"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_4_High_Reliability",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_4_1",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4",
+      "qos_config_name": [
+        "QoS_Config_48_4_1"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_4_2",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4",
+      "qos_config_name": [
+        "QoS_Config_48_4_2"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_3_Low_Latency",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_3",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_3_High_Reliability",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_3",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_3_2",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_3",
+      "qos_config_name": [
+        "QoS_Config_48_3_2"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_2_Low_Latency",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_2_High_Reliability",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_2",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_2_2",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_2",
+      "qos_config_name": [
+        "QoS_Config_48_2_2"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_1_Low_Latency",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_1_High_Reliability",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_1",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_1_2",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_1",
+      "qos_config_name": [
+        "QoS_Config_48_1_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_4_High_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_48_4",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_4_1",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_48_4",
+      "qos_config_name": [
+        "QoS_Config_48_4_1"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_4_2",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_48_4",
+      "qos_config_name": [
+        "QoS_Config_48_4_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_3_High_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_48_3",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_3_2",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_48_3",
+      "qos_config_name": [
+        "QoS_Config_48_3_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_2_High_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_48_2",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_2_2",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_48_2",
+      "qos_config_name": [
+        "QoS_Config_48_2_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_1_High_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_48_1",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_1_2",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_48_1",
+      "qos_config_name": [
+        "QoS_Config_48_1_2"
+      ]
+    },
+    {
+      "name": "VND_SingleDev_TwoChanStereoSnk_OneChanStereoSrc_32khz_60octs_Low_Latency_1",
+      "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_OneChanStereoSrc_32khz_60octs_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "VND_SingleDev_TwoChanStereoSnk_OneChanStereoSrc_32khz_60oct_R3_L22_1",
+      "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_OneChanStereoSrc_32khz_60octs_1",
+      "qos_config_name": [
+        "VND_QoS_Config_R3_L22"
+      ]
+    },
+    {
+      "name": "VND_DualDev_OneChanStereoSnk_48khz_100octs_High_Reliability_1",
+      "codec_config_name": "VND_DualDev_OneChanStereoSnk_48khz_100octs_1",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "VND_DualDev_OneChanStereoSnk_48khz_100octs_R15_L70_1",
+      "codec_config_name": "VND_DualDev_OneChanStereoSnk_48khz_100octs_1",
+      "qos_config_name": [
+        "VND_QoS_Config_R15_L70"
+      ]
+    },
+    {
+      "name": "VND_SingleDev_OneChanStereoSnk_48khz_100octs_High_Reliability_1",
+      "codec_config_name": "VND_SingleDev_OneChanStereoSnk_48khz_100octs_1",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "VND_SingleDev_OneChanStereoSnk_48khz_100octs_R15_L70_1",
+      "codec_config_name": "VND_SingleDev_OneChanStereoSnk_48khz_100octs_1",
+      "qos_config_name": [
+        "VND_QoS_Config_R15_L70"
+      ]
+    },
+    {
+      "name": "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_High_Reliability_1",
+      "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_1",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_R15_L70_1",
+      "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_1",
+      "qos_config_name": [
+        "VND_QoS_Config_R15_L70"
+      ]
+    },
+    {
+      "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_High_Reliability_1",
+      "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_1",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_R5_L12_1",
+      "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_1",
+      "qos_config_name": [
+        "VND_QoS_Config_R5_L12"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_32_2_Balanced_Reliability",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_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",
+      "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",
+      "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",
+      "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",
+      "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",
+      "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",
+      "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",
+      "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",
+      "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",
+      "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",
+      "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",
+      "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",
+      "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",
+      "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",
+      "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",
+      "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",
+      "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",
+      "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",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1_Balanced_Reliability",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_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",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2_Balanced_Reliability",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_Balanced_Reliability_1",
+      "codec_config_name": "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_1",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_R11_L40_1",
+      "codec_config_name": "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_1",
+      "qos_config_name": [
+        "VND_QoS_Config_R11_L40"
+      ]
+    },
+    {
+      "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_R5_L12_TwoChanStereoSrc_16khz_30octs_R3_L12_1",
+      "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_TwoChanStereoSrc_16khz_30octs_1",
+      "qos_config_name": [
+        "VND_QoS_Config_R5_L12",
+        "VND_QoS_Config_R3_L12"
+      ]
+    },
+    {
+      "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_TwoChanStereoSrc_16khz_30octs_Balanced_Reliability_1",
+      "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_TwoChanStereoSrc_16khz_30octs_1",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    }
+  ],
+  "codec_configurations": [
+    {
+      "name": "DualDev_OneChanStereoSnk_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": "DualDev_OneChanStereoSnk_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,
+            "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_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,
+            "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_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
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSrc_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,
+            "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_OneChanMonoSrc_24_2",
+      "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": [
+                  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_32_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": [
+                  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_32_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,
+            "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": "SingleDev_OneChanMonoSnk_32_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": [
+                  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_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
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "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_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
+                ]
+              }
+            },
+            {
+              "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",
+          "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_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": [
+                  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": {
+            "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_OneChanMonoSnk_OneChanMonoSrc_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": "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_OneChanMonoSrc_16_2",
+      "subconfigurations": [
+        {
+          "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": "SingleDev_OneChanMonoSrc_48_4",
+      "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": [
+                  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_OneChanMonoSrc_48_3",
+      "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": [
+                  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": [
+                  90,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_48_2",
+      "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": [
+                  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_OneChanMonoSrc_48_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": [
+                  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
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_32_2",
+      "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": [
+                  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_OneChanMonoSrc_32_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": [
+                  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": "SingleDev_OneChanMonoSrc_24_2",
+      "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": [
+                  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
+                ]
+              }
+            },
+            {
+              "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_OneChanMonoSrc_16_2",
+      "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": [
+                  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_OneChanMonoSrc_16_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": [
+                  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_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,
+            "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": "DualDev_OneChanStereoSnk_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,
+            "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": "DualDev_OneChanStereoSnk_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,
+            "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": "DualDev_OneChanStereoSnk_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,
+            "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
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_4",
+      "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": [
+                  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_OneChanStereoSnk_48_3",
+      "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": [
+                  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_OneChanStereoSnk_48_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": [
+                  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_OneChanStereoSnk_48_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": [
+                  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
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_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,
+            "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
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_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,
+            "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": [
+                  90,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_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,
+            "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": [
+                  100,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_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,
+            "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": [
+                  3,
+                  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
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "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
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "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,
+            "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": [
+                  3,
+                  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": "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,
+            "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": [
+                  100,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "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,
+            "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": [
+                  100,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "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,
+            "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": [
+                  3,
+                  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
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_4_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": [
+                  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": 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_48_4_OneChanStereoSrc_24_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": [
+                  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": 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": [
+                  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": "DualDev_OneChanStereoSnk_48_4_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": [
+                  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": 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": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_4_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": [
+                  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": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_24_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": [
+                  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": "DualDev_OneChanStereoSnk_48_4_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": [
+                  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_OneChanDoubleStereoSnk_48_4_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": [
+                  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": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_24_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": [
+                  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": "DualDev_OneChanDoubleStereoSnk_48_4_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": [
+                  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": "SingleDev_TwoChanStereoSnk_48_4_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": [
+                  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": [
+                  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": {
+            "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_48_4_OneChanMonoSrc_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",
+          "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_TwoChanStereoSnk_48_4_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": [
+                  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": {
+            "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": "SingleDev_OneChanStereoSnk_48_4_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": [
+                  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_OneChanStereoSnk_48_4_OneChanMonoSrc_24_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": [
+                  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_OneChanStereoSnk_48_4_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": [
+                  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": "SingleDev_OneChanMonoSnk_48_4_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": [
+                  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,
+            "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": [
+                  3,
+                  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
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "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": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  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
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_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,
+            "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": [
+                  100,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "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": [
+                  100,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "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,
+            "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": [
+                  100,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "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,
+            "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
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "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": [
+                  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": "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,
+            "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": [
+                  3,
+                  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
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "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": "DualDev_OneChanStereoSnk_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,
+            "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_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,
+            "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
+                ]
+              }
+            },
+            {
+              "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_OneChanStereoSnk_24_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": [
+                  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": "SingleDev_OneChanStereoSnk_24_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": [
+                  5
+                ]
+              }
+            },
+            {
+              "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": [
+                  45,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_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": [
+                  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": [
+                  60,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "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
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    }
+  ],
+  "qos_configurations": [
+    {
+      "name": "QoS_Config_16_1_1",
+      "retransmission_number": 2,
+      "max_transport_latency": 8
+    },
+    {
+      "name": "QoS_Config_16_1_2",
+      "retransmission_number": 13,
+      "max_transport_latency": 75
+    },
+    {
+      "name": "QoS_Config_16_2_1",
+      "retransmission_number": 2,
+      "max_transport_latency": 10
+    },
+    {
+      "name": "QoS_Config_16_2_2",
+      "retransmission_number": 13,
+      "max_transport_latency": 95
+    },
+    {
+      "name": "QoS_Config_24_1_1",
+      "retransmission_number": 2,
+      "max_transport_latency": 8
+    },
+    {
+      "name": "QoS_Config_24_1_2",
+      "retransmission_number": 13,
+      "max_transport_latency": 75
+    },
+    {
+      "name": "QoS_Config_24_2_1",
+      "retransmission_number": 2,
+      "max_transport_latency": 10
+    },
+    {
+      "name": "QoS_Config_24_2_2",
+      "retransmission_number": 13,
+      "max_transport_latency": 95
+    },
+    {
+      "name": "QoS_Config_32_1_1",
+      "retransmission_number": 2,
+      "max_transport_latency": 8
+    },
+    {
+      "name": "QoS_Config_32_1_2",
+      "retransmission_number": 13,
+      "max_transport_latency": 75
+    },
+    {
+      "name": "QoS_Config_32_2_1",
+      "retransmission_number": 2,
+      "max_transport_latency": 10
+    },
+    {
+      "name": "QoS_Config_32_2_2",
+      "retransmission_number": 13,
+      "max_transport_latency": 95
+    },
+    {
+      "name": "QoS_Config_48_1_2",
+      "retransmission_number": 13,
+      "max_transport_latency": 75
+    },
+    {
+      "name": "QoS_Config_48_2_2",
+      "retransmission_number": 13,
+      "max_transport_latency": 95
+    },
+    {
+      "name": "QoS_Config_48_3_2",
+      "retransmission_number": 13,
+      "max_transport_latency": 75
+    },
+    {
+      "name": "QoS_Config_48_4_1",
+      "retransmission_number": 5,
+      "max_transport_latency": 20
+    },
+    {
+      "name": "QoS_Config_48_4_2",
+      "retransmission_number": 13,
+      "max_transport_latency": 100
+    },
+    {
+      "name": "VND_QoS_Config_R3_L22",
+      "retransmission_number": 3,
+      "max_transport_latency": 22
+    },
+    {
+      "name": "VND_QoS_Config_R15_L70",
+      "retransmission_number": 15,
+      "max_transport_latency": 70
+    },
+    {
+      "name": "VND_QoS_Config_R5_L12",
+      "retransmission_number": 5,
+      "max_transport_latency": 12
+    },
+    {
+      "name": "VND_QoS_Config_R11_L40",
+      "retransmission_number": 11,
+      "max_transport_latency": 40
+    },
+    {
+      "name": "VND_QoS_Config_R3_L12",
+      "retransmission_number": 3,
+      "max_transport_latency": 12
+    },
+    {
+      "name": "QoS_Config_Low_Latency",
+      "target_latency": "LOW",
+      "retransmission_number": 0,
+      "max_transport_latency": 0
+    },
+    {
+      "name": "QoS_Config_Balanced_Reliability",
+      "target_latency": "BALANCED_RELIABILITY",
+      "retransmission_number": 0,
+      "max_transport_latency": 0
+    },
+    {
+      "name": "QoS_Config_High_Reliability",
+      "target_latency": "HIGH_RELIABILITY",
+      "retransmission_number": 0,
+      "max_transport_latency": 0
+    }
+
+  ]
+}
diff --git a/bluetooth/audio/utils/le_audio_configuration_set/audio_set_scenarios.fbs b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_scenarios.fbs
new file mode 100644
index 0000000..e898bdc
--- /dev/null
+++ b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_scenarios.fbs
@@ -0,0 +1,36 @@
+/*
+ *  Copyright (c) 2022 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.
+ *
+ */
+namespace aidl.android.hardware.bluetooth.audio.le_audio;
+/// Scenario represents the use case such as "Media", "Conversation", etc.
+/// Each scenario can list any number of codec configurations by their names in
+/// the order of preference. That means if the first entry does not meet all
+/// the current requirements (such as peer device capabilities etc.) next
+/// configurations are being checked.
+///
+/// The referenced codec configurations are defined by the
+/// audio_set_configurations.fbs schema and loaded from a different source file.
+/// Multiple scenarios can reference same codec configurations.
+table AudioSetScenario {
+    _comments_: [string];
+    name: string (key, required);
+    configurations: [string] (required);
+}
+table AudioSetScenarios {
+    _comments_: [string];
+    scenarios: [AudioSetScenario] (required);
+}
+root_type AudioSetScenarios;
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
new file mode 100644
index 0000000..a28c6cd
--- /dev/null
+++ b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_scenarios.json
@@ -0,0 +1,304 @@
+{
+  "_comments_": [
+    "== Audio Set Scenarios ==",
+    "  Each defined scenario references externally defined audio set",
+    "  configurations, listed in the order of priority."
+  ],
+  "scenarios": [
+    {
+      "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"
+      ]
+    },
+    {
+      "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",
+        "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"
+      ]
+    },
+    {
+      "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",
+        "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"
+      ]
+    },
+    {
+      "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"
+      ]
+    },
+    {
+      "name": "Live",
+      "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"
+      ]
+    }
+  ]
+}
diff --git a/bluetooth/finder/aidl/Android.bp b/bluetooth/finder/aidl/Android.bp
new file mode 100644
index 0000000..24f5ca5
--- /dev/null
+++ b/bluetooth/finder/aidl/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+aidl_interface {
+    name: "android.hardware.bluetooth.finder",
+    vendor_available: true,
+    srcs: ["android/hardware/bluetooth/finder/*.aidl"],
+    stability: "vintf",
+
+    backend: {
+        ndk: {
+            enabled: true,
+        },
+        java: {
+            enabled: true,
+            sdk_version: "module_current",
+            min_sdk_version: "30",
+            apex_available: [
+                "com.android.tethering",
+            ],
+        },
+    },
+}
diff --git a/bluetooth/finder/aidl/aidl_api/android.hardware.bluetooth.finder/current/android/hardware/bluetooth/finder/Eid.aidl b/bluetooth/finder/aidl/aidl_api/android.hardware.bluetooth.finder/current/android/hardware/bluetooth/finder/Eid.aidl
new file mode 100644
index 0000000..42461c5
--- /dev/null
+++ b/bluetooth/finder/aidl/aidl_api/android.hardware.bluetooth.finder/current/android/hardware/bluetooth/finder/Eid.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.finder;
+@VintfStability
+parcelable Eid {
+  byte[20] bytes;
+}
diff --git a/bluetooth/finder/aidl/aidl_api/android.hardware.bluetooth.finder/current/android/hardware/bluetooth/finder/IBluetoothFinder.aidl b/bluetooth/finder/aidl/aidl_api/android.hardware.bluetooth.finder/current/android/hardware/bluetooth/finder/IBluetoothFinder.aidl
new file mode 100644
index 0000000..4bc9041
--- /dev/null
+++ b/bluetooth/finder/aidl/aidl_api/android.hardware.bluetooth.finder/current/android/hardware/bluetooth/finder/IBluetoothFinder.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.finder;
+@VintfStability
+interface IBluetoothFinder {
+  void sendEids(in android.hardware.bluetooth.finder.Eid[] eids);
+  void setPoweredOffFinderMode(in boolean enable);
+  boolean getPoweredOffFinderMode();
+}
diff --git a/bluetooth/finder/aidl/android/hardware/bluetooth/finder/Eid.aidl b/bluetooth/finder/aidl/android/hardware/bluetooth/finder/Eid.aidl
new file mode 100644
index 0000000..0de306f
--- /dev/null
+++ b/bluetooth/finder/aidl/android/hardware/bluetooth/finder/Eid.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.finder;
+
+/**
+ * Find My Device network ephemeral identifier
+ */
+@VintfStability
+parcelable Eid {
+    byte[20] bytes;
+}
diff --git a/bluetooth/finder/aidl/android/hardware/bluetooth/finder/IBluetoothFinder.aidl b/bluetooth/finder/aidl/android/hardware/bluetooth/finder/IBluetoothFinder.aidl
new file mode 100644
index 0000000..a374c2a
--- /dev/null
+++ b/bluetooth/finder/aidl/android/hardware/bluetooth/finder/IBluetoothFinder.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.finder;
+
+import android.hardware.bluetooth.finder.Eid;
+
+@VintfStability
+interface IBluetoothFinder {
+    /**
+     * API to set Find My Device network EIDs to the Bluetooth Controller
+     *
+     * @param eids array of 20 bytes EID to the Bluetooth
+     * controller
+     */
+    void sendEids(in Eid[] eids);
+
+    /**
+     * API to enable the powered-off finder feature, which allows the Bluetooth controller to send
+     * beacons after the device is powered off.
+     *
+     * @param enable true to enable; false to disable
+     */
+    void setPoweredOffFinderMode(in boolean enable);
+
+    /**
+     * API for retrieving feature enablement status
+     *
+     * @return the value last set by setPoweredOffFinderMode, false if setPoweredOffFinderMode was
+     *         never been invoked since boot.
+     */
+    boolean getPoweredOffFinderMode();
+}
diff --git a/bluetooth/finder/aidl/default/Android.bp b/bluetooth/finder/aidl/default/Android.bp
new file mode 100644
index 0000000..b364ae1
--- /dev/null
+++ b/bluetooth/finder/aidl/default/Android.bp
@@ -0,0 +1,42 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+    name: "android.hardware.bluetooth.finder-service.default",
+    relative_install_path: "hw",
+    init_rc: ["bluetooth-finder-service-default.rc"],
+    vintf_fragments: [":manifest_android.hardware.bluetooth.finder-service.default.xml"],
+    vendor: true,
+    srcs: [
+        "BluetoothFinder.cpp",
+        "service.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.bluetooth.finder-V1-ndk",
+        "libbase",
+        "libbinder_ndk",
+        "libhidlbase",
+        "libutils",
+        "liblog",
+    ],
+}
+
+filegroup {
+    name: "manifest_android.hardware.bluetooth.finder-service.default.xml",
+    srcs: ["bluetooth-finder-service-default.xml"],
+}
diff --git a/bluetooth/finder/aidl/default/BluetoothFinder.cpp b/bluetooth/finder/aidl/default/BluetoothFinder.cpp
new file mode 100644
index 0000000..236a1f8
--- /dev/null
+++ b/bluetooth/finder/aidl/default/BluetoothFinder.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BluetoothFinder.h"
+
+namespace aidl::android::hardware::bluetooth::finder::impl {
+
+::ndk::ScopedAStatus BluetoothFinder::sendEids(const ::std::vector<Eid>& keys) {
+  keys_.insert(keys_.end(), keys.begin(), keys.end());
+  return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus BluetoothFinder::setPoweredOffFinderMode(bool enable) {
+  pof_enabled_ = enable;
+  return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus BluetoothFinder::getPoweredOffFinderMode(
+    bool* _aidl_return) {
+  *_aidl_return = pof_enabled_;
+  return ::ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::bluetooth::finder::impl
diff --git a/bluetooth/finder/aidl/default/BluetoothFinder.h b/bluetooth/finder/aidl/default/BluetoothFinder.h
new file mode 100644
index 0000000..16110f6
--- /dev/null
+++ b/bluetooth/finder/aidl/default/BluetoothFinder.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/bluetooth/finder/BnBluetoothFinder.h>
+
+#include <vector>
+
+namespace aidl::android::hardware::bluetooth::finder::impl {
+
+using ::aidl::android::hardware::bluetooth::finder::BnBluetoothFinder;
+using ::aidl::android::hardware::bluetooth::finder::Eid;
+
+class BluetoothFinder : public BnBluetoothFinder {
+ public:
+  BluetoothFinder() = default;
+
+  ::ndk::ScopedAStatus sendEids(const ::std::vector<Eid>& keys) override;
+  ::ndk::ScopedAStatus setPoweredOffFinderMode(bool enable) override;
+  ::ndk::ScopedAStatus getPoweredOffFinderMode(bool* _aidl_return) override;
+
+ private:
+  bool pof_enabled_;
+  std::vector<Eid> keys_;
+};
+
+}  // namespace aidl::android::hardware::bluetooth::finder::impl
diff --git a/bluetooth/finder/aidl/default/bluetooth-finder-service-default.rc b/bluetooth/finder/aidl/default/bluetooth-finder-service-default.rc
new file mode 100644
index 0000000..64bbf09
--- /dev/null
+++ b/bluetooth/finder/aidl/default/bluetooth-finder-service-default.rc
@@ -0,0 +1,6 @@
+service vendor.bluetooth.finder-default /vendor/bin/hw/android.hardware.bluetooth.finder-service.default
+    class hal
+    capabilities BLOCK_SUSPEND NET_ADMIN SYS_NICE
+    user bluetooth
+    group bluetooth
+    task_profiles ServicePerformance
diff --git a/bluetooth/finder/aidl/default/bluetooth-finder-service-default.xml b/bluetooth/finder/aidl/default/bluetooth-finder-service-default.xml
new file mode 100644
index 0000000..be7c00d
--- /dev/null
+++ b/bluetooth/finder/aidl/default/bluetooth-finder-service-default.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.bluetooth.finder</name>
+        <version>1</version>
+        <fqname>IBluetoothFinder/default</fqname>
+    </hal>
+</manifest>
diff --git a/bluetooth/finder/aidl/default/service.cpp b/bluetooth/finder/aidl/default/service.cpp
new file mode 100644
index 0000000..a117df8
--- /dev/null
+++ b/bluetooth/finder/aidl/default/service.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "aidl.android.hardware.bluetooth.finder.default"
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <utils/Log.h>
+
+#include "BluetoothFinder.h"
+
+using ::aidl::android::hardware::bluetooth::finder::impl::BluetoothFinder;
+
+int main(int /* argc */, char** /* argv */) {
+  ALOGI("Bluetooth Finder HAL registering");
+  if (!ABinderProcess_setThreadPoolMaxThreadCount(0)) {
+    ALOGE("failed to set thread pool max thread count");
+    return 1;
+  }
+
+  std::shared_ptr<BluetoothFinder> service =
+      ndk::SharedRefBase::make<BluetoothFinder>();
+  std::string instance =
+      std::string() + BluetoothFinder::descriptor + "/default";
+  auto result =
+      AServiceManager_addService(service->asBinder().get(), instance.c_str());
+  if (result == STATUS_OK) {
+    ABinderProcess_joinThreadPool();
+  } else {
+    ALOGE("Could not register as a service!");
+  }
+  return 0;
+}
diff --git a/bluetooth/finder/aidl/vts/Android.bp b/bluetooth/finder/aidl/vts/Android.bp
new file mode 100644
index 0000000..6b0285e
--- /dev/null
+++ b/bluetooth/finder/aidl/vts/Android.bp
@@ -0,0 +1,41 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsHalBluetoothFinderTargetTest",
+    defaults: [
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalBluetoothFinderTargetTest.cpp"],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libbinder_ndk",
+        "liblog",
+        "libutils",
+    ],
+    static_libs: [
+        "android.hardware.bluetooth.finder-V1-ndk",
+        "libbluetooth-types",
+    ],
+    test_config: "VtsHalBluetoothFinderTargetTest.xml",
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/bluetooth/finder/aidl/vts/VtsHalBluetoothFinderTargetTest.cpp b/bluetooth/finder/aidl/vts/VtsHalBluetoothFinderTargetTest.cpp
new file mode 100644
index 0000000..be07a7d
--- /dev/null
+++ b/bluetooth/finder/aidl/vts/VtsHalBluetoothFinderTargetTest.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/bluetooth/finder/IBluetoothFinder.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+
+#include <array>
+#include <vector>
+
+using ::aidl::android::hardware::bluetooth::finder::Eid;
+using ::aidl::android::hardware::bluetooth::finder::IBluetoothFinder;
+using ::ndk::ScopedAStatus;
+
+class BluetoothFinderTest : public ::testing::TestWithParam<std::string> {
+ public:
+  virtual void SetUp() override {
+    ALOGI("SetUp Finder Test");
+    bluetooth_finder = IBluetoothFinder::fromBinder(
+        ndk::SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+    ASSERT_NE(bluetooth_finder, nullptr);
+  }
+
+  virtual void TearDown() override {
+    ALOGI("TearDown Finder Test");
+    bluetooth_finder = nullptr;
+    ASSERT_EQ(bluetooth_finder, nullptr);
+  }
+
+  ScopedAStatus sendEids(uint8_t num);
+  ScopedAStatus setPoweredOffFinderMode(bool enable);
+  ScopedAStatus getPoweredOffFinderMode(bool* status);
+
+ private:
+  std::shared_ptr<IBluetoothFinder> bluetooth_finder;
+};
+
+ScopedAStatus BluetoothFinderTest::sendEids(uint8_t numKeys) {
+  std::vector<Eid> keys(numKeys);
+  for (uint_t i = 0; i < numKeys; i++) {
+    std::array<uint8_t, 20> key;
+    key.fill(i + 1);
+    keys[i].bytes = key;
+  }
+  return bluetooth_finder->sendEids(keys);
+}
+
+ScopedAStatus BluetoothFinderTest::setPoweredOffFinderMode(bool enable) {
+  return bluetooth_finder->setPoweredOffFinderMode(enable);
+}
+
+ScopedAStatus BluetoothFinderTest::getPoweredOffFinderMode(bool* status) {
+  return bluetooth_finder->getPoweredOffFinderMode(status);
+}
+
+TEST_P(BluetoothFinderTest, SendEidsSingle) {
+  ScopedAStatus status = sendEids(1);
+  ASSERT_TRUE(status.isOk());
+}
+
+TEST_P(BluetoothFinderTest, Send255Eids) {
+  ScopedAStatus status = sendEids(255);
+  ASSERT_TRUE(status.isOk());
+}
+
+TEST_P(BluetoothFinderTest, setAndGetPoweredOffFinderModeEnable) {
+  ScopedAStatus status = setPoweredOffFinderMode(true);
+  ASSERT_TRUE(status.isOk());
+  bool pof_status;
+  status = getPoweredOffFinderMode(&pof_status);
+  ASSERT_TRUE(status.isOk());
+  ASSERT_TRUE(pof_status);
+}
+
+TEST_P(BluetoothFinderTest, setAndGetPoweredOffFinderModeDisable) {
+  ScopedAStatus status = setPoweredOffFinderMode(false);
+  ASSERT_TRUE(status.isOk());
+  bool pof_status;
+  status = getPoweredOffFinderMode(&pof_status);
+  ASSERT_TRUE(status.isOk());
+  ASSERT_TRUE(!pof_status);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BluetoothFinderTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothFinderTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             IBluetoothFinder::descriptor)),
+                         android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  ABinderProcess_startThreadPool();
+  int status = RUN_ALL_TESTS();
+  ALOGI("Test result = %d", status);
+  return status;
+}
diff --git a/bluetooth/finder/aidl/vts/VtsHalBluetoothFinderTargetTest.xml b/bluetooth/finder/aidl/vts/VtsHalBluetoothFinderTargetTest.xml
new file mode 100644
index 0000000..46053dd
--- /dev/null
+++ b/bluetooth/finder/aidl/vts/VtsHalBluetoothFinderTargetTest.xml
@@ -0,0 +1,33 @@
+<!--
+  Copyright (C) 2023 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<configuration description="Runs VtsHalBluetoothFinderTargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsHalBluetoothFinderTargetTest->/data/local/tmp/VtsHalBluetoothFinderTargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalBluetoothFinderTargetTest" />
+    </test>
+</configuration>
diff --git a/bluetooth/lmp_event/aidl/Android.bp b/bluetooth/lmp_event/aidl/Android.bp
new file mode 100644
index 0000000..6c2f278
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/Android.bp
@@ -0,0 +1,33 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.bluetooth.lmp_event",
+    vendor_available: true,
+    host_supported: true,
+    srcs: ["android/hardware/bluetooth/lmp_event/*.aidl"],
+    stability: "vintf",
+    backend: {
+        java: {
+            enabled: true,
+            platform_apis: true,
+        },
+        cpp: {
+            enabled: true,
+        },
+        ndk: {
+            enabled: true,
+            min_sdk_version: "33",
+        },
+        rust: {
+            enabled: true,
+            min_sdk_version: "33",
+        },
+    },
+}
diff --git a/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/AddressType.aidl b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/AddressType.aidl
new file mode 100644
index 0000000..0f239e8
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/AddressType.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.lmp_event;
+@Backing(type="byte") @VintfStability
+enum AddressType {
+  PUBLIC = 0x00,
+  RANDOM = 0x01,
+}
diff --git a/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/Direction.aidl b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/Direction.aidl
new file mode 100644
index 0000000..6f807cc
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/Direction.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.lmp_event;
+@Backing(type="byte") @VintfStability
+enum Direction {
+  TX = 0x00,
+  RX = 0x01,
+}
diff --git a/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/IBluetoothLmpEvent.aidl b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/IBluetoothLmpEvent.aidl
new file mode 100644
index 0000000..3431010
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/IBluetoothLmpEvent.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.lmp_event;
+@VintfStability
+interface IBluetoothLmpEvent {
+  void registerForLmpEvents(in android.hardware.bluetooth.lmp_event.IBluetoothLmpEventCallback callback, in android.hardware.bluetooth.lmp_event.AddressType addressType, in byte[6] address, in android.hardware.bluetooth.lmp_event.LmpEventId[] lmpEventIds);
+  void unregisterLmpEvents(in android.hardware.bluetooth.lmp_event.AddressType addressType, in byte[6] address);
+}
diff --git a/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/IBluetoothLmpEventCallback.aidl b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/IBluetoothLmpEventCallback.aidl
new file mode 100644
index 0000000..fc6758c
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/IBluetoothLmpEventCallback.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.lmp_event;
+@VintfStability
+interface IBluetoothLmpEventCallback {
+  void onEventGenerated(in android.hardware.bluetooth.lmp_event.Timestamp timestamp, in android.hardware.bluetooth.lmp_event.AddressType addressType, in byte[6] address, in android.hardware.bluetooth.lmp_event.Direction direction, in android.hardware.bluetooth.lmp_event.LmpEventId lmpEventId, in char connEventCounter);
+  void onRegistered(in boolean status);
+}
diff --git a/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/LmpEventId.aidl b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/LmpEventId.aidl
new file mode 100644
index 0000000..4ee95d1
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/LmpEventId.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.lmp_event;
+@Backing(type="byte") @VintfStability
+enum LmpEventId {
+  CONNECT_IND = 0x00,
+  LL_PHY_UPDATE_IND = 0x01,
+}
diff --git a/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/Timestamp.aidl b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/Timestamp.aidl
new file mode 100644
index 0000000..5ef32ba
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/Timestamp.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.lmp_event;
+@VintfStability
+parcelable Timestamp {
+  long systemTimeUs;
+  long bluetoothTimeUs;
+}
diff --git a/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/AddressType.aidl b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/AddressType.aidl
new file mode 100644
index 0000000..6bfc7c7
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/AddressType.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.lmp_event;
+
+/**
+ * Type of Address
+ */
+@VintfStability
+@Backing(type="byte")
+enum AddressType {
+    PUBLIC = 0x00,
+    RANDOM = 0x01,
+}
diff --git a/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/Direction.aidl b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/Direction.aidl
new file mode 100644
index 0000000..884c2bb
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/Direction.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.lmp_event;
+
+/**
+ * Direction of the LMP event
+ */
+@VintfStability
+@Backing(type="byte")
+enum Direction {
+    TX = 0x00,
+    RX = 0x01,
+}
diff --git a/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/IBluetoothLmpEvent.aidl b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/IBluetoothLmpEvent.aidl
new file mode 100644
index 0000000..3828af6
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/IBluetoothLmpEvent.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.lmp_event;
+
+import android.hardware.bluetooth.lmp_event.IBluetoothLmpEventCallback;
+import android.hardware.bluetooth.lmp_event.AddressType;
+import android.hardware.bluetooth.lmp_event.LmpEventId;
+
+@VintfStability
+interface IBluetoothLmpEvent {
+    /**
+     * API to monitor specific LMP event timestamp for given Bluetooth device.
+     *
+     * @param callback An instance of the |IBluetoothLmpEventCallback| AIDL interface object.
+     * @param addressType  Type of bluetooth address.
+     * @param address Bluetooth address to monitor.
+     * @param lmpEventIds LMP events to monitor.
+     */
+    void registerForLmpEvents(in IBluetoothLmpEventCallback callback,
+                              in AddressType addressType,
+                              in byte[6] address,
+                              in LmpEventId[] lmpEventIds);
+
+    /**
+     * API to stop monitoring a given Bluetooth device.
+     *
+     * @param addressType  Type of Bluetooth address.
+     * @param address Bluetooth device to stop monitoring.
+     */
+    void unregisterLmpEvents(in AddressType addressType, in byte[6] address);
+}
diff --git a/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/IBluetoothLmpEventCallback.aidl b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/IBluetoothLmpEventCallback.aidl
new file mode 100644
index 0000000..3295ef0
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/IBluetoothLmpEventCallback.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.lmp_event;
+
+import android.hardware.bluetooth.lmp_event.Direction;
+import android.hardware.bluetooth.lmp_event.AddressType;
+import android.hardware.bluetooth.lmp_event.LmpEventId;
+import android.hardware.bluetooth.lmp_event.Timestamp;
+
+@VintfStability
+interface IBluetoothLmpEventCallback {
+    /**
+     * Callback when monitored LMP event invoked.
+     *
+     * @param timestamp Timestamp when the LMP event invoked
+     * @param addressType  Type of Bluetooth address.
+     * @param address Remote bluetooth address that invoke LMP event
+     * @param direction Direction of the invoked LMP event
+     * @param lmpEventId LMP event id that bluetooth chip invoked
+     * @param connEventCounter counter incremented by one for each new connection event
+     */
+    void onEventGenerated(in Timestamp timestamp,
+                          in AddressType addressType,
+                          in byte[6] address,
+                          in Direction direction,
+                          in LmpEventId lmpEventId,
+                          in char connEventCounter);
+
+    /**
+     * Callback when registration done.
+     */
+    void onRegistered(in boolean status);
+}
diff --git a/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/LmpEventId.aidl b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/LmpEventId.aidl
new file mode 100644
index 0000000..3584b0c
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/LmpEventId.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.lmp_event;
+
+/**
+ * LMP event id to be monitored
+ * CONNECT_IND indicator for initiating connection
+ * LL_PHY_UPDATE_IND indicator for PHY update
+ */
+@VintfStability
+@Backing(type="byte")
+enum LmpEventId {
+    CONNECT_IND = 0x00,
+    LL_PHY_UPDATE_IND = 0x01,
+}
diff --git a/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/Timestamp.aidl b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/Timestamp.aidl
new file mode 100644
index 0000000..e3c991d
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/Timestamp.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.lmp_event;
+
+/**
+ * Generic structure to return the timestamp
+ */
+@VintfStability
+parcelable Timestamp {
+    /**
+     * Timestamp in microsecond since system boot.
+     *  if systemTimeUs is set to 0, its value is to be ignored
+     */
+    long systemTimeUs;
+    /**
+     * Timestamp in microsecond since Bluetooth controller power up.
+     */
+    long bluetoothTimeUs;
+}
diff --git a/bluetooth/lmp_event/aidl/default/Android.bp b/bluetooth/lmp_event/aidl/default/Android.bp
new file mode 100644
index 0000000..f8ca5e6
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/default/Android.bp
@@ -0,0 +1,28 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+rust_binary {
+    name: "android.hardware.bluetooth.lmp_event-service.default",
+    relative_install_path: "hw",
+    init_rc: ["lmp_event-default.rc"],
+    vintf_fragments: [":manifest_android.hardware.bluetooth.lmp_event-service.default.xml"],
+    vendor: true,
+    rustlibs: [
+        "liblogger",
+        "liblog_rust",
+        "libbinder_rs",
+        "android.hardware.bluetooth.lmp_event-V1-rust",
+    ],
+    srcs: [ "src/main.rs" ],
+}
+
+filegroup {
+    name: "manifest_android.hardware.bluetooth.lmp_event-service.default.xml",
+    srcs: [ "lmp_event-default.xml" ],
+}
diff --git a/bluetooth/lmp_event/aidl/default/lmp_event-default.rc b/bluetooth/lmp_event/aidl/default/lmp_event-default.rc
new file mode 100644
index 0000000..845e04d
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/default/lmp_event-default.rc
@@ -0,0 +1,6 @@
+service vendor.bluetooth.lmp_event-default /vendor/bin/hw/android.hardware.bluetooth.lmp_event-service.default
+    class hal
+    capabilities BLOCK_SUSPEND NET_ADMIN SYS_NICE
+    user bluetooth
+    group bluetooth
+    task_profiles HighPerformance
diff --git a/bluetooth/lmp_event/aidl/default/lmp_event-default.xml b/bluetooth/lmp_event/aidl/default/lmp_event-default.xml
new file mode 100644
index 0000000..24d93f8
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/default/lmp_event-default.xml
@@ -0,0 +1,10 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.bluetooth.lmp_event</name>
+        <version>1</version>
+        <interface>
+            <name>IBluetoothLmpEvent</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/bluetooth/lmp_event/aidl/default/src/lmp_event.rs b/bluetooth/lmp_event/aidl/default/src/lmp_event.rs
new file mode 100644
index 0000000..f016c3f
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/default/src/lmp_event.rs
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//! Implements LMP Event AIDL Interface.
+
+use android_hardware_bluetooth_lmp_event::aidl::android::hardware::bluetooth::lmp_event::{
+    Direction::Direction, AddressType::AddressType, IBluetoothLmpEvent::IBluetoothLmpEvent,
+    IBluetoothLmpEventCallback::IBluetoothLmpEventCallback, LmpEventId::LmpEventId,
+    Timestamp::Timestamp,
+};
+
+use binder::{Interface, Result, Strong};
+
+use log::info;
+use std::thread;
+use std::time;
+
+
+pub struct LmpEvent;
+
+impl LmpEvent {
+    pub fn new() -> Self {
+        Self
+    }
+}
+
+impl Interface for LmpEvent {}
+
+impl IBluetoothLmpEvent for LmpEvent {
+    fn registerForLmpEvents(&self,
+                            callback: &Strong<dyn IBluetoothLmpEventCallback>,
+                            address_type: AddressType,
+                            address: &[u8; 6],
+                            lmp_event_ids: &[LmpEventId]
+    ) -> Result<()> {
+        info!("registerForLmpEvents");
+
+        let cb = callback.clone();
+        let addr_type = address_type;
+        let addr = address.clone();
+        let lmp_event = lmp_event_ids.to_vec();
+
+        let thread_handle = thread::spawn(move || {
+            let ts = Timestamp {
+                bluetoothTimeUs: 1000000,
+                systemTimeUs: 2000000,
+            };
+
+            info!("sleep for 1000 ms");
+            thread::sleep(time::Duration::from_millis(1000));
+
+            info!("callback event");
+            cb.onEventGenerated(&ts, addr_type, &addr, Direction::RX, lmp_event[0], 1)
+                .expect("onEventGenerated failed");
+        });
+
+        info!("callback register");
+        callback.onRegistered(true)?;
+
+        thread_handle.join().expect("join failed");
+        Ok(())
+    }
+    fn unregisterLmpEvents(&self, _address_type: AddressType, _address: &[u8; 6]) -> Result<()> {
+        info!("unregisterLmpEvents");
+
+        Ok(())
+    }
+}
diff --git a/bluetooth/lmp_event/aidl/default/src/main.rs b/bluetooth/lmp_event/aidl/default/src/main.rs
new file mode 100644
index 0000000..cbdd4d1
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/default/src/main.rs
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//! Implements LMP Event Example Service.
+
+
+use android_hardware_bluetooth_lmp_event::aidl::android::hardware::bluetooth::lmp_event::IBluetoothLmpEvent::{
+    IBluetoothLmpEvent, BnBluetoothLmpEvent
+};
+
+use binder::BinderFeatures;
+use log::{info, Level};
+
+mod lmp_event;
+
+const LOG_TAG: &str = "lmp_event_service_example";
+
+fn main() {
+    info!("{LOG_TAG}: starting service");
+    let logger_success = logger::init(
+        logger::Config::default().with_tag_on_device(LOG_TAG).with_min_level(Level::Trace)
+    );
+    if !logger_success {
+        panic!("{LOG_TAG}: Failed to start logger");
+    }
+
+    binder::ProcessState::set_thread_pool_max_thread_count(0);
+
+    let lmp_event_service = lmp_event::LmpEvent::new();
+    let lmp_event_service_binder = BnBluetoothLmpEvent::new_binder(lmp_event_service, BinderFeatures::default());
+
+    binder::add_service(
+        &format!("{}/default", lmp_event::LmpEvent::get_descriptor()),
+        lmp_event_service_binder.as_binder(),
+    ).expect("Failed to register service");
+
+    binder::ProcessState::join_thread_pool()
+}
diff --git a/bluetooth/lmp_event/aidl/vts/Android.bp b/bluetooth/lmp_event/aidl/vts/Android.bp
new file mode 100644
index 0000000..b89351e
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/vts/Android.bp
@@ -0,0 +1,20 @@
+cc_test {
+    name: "VtsHalLmpEventTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalLmpEventTargetTest.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libbinder_ndk"
+    ],
+    static_libs: [
+        "android.hardware.bluetooth.lmp_event-V1-ndk",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ]
+}
+
diff --git a/bluetooth/lmp_event/aidl/vts/VtsHalLmpEventTargetTest.cpp b/bluetooth/lmp_event/aidl/vts/VtsHalLmpEventTargetTest.cpp
new file mode 100644
index 0000000..c49f60b
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/vts/VtsHalLmpEventTargetTest.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the std::shared_ptrecific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "lmp_event_hal_test"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+
+#include <aidl/android/hardware/bluetooth/lmp_event/BnBluetoothLmpEvent.h>
+#include <aidl/android/hardware/bluetooth/lmp_event/BnBluetoothLmpEventCallback.h>
+#include <aidl/android/hardware/bluetooth/lmp_event/Direction.h>
+#include <aidl/android/hardware/bluetooth/lmp_event/AddressType.h>
+#include <aidl/android/hardware/bluetooth/lmp_event/LmpEventId.h>
+#include <aidl/android/hardware/bluetooth/lmp_event/Timestamp.h>
+
+#include <android/binder_auto_utils.h>
+#include <android/binder_manager.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <log/log.h>
+
+#include <chrono>
+#include <condition_variable>
+#include <cinttypes>
+#include <thread>
+
+using ::aidl::android::hardware::bluetooth::lmp_event::BnBluetoothLmpEventCallback;
+using ::aidl::android::hardware::bluetooth::lmp_event::IBluetoothLmpEvent;
+using ::aidl::android::hardware::bluetooth::lmp_event::IBluetoothLmpEventCallback;
+using ::aidl::android::hardware::bluetooth::lmp_event::Direction;
+using ::aidl::android::hardware::bluetooth::lmp_event::AddressType;
+using ::aidl::android::hardware::bluetooth::lmp_event::LmpEventId;
+using ::aidl::android::hardware::bluetooth::lmp_event::Timestamp;
+
+using ::android::ProcessState;
+using ::ndk::SpAIBinder;
+
+namespace {
+    static constexpr std::chrono::milliseconds kEventTimeoutMs(10000);
+}
+
+class BluetoothLmpEventTest : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        ALOGI("%s", __func__);
+
+        ibt_lmp_event_ = IBluetoothLmpEvent::fromBinder(SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+        ASSERT_NE(ibt_lmp_event_, nullptr);
+
+        ibt_lmp_event_cb_ = ndk::SharedRefBase::make<BluetoothLmpEventCallback>(*this);
+        ASSERT_NE(ibt_lmp_event_cb_, nullptr);
+    }
+
+    virtual void TearDown() override {
+        ALOGI("%s", __func__);
+        ibt_lmp_event_->unregisterLmpEvents(address_type, address);
+
+        ibt_lmp_event_cb_ = nullptr;
+    }
+
+    class BluetoothLmpEventCallback : public BnBluetoothLmpEventCallback {
+        public:
+            BluetoothLmpEventTest& parent_;
+            BluetoothLmpEventCallback(BluetoothLmpEventTest& parent)
+                : parent_(parent) {}
+            ~BluetoothLmpEventCallback() = default;
+
+            ::ndk::ScopedAStatus onEventGenerated(const Timestamp& timestamp, AddressType address_type,
+                    const std::array<uint8_t, 6>& address, Direction direction,
+                    LmpEventId lmp_event_id, char16_t conn_event_counter) override {
+                for (auto t: address) {
+                    ALOGD("%s: 0x%02x", __func__, t);
+                }
+                if (direction == Direction::TX) {
+                    ALOGD("%s: Transmitting", __func__);
+                } else if (direction == Direction::RX) {
+                    ALOGD("%s: Receiving", __func__);
+                }
+                if (address_type == AddressType::PUBLIC) {
+                    ALOGD("%s: Public address", __func__);
+                } else if (address_type == AddressType::RANDOM) {
+                    ALOGD("%s: Random address", __func__);
+                }
+                if (lmp_event_id == LmpEventId::CONNECT_IND) {
+                    ALOGD("%s: initiating connection", __func__);
+                } else if (lmp_event_id == LmpEventId::LL_PHY_UPDATE_IND) {
+                    ALOGD("%s: PHY update indication", __func__);
+                }
+
+                ALOGD("%s: time: %" PRId64 "counter value: %x", __func__, timestamp.bluetoothTimeUs, conn_event_counter);
+
+                parent_.event_recv = true;
+                parent_.notify();
+
+                return ::ndk::ScopedAStatus::ok();
+            }
+            ::ndk::ScopedAStatus onRegistered(bool status) override {
+                ALOGD("%s: status: %d", __func__, status);
+                parent_.status_recv = status;
+                parent_.notify();
+                return ::ndk::ScopedAStatus::ok();
+            }
+    };
+
+    inline void notify() {
+        std::unique_lock<std::mutex> lock(lmp_event_mtx);
+        lmp_event_cv.notify_one();
+    }
+
+    inline void wait(bool is_register_event) {
+        std::unique_lock<std::mutex> lock(lmp_event_mtx);
+
+
+        if (is_register_event) {
+            lmp_event_cv.wait(lock, [&]() { return status_recv == true; });
+        } else {
+            lmp_event_cv.wait_for(lock, kEventTimeoutMs,
+                    [&](){ return event_recv == true; });
+        }
+
+    }
+
+    std::shared_ptr<IBluetoothLmpEvent> ibt_lmp_event_;
+    std::shared_ptr<IBluetoothLmpEventCallback> ibt_lmp_event_cb_;
+
+    AddressType address_type;
+    std::array<uint8_t, 6> address;
+
+    std::atomic<bool> event_recv;
+    bool status_recv;
+
+    std::mutex lmp_event_mtx;
+    std::condition_variable lmp_event_cv;
+};
+
+TEST_P(BluetoothLmpEventTest, RegisterAndReceive) {
+    address = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+    address_type = AddressType::RANDOM;
+    std::vector<LmpEventId> lmp_event_ids{LmpEventId::CONNECT_IND, LmpEventId::LL_PHY_UPDATE_IND};
+
+    ibt_lmp_event_->registerForLmpEvents(ibt_lmp_event_cb_, address_type, address, lmp_event_ids);
+    wait(true);
+    EXPECT_EQ(true, status_recv);
+
+    /* Wait for event generated here */
+    wait(false);
+    EXPECT_EQ(true, event_recv);
+
+    ibt_lmp_event_->unregisterLmpEvents(address_type, address);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BluetoothLmpEventTest);
+INSTANTIATE_TEST_SUITE_P(BluetoothLmpEvent, BluetoothLmpEventTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IBluetoothLmpEvent::descriptor)),
+                         android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ProcessState::self()->setThreadPoolMaxThreadCount(1);
+    ProcessState::self()->startThreadPool();
+    return RUN_ALL_TESTS();
+}
+
diff --git a/bluetooth/ranging/OWNERS b/bluetooth/ranging/OWNERS
new file mode 100644
index 0000000..3d95624
--- /dev/null
+++ b/bluetooth/ranging/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 27441
+
+include platform/packages/modules/Bluetooth:/OWNERS
+
+chienyuanhuang@google.com
diff --git a/bluetooth/ranging/aidl/Android.bp b/bluetooth/ranging/aidl/Android.bp
new file mode 100644
index 0000000..9e53ef6
--- /dev/null
+++ b/bluetooth/ranging/aidl/Android.bp
@@ -0,0 +1,39 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.bluetooth.ranging",
+    vendor_available: true,
+    host_supported: true,
+    srcs: ["android/hardware/bluetooth/ranging/*.aidl"],
+    stability: "vintf",
+    backend: {
+        ndk: {
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.btservices",
+            ],
+            min_sdk_version: "33",
+        },
+    },
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/AddressType.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/AddressType.aidl
new file mode 100644
index 0000000..fc417f0
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/AddressType.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.ranging;
+@Backing(type="int") @VintfStability
+enum AddressType {
+  PUBLIC = 0x00,
+  RANDOM = 0x01,
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/BluetoothChannelSoundingParameters.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/BluetoothChannelSoundingParameters.aidl
new file mode 100644
index 0000000..e8fefbe
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/BluetoothChannelSoundingParameters.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.ranging;
+@VintfStability
+parcelable BluetoothChannelSoundingParameters {
+  android.hardware.bluetooth.ranging.SessionType sessionType;
+  int aclHandle;
+  int l2capCid;
+  int realTimeProcedureDataAttHandle;
+  android.hardware.bluetooth.ranging.Role role;
+  boolean localSupportsSoundingPhaseBasedRanging;
+  boolean remoteSupportsSoundingPhaseBaseRanging;
+  android.hardware.bluetooth.ranging.Config config;
+  android.hardware.bluetooth.ranging.DeviceAddress address;
+  @nullable android.hardware.bluetooth.ranging.VendorSpecificData[] vendorSpecificData;
+  android.hardware.bluetooth.ranging.LocationType locationType;
+  android.hardware.bluetooth.ranging.SightType sightType;
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl
new file mode 100644
index 0000000..8fc77ae
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.ranging;
+@VintfStability
+parcelable ChannelSoudingRawData {
+  int procedureCounter;
+  int[] frequencyCompensation;
+  boolean aborted;
+  android.hardware.bluetooth.ranging.ChannelSoundingSingleSideData initiatorData;
+  android.hardware.bluetooth.ranging.ChannelSoundingSingleSideData reflectorData;
+  byte[] stepChannels;
+  @nullable int[] toaTodInitiator;
+  @nullable int[] todToaReflector;
+  android.hardware.bluetooth.ranging.ModeType[] stepMode;
+  byte numAntennaPaths;
+  long timestampMs;
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl
new file mode 100644
index 0000000..ddaba72
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.ranging;
+@VintfStability
+parcelable ChannelSoundingSingleSideData {
+  @nullable List<android.hardware.bluetooth.ranging.StepTonePct> stepTonePcts;
+  @nullable byte[] packetQuality;
+  @nullable byte[] packetRssiDbm;
+  @nullable android.hardware.bluetooth.ranging.Nadm[] packetNadm;
+  @nullable int[] measuredFreqOffset;
+  @nullable List<android.hardware.bluetooth.ranging.ComplexNumber> packetPct1;
+  @nullable List<android.hardware.bluetooth.ranging.ComplexNumber> packetPct2;
+  byte referencePowerDbm;
+  @nullable byte[] vendorSpecificCsSingleSidedata;
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ComplexNumber.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ComplexNumber.aidl
new file mode 100644
index 0000000..4d5ac21
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ComplexNumber.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.ranging;
+@VintfStability
+parcelable ComplexNumber {
+  double real;
+  double imaginary;
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/Config.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/Config.aidl
new file mode 100644
index 0000000..c9ac991
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/Config.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.ranging;
+@VintfStability
+parcelable Config {
+  android.hardware.bluetooth.ranging.ModeType modeType;
+  android.hardware.bluetooth.ranging.SubModeType subModeType;
+  android.hardware.bluetooth.ranging.RttType rttType;
+  byte[10] channelMap;
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/CsSecurityLevel.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/CsSecurityLevel.aidl
new file mode 100644
index 0000000..6a31547
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/CsSecurityLevel.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.ranging;
+@Backing(type="int") @VintfStability
+enum CsSecurityLevel {
+  NOT_SUPPORTED = 0x00,
+  ONE = 0x01,
+  TWO = 0x02,
+  THREE = 0x03,
+  FOUR = 0x04,
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/DeviceAddress.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/DeviceAddress.aidl
new file mode 100644
index 0000000..69cad5d
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/DeviceAddress.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.ranging;
+@VintfStability
+parcelable DeviceAddress {
+  android.hardware.bluetooth.ranging.AddressType addressType;
+  byte[6] address;
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/IBluetoothChannelSounding.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/IBluetoothChannelSounding.aidl
new file mode 100644
index 0000000..004a482
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/IBluetoothChannelSounding.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.ranging;
+@VintfStability
+interface IBluetoothChannelSounding {
+  @nullable android.hardware.bluetooth.ranging.VendorSpecificData[] getVendorSpecificData();
+  @nullable android.hardware.bluetooth.ranging.SessionType[] getSupportedSessionTypes();
+  android.hardware.bluetooth.ranging.CsSecurityLevel getMaxSupportedCsSecurityLevel();
+  @nullable android.hardware.bluetooth.ranging.IBluetoothChannelSoundingSession openSession(in android.hardware.bluetooth.ranging.BluetoothChannelSoundingParameters params, in android.hardware.bluetooth.ranging.IBluetoothChannelSoundingSessionCallback callback);
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSession.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSession.aidl
new file mode 100644
index 0000000..9f691b4
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSession.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.ranging;
+@VintfStability
+interface IBluetoothChannelSoundingSession {
+  @nullable android.hardware.bluetooth.ranging.VendorSpecificData[] getVendorSpecificReplies();
+  android.hardware.bluetooth.ranging.ResultType[] getSupportedResultTypes();
+  boolean isAbortedProcedureRequired();
+  void writeRawData(in android.hardware.bluetooth.ranging.ChannelSoudingRawData rawData);
+  void close(android.hardware.bluetooth.ranging.Reason reason);
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSessionCallback.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSessionCallback.aidl
new file mode 100644
index 0000000..d6622de
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSessionCallback.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.ranging;
+@VintfStability
+interface IBluetoothChannelSoundingSessionCallback {
+  void onOpened(android.hardware.bluetooth.ranging.Reason reason);
+  void onOpenFailed(android.hardware.bluetooth.ranging.Reason reason);
+  void onResult(in android.hardware.bluetooth.ranging.RangingResult result);
+  void onClose(android.hardware.bluetooth.ranging.Reason reason);
+  void onCloseFailed(android.hardware.bluetooth.ranging.Reason reason);
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/LocationType.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/LocationType.aidl
new file mode 100644
index 0000000..d95af26
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/LocationType.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.ranging;
+@Backing(type="byte") @VintfStability
+enum LocationType {
+  UNKNOWN = 0x00,
+  INDOOR = 0x01,
+  OUTDOOR = 0x02,
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ModeType.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ModeType.aidl
new file mode 100644
index 0000000..75cdabc
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ModeType.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.ranging;
+@Backing(type="int") @VintfStability
+enum ModeType {
+  ZERO = 0x00,
+  ONE = 0x01,
+  TWO = 0x02,
+  THREE = 0x03,
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/Nadm.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/Nadm.aidl
new file mode 100644
index 0000000..a0aa47b
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/Nadm.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.ranging;
+@Backing(type="byte") @VintfStability
+enum Nadm {
+  ATTACK_IS_EXTREMELY_UNLIKELY = 0x00,
+  ATTACK_IS_VERY_UNLIKELY = 0x01,
+  ATTACK_IS_UNLIKELY = 0x02,
+  ATTACK_IS_POSSIBLE = 0x03,
+  ATTACK_IS_LIKELY = 0x04,
+  ATTACK_IS_VERY_LIKELY = 0x05,
+  ATTACK_IS_EXTREMELY_LIKELY = 0x06,
+  UNKNOWN = 0xFFu8,
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/RangingResult.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/RangingResult.aidl
new file mode 100644
index 0000000..d092b80
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/RangingResult.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.ranging;
+@VintfStability
+parcelable RangingResult {
+  double resultMeters;
+  double errorMeters;
+  double azimuthDegrees;
+  double errorAzimuthDegrees;
+  double altitudeDegrees;
+  double errorAltitudeDegrees;
+  double delaySpreadMeters;
+  byte confidenceLevel;
+  android.hardware.bluetooth.ranging.Nadm detectedAttackLevel;
+  double velocityMetersPerSecond;
+  @nullable byte[] vendorSpecificCsRangingResultsData;
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/Reason.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/Reason.aidl
new file mode 100644
index 0000000..ddd44fe
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/Reason.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.ranging;
+@Backing(type="int") @VintfStability
+enum Reason {
+  LOCAL_STACK_REQUEST,
+  HAL_INITIATED,
+  HARDWARE_INITIATED,
+  ERROR_INVALID_PARAMETER,
+  ERROR_UNKNOWN,
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ResultType.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ResultType.aidl
new file mode 100644
index 0000000..b3e098c
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ResultType.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.ranging;
+@Backing(type="int") @VintfStability
+enum ResultType {
+  RESULT_METERS = 0x00,
+  ERROR_METERS = 0x01,
+  AZIMUTH_DEGREES = 0x02,
+  ERROR_AZIMUTH_DEGREES = 0x03,
+  ALTITUDE_DEGREES = 0x04,
+  ERROR_ALTITUDE_DEGREES = 0x05,
+  DELAY_SPREAD_METERS = 0x06,
+  CONFIDENCE_LEVEL = 0x07,
+  SECURITY_LEVEL = 0x08,
+  VELOCITY = 0x09,
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/Role.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/Role.aidl
new file mode 100644
index 0000000..61ee1aa
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/Role.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.ranging;
+@Backing(type="int") @VintfStability
+enum Role {
+  INITIATOR = 0,
+  REFLECTOR = 1,
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/RttType.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/RttType.aidl
new file mode 100644
index 0000000..e662c07
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/RttType.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.ranging;
+@Backing(type="int") @VintfStability
+enum RttType {
+  AA_COARSE = 0x00,
+  WITH_32_BIT_SOUNDING_SEQUENCE = 0x01,
+  WITH_96_BIT_SOUNDING_SEQUENCE = 0x02,
+  WITH_32_BIT_RANDOM_SEQUENCE = 0x03,
+  WITH_64_BIT_RANDOM_SEQUENCE = 0x04,
+  WITH_96_BIT_RANDOM_SEQUENCE = 0x05,
+  WITH_128_BIT_RANDOM_SEQUENCE = 0x06,
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/SessionType.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/SessionType.aidl
new file mode 100644
index 0000000..d43022f
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/SessionType.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.ranging;
+@Backing(type="int") @VintfStability
+enum SessionType {
+  SOFTWARE_STACK_DATA_PARSING = 0,
+  HARDWARE_OFFLOAD_DATA_PARSING = 1,
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/SightType.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/SightType.aidl
new file mode 100644
index 0000000..6e96ba4
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/SightType.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.ranging;
+@Backing(type="byte") @VintfStability
+enum SightType {
+  UNKNOWN = 0x00,
+  LINE_OF_SIGHT = 0x01,
+  NON_LINE_OF_SIGHT = 0x02,
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/StepTonePct.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/StepTonePct.aidl
new file mode 100644
index 0000000..4125748
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/StepTonePct.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.ranging;
+@VintfStability
+parcelable StepTonePct {
+  List<android.hardware.bluetooth.ranging.ComplexNumber> tonePcts;
+  byte[] toneQualityIndicator;
+  byte toneExtensionAntennaIndex;
+  const int TONE_QUALITY_GOOD = 0;
+  const int TONE_QUALITY_MEDIUM = 1;
+  const int TONE_QUALITY_LOW = 2;
+  const int TONE_QUALITY_UNAVAILABLE = 3;
+  const int EXTENSION_SLOT_NONE = 0;
+  const int EXTENSION_SLOT_TONE_NOT_EXPECTED_TO_BE_PRESENT = 1;
+  const int EXTENSION_SLOT_TONE_EXPECTED_TO_BE_PRESENT = 2;
+  const int EXTENSION_SLOT_SHIFT_AMOUNT = 4;
+  const byte TONE_EXTENSION_ANTENNA_1 = 0x0;
+  const byte TONE_EXTENSION_ANTENNA_2 = 0x1;
+  const byte TONE_EXTENSION_ANTENNA_3 = 0x2;
+  const byte TONE_EXTENSION_ANTENNA_4 = 0x3;
+  const byte TONE_EXTENSION_UNUSED = 0xFFu8;
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/SubModeType.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/SubModeType.aidl
new file mode 100644
index 0000000..f660c91
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/SubModeType.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.ranging;
+@Backing(type="int") @VintfStability
+enum SubModeType {
+  ONE = 0x01,
+  TWO = 0x02,
+  THREE = 0x03,
+  UNUSED = 0xff,
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/VendorSpecificData.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/VendorSpecificData.aidl
new file mode 100644
index 0000000..13bf696
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/VendorSpecificData.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.ranging;
+@VintfStability
+parcelable VendorSpecificData {
+  byte[16] characteristicUuid;
+  byte[] opaqueValue;
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/AddressType.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/AddressType.aidl
new file mode 100644
index 0000000..bd03213
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/AddressType.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+@VintfStability
+@Backing(type="int")
+enum AddressType {
+    PUBLIC = 0x00,
+    RANDOM = 0x01,
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/BluetoothChannelSoundingParameters.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/BluetoothChannelSoundingParameters.aidl
new file mode 100644
index 0000000..0cda847
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/BluetoothChannelSoundingParameters.aidl
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+import android.hardware.bluetooth.ranging.Config;
+import android.hardware.bluetooth.ranging.DeviceAddress;
+import android.hardware.bluetooth.ranging.LocationType;
+import android.hardware.bluetooth.ranging.Role;
+import android.hardware.bluetooth.ranging.SessionType;
+import android.hardware.bluetooth.ranging.SightType;
+import android.hardware.bluetooth.ranging.VendorSpecificData;
+
+/**
+ * Parameters for IBluetoothChannelSoundingSession.openSession().
+ */
+@VintfStability
+parcelable BluetoothChannelSoundingParameters {
+    SessionType sessionType;
+    /**
+     * Acl handle of the connection.
+     */
+    int aclHandle;
+    /**
+     * L2CAP Cid, needed in case of EATT which may use dynamic channel for GATT.
+     */
+    int l2capCid;
+    /**
+     * ATT handle of the Real-time Procedure Data.
+     */
+    int realTimeProcedureDataAttHandle;
+    /**
+     * Role of the local device.
+     */
+    Role role;
+    /**
+     * If sounding phase-based ranging is supported by the local device.
+     */
+    boolean localSupportsSoundingPhaseBasedRanging;
+    /**
+     * If sounding phase-based ranging is supported by the remote device.
+     */
+    boolean remoteSupportsSoundingPhaseBaseRanging;
+    /**
+     * CS conifg used for procedure enable.
+     */
+    Config config;
+    /**
+     * Device address of the remote device.
+     */
+    DeviceAddress address;
+    /**
+     * Vendor-specific data get from remote GATT Server
+     */
+    @nullable VendorSpecificData[] vendorSpecificData;
+    /**
+     * Specifies the preferred location type of the use case (indoor, outdoor, unknown), this is
+     * used by the HAL to choose the corresponding ranging algorithm if it supports multiple
+     * algorithms
+     */
+    LocationType locationType;
+    /**
+     * Specifies the preferred sight type of the use case (line-of-sight, non-line-of-sight,
+     * unknown), this is used by the HAL to choose the corresponding ranging algorithm if it
+     * supports multiple algorithms
+     */
+    SightType sightType;
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl
new file mode 100644
index 0000000..0106865
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+import android.hardware.bluetooth.ranging.ChannelSoundingSingleSideData;
+import android.hardware.bluetooth.ranging.ModeType;
+
+/**
+ * Raw ranging data of Channel Sounding.
+ */
+@VintfStability
+parcelable ChannelSoudingRawData {
+    /**
+     * Procedure counter of the CS procedure.
+     */
+    int procedureCounter;
+    /**
+     * Frequency Compensation indicates fractional frequency
+     * offset (FFO) value of initiator, in 0.01ppm
+     */
+    int[] frequencyCompensation;
+    /**
+     * Indicate if the procedure aborted.
+     */
+    boolean aborted;
+    /**
+     * Common data for both initator and reflector sided.
+     */
+    ChannelSoundingSingleSideData initiatorData;
+    ChannelSoundingSingleSideData reflectorData;
+    /**
+     * The channel indices of every step in a CS procedure (in time order).
+     */
+    byte[] stepChannels;
+    /**
+     * Toa_tod_initator from mode-1 or mode-3 steps in a CS procedure (in time order).
+     * Time of flight = 0.5 * (toa_tod_initiator - tod_toa_reflector).
+     */
+    @nullable int[] toaTodInitiator;
+    /**
+     * Tod_toa_reflector from mode-1 or mode-3 steps in a CS procedure (in time order).
+     * Time of flight = 0.5 * (toa_tod_initiator - tod_toa_reflector).
+     */
+    @nullable int[] todToaReflector;
+    /**
+     * CS mode (0, 1, 2, 3) of each CS step.
+     */
+    ModeType[] stepMode;
+    /**
+     * Number of antenna paths (1 to 4) reported in the CS procedure.
+     */
+    byte numAntennaPaths;
+    /**
+     * Timestamp when the procedure is created. Using epoch time in ms (e.g., 1697673127175).
+     */
+    long timestampMs;
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl
new file mode 100644
index 0000000..942fc0d
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+import android.hardware.bluetooth.ranging.ComplexNumber;
+import android.hardware.bluetooth.ranging.Nadm;
+import android.hardware.bluetooth.ranging.StepTonePct;
+
+/**
+ * Raw ranging data of Channel Sounding from either Initator or Reflector
+ */
+@VintfStability
+parcelable ChannelSoundingSingleSideData {
+    /**
+     * PCT (complex value) measured from mode-2 or mode-3 steps in a CS procedure (in time order).
+     */
+    @nullable List<StepTonePct> stepTonePcts;
+    /**
+     * Packet Quality from mode-1 or mode-3 steps in a CS procedures (in time order).
+     */
+    @nullable byte[] packetQuality;
+    /**
+     * Packet RSSI (-127 to 20) of mode-0, mode-1, or mode-3 step data, in dBm.
+     */
+    @nullable byte[] packetRssiDbm;
+    /**
+     * Packet NADM of mode-1 or mode-3 step data for attack detection.
+     */
+    @nullable Nadm[] packetNadm;
+    /**
+     * Measured Frequency Offset from mode 0, relative to the remote device, in 0.01ppm
+     */
+    @nullable int[] measuredFreqOffset;
+    /**
+     * Packet_PCT1 or packet_PCT2 of mode-1 or mode-3, if sounding sequence is used and sounding
+     * phase-based ranging is supported.
+     */
+    @nullable List<ComplexNumber> packetPct1;
+    @nullable List<ComplexNumber> packetPct2;
+    /**
+     * Reference power level (-127 to 20) of the signal in the procedure, in dBm.
+     */
+    byte referencePowerDbm;
+    /**
+     * Parameter for vendors to place vendor-specific raw ranging data.
+     */
+    @nullable byte[] vendorSpecificCsSingleSidedata;
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ComplexNumber.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ComplexNumber.aidl
new file mode 100644
index 0000000..5253d9f
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ComplexNumber.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+@VintfStability
+parcelable ComplexNumber {
+    double real;
+    double imaginary;
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/Config.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/Config.aidl
new file mode 100644
index 0000000..85ae4c1
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/Config.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+import android.hardware.bluetooth.ranging.ModeType;
+import android.hardware.bluetooth.ranging.RttType;
+import android.hardware.bluetooth.ranging.SubModeType;
+
+@VintfStability
+parcelable Config {
+    /**
+     * Main_Mode_Type of the CS conifg
+     */
+    ModeType modeType;
+    /**
+     * Sub_Mode_Type of the CS conifg
+     */
+    SubModeType subModeType;
+    /**
+     * RTT_Type of the CS conifg
+     */
+    RttType rttType;
+    /**
+     * Channel_Map of the CS conifg, this parameter contains 80 1-bit fields. The nth such field
+     * (in the range 0 to 78) contains the value for the CS channel index n.
+     *
+     * Channel n is enabled for CS procedure = 1
+     * Channel n is disabled for CS procedure = 0
+     */
+    byte[10] channelMap;
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/CsSecurityLevel.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/CsSecurityLevel.aidl
new file mode 100644
index 0000000..3fd4424
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/CsSecurityLevel.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+@VintfStability
+@Backing(type="int")
+enum CsSecurityLevel {
+    /**
+     * Ranging algorithm is not implemented.
+     */
+    NOT_SUPPORTED = 0x00,
+    /**
+     * Either CS tone or CS RTT.
+     */
+    ONE = 0x01,
+    /**
+     * 150 ns CS RTT accuracy and CS tones.
+     */
+    TWO = 0x02,
+    /**
+     * 10 ns CS RTT accuracy and CS tones.
+     */
+    THREE = 0x03,
+    /**
+     * Level 3 with the addition of CS RTT sounding sequence or random sequence
+     * payloads, and support of the Normalized Attack Detector Metric requirements.
+     */
+    FOUR = 0x04,
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/DeviceAddress.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/DeviceAddress.aidl
new file mode 100644
index 0000000..c847c30
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/DeviceAddress.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+import android.hardware.bluetooth.ranging.AddressType;
+
+/**
+ * Bluetooth address with address type
+ */
+@VintfStability
+parcelable DeviceAddress {
+    AddressType addressType;
+    byte[6] address;
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/IBluetoothChannelSounding.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/IBluetoothChannelSounding.aidl
new file mode 100644
index 0000000..45ec79f
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/IBluetoothChannelSounding.aidl
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+import android.hardware.bluetooth.ranging.BluetoothChannelSoundingParameters;
+import android.hardware.bluetooth.ranging.CsSecurityLevel;
+import android.hardware.bluetooth.ranging.IBluetoothChannelSoundingSession;
+import android.hardware.bluetooth.ranging.IBluetoothChannelSoundingSessionCallback;
+import android.hardware.bluetooth.ranging.Nadm;
+import android.hardware.bluetooth.ranging.SessionType;
+import android.hardware.bluetooth.ranging.VendorSpecificData;
+
+/**
+ * The interface for the Bluetooth stack to get vendor specifc data and open session
+ * for channel sounding.
+ */
+@VintfStability
+interface IBluetoothChannelSounding {
+    /**
+     * API to get vendor-specific data, the Bluetooth stack will provision the GATT server with
+     * these vendor-specific UUIDs and data.
+     *
+     * @return an array of vendor specifc data
+     */
+    @nullable VendorSpecificData[] getVendorSpecificData();
+
+    /**
+     * API to get supported session types of the HAL
+     *
+     * @return an array of supported session types
+     */
+    @nullable SessionType[] getSupportedSessionTypes();
+
+    /**
+     * API to get max supported security level (0 to 4) of CS for ranging algorithms.
+     *
+     *  See: https://bluetooth.com/specifications/specs/channel-sounding-cr-pr/
+     *
+     * @return CsSecurityLevel that indicates max supported security level of CS for ranging
+     *         algorithms.
+     */
+    CsSecurityLevel getMaxSupportedCsSecurityLevel();
+
+    /**
+     * API to open session for channel sounding and register the corresponeding callback
+     *
+     * @return an instance of IBluetoothChannelSoundingSession
+     */
+    @nullable IBluetoothChannelSoundingSession openSession(
+            in BluetoothChannelSoundingParameters params,
+            in IBluetoothChannelSoundingSessionCallback callback);
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSession.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSession.aidl
new file mode 100644
index 0000000..97b147e
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSession.aidl
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+import android.hardware.bluetooth.ranging.ChannelSoudingRawData;
+import android.hardware.bluetooth.ranging.Reason;
+import android.hardware.bluetooth.ranging.ResultType;
+import android.hardware.bluetooth.ranging.VendorSpecificData;
+
+/**
+ * Session of Channel Sounding get from IBluetoothChannelSounding.openSession().
+ * Used by the Bluetooth stack to get preferred config from HAL and provide raw ranging data to
+ * the HAL.
+ */
+@VintfStability
+interface IBluetoothChannelSoundingSession {
+    /**
+     * API to get vendor-specifc replies
+     *
+     * @return an array of vendor-specifc data
+     */
+    @nullable VendorSpecificData[] getVendorSpecificReplies();
+
+    /**
+     * API to obtain supported result types. The Bluetooth stack should use this function to check
+     * for supported result types and ignore unsupported types in the RangingResult.
+     *
+     * @return an array of vendor-specifc data
+     */
+    ResultType[] getSupportedResultTypes();
+
+    /**
+     * Indicate whether the HAL would like to receive raw data of abort procedures.
+     * If this function returns true, the Bluetooth stack should pass the data to the HAL using
+     * the writeRawData() function, even if the CS procedure is aborted.
+     *
+     * @return true if the HAL would like to receive raw data of abort procedures.
+     */
+    boolean isAbortedProcedureRequired();
+
+    /**
+     * API to provide raw ranging data to the HAL. The HAL converts this data into meaningful
+     * ranging results using a proprietary algorithm and then calls back to the Bluetooth stack via
+     * IBluetoothChannelSoundingSessionCallback.onResult().
+     */
+    void writeRawData(in ChannelSoudingRawData rawData);
+
+    /**
+     * Close the current session. Object is no longer useful after this method.
+     */
+    void close(Reason reason);
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSessionCallback.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSessionCallback.aidl
new file mode 100644
index 0000000..6901305
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSessionCallback.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+import android.hardware.bluetooth.ranging.RangingResult;
+import android.hardware.bluetooth.ranging.Reason;
+
+/**
+ * The callback from the HAL to the stack.
+ * Register by IBluetoothChannelSoundingSession.openSession().
+ */
+@VintfStability
+interface IBluetoothChannelSoundingSessionCallback {
+    /**
+     * Invoked when IBluetoothChannelSounding.openSession() is successful.
+     */
+    void onOpened(Reason reason);
+    /**
+     * Invoked when IBluetoothChannelSounding.openSession() fails.
+     */
+    void onOpenFailed(Reason reason);
+    /**
+     * Invoked when HAL get raning result.
+     */
+    void onResult(in RangingResult result);
+    /**
+     * Invoked when IBluetoothChannelSoundingSession.close() is successful.
+     */
+    void onClose(Reason reason);
+    /**
+     * Invoked when IBluetoothChannelSoundingSession.close() fails.
+     */
+    void onCloseFailed(Reason reason);
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/LocationType.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/LocationType.aidl
new file mode 100644
index 0000000..bccf291
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/LocationType.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+@VintfStability
+@Backing(type="byte")
+enum LocationType {
+    UNKNOWN = 0x00,
+    INDOOR = 0x01,
+    OUTDOOR = 0x02,
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ModeType.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ModeType.aidl
new file mode 100644
index 0000000..2058ae8
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ModeType.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+@VintfStability
+@Backing(type="int")
+enum ModeType {
+    ZERO = 0x00,
+    ONE = 0x01,
+    TWO = 0x02,
+    THREE = 0x03,
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/Nadm.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/Nadm.aidl
new file mode 100644
index 0000000..3cfb22f
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/Nadm.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+@VintfStability
+@Backing(type="byte")
+enum Nadm {
+    ATTACK_IS_EXTREMELY_UNLIKELY = 0x00,
+    ATTACK_IS_VERY_UNLIKELY = 0x01,
+    ATTACK_IS_UNLIKELY = 0x02,
+    ATTACK_IS_POSSIBLE = 0x03,
+    ATTACK_IS_LIKELY = 0x04,
+    ATTACK_IS_VERY_LIKELY = 0x05,
+    ATTACK_IS_EXTREMELY_LIKELY = 0x06,
+    UNKNOWN = 0xFFu8,
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/RangingResult.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/RangingResult.aidl
new file mode 100644
index 0000000..65907dd
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/RangingResult.aidl
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+import android.hardware.bluetooth.ranging.Nadm;
+
+/**
+ * Generic structure to return the ranging result
+ */
+@VintfStability
+parcelable RangingResult {
+    /**
+     * Estimated distance in meters.
+     */
+    double resultMeters;
+    /**
+     * Potential distance estimate error (plus or minus) in meters, always positive.
+     */
+    double errorMeters;
+    /**
+     * Azimuth Angle measurement in degrees.
+     *
+     * Azimuth of remote device in horizontal coordinate system, this measured from azimuth north
+     * and increasing eastward. When the remote device in azimuth north, this angle is 0, when the
+     * remote device in azimuth south, this angle is 180.
+     *
+     * See: <a href="https://en.wikipedia.org/wiki/Horizontal_coordinate_system">Horizontal
+     *  coordinate system</a>for the details
+     *
+     * On an Android device, azimuth north is defined as the angle perpendicular away from the
+     * back of the device when holding it in portrait mode upright.
+     *
+     * The Azimuth north is defined as the direction in which the top edge of the device is
+     * facing when it is placed flat.
+     *
+     */
+    double azimuthDegrees;
+    /**
+     * Estimated error (plus or minus) of azimuth angle measurement in degrees, always positive.
+     */
+    double errorAzimuthDegrees;
+    /**
+     * Altitude Angle measurement in degrees.
+     *
+     * Altitude of remote device in horizontal coordinate system, this is the angle between the
+     * remote device and the top edge of local device. When local device is placed flat, the angle
+     * of the zenith is 90, the angle of the nadir is -90.
+     *
+     * See: https://en.wikipedia.org/wiki/Horizontal_coordinate_system
+     */
+    double altitudeDegrees;
+    /**
+     * Estimated error (plus or minus) of altitude angle measurement in degrees, always positive.
+     */
+    double errorAltitudeDegrees;
+    /**
+     * Estimated delay spread in meters of the measured channel. This is a measure of multipath
+     * richness of the channel.
+     */
+    double delaySpreadMeters;
+    /**
+     * A normalized value from 0 (low confidence) to 100 (high confidence) representing the
+     * confidence of estimated distance.
+     */
+    byte confidenceLevel;
+    /**
+     * A value representing the chance of being attacked for the measurement.
+     */
+    Nadm detectedAttackLevel;
+    /**
+     * Estimated velocity, in the direction of line between two devices, of the moving object in
+     * meters/sec.
+     */
+    double velocityMetersPerSecond;
+    /**
+     * Parameter for vendors to place vendor-specific ranging results data.
+     */
+    @nullable byte[] vendorSpecificCsRangingResultsData;
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/Reason.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/Reason.aidl
new file mode 100644
index 0000000..4f587de
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/Reason.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+@VintfStability
+@Backing(type="int")
+enum Reason {
+    LOCAL_STACK_REQUEST,
+    HAL_INITIATED,
+    HARDWARE_INITIATED,
+    ERROR_INVALID_PARAMETER,
+    ERROR_UNKNOWN,
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ResultType.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ResultType.aidl
new file mode 100644
index 0000000..561b7dd
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ResultType.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+@VintfStability
+@Backing(type="int")
+enum ResultType {
+    RESULT_METERS = 0x00,
+    ERROR_METERS = 0x01,
+    AZIMUTH_DEGREES = 0x02,
+    ERROR_AZIMUTH_DEGREES = 0x03,
+    ALTITUDE_DEGREES = 0x04,
+    ERROR_ALTITUDE_DEGREES = 0x05,
+    DELAY_SPREAD_METERS = 0x06,
+    CONFIDENCE_LEVEL = 0x07,
+    SECURITY_LEVEL = 0x08,
+    VELOCITY = 0x09,
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/Role.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/Role.aidl
new file mode 100644
index 0000000..b531935
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/Role.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+@VintfStability
+@Backing(type="int")
+enum Role {
+    INITIATOR = 0,
+    REFLECTOR = 1,
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/RttType.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/RttType.aidl
new file mode 100644
index 0000000..6e163c9
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/RttType.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+@VintfStability
+@Backing(type="int")
+enum RttType {
+    AA_COARSE = 0x00,
+    WITH_32_BIT_SOUNDING_SEQUENCE = 0x01,
+    WITH_96_BIT_SOUNDING_SEQUENCE = 0x02,
+    WITH_32_BIT_RANDOM_SEQUENCE = 0x03,
+    WITH_64_BIT_RANDOM_SEQUENCE = 0x04,
+    WITH_96_BIT_RANDOM_SEQUENCE = 0x05,
+    WITH_128_BIT_RANDOM_SEQUENCE = 0x06,
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/SessionType.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/SessionType.aidl
new file mode 100644
index 0000000..4f0d529
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/SessionType.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+@VintfStability
+@Backing(type="int")
+enum SessionType {
+    /**
+     * Stack parses raw data and passes it to the HAL
+     */
+    SOFTWARE_STACK_DATA_PARSING = 0,
+    /**
+     * Offloader parses raw data
+     */
+    HARDWARE_OFFLOAD_DATA_PARSING = 1
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/SightType.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/SightType.aidl
new file mode 100644
index 0000000..14106e0
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/SightType.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+@VintfStability
+@Backing(type="byte")
+enum SightType {
+    UNKNOWN = 0x00,
+    LINE_OF_SIGHT = 0x01,
+    NON_LINE_OF_SIGHT = 0x02,
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/StepTonePct.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/StepTonePct.aidl
new file mode 100644
index 0000000..4650861
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/StepTonePct.aidl
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+import android.hardware.bluetooth.ranging.ComplexNumber;
+
+/**
+ * Tone PCT data with quality indicator from a mode-2 or mode-3 step.
+ */
+@VintfStability
+parcelable StepTonePct {
+    /**
+     * PCT measured from mode-2 or mode-3 steps
+     * (in ascending order of antenna position with tone extension data at the end).
+     */
+    List<ComplexNumber> tonePcts;
+    const int TONE_QUALITY_GOOD = 0;
+    const int TONE_QUALITY_MEDIUM = 1;
+    const int TONE_QUALITY_LOW = 2;
+    const int TONE_QUALITY_UNAVAILABLE = 3;
+    const int EXTENSION_SLOT_NONE = 0;
+    const int EXTENSION_SLOT_TONE_NOT_EXPECTED_TO_BE_PRESENT = 1;
+    const int EXTENSION_SLOT_TONE_EXPECTED_TO_BE_PRESENT = 2;
+    /**
+     * Shift amount for extension slot (bits 4 to 7).
+     */
+    const int EXTENSION_SLOT_SHIFT_AMOUNT = 4;
+    /**
+     * Tone_Quality_Indicator defined in the LE CS Subevent Result event
+     *
+     * Bits 0 to 3:
+     * 0x0 = Tone quality is good
+     * 0x1 = Tone quality is medium
+     * 0x2 = Tone quality is low
+     * 0x3 = Tone quality is unavailable
+     *
+     * Bits 4 to 7:
+     * 0x0 = Not tone extension slot
+     * 0x1 = Tone extension slot; tone not expected to be present
+     * 0x2 = Tone extension slot; tone expected to be present
+     *
+     * See: https://bluetooth.com/specifications/specs/channel-sounding-cr-pr/
+     */
+    byte[] toneQualityIndicator;
+
+    const byte TONE_EXTENSION_ANTENNA_1 = 0x0;
+    const byte TONE_EXTENSION_ANTENNA_2 = 0x1;
+    const byte TONE_EXTENSION_ANTENNA_3 = 0x2;
+    const byte TONE_EXTENSION_ANTENNA_4 = 0x3;
+    const byte TONE_EXTENSION_UNUSED = 0xFFu8;
+    /**
+     * Tone Extension Antenna Index indicates the Antenna position used in tone extension slot
+     *
+     * 0x00 = A1
+     * 0x01 = A2
+     * 0x02 = A3
+     * 0x03 = A4
+     * 0xFF = Tone extension not used
+     */
+    byte toneExtensionAntennaIndex;
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/SubModeType.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/SubModeType.aidl
new file mode 100644
index 0000000..ca9bfcb
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/SubModeType.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+@VintfStability
+@Backing(type="int")
+enum SubModeType {
+    ONE = 0x01,
+    TWO = 0x02,
+    THREE = 0x03,
+    UNUSED = 0xff,
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/VendorSpecificData.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/VendorSpecificData.aidl
new file mode 100644
index 0000000..a8c9a2a
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/VendorSpecificData.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+/**
+ * Vendor specific data for GATT.
+ */
+@VintfStability
+parcelable VendorSpecificData {
+    byte[16] characteristicUuid;
+    byte[] opaqueValue;
+}
diff --git a/bluetooth/ranging/aidl/default/Android.bp b/bluetooth/ranging/aidl/default/Android.bp
new file mode 100644
index 0000000..5072a43
--- /dev/null
+++ b/bluetooth/ranging/aidl/default/Android.bp
@@ -0,0 +1,29 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+    name: "android.hardware.bluetooth.ranging-service.default",
+    relative_install_path: "hw",
+    init_rc: ["bluetooth-ranging-service-default.rc"],
+    vintf_fragments: [":manifest_android.hardware.bluetooth.ranging-service.default.xml"],
+    vendor: true,
+    srcs: [
+        "BluetoothChannelSounding.cpp",
+        "BluetoothChannelSoundingSession.cpp",
+        "service.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.bluetooth.ranging-V1-ndk",
+        "libbase",
+        "libbinder_ndk",
+        "libhidlbase",
+        "libutils",
+        "liblog",
+    ],
+}
+
+filegroup {
+    name: "manifest_android.hardware.bluetooth.ranging-service.default.xml",
+    srcs: ["bluetooth-ranging-service-default.xml"],
+}
diff --git a/bluetooth/ranging/aidl/default/BluetoothChannelSounding.cpp b/bluetooth/ranging/aidl/default/BluetoothChannelSounding.cpp
new file mode 100644
index 0000000..3807d4f
--- /dev/null
+++ b/bluetooth/ranging/aidl/default/BluetoothChannelSounding.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BluetoothChannelSounding.h"
+
+#include "BluetoothChannelSoundingSession.h"
+
+namespace aidl::android::hardware::bluetooth::ranging::impl {
+
+BluetoothChannelSounding::BluetoothChannelSounding() {}
+BluetoothChannelSounding::~BluetoothChannelSounding() {}
+
+ndk::ScopedAStatus BluetoothChannelSounding::getVendorSpecificData(
+    std::optional<
+        std::vector<std::optional<VendorSpecificData>>>* /*_aidl_return*/) {
+  return ::ndk::ScopedAStatus::ok();
+}
+ndk::ScopedAStatus BluetoothChannelSounding::getSupportedSessionTypes(
+    std::optional<std::vector<SessionType>>* _aidl_return) {
+  std::vector<SessionType> supported_session_types = {};
+  *_aidl_return = supported_session_types;
+  return ::ndk::ScopedAStatus::ok();
+}
+ndk::ScopedAStatus BluetoothChannelSounding::getMaxSupportedCsSecurityLevel(
+    CsSecurityLevel* _aidl_return) {
+  CsSecurityLevel security_level = CsSecurityLevel::NOT_SUPPORTED;
+  *_aidl_return = security_level;
+  return ::ndk::ScopedAStatus::ok();
+}
+ndk::ScopedAStatus BluetoothChannelSounding::openSession(
+    const BluetoothChannelSoundingParameters& /*in_params*/,
+    const std::shared_ptr<IBluetoothChannelSoundingSessionCallback>&
+        in_callback,
+    std::shared_ptr<IBluetoothChannelSoundingSession>* _aidl_return) {
+  if (in_callback == nullptr) {
+    return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+        EX_ILLEGAL_ARGUMENT, "Invalid nullptr callback");
+  }
+  std::shared_ptr<BluetoothChannelSoundingSession> session = nullptr;
+  session = ndk::SharedRefBase::make<BluetoothChannelSoundingSession>(
+      in_callback, Reason::LOCAL_STACK_REQUEST);
+  *_aidl_return = session;
+  return ::ndk::ScopedAStatus::ok();
+}
+}  // namespace aidl::android::hardware::bluetooth::ranging::impl
diff --git a/bluetooth/ranging/aidl/default/BluetoothChannelSounding.h b/bluetooth/ranging/aidl/default/BluetoothChannelSounding.h
new file mode 100644
index 0000000..d6b5c03
--- /dev/null
+++ b/bluetooth/ranging/aidl/default/BluetoothChannelSounding.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/bluetooth/ranging/BnBluetoothChannelSounding.h>
+
+#include <vector>
+
+namespace aidl::android::hardware::bluetooth::ranging::impl {
+
+using ::aidl::android::hardware::bluetooth::ranging::
+    BluetoothChannelSoundingParameters;
+using ::aidl::android::hardware::bluetooth::ranging::BnBluetoothChannelSounding;
+using ::aidl::android::hardware::bluetooth::ranging::CsSecurityLevel;
+using ::aidl::android::hardware::bluetooth::ranging::
+    IBluetoothChannelSoundingSession;
+using ::aidl::android::hardware::bluetooth::ranging::
+    IBluetoothChannelSoundingSessionCallback;
+using ::aidl::android::hardware::bluetooth::ranging::SessionType;
+using ::aidl::android::hardware::bluetooth::ranging::VendorSpecificData;
+
+class BluetoothChannelSounding : public BnBluetoothChannelSounding {
+ public:
+  BluetoothChannelSounding();
+  ~BluetoothChannelSounding();  // Add the destructor declaration
+  ndk::ScopedAStatus getVendorSpecificData(
+      std::optional<std::vector<std::optional<VendorSpecificData>>>*
+          _aidl_return) override;
+  ndk::ScopedAStatus getSupportedSessionTypes(
+      std::optional<std::vector<SessionType>>* _aidl_return) override;
+  ndk::ScopedAStatus getMaxSupportedCsSecurityLevel(
+      CsSecurityLevel* _aidl_return) override;
+  ndk::ScopedAStatus openSession(
+      const BluetoothChannelSoundingParameters& in_params,
+      const std::shared_ptr<IBluetoothChannelSoundingSessionCallback>&
+          in_callback,
+      std::shared_ptr<IBluetoothChannelSoundingSession>* _aidl_return) override;
+};
+
+}  // namespace aidl::android::hardware::bluetooth::ranging::impl
diff --git a/bluetooth/ranging/aidl/default/BluetoothChannelSoundingSession.cpp b/bluetooth/ranging/aidl/default/BluetoothChannelSoundingSession.cpp
new file mode 100644
index 0000000..6c58a07
--- /dev/null
+++ b/bluetooth/ranging/aidl/default/BluetoothChannelSoundingSession.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BluetoothChannelSoundingSession.h"
+
+namespace aidl::android::hardware::bluetooth::ranging::impl {
+
+BluetoothChannelSoundingSession::BluetoothChannelSoundingSession(
+    std::shared_ptr<IBluetoothChannelSoundingSessionCallback> callback,
+    Reason reason) {
+  callback_ = callback;
+  callback_->onOpened(reason);
+}
+
+ndk::ScopedAStatus BluetoothChannelSoundingSession::getVendorSpecificReplies(
+    std::optional<
+        std::vector<std::optional<VendorSpecificData>>>* /*_aidl_return*/) {
+  return ::ndk::ScopedAStatus::ok();
+}
+ndk::ScopedAStatus BluetoothChannelSoundingSession::getSupportedResultTypes(
+    std::vector<ResultType>* _aidl_return) {
+  std::vector<ResultType> supported_result_types = {ResultType::RESULT_METERS};
+  *_aidl_return = supported_result_types;
+  return ::ndk::ScopedAStatus::ok();
+}
+ndk::ScopedAStatus BluetoothChannelSoundingSession::isAbortedProcedureRequired(
+    bool* _aidl_return) {
+  *_aidl_return = false;
+  return ::ndk::ScopedAStatus::ok();
+}
+ndk::ScopedAStatus BluetoothChannelSoundingSession::writeRawData(
+    const ChannelSoudingRawData& /*in_rawData*/) {
+  RangingResult ranging_result;
+  ranging_result.resultMeters = 0.0;
+  callback_->onResult(ranging_result);
+  return ::ndk::ScopedAStatus::ok();
+}
+ndk::ScopedAStatus BluetoothChannelSoundingSession::close(Reason in_reason) {
+  callback_->onClose(in_reason);
+  return ::ndk::ScopedAStatus::ok();
+}
+}  // namespace aidl::android::hardware::bluetooth::ranging::impl
diff --git a/bluetooth/ranging/aidl/default/BluetoothChannelSoundingSession.h b/bluetooth/ranging/aidl/default/BluetoothChannelSoundingSession.h
new file mode 100644
index 0000000..6703f7f
--- /dev/null
+++ b/bluetooth/ranging/aidl/default/BluetoothChannelSoundingSession.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/bluetooth/ranging/BnBluetoothChannelSoundingSession.h>
+#include <aidl/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSessionCallback.h>
+
+#include <vector>
+
+namespace aidl::android::hardware::bluetooth::ranging::impl {
+
+using ::aidl::android::hardware::bluetooth::ranging::ChannelSoudingRawData;
+using ::aidl::android::hardware::bluetooth::ranging::Reason;
+using ::aidl::android::hardware::bluetooth::ranging::ResultType;
+using ::aidl::android::hardware::bluetooth::ranging::VendorSpecificData;
+
+class BluetoothChannelSoundingSession
+    : public BnBluetoothChannelSoundingSession {
+ public:
+  BluetoothChannelSoundingSession(
+      std::shared_ptr<IBluetoothChannelSoundingSessionCallback> callback,
+      Reason reason);
+
+  ndk::ScopedAStatus getVendorSpecificReplies(
+      std::optional<std::vector<std::optional<VendorSpecificData>>>*
+          _aidl_return) override;
+  ndk::ScopedAStatus getSupportedResultTypes(
+      std::vector<ResultType>* _aidl_return) override;
+  ndk::ScopedAStatus isAbortedProcedureRequired(bool* _aidl_return) override;
+  ndk::ScopedAStatus writeRawData(
+      const ChannelSoudingRawData& in_rawData) override;
+  ndk::ScopedAStatus close(Reason in_reason) override;
+
+ private:
+  std::shared_ptr<IBluetoothChannelSoundingSessionCallback> callback_;
+};
+
+}  // namespace aidl::android::hardware::bluetooth::ranging::impl
diff --git a/bluetooth/ranging/aidl/default/bluetooth-ranging-service-default.rc b/bluetooth/ranging/aidl/default/bluetooth-ranging-service-default.rc
new file mode 100644
index 0000000..fabb409
--- /dev/null
+++ b/bluetooth/ranging/aidl/default/bluetooth-ranging-service-default.rc
@@ -0,0 +1,6 @@
+service vendor.bluetooth.ranging-default /vendor/bin/hw/android.hardware.bluetooth.ranging-service.default
+    class hal
+    capabilities BLOCK_SUSPEND NET_ADMIN SYS_NICE
+    user bluetooth
+    group bluetooth
+    task_profiles HighPerformance
diff --git a/bluetooth/ranging/aidl/default/bluetooth-ranging-service-default.xml b/bluetooth/ranging/aidl/default/bluetooth-ranging-service-default.xml
new file mode 100644
index 0000000..fe3613d
--- /dev/null
+++ b/bluetooth/ranging/aidl/default/bluetooth-ranging-service-default.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.bluetooth.ranging</name>
+        <version>1</version>
+        <fqname>IBluetoothChannelSounding/default</fqname>
+    </hal>
+</manifest>
diff --git a/bluetooth/ranging/aidl/default/service.cpp b/bluetooth/ranging/aidl/default/service.cpp
new file mode 100644
index 0000000..83e539e
--- /dev/null
+++ b/bluetooth/ranging/aidl/default/service.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "aidl.android.hardware.bluetooth.ranging.service.default"
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <utils/Log.h>
+
+#include "BluetoothChannelSounding.h"
+#include "BluetoothChannelSoundingSession.h"
+
+using ::aidl::android::hardware::bluetooth::ranging::impl::
+    BluetoothChannelSounding;
+
+int main(int /* argc */, char** /* argv */) {
+  ALOGI("Bluetooth Ranging HAL registering");
+  if (!ABinderProcess_setThreadPoolMaxThreadCount(0)) {
+    ALOGE("Failed to set thread pool max thread count");
+    return 1;
+  }
+
+  std::shared_ptr<BluetoothChannelSounding> service =
+      ndk::SharedRefBase::make<BluetoothChannelSounding>();
+  std::string instance =
+      std::string() + BluetoothChannelSounding::descriptor + "/default";
+  auto result =
+      AServiceManager_addService(service->asBinder().get(), instance.c_str());
+  if (result == STATUS_OK) {
+    ABinderProcess_joinThreadPool();
+  } else {
+    ALOGE("Could not register as a service!");
+  }
+  return 0;
+}
diff --git a/bluetooth/ranging/aidl/vts/Android.bp b/bluetooth/ranging/aidl/vts/Android.bp
new file mode 100644
index 0000000..ead9992
--- /dev/null
+++ b/bluetooth/ranging/aidl/vts/Android.bp
@@ -0,0 +1,27 @@
+package {
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsHalBluetoothRangingTargetTest",
+    defaults: [
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalBluetoothRangingTargetTest.cpp"],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libcutils",
+        "liblog",
+        "libutils",
+    ],
+    static_libs: [
+        "android.hardware.bluetooth.ranging-V1-ndk",
+        "libbluetooth-types",
+    ],
+    test_config: "VtsHalBluetoothRangingTargetTest.xml",
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/bluetooth/ranging/aidl/vts/VtsHalBluetoothRangingTargetTest.cpp b/bluetooth/ranging/aidl/vts/VtsHalBluetoothRangingTargetTest.cpp
new file mode 100644
index 0000000..702df95
--- /dev/null
+++ b/bluetooth/ranging/aidl/vts/VtsHalBluetoothRangingTargetTest.cpp
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/bluetooth/ranging/BnBluetoothChannelSoundingSessionCallback.h>
+#include <aidl/android/hardware/bluetooth/ranging/IBluetoothChannelSounding.h>
+#include <aidl/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSessionCallback.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+
+using aidl::android::hardware::bluetooth::ranging::
+    BluetoothChannelSoundingParameters;
+using aidl::android::hardware::bluetooth::ranging::
+    BnBluetoothChannelSoundingSessionCallback;
+using aidl::android::hardware::bluetooth::ranging::ChannelSoudingRawData;
+using aidl::android::hardware::bluetooth::ranging::CsSecurityLevel;
+using aidl::android::hardware::bluetooth::ranging::IBluetoothChannelSounding;
+using aidl::android::hardware::bluetooth::ranging::
+    IBluetoothChannelSoundingSession;
+using aidl::android::hardware::bluetooth::ranging::
+    IBluetoothChannelSoundingSessionCallback;
+using aidl::android::hardware::bluetooth::ranging::RangingResult;
+using aidl::android::hardware::bluetooth::ranging::Reason;
+using aidl::android::hardware::bluetooth::ranging::ResultType;
+using aidl::android::hardware::bluetooth::ranging::SessionType;
+using aidl::android::hardware::bluetooth::ranging::VendorSpecificData;
+using ndk::ScopedAStatus;
+
+class BluetoothChannelSoundingSessionCallback
+    : public BnBluetoothChannelSoundingSessionCallback {
+ public:
+  ScopedAStatus onOpened(Reason reason) override;
+  ScopedAStatus onOpenFailed(Reason reason) override;
+  ScopedAStatus onResult(const RangingResult& in_result) override;
+  ScopedAStatus onClose(Reason reason) override;
+  ScopedAStatus onCloseFailed(Reason reason) override;
+};
+
+ScopedAStatus BluetoothChannelSoundingSessionCallback::onOpened(
+    Reason /*reason*/) {
+  return ::ndk::ScopedAStatus::ok();
+}
+ScopedAStatus BluetoothChannelSoundingSessionCallback::onOpenFailed(
+    Reason /*reason*/) {
+  return ::ndk::ScopedAStatus::ok();
+}
+ScopedAStatus BluetoothChannelSoundingSessionCallback::onResult(
+    const RangingResult& /*in_result*/) {
+  return ::ndk::ScopedAStatus::ok();
+}
+ScopedAStatus BluetoothChannelSoundingSessionCallback::onClose(
+    Reason /*reason*/) {
+  return ::ndk::ScopedAStatus::ok();
+}
+ScopedAStatus BluetoothChannelSoundingSessionCallback::onCloseFailed(
+    Reason /*reason*/) {
+  return ::ndk::ScopedAStatus::ok();
+}
+
+class BluetoothRangingTest : public ::testing::TestWithParam<std::string> {
+ public:
+  virtual void SetUp() override {
+    ALOGI("SetUp Ranging Test");
+    bluetooth_channel_sounding_ = IBluetoothChannelSounding::fromBinder(
+        ndk::SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+    ASSERT_NE(bluetooth_channel_sounding_, nullptr);
+  }
+
+  virtual void TearDown() override {
+    ALOGI("TearDown Ranging Test");
+    bluetooth_channel_sounding_ = nullptr;
+    ASSERT_EQ(bluetooth_channel_sounding_, nullptr);
+  }
+
+  ScopedAStatus getVendorSpecificData(
+      std::optional<std::vector<std::optional<VendorSpecificData>>>*
+          _aidl_return);
+  ScopedAStatus getSupportedSessionTypes(
+      std::optional<std::vector<SessionType>>* _aidl_return);
+  ScopedAStatus getMaxSupportedCsSecurityLevel(CsSecurityLevel* _aidl_return);
+  ScopedAStatus openSession(
+      const BluetoothChannelSoundingParameters& in_params,
+      const std::shared_ptr<IBluetoothChannelSoundingSessionCallback>&
+          in_callback,
+      std::shared_ptr<IBluetoothChannelSoundingSession>* _aidl_return);
+
+  ScopedAStatus initBluetoothChannelSoundingSession(
+      std::shared_ptr<IBluetoothChannelSoundingSession>* session) {
+    BluetoothChannelSoundingParameters params;
+    std::shared_ptr<BluetoothChannelSoundingSessionCallback> callback = nullptr;
+    callback =
+        ndk::SharedRefBase::make<BluetoothChannelSoundingSessionCallback>();
+    ScopedAStatus status = openSession(params, callback, session);
+    return status;
+  }
+
+ private:
+  std::shared_ptr<IBluetoothChannelSounding> bluetooth_channel_sounding_;
+};
+
+ScopedAStatus BluetoothRangingTest::getVendorSpecificData(
+    std::optional<std::vector<std::optional<VendorSpecificData>>>*
+        _aidl_return) {
+  return bluetooth_channel_sounding_->getVendorSpecificData(_aidl_return);
+}
+ScopedAStatus BluetoothRangingTest::getSupportedSessionTypes(
+    std::optional<std::vector<SessionType>>* _aidl_return) {
+  return bluetooth_channel_sounding_->getSupportedSessionTypes(_aidl_return);
+}
+
+ScopedAStatus BluetoothRangingTest::getMaxSupportedCsSecurityLevel(
+    CsSecurityLevel* _aidl_return) {
+  return bluetooth_channel_sounding_->getMaxSupportedCsSecurityLevel(
+      _aidl_return);
+}
+ScopedAStatus BluetoothRangingTest::openSession(
+    const BluetoothChannelSoundingParameters& in_params,
+    const std::shared_ptr<IBluetoothChannelSoundingSessionCallback>&
+        in_callback,
+    std::shared_ptr<IBluetoothChannelSoundingSession>* _aidl_return) {
+  return bluetooth_channel_sounding_->openSession(in_params, in_callback,
+                                                  _aidl_return);
+}
+
+TEST_P(BluetoothRangingTest, SetupAndTearDown) {}
+
+TEST_P(BluetoothRangingTest, GetVendorSpecificData) {
+  std::optional<std::vector<std::optional<VendorSpecificData>>>
+      vendor_specific_data;
+  ScopedAStatus status = getVendorSpecificData(&vendor_specific_data);
+  ASSERT_TRUE(status.isOk());
+}
+
+TEST_P(BluetoothRangingTest, GetSupportedSessionTypes) {
+  std::optional<std::vector<SessionType>> supported_session_types;
+  ScopedAStatus status = getSupportedSessionTypes(&supported_session_types);
+  ASSERT_TRUE(status.isOk());
+}
+
+TEST_P(BluetoothRangingTest, GetMaxSupportedCsSecurityLevel) {
+  CsSecurityLevel security_level;
+  ScopedAStatus status = getMaxSupportedCsSecurityLevel(&security_level);
+  ASSERT_TRUE(status.isOk());
+}
+
+TEST_P(BluetoothRangingTest, OpenSession) {
+  BluetoothChannelSoundingParameters params;
+  std::shared_ptr<BluetoothChannelSoundingSessionCallback> callback = nullptr;
+  callback =
+      ndk::SharedRefBase::make<BluetoothChannelSoundingSessionCallback>();
+  std::shared_ptr<IBluetoothChannelSoundingSession> session;
+  ScopedAStatus status = openSession(params, callback, &session);
+  ASSERT_TRUE(status.isOk());
+}
+
+TEST_P(BluetoothRangingTest, GetVendorSpecificReplies) {
+  std::shared_ptr<IBluetoothChannelSoundingSession> session;
+  auto status = initBluetoothChannelSoundingSession(&session);
+  ASSERT_TRUE(status.isOk());
+  if (session != nullptr) {
+    std::optional<std::vector<std::optional<VendorSpecificData>>>
+        vendor_specific_data;
+    status = session->getVendorSpecificReplies(&vendor_specific_data);
+    ASSERT_TRUE(status.isOk());
+  }
+}
+
+TEST_P(BluetoothRangingTest, GetSupportedResultTypes) {
+  std::shared_ptr<IBluetoothChannelSoundingSession> session;
+  auto status = initBluetoothChannelSoundingSession(&session);
+  ASSERT_TRUE(status.isOk());
+  if (session != nullptr) {
+    std::vector<ResultType> supported_result_types;
+    status = session->getSupportedResultTypes(&supported_result_types);
+    ASSERT_TRUE(status.isOk());
+  }
+}
+
+TEST_P(BluetoothRangingTest, IsAbortedProcedureRequired) {
+  std::shared_ptr<IBluetoothChannelSoundingSession> session;
+  auto status = initBluetoothChannelSoundingSession(&session);
+  ASSERT_TRUE(status.isOk());
+  if (session != nullptr) {
+    bool is_abort_procedure_required = true;
+    status = session->isAbortedProcedureRequired(&is_abort_procedure_required);
+    ASSERT_TRUE(status.isOk());
+  }
+}
+
+TEST_P(BluetoothRangingTest, WriteRawData) {
+  std::shared_ptr<IBluetoothChannelSoundingSession> session;
+  auto status = initBluetoothChannelSoundingSession(&session);
+  ASSERT_TRUE(status.isOk());
+  if (session != nullptr) {
+    ChannelSoudingRawData raw_data;
+    status = session->writeRawData(raw_data);
+    ASSERT_TRUE(status.isOk());
+  }
+}
+
+TEST_P(BluetoothRangingTest, CloseSession) {
+  std::shared_ptr<IBluetoothChannelSoundingSession> session;
+  auto status = initBluetoothChannelSoundingSession(&session);
+  ASSERT_TRUE(status.isOk());
+  if (session != nullptr) {
+    status = session->close(Reason::LOCAL_STACK_REQUEST);
+    ASSERT_TRUE(status.isOk());
+  }
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BluetoothRangingTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothRangingTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             IBluetoothChannelSounding::descriptor)),
+                         android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  ABinderProcess_startThreadPool();
+  int status = RUN_ALL_TESTS();
+  ALOGI("Test result = %d", status);
+  return status;
+}
\ No newline at end of file
diff --git a/bluetooth/ranging/aidl/vts/VtsHalBluetoothRangingTargetTest.xml b/bluetooth/ranging/aidl/vts/VtsHalBluetoothRangingTargetTest.xml
new file mode 100644
index 0000000..624b77e
--- /dev/null
+++ b/bluetooth/ranging/aidl/vts/VtsHalBluetoothRangingTargetTest.xml
@@ -0,0 +1,33 @@
+<!--
+  Copyright (C) 2023 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<configuration description="Runs VtsHalBluetoothRangingTargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsHalBluetoothRangingTargetTest->/data/local/tmp/VtsHalBluetoothRangingTargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalBluetoothRangingTargetTest" />
+    </test>
+</configuration>
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/Metadata.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/Metadata.aidl
index 3298cac..7769b8c 100644
--- a/broadcastradio/aidl/android/hardware/broadcastradio/Metadata.aidl
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/Metadata.aidl
@@ -70,9 +70,9 @@
     /**
      * Station name.
      *
-     * This is a generic field to cover any radio technology.
+     * <p>This is a generic field to cover any radio technology.
      *
-     * If the PROGRAM_NAME has the same content as DAB_*_NAME or RDS_PS,
+     * <p>Note: If the program name has the same content as dab*Name or ({@link Metadata#rdsPs},
      * it may not be present, to preserve space - framework must repopulate
      * it on the client side.
      */
@@ -86,10 +86,10 @@
     /**
      * DAB ensemble name abbreviated (string).
      *
-     * The string must be up to 8 characters long.
+     * <p>Note: The string must be up to 8 characters long.
      *
-     * If the short variant is present, the long (DAB_ENSEMBLE_NAME) one must be
-     * present as well.
+     * <p>Note: If the short variant is present, the long ({@link Metadata#dabEnsembleName})
+     * one must be present as well.
      */
     String dabEnsembleNameShort;
 
@@ -99,7 +99,9 @@
     String dabServiceName;
 
     /**
-     * DAB service name abbreviated (see DAB_ENSEMBLE_NAME_SHORT) (string)
+     * DAB service name abbreviated (string)
+     *
+     * <p>Note: The string must be up to 8 characters long.
      */
     String dabServiceNameShort;
 
@@ -109,7 +111,9 @@
     String dabComponentName;
 
     /**
-     * DAB component name abbreviated (see DAB_ENSEMBLE_NAME_SHORT) (string)
+     * DAB component name abbreviated (string)
+     *
+     * <p>Note: The string must be up to 8 characters long.
      */
     String dabComponentNameShort;
 }
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/ProgramIdentifier.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramIdentifier.aidl
index 2057d97..a2de5d6 100644
--- a/broadcastradio/aidl/android/hardware/broadcastradio/ProgramIdentifier.aidl
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramIdentifier.aidl
@@ -30,8 +30,10 @@
     IdentifierType type = IdentifierType.INVALID;
 
     /**
-     * The uint64_t value field holds the value in format described in comments
-     * for IdentifierType enum.
+     * The value field holds the value in format described in comments for IdentifierType enum.
+     *
+     * The value should be 64-bit unsigned integer, but is represented as 64-bit signed integer
+     * in AIDL.
      */
     long value;
 }
diff --git a/broadcastradio/aidl/default/VirtualRadio.cpp b/broadcastradio/aidl/default/VirtualRadio.cpp
index 126bcff..86c5a96 100644
--- a/broadcastradio/aidl/default/VirtualRadio.cpp
+++ b/broadcastradio/aidl/default/VirtualRadio.cpp
@@ -53,18 +53,18 @@
     static VirtualRadio amFmRadioMock(
         "AM/FM radio mock",
         {
-            {makeSelectorAmfm(/* frequency= */ 94900), "Wild 94.9", "Drake ft. Rihanna",
+            {makeSelectorAmfm(/* frequency= */ 94900u), "Wild 94.9", "Drake ft. Rihanna",
                 "Too Good"},
-            {makeSelectorAmfm(/* frequency= */ 96500), "KOIT", "Celine Dion", "All By Myself"},
-            {makeSelectorAmfm(/* frequency= */ 97300), "Alice@97.3", "Drops of Jupiter", "Train"},
-            {makeSelectorAmfm(/* frequency= */ 99700), "99.7 Now!", "The Chainsmokers", "Closer"},
-            {makeSelectorAmfm(/* frequency= */ 101300), "101-3 KISS-FM", "Justin Timberlake",
+            {makeSelectorAmfm(/* frequency= */ 96500u), "KOIT", "Celine Dion", "All By Myself"},
+            {makeSelectorAmfm(/* frequency= */ 97300u), "Alice@97.3", "Drops of Jupiter", "Train"},
+            {makeSelectorAmfm(/* frequency= */ 99700u), "99.7 Now!", "The Chainsmokers", "Closer"},
+            {makeSelectorAmfm(/* frequency= */ 101300u), "101-3 KISS-FM", "Justin Timberlake",
                 "Rock Your Body"},
-            {makeSelectorAmfm(/* frequency= */ 103700), "iHeart80s @ 103.7", "Michael Jackson",
+            {makeSelectorAmfm(/* frequency= */ 103700u), "iHeart80s @ 103.7", "Michael Jackson",
                 "Billie Jean"},
-            {makeSelectorAmfm(/* frequency= */ 106100), "106 KMEL", "Drake", "Marvins Room"},
-            {makeSelectorAmfm(/* frequency= */ 700), "700 AM", "Artist700", "Title700"},
-            {makeSelectorAmfm(/* frequency= */ 1700), "1700 AM", "Artist1700", "Title1700"},
+            {makeSelectorAmfm(/* frequency= */ 106100u), "106 KMEL", "Drake", "Marvins Room"},
+            {makeSelectorAmfm(/* frequency= */ 700u), "700 AM", "Artist700", "Title700"},
+            {makeSelectorAmfm(/* frequency= */ 1700u), "1700 AM", "Artist1700", "Title1700"},
         });
     // clang-format on
     return amFmRadioMock;
@@ -77,13 +77,13 @@
         "DAB radio mock",
         {
             {makeSelectorDab(/* sidExt= */ 0xA000000001u, /* ensemble= */ 0x0001u,
-                /* freq= */ 225648), "BBC Radio 1", "Khalid", "Talk"},
+                /* freq= */ 225648u), "BBC Radio 1", "Khalid", "Talk"},
             {makeSelectorDab(/* sidExt= */ 0xB000000001u, /* ensemble= */ 0x1001u,
-                /* freq= */ 222064), "Classic FM", "Jean Sibelius", "Andante Festivo"},
+                /* freq= */ 222064u), "Classic FM", "Jean Sibelius", "Andante Festivo"},
             {makeSelectorDab(/* sidExt= */ 0xB000000002u, /* ensemble= */ 0x1002u,
-                /* freq= */ 227360), "Absolute Radio", "Coldplay", "Clocks"},
+                /* freq= */ 227360u), "Absolute Radio", "Coldplay", "Clocks"},
             {makeSelectorDab(/* sidExt= */ 0xB000000002u, /* ensemble= */ 0x1002u,
-                /* freq= */ 222064), "Absolute Radio", "Coldplay", "Clocks"},
+                /* freq= */ 222064u), "Absolute Radio", "Coldplay", "Clocks"},
         });
     // clang-format on
     return dabRadioMock;
diff --git a/broadcastradio/common/utilsaidl/Utils.cpp b/broadcastradio/common/utilsaidl/Utils.cpp
index 0551bad..de4f529 100644
--- a/broadcastradio/common/utilsaidl/Utils.cpp
+++ b/broadcastradio/common/utilsaidl/Utils.cpp
@@ -204,7 +204,7 @@
 }
 
 bool isValid(const ProgramIdentifier& id) {
-    int64_t val = id.value;
+    uint64_t val = static_cast<uint64_t>(id.value);
     bool valid = true;
 
     auto expect = [&valid](bool condition, const string& message) {
@@ -231,11 +231,11 @@
             expect(val <= 0xFFFFu, "16bit id");
             break;
         case IdentifierType::HD_STATION_ID_EXT: {
-            int64_t stationId = val & 0xFFFFFFFF;  // 32bit
+            uint64_t stationId = val & 0xFFFFFFFF;  // 32bit
             val >>= 32;
-            int64_t subchannel = val & 0xF;  // 4bit
+            uint64_t subchannel = val & 0xF;  // 4bit
             val >>= 4;
-            int64_t freq = val & 0x3FFFF;  // 18bit
+            uint64_t freq = val & 0x3FFFF;  // 18bit
             expect(stationId != 0u, "HD station id != 0");
             expect(subchannel < 8u, "HD subch < 8");
             expect(freq > 100u, "f > 100kHz");
@@ -252,9 +252,9 @@
             break;
         }
         case IdentifierType::DAB_SID_EXT: {
-            int64_t sid = val & 0xFFFFFFFF;  // 32bit
+            uint64_t sid = val & 0xFFFFFFFF;  // 32bit
             val >>= 32;
-            int64_t ecc = val & 0xFF;  // 8bit
+            uint64_t ecc = val & 0xFF;  // 8bit
             expect(sid != 0u, "DAB SId != 0");
             expect(ecc >= 0xA0u && ecc <= 0xF6u, "Invalid ECC, see ETSI TS 101 756 V2.1.1");
             break;
@@ -305,19 +305,19 @@
     return {type, value};
 }
 
-ProgramSelector makeSelectorAmfm(int32_t frequency) {
+ProgramSelector makeSelectorAmfm(uint32_t frequency) {
     ProgramSelector sel = {};
     sel.primaryId = makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, frequency);
     return sel;
 }
 
-ProgramSelector makeSelectorDab(int64_t sidExt) {
+ProgramSelector makeSelectorDab(uint64_t sidExt) {
     ProgramSelector sel = {};
     sel.primaryId = makeIdentifier(IdentifierType::DAB_SID_EXT, sidExt);
     return sel;
 }
 
-ProgramSelector makeSelectorDab(int64_t sidExt, int32_t ensemble, int64_t freq) {
+ProgramSelector makeSelectorDab(uint64_t sidExt, uint32_t ensemble, uint64_t freq) {
     ProgramSelector sel = {};
     sel.primaryId = makeIdentifier(IdentifierType::DAB_SID_EXT, sidExt);
     vector<ProgramIdentifier> secondaryIds = {
diff --git a/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h b/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h
index ad075f2..ee85a17 100644
--- a/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h
+++ b/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h
@@ -137,9 +137,9 @@
 bool isValid(const ProgramSelector& sel);
 
 ProgramIdentifier makeIdentifier(IdentifierType type, int64_t value);
-ProgramSelector makeSelectorAmfm(int32_t frequency);
-ProgramSelector makeSelectorDab(int64_t sidExt);
-ProgramSelector makeSelectorDab(int64_t sidExt, int32_t ensemble, int64_t freq);
+ProgramSelector makeSelectorAmfm(uint32_t frequency);
+ProgramSelector makeSelectorDab(uint64_t sidExt);
+ProgramSelector makeSelectorDab(uint64_t sidExt, uint32_t ensemble, uint64_t freq);
 
 bool satisfies(const ProgramFilter& filter, const ProgramSelector& sel);
 
diff --git a/camera/device/default/ExternalCameraDevice.cpp b/camera/device/default/ExternalCameraDevice.cpp
index 677fb42..649bf43 100644
--- a/camera/device/default/ExternalCameraDevice.cpp
+++ b/camera/device/default/ExternalCameraDevice.cpp
@@ -399,6 +399,10 @@
     const uint8_t hotPixelMode = ANDROID_HOT_PIXEL_MODE_OFF;
     UPDATE(ANDROID_HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES, &hotPixelMode, 1);
 
+    // android.info
+    const uint8_t bufMgrVer = ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5;
+    UPDATE(ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &bufMgrVer, 1);
+
     // android.jpeg
     const int32_t jpegAvailableThumbnailSizes[] = {0,   0,   176, 144, 240, 144, 256,
                                                    144, 240, 160, 256, 154, 240, 180};
diff --git a/camera/device/default/ExternalCameraDeviceSession.cpp b/camera/device/default/ExternalCameraDeviceSession.cpp
index c962974..88e4b75 100644
--- a/camera/device/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/default/ExternalCameraDeviceSession.cpp
@@ -786,9 +786,8 @@
                 outputBuffer.bufferId = buffer.bufferId;
                 outputBuffer.status = BufferStatus::ERROR;
                 if (buffer.acquireFence >= 0) {
-                    native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
-                    handle->data[0] = buffer.acquireFence;
-                    outputBuffer.releaseFence = android::makeToAidl(handle);
+                    outputBuffer.releaseFence.fds.resize(1);
+                    outputBuffer.releaseFence.fds.at(0).set(buffer.acquireFence);
                 }
             } else {
                 offlineBuffers.push_back(buffer);
@@ -1769,9 +1768,8 @@
         result.outputBuffers[i].bufferId = req->buffers[i].bufferId;
         result.outputBuffers[i].status = BufferStatus::ERROR;
         if (req->buffers[i].acquireFence >= 0) {
-            native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
-            handle->data[0] = req->buffers[i].acquireFence;
-            result.outputBuffers[i].releaseFence = ::android::makeToAidl(handle);
+            result.outputBuffers[i].releaseFence.fds.resize(1);
+            result.outputBuffers[i].releaseFence.fds.at(0).set(req->buffers[i].acquireFence);
         }
     }
 
@@ -1815,18 +1813,16 @@
         if (req->buffers[i].fenceTimeout) {
             result.outputBuffers[i].status = BufferStatus::ERROR;
             if (req->buffers[i].acquireFence >= 0) {
-                native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
-                handle->data[0] = req->buffers[i].acquireFence;
-                result.outputBuffers[i].releaseFence = ::android::makeToAidl(handle);
+                result.outputBuffers[i].releaseFence.fds.resize(1);
+                result.outputBuffers[i].releaseFence.fds.at(0).set(req->buffers[i].acquireFence);
             }
             notifyError(req->frameNumber, req->buffers[i].streamId, ErrorCode::ERROR_BUFFER);
         } else {
             result.outputBuffers[i].status = BufferStatus::OK;
             // TODO: refactor
             if (req->buffers[i].acquireFence >= 0) {
-                native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
-                handle->data[0] = req->buffers[i].acquireFence;
-                result.outputBuffers[i].releaseFence = ::android::makeToAidl(handle);
+                result.outputBuffers[i].releaseFence.fds.resize(1);
+                result.outputBuffers[i].releaseFence.fds.at(0).set(req->buffers[i].acquireFence);
             }
         }
     }
diff --git a/camera/device/default/ExternalCameraUtils.cpp b/camera/device/default/ExternalCameraUtils.cpp
index cfb95f2..30c216f 100644
--- a/camera/device/default/ExternalCameraUtils.cpp
+++ b/camera/device/default/ExternalCameraUtils.cpp
@@ -402,7 +402,10 @@
         buffer_handle_t buf,
         /*out*/ buffer_handle_t** outBufPtr) {
     using ::aidl::android::hardware::camera::common::Status;
-    if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) {
+    // AIDL does not have null NativeHandles. It sends empty handles instead.
+    // We check for when the buf is empty instead of when buf is null.
+    bool isBufEmpty = buf == nullptr || (buf->numFds == 0 && buf->numInts == 0);
+    if (isBufEmpty && bufId == BUFFER_ID_NO_BUFFER) {
         ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
         return Status::ILLEGAL_ARGUMENT;
     }
@@ -857,4 +860,4 @@
 }  // namespace device
 }  // namespace camera
 }  // namespace hardware
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/cas/aidl/default/service.cpp b/cas/aidl/default/service.cpp
index bed2f01..076c7bb 100644
--- a/cas/aidl/default/service.cpp
+++ b/cas/aidl/default/service.cpp
@@ -31,6 +31,7 @@
 
 int main() {
     ABinderProcess_setThreadPoolMaxThreadCount(8);
+    ABinderProcess_startThreadPool();
 
     // Setup hwbinder service
     std::shared_ptr<MediaCasService> service = ::ndk::SharedRefBase::make<MediaCasService>();
diff --git a/common/aidl/Android.bp b/common/aidl/Android.bp
index f3ea8e8..1457b8a 100644
--- a/common/aidl/Android.bp
+++ b/common/aidl/Android.bp
@@ -38,7 +38,7 @@
         },
         rust: {
             enabled: true,
-        }
+        },
     },
     frozen: true,
     versions: [
diff --git a/compatibility_matrices/Android.bp b/compatibility_matrices/Android.bp
index 712f28a..9bee3b9 100644
--- a/compatibility_matrices/Android.bp
+++ b/compatibility_matrices/Android.bp
@@ -31,7 +31,6 @@
         "kernel_config_q_4.14",
         "kernel_config_q_4.19",
     ],
-    core_hals: "only",
 }
 
 vintf_compatibility_matrix {
@@ -45,7 +44,6 @@
         "kernel_config_r_4.19",
         "kernel_config_r_5.4",
     ],
-    core_hals: "only",
 }
 
 vintf_compatibility_matrix {
@@ -59,7 +57,6 @@
         "kernel_config_s_5.4",
         "kernel_config_s_5.10",
     ],
-    core_hals: "only",
 }
 
 vintf_compatibility_matrix {
@@ -72,7 +69,6 @@
         "kernel_config_t_5.10",
         "kernel_config_t_5.15",
     ],
-    core_hals: "only",
 }
 
 vintf_compatibility_matrix {
@@ -85,7 +81,6 @@
         "kernel_config_u_5.15",
         "kernel_config_u_6.1",
     ],
-    core_hals: "only",
 }
 
 vintf_compatibility_matrix {
@@ -95,8 +90,7 @@
         "compatibility_matrix.9.xml",
     ],
     kernel_configs: [
-        "kernel_config_v_5.15",
         "kernel_config_v_6.1",
+        "kernel_config_v_6.6",
     ],
-    core_hals: "only",
 }
diff --git a/compatibility_matrices/Android.mk b/compatibility_matrices/Android.mk
index d356cf3..c2ffb84 100644
--- a/compatibility_matrices/Android.mk
+++ b/compatibility_matrices/Android.mk
@@ -106,9 +106,15 @@
     framework_compatibility_matrix.6.xml \
     framework_compatibility_matrix.7.xml \
     framework_compatibility_matrix.8.xml \
-    framework_compatibility_matrix.9.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.9.xml
+endif
+
 my_framework_matrix_deps += \
     $(my_system_matrix_deps)
 
diff --git a/compatibility_matrices/build/vintf_compatibility_matrix.go b/compatibility_matrices/build/vintf_compatibility_matrix.go
index 4f342b2..c72cbde 100644
--- a/compatibility_matrices/build/vintf_compatibility_matrix.go
+++ b/compatibility_matrices/build/vintf_compatibility_matrix.go
@@ -35,10 +35,10 @@
 	pctx = android.NewPackageContext("android/vintf")
 
 	assembleVintfRule = pctx.AndroidStaticRule("assemble_vintf", blueprint.RuleParams{
-		Command:     `${assembleVintfCmd} -i ${inputs} -o ${out} ${extraParams}`,
+		Command:     `${assembleVintfCmd} -i ${inputs} -o ${out}`,
 		CommandDeps: []string{"${assembleVintfCmd}"},
 		Description: "assemble_vintf -i ${inputs}",
-	}, "inputs", "extraParams")
+	}, "inputs")
 
 	xmllintXsd = pctx.AndroidStaticRule("xmllint-xsd", blueprint.RuleParams{
 		Command:     `$XmlLintCmd --quiet --schema $xsd $in > /dev/null && touch -a $out`,
@@ -64,13 +64,6 @@
 
 	// list of kernel_config modules to be combined to final output
 	Kernel_configs []string
-
-	// Default is "default" for compatibility matrices on /vendor
-	// and /odm, and "disallow" for compatibility matrices on /system,
-	// /product, and /system_ext.
-	// If value is "only", only android.* HALs are allowed. If value
-	// is "disallow", none of android.* HALs are allowed.
-	Core_hals *string
 }
 
 type vintfCompatibilityMatrixRule struct {
@@ -173,8 +166,7 @@
 		Implicits:   inputPaths,
 		Output:      g.genFile,
 		Args: map[string]string{
-			"inputs":      strings.Join(inputPaths.Strings(), ":"),
-			"extraParams": strings.Join(g.getExtraParams(), " "),
+			"inputs": strings.Join(inputPaths.Strings(), ":"),
 		},
 	})
 	g.generateValidateBuildAction(ctx, g.genFile, schema.Path())
@@ -199,23 +191,3 @@
 		},
 	}
 }
-
-// Return extra parameters to assemble_vintf.
-func (g *vintfCompatibilityMatrixRule) getExtraParams() []string {
-	var extraParams []string
-
-	coreHalsStrategy := proptools.StringDefault(
-		g.properties.Core_hals,
-		g.defaultCoreHalsStrategy(),
-	)
-	extraParams = append(extraParams, "--core-hals", proptools.ShellEscape(coreHalsStrategy))
-	return extraParams
-}
-
-func (g *vintfCompatibilityMatrixRule) defaultCoreHalsStrategy() string {
-	// TODO(b/290408770): default to "disallow" for FCMs
-
-	// For Device (vendor, odm) compatibility matrix, default is
-	// to not check anything.
-	return "default"
-}
diff --git a/compatibility_matrices/compatibility_matrix.8.xml b/compatibility_matrices/compatibility_matrix.8.xml
index 99dcdbb..9057788 100644
--- a/compatibility_matrices/compatibility_matrix.8.xml
+++ b/compatibility_matrices/compatibility_matrix.8.xml
@@ -52,7 +52,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" optional="true" updatable-via-apex="true">
          <name>android.hardware.authsecret</name>
          <version>1</version>
          <interface>
@@ -123,7 +123,7 @@
             <instance>virtual</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" optional="true" updatable-via-apex="true">
         <name>android.hardware.biometrics.fingerprint</name>
         <version>3</version>
         <interface>
@@ -314,7 +314,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" optional="true" updatable-via-apex="true">
         <name>android.hardware.security.keymint</name>
         <version>1-3</version>
         <interface>
@@ -323,7 +323,7 @@
             <instance>strongbox</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" optional="true" updatable-via-apex="true">
         <name>android.hardware.security.keymint</name>
         <version>1-3</version>
         <interface>
@@ -532,7 +532,7 @@
             <regex-instance>SIM[1-9][0-9]*</regex-instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" optional="true" updatable-via-apex="true">
         <name>android.hardware.security.secureclock</name>
         <version>1</version>
         <interface>
@@ -540,7 +540,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" optional="true" updatable-via-apex="true">
         <name>android.hardware.security.sharedsecret</name>
         <version>1</version>
         <interface>
@@ -692,7 +692,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" optional="true" updatable-via-apex="true">
         <name>android.hardware.uwb</name>
         <version>1</version>
         <interface>
diff --git a/compatibility_matrices/compatibility_matrix.9.xml b/compatibility_matrices/compatibility_matrix.9.xml
index 6ed8e8f..a7f0845 100644
--- a/compatibility_matrices/compatibility_matrix.9.xml
+++ b/compatibility_matrices/compatibility_matrix.9.xml
@@ -1,25 +1,7 @@
 <compatibility-matrix version="1.0" type="framework" level="9">
-    <hal format="hidl" optional="true">
-        <name>android.hardware.audio</name>
-        <version>6.0</version>
-        <version>7.0-1</version>
-        <interface>
-            <name>IDevicesFactory</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.audio.effect</name>
-        <version>6.0</version>
-        <version>7.0</version>
-        <interface>
-            <name>IEffectsFactory</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.audio.core</name>
-        <version>1</version>
+        <version>1-2</version>
         <interface>
             <name>IModule</name>
             <instance>default</instance>
@@ -38,7 +20,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.audio.effect</name>
-        <version>1</version>
+        <version>1-2</version>
         <interface>
             <name>IFactory</name>
             <instance>default</instance>
@@ -46,7 +28,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.audio.sounddose</name>
-        <version>1</version>
+        <version>1-2</version>
         <interface>
             <name>ISoundDoseFactory</name>
             <instance>default</instance>
@@ -62,7 +44,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.automotive.audiocontrol</name>
-        <version>2-3</version>
+        <version>2-4</version>
         <interface>
             <name>IAudioControl</name>
             <instance>default</instance>
@@ -140,13 +122,37 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.bluetooth.audio</name>
-        <version>3</version>
+        <version>3-4</version>
         <interface>
             <name>IBluetoothAudioProviderFactory</name>
             <instance>default</instance>
         </interface>
     </hal>
     <hal format="aidl" optional="true">
+        <name>android.hardware.bluetooth.ranging</name>
+        <version>1</version>
+        <interface>
+            <name>IBluetoothChannelSounding</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.bluetooth.finder</name>
+        <version>1</version>
+        <interface>
+            <name>IBluetoothFinder</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.bluetooth.lmp_event</name>
+        <version>1</version>
+        <interface>
+            <name>IBluetoothLmpEvent</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
         <name>android.hardware.boot</name>
         <interface>
             <name>IBootControl</name>
@@ -249,7 +255,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.health</name>
-        <version>1-2</version>
+        <version>3</version>
         <interface>
             <name>IHealth</name>
             <instance>default</instance>
@@ -302,6 +308,15 @@
             <instance>default</instance>
         </interface>
     </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.security.secretkeeper</name>
+        <version>1</version>
+        <interface>
+            <name>ISecretkeeper</name>
+            <instance>default</instance>
+            <instance>nonsecure</instance>
+        </interface>
+    </hal>
     <hal format="aidl" optional="true" updatable-via-apex="true">
         <name>android.hardware.security.keymint</name>
         <version>1-3</version>
@@ -543,7 +558,7 @@
     </hal>
     <hal format="aidl" optional="true">
          <name>android.hardware.soundtrigger3</name>
-         <version>1</version>
+         <version>1-2</version>
          <interface>
              <name>ISoundTriggerHw</name>
              <instance>default</instance>
@@ -574,6 +589,14 @@
         </interface>
     </hal>
     <hal format="aidl" optional="true">
+        <name>android.hardware.threadnetwork</name>
+        <version>1</version>
+        <interface>
+            <name>IThreadChip</name>
+            <instance>chip0</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
         <name>android.hardware.tv.hdmi.cec</name>
         <version>1</version>
         <interface>
diff --git a/compatibility_matrices/exclude/fcm_exclude.cpp b/compatibility_matrices/exclude/fcm_exclude.cpp
index d92c0b9..2cb4ffa 100644
--- a/compatibility_matrices/exclude/fcm_exclude.cpp
+++ b/compatibility_matrices/exclude/fcm_exclude.cpp
@@ -142,6 +142,7 @@
 
             // AIDL
             "android.hardware.audio.core.sounddose@1",
+            "android.hardware.audio.core.sounddose@2",
 
             // Deprecated HALs.
             "android.hardware.bluetooth.audio@1",
diff --git a/drm/aidl/Android.bp b/drm/aidl/Android.bp
index fb04d84..afcb603 100644
--- a/drm/aidl/Android.bp
+++ b/drm/aidl/Android.bp
@@ -23,7 +23,7 @@
             sdk_version: "module_current",
         },
         ndk: {
-            min_sdk_version: "UpsideDownCake",
+            min_sdk_version: "34",
         },
     },
     double_loadable: true,
diff --git a/gnss/aidl/default/Android.bp b/gnss/aidl/default/Android.bp
index ca5a41f..7310922 100644
--- a/gnss/aidl/default/Android.bp
+++ b/gnss/aidl/default/Android.bp
@@ -26,12 +26,7 @@
 cc_binary {
     name: "android.hardware.gnss-service.example",
     relative_install_path: "hw",
-    init_rc: [
-        "gnss-default.rc",
-    ],
-    vintf_fragments: [
-        "gnss-default.xml",
-    ],
+    installable: false, // install APEX instead
     vendor: true,
     cflags: [
         "-Wall",
@@ -73,3 +68,35 @@
         "android.hardware.gnss@common-default-lib",
     ],
 }
+
+prebuilt_etc {
+    name: "gnss-default.rc",
+    src: "gnss-default.rc",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "gnss-default.xml",
+    src: "gnss-default.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
+
+apex {
+    name: "com.android.hardware.gnss",
+    manifest: "apex_manifest.json",
+    file_contexts: "apex_file_contexts",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    updatable: false,
+    vendor: true,
+
+    binaries: [
+        "android.hardware.gnss-service.example",
+    ],
+    prebuilts: [
+        "gnss-default.rc",
+        "gnss-default.xml",
+        "android.hardware.location.gps.prebuilt.xml", // permission
+    ],
+}
diff --git a/gnss/aidl/default/apex_file_contexts b/gnss/aidl/default/apex_file_contexts
new file mode 100644
index 0000000..83b01ed
--- /dev/null
+++ b/gnss/aidl/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                                          u:object_r:vendor_file:s0
+/etc(/.*)?                                                      u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.gnss-service\.example                u:object_r:hal_gnss_default_exec:s0
diff --git a/gnss/aidl/default/apex_manifest.json b/gnss/aidl/default/apex_manifest.json
new file mode 100644
index 0000000..9b2db23
--- /dev/null
+++ b/gnss/aidl/default/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.gnss",
+    "version": 1
+}
diff --git a/gnss/aidl/default/gnss-default.rc b/gnss/aidl/default/gnss-default.rc
index fe179c3..d47b3a5 100644
--- a/gnss/aidl/default/gnss-default.rc
+++ b/gnss/aidl/default/gnss-default.rc
@@ -1,4 +1,4 @@
-service vendor.gnss-default /vendor/bin/hw/android.hardware.gnss-service.example
+service vendor.gnss-default /apex/com.android.hardware.gnss/bin/hw/android.hardware.gnss-service.example
     class hal
     user nobody
     group nobody
diff --git a/gnss/aidl/vts/gnss_hal_test.cpp b/gnss/aidl/vts/gnss_hal_test.cpp
index 4f5e6a0..5e2cbe3 100644
--- a/gnss/aidl/vts/gnss_hal_test.cpp
+++ b/gnss/aidl/vts/gnss_hal_test.cpp
@@ -486,8 +486,6 @@
 
     auto status = aidl_gnss_hal_->startSvStatus();
     EXPECT_TRUE(status.isOk());
-    ASSERT_TRUE(aidl_gnss_cb_->sv_info_list_timestamps_millis_cbq_.size() ==
-                aidl_gnss_cb_->sv_info_list_cbq_.size());
     long lastElapsedRealtimeMillis = 0;
     for (int i = 0; i < numMeasurementEvents; i++) {
         long timeStamp;
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
index 18d36e4..323e358 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
@@ -1554,6 +1554,7 @@
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, SetDisplayBrightness) {
+    EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::ON).isOk());
     const auto& [status, capabilities] =
             mComposerClient->getDisplayCapabilities(getPrimaryDisplayId());
     ASSERT_TRUE(status.isOk());
diff --git a/health/aidl/Android.bp b/health/aidl/Android.bp
index e288f17..4691dd6 100644
--- a/health/aidl/Android.bp
+++ b/health/aidl/Android.bp
@@ -48,7 +48,7 @@
         },
 
     ],
-    frozen: true,
+    frozen: false,
 
 }
 
@@ -80,7 +80,7 @@
     name: "android.hardware.health-translate-ndk",
     defaults: ["android.hardware.health-translate-ndk_defaults"],
     shared_libs: [
-        "android.hardware.health-V2-ndk",
+        "android.hardware.health-V3-ndk",
     ],
 }
 
@@ -97,7 +97,7 @@
     name: "android.hardware.health-translate-java",
     srcs: ["android/hardware/health/Translate.java"],
     libs: [
-        "android.hardware.health-V2-java",
+        "android.hardware.health-V3-java",
         "android.hardware.health-V2.0-java",
         "android.hardware.health-V2.1-java",
     ],
diff --git a/health/aidl/aidl_api/android.hardware.health/current/android/hardware/health/BatteryHealthData.aidl b/health/aidl/aidl_api/android.hardware.health/current/android/hardware/health/BatteryHealthData.aidl
index 2dd01b1..089c8ac 100644
--- a/health/aidl/aidl_api/android.hardware.health/current/android/hardware/health/BatteryHealthData.aidl
+++ b/health/aidl/aidl_api/android.hardware.health/current/android/hardware/health/BatteryHealthData.aidl
@@ -37,4 +37,6 @@
   long batteryManufacturingDateSeconds;
   long batteryFirstUsageSeconds;
   long batteryStateOfHealth;
+  @nullable String batterySerialNumber;
+  android.hardware.health.BatteryPartStatus batteryPartStatus = android.hardware.health.BatteryPartStatus.UNSUPPORTED;
 }
diff --git a/health/aidl/aidl_api/android.hardware.health/current/android/hardware/health/BatteryPartStatus.aidl b/health/aidl/aidl_api/android.hardware.health/current/android/hardware/health/BatteryPartStatus.aidl
new file mode 100644
index 0000000..e013e31
--- /dev/null
+++ b/health/aidl/aidl_api/android.hardware.health/current/android/hardware/health/BatteryPartStatus.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.health;
+@Backing(type="int") @VintfStability
+enum BatteryPartStatus {
+  UNSUPPORTED,
+  ORIGINAL,
+  REPLACED,
+}
diff --git a/health/aidl/android/hardware/health/BatteryHealthData.aidl b/health/aidl/android/hardware/health/BatteryHealthData.aidl
index 594bcce..7245298 100644
--- a/health/aidl/android/hardware/health/BatteryHealthData.aidl
+++ b/health/aidl/android/hardware/health/BatteryHealthData.aidl
@@ -16,6 +16,8 @@
 
 package android.hardware.health;
 
+import android.hardware.health.BatteryPartStatus;
+
 /*
  * Battery health data
  */
@@ -36,4 +38,14 @@
      * Otherwise, value must be in the range 0 to 100.
      */
     long batteryStateOfHealth;
+    /**
+     * Serial number of the battery. Null if not supported. If supported, a string of at least 6
+     * alphanumeric characters. Characters may either be upper or lower case, but for comparison
+     * and uniqueness purposes, must be treated as case-insensitive.
+     */
+    @nullable String batterySerialNumber;
+    /**
+     * Indicator for part originality of the battery.
+     */
+    BatteryPartStatus batteryPartStatus = BatteryPartStatus.UNSUPPORTED;
 }
diff --git a/health/aidl/android/hardware/health/BatteryPartStatus.aidl b/health/aidl/android/hardware/health/BatteryPartStatus.aidl
new file mode 100644
index 0000000..6c2060a
--- /dev/null
+++ b/health/aidl/android/hardware/health/BatteryPartStatus.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.health;
+
+/**
+ * Possible values for BatteryPartStatus.
+ * Note: These are currently in sync with BatteryManager and must not
+ * be extended / altered.
+ */
+@VintfStability
+@Backing(type="int")
+enum BatteryPartStatus {
+    /**
+     * Device cannot differentiate an original battery from a replaced battery.
+     */
+    UNSUPPORTED = 0,
+    /**
+     * Device has the original battery it was manufactured with.
+     */
+    ORIGINAL = 1,
+    /**
+     * Device has a replaced battery.
+     */
+    REPLACED = 2,
+}
diff --git a/health/aidl/default/Android.bp b/health/aidl/default/Android.bp
index b51e4f3..2071f08 100644
--- a/health/aidl/default/Android.bp
+++ b/health/aidl/default/Android.bp
@@ -29,7 +29,7 @@
         "libcutils",
         "liblog",
         "libutils",
-        "android.hardware.health-V2-ndk",
+        "android.hardware.health-V3-ndk",
 
         // TODO(b/177269435): remove when BatteryMonitor works with AIDL HealthInfo.
         "libhidlbase",
@@ -48,7 +48,7 @@
     name: "libhealth_aidl_charger_defaults",
     shared_libs: [
         // common
-        "android.hardware.health-V2-ndk",
+        "android.hardware.health-V3-ndk",
         "libbase",
         "libcutils",
         "liblog",
@@ -195,7 +195,7 @@
         "service_fuzzer_defaults",
     ],
     static_libs: [
-        "android.hardware.health-V2-ndk",
+        "android.hardware.health-V3-ndk",
         "libbase",
         "liblog",
         "fuzz_libhealth_aidl_impl",
diff --git a/health/aidl/default/Health.cpp b/health/aidl/default/Health.cpp
index 1d8cc13..b2c0f0a 100644
--- a/health/aidl/default/Health.cpp
+++ b/health/aidl/default/Health.cpp
@@ -62,6 +62,18 @@
 
 Health::~Health() {}
 
+static inline ndk::ScopedAStatus TranslateStatus(::android::status_t err) {
+    switch (err) {
+        case ::android::OK:
+            return ndk::ScopedAStatus::ok();
+        case ::android::NAME_NOT_FOUND:
+            return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+        default:
+            return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                    IHealth::STATUS_UNKNOWN, ::android::statusToString(err).c_str());
+    }
+}
+
 //
 // Getters.
 //
@@ -78,16 +90,7 @@
         LOG(DEBUG) << "getProperty(" << id << ")"
                    << " fails: (" << err << ") " << ::android::statusToString(err);
     }
-
-    switch (err) {
-        case ::android::OK:
-            return ndk::ScopedAStatus::ok();
-        case ::android::NAME_NOT_FOUND:
-            return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
-        default:
-            return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
-                    IHealth::STATUS_UNKNOWN, ::android::statusToString(err).c_str());
-    }
+    return TranslateStatus(err);
 }
 
 ndk::ScopedAStatus Health::getChargeCounterUah(int32_t* out) {
@@ -153,6 +156,21 @@
         !res.isOk()) {
         LOG(WARNING) << "Cannot get Battery_state_of_health: " << res.getDescription();
     }
+    if (auto res = battery_monitor_.getSerialNumber(&out->batterySerialNumber);
+        res != ::android::OK) {
+        LOG(WARNING) << "Cannot get Battery_serial_number: "
+                     << TranslateStatus(res).getDescription();
+    }
+
+    int64_t part_status = static_cast<int64_t>(BatteryPartStatus::UNSUPPORTED);
+    if (auto res = GetProperty<int64_t>(&battery_monitor_, ::android::BATTERY_PROP_PART_STATUS,
+                                        static_cast<int64_t>(BatteryPartStatus::UNSUPPORTED),
+                                        &part_status);
+        !res.isOk()) {
+        LOG(WARNING) << "Cannot get Battery_part_status: " << res.getDescription();
+    }
+    out->batteryPartStatus = static_cast<BatteryPartStatus>(part_status);
+
     return ndk::ScopedAStatus::ok();
 }
 
diff --git a/health/aidl/default/android.hardware.health-service.example.xml b/health/aidl/default/android.hardware.health-service.example.xml
index 1fe9b8d..2acaaba 100644
--- a/health/aidl/default/android.hardware.health-service.example.xml
+++ b/health/aidl/default/android.hardware.health-service.example.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.health</name>
-        <version>2</version>
+        <version>3</version>
         <fqname>IHealth/default</fqname>
     </hal>
 </manifest>
diff --git a/health/aidl/vts/functional/Android.bp b/health/aidl/vts/functional/Android.bp
index b735a87..6d2b530 100644
--- a/health/aidl/vts/functional/Android.bp
+++ b/health/aidl/vts/functional/Android.bp
@@ -39,7 +39,7 @@
         "libbinder_ndk",
     ],
     static_libs: [
-        "android.hardware.health-V2-ndk",
+        "android.hardware.health-V3-ndk",
         "libgmock",
     ],
     header_libs: [
diff --git a/health/aidl/vts/functional/VtsHalHealthTargetTest.cpp b/health/aidl/vts/functional/VtsHalHealthTargetTest.cpp
index 783ce11..9360789 100644
--- a/health/aidl/vts/functional/VtsHalHealthTargetTest.cpp
+++ b/health/aidl/vts/functional/VtsHalHealthTargetTest.cpp
@@ -84,6 +84,21 @@
     return AnyOfArray(enum_range<T>().begin(), enum_range<T>().end());
 }
 
+MATCHER(IsValidSerialNumber, "") {
+    if (!arg) {
+        return true;
+    }
+    if (arg->size() < 6) {
+        return false;
+    }
+    for (const auto& c : *arg) {
+        if (!isalnum(c)) {
+            return false;
+        }
+    }
+    return true;
+}
+
 class HealthAidl : public testing::TestWithParam<std::string> {
   public:
     void SetUp() override {
@@ -270,7 +285,7 @@
     ASSERT_THAT(static_cast<int>(value), AnyOf(Eq(1), Eq(4)));
 }
 
-MATCHER(IsValidHealthData, "") {
+MATCHER_P(IsValidHealthData, version, "") {
     *result_listener << "value is " << arg.toString() << ".";
     if (!ExplainMatchResult(Ge(-1), arg.batteryManufacturingDateSeconds, result_listener)) {
         *result_listener << " for batteryManufacturingDateSeconds.";
@@ -284,6 +299,15 @@
         *result_listener << " for batteryStateOfHealth.";
         return false;
     }
+    if (!ExplainMatchResult(IsValidSerialNumber(), arg.batterySerialNumber, result_listener)) {
+        *result_listener << " for batterySerialNumber.";
+        return false;
+    }
+    if (!ExplainMatchResult(IsValidEnum<BatteryPartStatus>(), arg.batteryPartStatus,
+                            result_listener)) {
+        *result_listener << " for batteryPartStatus.";
+        return false;
+    }
 
     return true;
 }
@@ -303,7 +327,7 @@
     status = health->getBatteryHealthData(&value);
     ASSERT_THAT(status, AnyOf(IsOk(), ExceptionIs(EX_UNSUPPORTED_OPERATION)));
     if (!status.isOk()) return;
-    ASSERT_THAT(value, IsValidHealthData());
+    ASSERT_THAT(value, IsValidHealthData(version));
 }
 
 MATCHER(IsValidStorageInfo, "") {
diff --git a/health/utils/libhealthshim/Android.bp b/health/utils/libhealthshim/Android.bp
index 14c32ae..b0ea743 100644
--- a/health/utils/libhealthshim/Android.bp
+++ b/health/utils/libhealthshim/Android.bp
@@ -34,7 +34,7 @@
         "-Werror",
     ],
     static_libs: [
-        "android.hardware.health-V2-ndk",
+        "android.hardware.health-V3-ndk",
         "android.hardware.health-translate-ndk",
         "android.hardware.health@1.0",
         "android.hardware.health@2.0",
diff --git a/health/utils/libhealthshim/shim.cpp b/health/utils/libhealthshim/shim.cpp
index 6a5f512..a5ba919 100644
--- a/health/utils/libhealthshim/shim.cpp
+++ b/health/utils/libhealthshim/shim.cpp
@@ -230,6 +230,7 @@
 ScopedAStatus HealthShim::getBatteryHealthData(BatteryHealthData* out) {
     out->batteryManufacturingDateSeconds = 0;
     out->batteryFirstUsageSeconds = 0;
+    out->batteryPartStatus = BatteryPartStatus::UNSUPPORTED;
     return ResultToStatus(Result::NOT_SUPPORTED);
 }
 
diff --git a/ir/aidl/default/android.hardware.ir-service.example.rc b/ir/aidl/default/android.hardware.ir-service.example.rc
index 1a721da..d27f282 100644
--- a/ir/aidl/default/android.hardware.ir-service.example.rc
+++ b/ir/aidl/default/android.hardware.ir-service.example.rc
@@ -1,4 +1,4 @@
-service vendor.ir-default /apex/com.android.hardware.ir/bin/hw/android.hardware.ir-service.example
+service vendor.ir-default /vendor/bin/hw/android.hardware.ir-service.example
     class hal
     user system
     group system
diff --git a/keymaster/4.0/support/fuzzer/Android.bp b/keymaster/4.0/support/fuzzer/Android.bp
index 8bc681a..f61d10f 100644
--- a/keymaster/4.0/support/fuzzer/Android.bp
+++ b/keymaster/4.0/support/fuzzer/Android.bp
@@ -39,9 +39,17 @@
     ],
     fuzz_config: {
         cc: [
-            "android-media-fuzzing-reports@google.com",
+            "android-hardware-security@google.com",
         ],
-        componentid: 533764,
+        componentid: 1084733,
+        hotlists: [
+            "4593311",
+        ],
+        description: "The fuzzer targets the APIs of libkeymaster4support",
+        vector: "local_no_privileges_required",
+        service_privilege: "privileged",
+        users: "multi_user",
+        fuzzed_code_usage: "shipped",
     },
 }
 
diff --git a/media/bufferpool/aidl/default/BufferPoolClient.cpp b/media/bufferpool/aidl/default/BufferPoolClient.cpp
index e9777d8..0e249d5 100644
--- a/media/bufferpool/aidl/default/BufferPoolClient.cpp
+++ b/media/bufferpool/aidl/default/BufferPoolClient.cpp
@@ -297,7 +297,7 @@
       mLastEvictCacheMs(::android::elapsedRealtime()) {
     IAccessor::ConnectionInfo conInfo;
     bool valid = false;
-    if(accessor->connect(observer, &conInfo).isOk()) {
+    if (accessor && accessor->connect(observer, &conInfo).isOk()) {
         auto channel = std::make_unique<BufferStatusChannel>(conInfo.toFmqDesc);
         auto observer = std::make_unique<BufferInvalidationListener>(conInfo.fromFmqDesc);
 
diff --git a/media/c2/aidl/Android.bp b/media/c2/aidl/Android.bp
index 3c0915d..84cb382 100644
--- a/media/c2/aidl/Android.bp
+++ b/media/c2/aidl/Android.bp
@@ -42,11 +42,8 @@
             ],
         },
         rust: {
-            min_sdk_version: "31",
-            enabled: true,
-            additional_rustlibs: [
-                "libnativewindow_rs",
-            ],
+            // No users, and no rust implementation of android.os.Surface yet
+            enabled: false,
         },
     },
 }
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IConfigurable.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IConfigurable.aidl
index 32f5abd..04e776e 100644
--- a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IConfigurable.aidl
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IConfigurable.aidl
@@ -37,12 +37,23 @@
   android.hardware.media.c2.IConfigurable.ConfigResult config(in android.hardware.media.c2.Params inParams, in boolean mayBlock);
   int getId();
   String getName();
-  android.hardware.media.c2.Params query(in int[] indices, in boolean mayBlock);
+  android.hardware.media.c2.IConfigurable.QueryResult query(in int[] indices, in boolean mayBlock);
   android.hardware.media.c2.ParamDescriptor[] querySupportedParams(in int start, in int count);
-  android.hardware.media.c2.FieldSupportedValuesQueryResult[] querySupportedValues(in android.hardware.media.c2.FieldSupportedValuesQuery[] inFields, in boolean mayBlock);
+  android.hardware.media.c2.IConfigurable.QuerySupportedValuesResult querySupportedValues(in android.hardware.media.c2.FieldSupportedValuesQuery[] inFields, in boolean mayBlock);
   @VintfStability
   parcelable ConfigResult {
     android.hardware.media.c2.Params params;
     android.hardware.media.c2.SettingResult[] failures;
+    android.hardware.media.c2.Status status;
+  }
+  @VintfStability
+  parcelable QueryResult {
+    android.hardware.media.c2.Params params;
+    android.hardware.media.c2.Status status;
+  }
+  @VintfStability
+  parcelable QuerySupportedValuesResult {
+    android.hardware.media.c2.FieldSupportedValuesQueryResult[] values;
+    android.hardware.media.c2.Status status;
   }
 }
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IGraphicBufferAllocator.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IGraphicBufferAllocator.aidl
index 3e460dd..e13ba1f 100644
--- a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IGraphicBufferAllocator.aidl
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IGraphicBufferAllocator.aidl
@@ -39,7 +39,7 @@
   ParcelFileDescriptor getWaitableFd();
   parcelable Allocation {
     android.hardware.HardwareBuffer buffer;
-    ParcelFileDescriptor fence;
+    @nullable ParcelFileDescriptor fence;
   }
   parcelable Description {
     int width;
diff --git a/media/c2/aidl/android/hardware/media/c2/IConfigurable.aidl b/media/c2/aidl/android/hardware/media/c2/IConfigurable.aidl
index 7fdb825..1481c15 100644
--- a/media/c2/aidl/android/hardware/media/c2/IConfigurable.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/IConfigurable.aidl
@@ -21,6 +21,7 @@
 import android.hardware.media.c2.ParamDescriptor;
 import android.hardware.media.c2.Params;
 import android.hardware.media.c2.SettingResult;
+import android.hardware.media.c2.Status;
 
 /**
  * Generic configuration interface presented by all configurable Codec2 objects.
@@ -34,12 +35,42 @@
      * Return parcelable for config() interface.
      *
      * This includes the successful config settings along with the failure reasons of
-     * the specified setting.
+     * the specified setting. @p status is for the compatibility with HIDL interface.
+     * (The value is defined in Status.aidl, and possible values are enumerated
+     * in config() interface definition)
      */
     @VintfStability
     parcelable ConfigResult {
         Params params;
         SettingResult[] failures;
+        Status status;
+    }
+
+    /**
+     * Return parcelable for query() interface.
+     *
+     * @p params is the parameter descripion for queried configuration indices.
+     * @p status is for the compatibility with HIDL interface. (The value is defined in
+     * Status.aidl, and possible values are enumerated in query() interface definition)
+     */
+    @VintfStability
+    parcelable QueryResult {
+        Params params;
+        Status status;
+    }
+
+    /**
+     * Return parcelable for querySupportedValues() interface.
+     *
+     * @p values is the value descripion for queried configuration fields.
+     * @p status is for the compatibility with HIDL interface. (The value is defined in
+     * Status.aidl, and possible values are enumerated in querySupportedValues()
+     * interface definition)
+     */
+    @VintfStability
+    parcelable QuerySupportedValuesResult {
+        FieldSupportedValuesQueryResult[] values;
+        Status status;
     }
 
     /**
@@ -82,7 +113,8 @@
      * @param mayBlock Whether this call may block or not.
      * @return result of config. Params in the result should be in same order
      *     with @p inParams.
-     * @throws ServiceSpecificException with one of the following values:
+     *
+     *     Returned @p status will be one of the following.
      *   - `Status::NO_MEMORY` - Some supported parameters could not be updated
      *                   successfully because they contained unsupported values.
      *                   These are returned in @p failures.
@@ -146,17 +178,22 @@
      *
      * @param indices List of C2Param structure indices to query.
      * @param mayBlock Whether this call may block or not.
-     * @return Flattened representation of std::vector<C2Param> object.
-     *     Unsupported settings are skipped in the results. The order in @p indices
-     *     still be preserved except skipped settings.
-     * @throws ServiceSpecificException with one of the following values:
+     * @return @p params is the flattened representation of std::vector<C2Param> object.
+     *     Technically unsupported settings can be either skipped or invalidated.
+     *     (Invalidated params will be skipped during unflattening to make these identical.)
+     *     In the future we will want these to be invalidated to make it easier
+     *     for the framework code.
+     *
+     *     The order in @p indices still be preserved except skipped settings.
+     *
+     *     Returned @p status will be one of the following.
      *   - `Status::NO_MEMORY` - Could not allocate memory for a supported parameter.
      *   - `Status::BLOCKING`  - Querying some parameters requires blocking, but
      *                   @p mayBlock is false.
      *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
      *   - `Status::CORRUPTED` - Some unknown error occurred.
      */
-    Params query(in int[] indices, in boolean mayBlock);
+    QueryResult query(in int[] indices, in boolean mayBlock);
 
     /**
      * Returns a list of supported parameters within a selected range of C2Param
@@ -197,9 +234,10 @@
      *
      * @param inFields List of field queries.
      * @param mayBlock Whether this call may block or not.
-     * @return List of supported values and results for the
+     * @return @p values is the list of supported values and results for the
      *     supplied queries.
-     * @throws ServiceSpecificException with one of the following values:
+     *
+     *     Returned @p status will be one of the following.
      *   - `Status::BLOCKING`  - Querying some parameters requires blocking, but
      *                   @p mayBlock is false.
      *   - `Status::NO_MEMORY` - Not enough memory to complete this method.
@@ -208,6 +246,6 @@
      *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
      *   - `Status::CORRUPTED` - Some unknown error occurred.
      */
-    FieldSupportedValuesQueryResult[] querySupportedValues(
+    QuerySupportedValuesResult querySupportedValues(
             in FieldSupportedValuesQuery[] inFields, in boolean mayBlock);
 }
diff --git a/media/c2/aidl/android/hardware/media/c2/IGraphicBufferAllocator.aidl b/media/c2/aidl/android/hardware/media/c2/IGraphicBufferAllocator.aidl
index 49c4ea4..1710242 100644
--- a/media/c2/aidl/android/hardware/media/c2/IGraphicBufferAllocator.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/IGraphicBufferAllocator.aidl
@@ -35,7 +35,7 @@
      */
     parcelable Allocation {
         HardwareBuffer buffer;
-        ParcelFileDescriptor fence;
+        @nullable ParcelFileDescriptor fence;
     }
 
     /**
diff --git a/radio/OWNERS b/radio/OWNERS
index 67ac2e2..8107287 100644
--- a/radio/OWNERS
+++ b/radio/OWNERS
@@ -2,3 +2,4 @@
 
 jackyu@google.com
 sarahchin@google.com
+jayachandranc@google.com
\ No newline at end of file
diff --git a/renderscript/1.0/default/Android.bp b/renderscript/1.0/default/Android.bp
index c68e370..23fa252 100644
--- a/renderscript/1.0/default/Android.bp
+++ b/renderscript/1.0/default/Android.bp
@@ -27,6 +27,12 @@
         "android.hardware.renderscript@1.0",
     ],
 
+    runtime_libs: [
+        "libRS_internal",
+        //TODO(b/313564579) Install libRSDriver as dependency of libRS_internal
+        "libRSDriver",
+    ],
+
     product_variables: {
         override_rs_driver: {
             cflags: ["-DOVERRIDE_RS_DRIVER=%s"],
diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.xml b/secure_element/aidl/vts/AndroidTest.xml
similarity index 61%
copy from audio/aidl/vts/VtsHalAudioCoreTargetTest.xml
copy to secure_element/aidl/vts/AndroidTest.xml
index 9d3adc1..94dfa82 100644
--- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.xml
+++ b/secure_element/aidl/vts/AndroidTest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 The Android Open Source Project
+<!-- 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.
@@ -13,26 +13,21 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="Runs VtsHalAudioCoreTargetTest.">
+<configuration description="Runs VtsHalSecureElementTargetTest.">
     <option name="test-suite-tag" value="apct" />
     <option name="test-suite-tag" value="apct-native" />
+    <option name="config-descriptor:metadata" key="token" value="SECURE_ELEMENT_SIM_CARD" />
 
-    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
-    <target_preparer class="com.android.tradefed.targetprep.StopServicesSetup"/>
-
-    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="run-command" value="setprop vts.native_server.on 1"/>
-        <option name="teardown-command" value="setprop vts.native_server.on 0"/>
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
     </target_preparer>
 
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
         <option name="cleanup" value="true" />
-        <option name="push" value="VtsHalAudioCoreTargetTest->/data/local/tmp/VtsHalAudioCoreTargetTest" />
+        <option name="push" value="VtsHalSecureElementTargetTest->/data/local/tmp/VtsHalSecureElementTargetTest" />
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.GTest" >
         <option name="native-test-device-path" value="/data/local/tmp" />
-        <option name="module-name" value="VtsHalAudioCoreTargetTest" />
-        <option name="native-test-timeout" value="10m" />
+        <option name="module-name" value="VtsHalSecureElementTargetTest" />
     </test>
 </configuration>
diff --git a/security/authgraph/aidl/Android.bp b/security/authgraph/aidl/Android.bp
index d94f640..f3d1281 100644
--- a/security/authgraph/aidl/Android.bp
+++ b/security/authgraph/aidl/Android.bp
@@ -34,7 +34,7 @@
             platform_apis: true,
         },
         ndk: {
-            apps_enabled: false,
+            enabled: true,
         },
         rust: {
             enabled: true,
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/Arc.cddl b/security/authgraph/aidl/android/hardware/security/authgraph/Arc.cddl
index 4c1b965..0bc39d6 100644
--- a/security/authgraph/aidl/android/hardware/security/authgraph/Arc.cddl
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/Arc.cddl
@@ -28,19 +28,19 @@
     ? -70003 : int,   ; Timestamp in milliseconds since some starting point (generally
                       ; the most recent device boot) which all of the applications within
                       ; the secure domain must agree upon
-    ? -70004 : bstr .size 16,      ; Nonce used in key exchange methods
+    ? -70004 : bstr .size 16,      ; Nonce (a cryptographic random number of 16 bytes) used in key
+                                   ; exchange methods
     ? -70005 : PayloadType,        ; Payload type, if needed to disambiguate, when processing an arc
     ? -70006 : int,                ; Version of the payload structure (if applicable)
     ? -70007 : int,                ; Sequence number (if needed to prevent replay attacks)
     ? -70008 : Direction           ; Direction of the encryption key (i.e. whether it is used to
                                    ; encrypt incoming messages or outgoing messages)
     ? -70009 : bool,               ; "authentication_completed" - this is used during authenticated
-                                   ; key exchange indicate whether signature verification is done
-    ? -70010 : bstr .size 32       ; "session_id" computed during key exchange protocol
+                                   ; key exchange to indicate whether signature verification is done
+    ? -70010 : bstr .size 32       ; "session_id" computed during the key exchange protocol
 }
 
-; Permissions indicate what an arc can be used with. Permissions are added to an arc during the
-; `create()` primitive operation and are propagated during `mint` and `snap` primitive operations.
+; Permissions indicate what an arc can be used with.
 Permission = &(
     -4770552 : IdentityEncoded,  ; "source_id" - in the operations performed by a source, the
                                  ; source adds its own identity to the permissions of an arc.
@@ -54,12 +54,10 @@
                                      ; biometrics.
 )
 
-; Limitations indicate what restrictions are applied on the usage of an arc. Permissions are added
-; to an arc during the `create` primitive operation and are propagated during `snap` primitive
-; operation.
+; Limitations indicate what restrictions are applied on the usage of an arc.
 Limitation = &(
-    -4770554 : bstr,      ; "challenge" - is added to an arc that transfers an auth key to a channel
-                          ; key, in order to ensure the freshness of the authentication.
+    -4770554 : bstr,      ; "challenge" - is added to an arc that encrypts an auth key from a
+                          ; channel key, in order to ensure the freshness of the authentication.
                           ; A challenge is issued by a sink (e.g. Keymint TA, Biometric TAs).
 )
 
@@ -83,7 +81,7 @@
     ; Any other payload formats should also be defined here
 )
 
-SecretKey = &(                     ; One of the payload types of an Arc is a secret key
+SecretKey = &(
     SymmetricKey,
     ECPrivateKey,    ; Private key of a key pair generated for key exchange
 )
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/IAuthGraphKeyExchange.aidl b/security/authgraph/aidl/android/hardware/security/authgraph/IAuthGraphKeyExchange.aidl
index 6ceb09c..a3fb959 100644
--- a/security/authgraph/aidl/android/hardware/security/authgraph/IAuthGraphKeyExchange.aidl
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/IAuthGraphKeyExchange.aidl
@@ -41,8 +41,8 @@
 interface IAuthGraphKeyExchange {
     /**
      * This method is invoked on P1 (source).
-     * Create an ephermeral EC key pair on NIST curve P-256 and a nonce (of 16 bytes) for
-     * key exchange.
+     * Create an ephermeral EC key pair on NIST curve P-256 and a nonce (a cryptographic random
+     * number of 16 bytes) for key exchange.
      *
      * @return SessionInitiationInfo including the `Key` containing the public key of the created
      * key pair and an arc from the per-boot key to the private key, the nonce, the persistent
@@ -52,8 +52,8 @@
      * `SessionInitiationInfo` serves two purposes:
      * i. A mapping to correlate `create` and `finish` calls to P1 in a particular instance of the
      *    key exchange protocol.
-     * ii.A way to minimize the in-memory storage (P1 can include the nonce in the protected headers
-     *    of the arc).
+     * ii.A way to minimize the in-memory storage of P1 allocated for key exchange (P1 can include
+     *    the nonce in the protected headers of the arc).
      * However, P1 should maintain some form of in-memory record to be able to verify that the input
      * `Key` sent to `finish` is from an unfinished instance of a key exchange protocol, to prevent
      * any replay attacks in `finish`.
@@ -66,9 +66,9 @@
      *     0. If either `peerPubKey`, `peerId`, `peerNonce` is not in the expected format, return
      *        errors: INVALID_PEER_KE_KEY, INVALID_IDENTITY, INVALID_PEER_NONCE respectively.
      *     1. Create an ephemeral EC key pair on NIST curve P-256.
-     *     2. Create a nonce (of 16 bytes).
-     *     3. Compute the diffie-hellman shared secret: Z.
-     *     4. Compute a salt = bstr .cbor [
+     *     2. Create a nonce (a cryptographic random number of 16 bytes).
+     *     3. Compute the Diffie-Hellman shared secret: Z.
+     *     4. Compute a salt_input = bstr .cbor [
      *            source_version:    int,                    ; from input `peerVersion`
      *            sink_pub_key:      bstr .cbor PlainPubKey, ; from step #1
      *            source_pub_key:    bstr .cbor PlainPubKey, ; from input `peerPubKey`
@@ -77,7 +77,8 @@
      *            sink_cert_chain:   bstr .cbor ExplicitKeyDiceCertChain, ; from own identity
      *            source_cert_chain: bstr .cbor ExplicitKeyDiceCertChain, ; from input `peerId`
      *        ]
-     *     5. Extract a cryptographic secret S from Z, using the salt from #4 above.
+     *     5. Extract a cryptographic secret S from Z, using the SHA256 digest of the salt_input
+     *        as the salt.
      *     6. Derive two symmetric encryption keys of 256 bits with:
      *        i. b"KE_ENCRYPTION_KEY_SOURCE_TO_SINK" as context for the key used to encrypt incoming
      *           messages
@@ -96,28 +97,29 @@
      *        part of the party's identity.
      *
      * @param peerPubKey - the public key of the key pair created by the peer (P1) for key exchange
+     *                     in `create`
      *
      * @param peerId - the persistent identity of the peer
      *
-     * @param peerNonce - nonce created by the peer
+     * @param peerNonce - nonce created by the peer in `create`
      *
      * @param peerVersion - an integer representing the latest protocol version (i.e. AIDL version)
      *                      supported by the peer
      *
-     * @return KeInitResult including the `Key` containing the public key of the created key pair,
-     * the nonce, the persistent identity, two shared key arcs from step #7, session id, signature
-     * over the session id and the negotiated protocol version. The negotiated protocol version
-     * should be less than or equal to the peer's version.
+     * @return KeInitResult including the `Key` containing the public key of the key pair created in
+     * step #1, the nonce from step #2, the persistent identity of P2, two shared key arcs
+     * from step #7, session id from step #10, signature over the session id from step #11 and the
+     * negotiated protocol version. The negotiated protocol version should be less than or equal to
+     * the `peerVersion`.
      *
-     * Note: The two shared key arcs in the return type: `KeInitResult` serves two purposes:
+     * Note: The two shared key arcs in the return type: `KeInitResult` serve two purposes:
      * i. A mapping to correlate `init` and `authenticationComplete` calls to P2 in a particular
      *    instance of the key exchange protocol.
      * ii.A way to minimize the in-memory storage of P2 allocated for key exchange.
      * However, P2 should maintain some in-memory record to be able to verify that the input
-     * `sharedkeys` sent to `authenticationComplete` and to any subsequent AuthGraph protocol
-     * methods are valid shared keys agreed with the party identified by `peerId`, to prevent
-     * any replay attacks in `authenticationComplete` and in any subsequent AuthGraph protocol
-     * methods which use the shared keys to encrypt the secret messages.
+     * `sharedkeys` sent to `authenticationComplete` are from an unfinished instance of a key
+     * exchange protocol carried out with the party identified by `peerId`, to prevent any replay
+     * attacks in `authenticationComplete`.
      */
     KeInitResult init(
             in PubKey peerPubKey, in Identity peerId, in byte[] peerNonce, in int peerVersion);
@@ -133,8 +135,8 @@
      *        exchange protocol, return error: INVALID_KE_KEY. Similarly, if the public key or the
      *        arc containing the private key in `ownKey` is invalid, return INVALID_PUB_KEY_IN_KEY
      *        and INVALID_PRIV_KEY_ARC_IN_KEY respectively.
-     *     1. Compute the diffie-hellman shared secret: Z.
-     *     2. Compute a salt = bstr .cbor [
+     *     1. Compute the Diffie-Hellman shared secret: Z.
+     *     2. Compute a salt_input = bstr .cbor [
      *            source_version:    int,                    ; the protocol version used in `create`
      *            sink_pub_key:      bstr .cbor PlainPubKey, ; from input `peerPubKey`
      *            source_pub_key:    bstr .cbor PlainPubKey, ; from the output of `create`
@@ -143,7 +145,8 @@
      *            sink_cert_chain:   bstr .cbor ExplicitKeyDiceCertChain, ; from input `peerId`
      *            source_cert_chain: bstr .cbor ExplicitKeyDiceCertChain, ; from own identity
      *        ]
-     *     3. Extract a cryptographic secret S from Z, using the salt from #2 above.
+     *     3. Extract a cryptographic secret S from Z, using the SHA256 digest of the salt_input
+     *        as the salt.
      *     4. Derive two symmetric encryption keys of 256 bits with:
      *        i. b"KE_ENCRYPTION_KEY_SOURCE_TO_SINK" as context for the key used to encrypt outgoing
      *           messages
@@ -164,25 +167,26 @@
      *        part of the party's identity.
      *
      * @param peerPubKey - the public key of the key pair created by the peer (P2) for key exchange
+     *                     in `init`
      *
      * @param peerId - the persistent identity of the peer
      *
      * @param peerSignature - the signature created by the peer over the session id computed by the
-     *                        peer
+     *                        peer in `init`
      *
-     * @param peerNonce - nonce created by the peer
+     * @param peerNonce - nonce created by the peer in `init`
      *
      * @param peerVersion - an integer representing the protocol version (i.e. AIDL version)
      *                      negotiated with the peer
      *
-     * @param ownKey - the key created by P1 (source) in `create()` for key exchange
+     * @param ownKey - the key created by P1 (source) in `create` for key exchange
      *
-     * @return SessionInfo including the two shared key arcs from step #9, session id and the
-     * signature over the session id.
+     * @return SessionInfo including the two shared key arcs from step #9, session id from step #7
+     * and the signature over the session id from step #10.
      *
-     * Note: The two shared key arcs in the return type: `SessionInfo` serves two purposes:
+     * Note: The two shared key arcs in the return type: `SessionInfo` serve two purposes:
      * i. A mapping to correlate the key exchange protocol taken place with a particular peer and
-     *    subsequent AuthGraph protocols execued with the same peer.
+     *    subsequent AuthGraph protocols executed with the same peer.
      * ii.A way to minimize the in-memory storage for shared keys.
      * However, P1 should maintain some in-memory record to be able to verify that the shared key
      * arcs sent to any subsequent AuthGraph protocol methods are valid shared keys agreed with the
@@ -196,21 +200,33 @@
      * This method is invoked on P2 (sink).
      * Perform the following steps:
      *   0. If input `sharedKeys` is invalid (i.e. they cannot be decrypted with P2's per-boot key
-     *      or they are not in P2's in-memory records as valid shared keys agreed with the party
-     *      identified by `peerId`), return error: INVALID_SHARED_KEY_ARCS.
+     *      or they are not in P2's in-memory records for unfinished instances of a key exchange
+     *      protocol carried out with the party identified by the identity included in the
+     *      `source_id` protected header of the shared key arcs),
+     *      return error: INVALID_SHARED_KEY_ARCS.
      *   1. Verify that both shared key arcs have the same session id and peer identity.
-     *   2. Verify the peer's signature over the session id attached to the shared key arcs'
-     *      headers. If successful, proceed, otherwise, return error: INVALID_SIGNATURE.
-     *   3. Mark authentication_complete = true in the shared key arcs' headers
+     *   2. Verify the `peerSignature` over the session id included in the `session_id` protected
+     *      header of the shared key arcs.
+     *      If successful, proceed, otherwise, return error: INVALID_SIGNATURE.
+     *   3. Mark authentication_complete = true in the shared key arcs' headers.
      *
      * @param peerSignature - the signature created by the peer over the session id computed by the
-     *                        peer
+     *                        peer in `finish`
      *
      * @param sharedKeys - two shared key arcs created by P2 in `init`. P2 obtains from the arcs'
      *                     protected headers, the session id and the peer's identity to verify the
      *                     peer's signature over the session id.
      *
      * @return Arc[] - an array of two updated shared key arcs
+     *
+     * Note: The two returned shared key arcs serve two purposes:
+     * i. A mapping to correlate the key exchange protocol taken place with a particular peer and
+     *    subsequent AuthGraph protocols executed with the same peer.
+     * ii.A way to minimize the in-memory storage for shared keys.
+     * However, P2 should maintain some in-memory record to be able to verify that the shared key
+     * arcs sent to any subsequent AuthGraph protocol methods are valid shared keys agreed with the
+     * party identified by the identity included in the `source_id` protected header of the shared
+     * key arcs, to prevent any replay attacks.
      */
     Arc[2] authenticationComplete(in SessionIdSignature peerSignature, in Arc[2] sharedKeys);
 }
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/SessionInfo.aidl b/security/authgraph/aidl/android/hardware/security/authgraph/SessionInfo.aidl
index ef49a1a..82b8c17 100644
--- a/security/authgraph/aidl/android/hardware/security/authgraph/SessionInfo.aidl
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/SessionInfo.aidl
@@ -26,8 +26,8 @@
 @RustDerive(Clone=true, Eq=true, PartialEq=true)
 parcelable SessionInfo {
     /**
-     * The arcs that encrypt the two derived symmetric encryption keys (for two-way communication)
-     * from the party's per-boot key.
+     * The arcs that encrypt the two derived symmetric encryption keys (for two-way communication).
+     * The encryption key is the party's per-boot key.
      */
     Arc[2] sharedKeys;
 
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/SessionInitiationInfo.aidl b/security/authgraph/aidl/android/hardware/security/authgraph/SessionInitiationInfo.aidl
index c630d91..8179ac2 100644
--- a/security/authgraph/aidl/android/hardware/security/authgraph/SessionInitiationInfo.aidl
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/SessionInitiationInfo.aidl
@@ -27,20 +27,22 @@
 @RustDerive(Clone=true, Eq=true, PartialEq=true)
 parcelable SessionInitiationInfo {
     /**
-     * An ephemeral EC key created for the ECDH process.
+     * An ephemeral EC key created for the Elliptic-curve Diffie-Hellman (ECDH) process.
      */
     Key key;
 
     /**
-     * The identity of the party who created the Diffie-Hellman key exchange key.
+     * The identity of the party who creates this `SessionInitiationInfo`.
      */
     Identity identity;
 
     /**
-     * Nonce value specific to this session. The nonce serves three purposes:
+     * Nonce (a cryptographic random number of 16 bytes) specific to this session.
+     * The nonce serves three purposes:
      * 1. freshness of key exchange
      * 2. creating a session id (a publicly known value related to the exchanged keys)
-     * 3. usage as salt into the HKDF-EXTRACT function during key derivation from the shared DH key
+     * 3. usage as salt into the HKDF-EXTRACT function during key derivation from the Diffie-Hellman
+     *    shared secret
      */
     byte[] nonce;
 
diff --git a/security/authgraph/aidl/vts/functional/Android.bp b/security/authgraph/aidl/vts/functional/Android.bp
index fc13759..28a70e2 100644
--- a/security/authgraph/aidl/vts/functional/Android.bp
+++ b/security/authgraph/aidl/vts/functional/Android.bp
@@ -46,3 +46,37 @@
         "vts",
     ],
 }
+
+rust_test {
+    name: "VtsAidlAuthGraphRoleTest",
+    srcs: ["role_test.rs"],
+    require_root: true,
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+    defaults: [
+        "authgraph_use_latest_hal_aidl_rust",
+    ],
+    rustlibs: [
+        "libauthgraph_vts_test",
+        "libbinder_rs",
+    ],
+}
+
+rust_library {
+    name: "libauthgraph_vts_test",
+    crate_name: "authgraph_vts_test",
+    srcs: ["lib.rs"],
+    defaults: [
+        "authgraph_use_latest_hal_aidl_rust",
+    ],
+    rustlibs: [
+        "libauthgraph_boringssl",
+        "libauthgraph_core",
+        "libauthgraph_hal",
+        "libauthgraph_nonsecure",
+        "libbinder_rs",
+        "libcoset",
+    ],
+}
diff --git a/security/authgraph/aidl/vts/functional/lib.rs b/security/authgraph/aidl/vts/functional/lib.rs
new file mode 100644
index 0000000..f4c1da9
--- /dev/null
+++ b/security/authgraph/aidl/vts/functional/lib.rs
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! VTS test library for AuthGraph functionality.
+//!
+//! This test code is bundled as a library, not as `[cfg(test)]`, to allow it to be
+//! re-used inside the (Rust) VTS tests of components that use AuthGraph.
+
+use android_hardware_security_authgraph::aidl::android::hardware::security::authgraph::{
+    Error::Error, IAuthGraphKeyExchange::IAuthGraphKeyExchange, Identity::Identity,
+    PlainPubKey::PlainPubKey, PubKey::PubKey, SessionIdSignature::SessionIdSignature,
+};
+use authgraph_boringssl as boring;
+use authgraph_core::{error::Error as AgError, keyexchange as ke};
+use coset::CborSerializable;
+use std::{cell::RefCell, rc::Rc};
+
+pub mod sink;
+pub mod source;
+
+/// Return an AuthGraphParticipant suitable for testing.
+pub fn test_ag_participant() -> Result<ke::AuthGraphParticipant, AgError> {
+    Ok(ke::AuthGraphParticipant::new(
+        boring::crypto_trait_impls(),
+        Rc::new(RefCell::new(boring::test_device::AgDevice::default())),
+        ke::MAX_OPENED_SESSIONS,
+    )?)
+}
+
+fn build_plain_pub_key(pub_key: &Option<Vec<u8>>) -> PubKey {
+    PubKey::PlainKey(PlainPubKey {
+        plainPubKey: pub_key.clone().unwrap(),
+    })
+}
+
+fn extract_plain_pub_key(pub_key: &Option<PubKey>) -> &PlainPubKey {
+    match pub_key {
+        Some(PubKey::PlainKey(pub_key)) => pub_key,
+        Some(PubKey::SignedKey(_)) => panic!("expect unsigned public key"),
+        None => panic!("expect pubKey to be populated"),
+    }
+}
+
+fn vec_to_identity(data: &[u8]) -> Identity {
+    Identity {
+        identity: data.to_vec(),
+    }
+}
+
+fn vec_to_signature(data: &[u8]) -> SessionIdSignature {
+    SessionIdSignature {
+        signature: data.to_vec(),
+    }
+}
diff --git a/security/authgraph/aidl/vts/functional/role_test.rs b/security/authgraph/aidl/vts/functional/role_test.rs
new file mode 100644
index 0000000..3075d8a
--- /dev/null
+++ b/security/authgraph/aidl/vts/functional/role_test.rs
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Tests of individual AuthGraph role (source or sink) functionality.
+
+#![cfg(test)]
+
+use authgraph_vts_test as vts;
+use android_hardware_security_authgraph::aidl::android::hardware::security::authgraph::{
+    IAuthGraphKeyExchange::IAuthGraphKeyExchange,
+};
+use binder::StatusCode;
+
+const AUTH_GRAPH_NONSECURE: &str =
+    "android.hardware.security.authgraph.IAuthGraphKeyExchange/nonsecure";
+
+/// Retrieve the /nonsecure instance of AuthGraph, which supports both sink and source roles.
+fn get_nonsecure() -> Option<binder::Strong<dyn IAuthGraphKeyExchange>> {
+    match binder::get_interface(AUTH_GRAPH_NONSECURE) {
+        Ok(ag) => Some(ag),
+        Err(StatusCode::NAME_NOT_FOUND) => None,
+        Err(e) => panic!("failed to get AuthGraph/nonsecure: {e:?}"),
+    }
+}
+
+/// Macro to require availability of a /nonsecure instance of AuthGraph.
+///
+/// Note that this macro triggers `return` if not found.
+macro_rules! require_nonsecure {
+    {} => {
+        match get_nonsecure() {
+            Some(v) => v,
+            None => {
+                eprintln!("Skipping test as no /nonsecure impl found");
+                return;
+            }
+        }
+    }
+}
+
+#[test]
+fn test_nonsecure_source_mainline() {
+    let mut sink = vts::test_ag_participant().expect("failed to create a local sink");
+    vts::source::test_mainline(&mut sink, require_nonsecure!());
+}
+#[test]
+fn test_nonsecure_source_corrupt_sig() {
+    let mut sink = vts::test_ag_participant().expect("failed to create a local sink");
+    vts::source::test_corrupt_sig(&mut sink, require_nonsecure!());
+}
+#[test]
+fn test_nonsecure_source_corrupt_keys() {
+    let mut sink = vts::test_ag_participant().expect("failed to create a local sink");
+    vts::source::test_corrupt_key(&mut sink, require_nonsecure!());
+}
+#[test]
+fn test_nonsecure_sink_mainline() {
+    let mut source = vts::test_ag_participant().expect("failed to create a local source");
+    vts::sink::test_mainline(&mut source, require_nonsecure!());
+}
+#[test]
+fn test_nonsecure_sink_corrupt_sig() {
+    let mut source = vts::test_ag_participant().expect("failed to create a local source");
+    vts::sink::test_corrupt_sig(&mut source, require_nonsecure!());
+}
+#[test]
+fn test_nonsecure_sink_corrupt_keys() {
+    let mut source = vts::test_ag_participant().expect("failed to create a local source");
+    vts::sink::test_corrupt_keys(&mut source, require_nonsecure!());
+}
diff --git a/security/authgraph/aidl/vts/functional/sink.rs b/security/authgraph/aidl/vts/functional/sink.rs
new file mode 100644
index 0000000..a331eef
--- /dev/null
+++ b/security/authgraph/aidl/vts/functional/sink.rs
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! VTS tests for sinks
+use super::*;
+use authgraph_core::{key, keyexchange as ke};
+
+/// Run AuthGraph tests against the provided sink, using a local test source implementation.
+pub fn test(
+    local_source: &mut ke::AuthGraphParticipant,
+    sink: binder::Strong<dyn IAuthGraphKeyExchange>,
+) {
+    test_mainline(local_source, sink.clone());
+    test_corrupt_sig(local_source, sink.clone());
+    test_corrupt_keys(local_source, sink);
+}
+
+/// Perform mainline AuthGraph key exchange with the provided sink and local implementation.
+/// Return the agreed AES keys in plaintext, together with the session ID.
+pub fn test_mainline(
+    local_source: &mut ke::AuthGraphParticipant,
+    sink: binder::Strong<dyn IAuthGraphKeyExchange>,
+) -> ([key::AesKey; 2], Vec<u8>) {
+    // Step 1: create an ephemeral ECDH key at the (local) source.
+    let source_init_info = local_source
+        .create()
+        .expect("failed to create() with local impl");
+
+    // Step 2: pass the source's ECDH public key and other session info to the (remote) sink.
+    let init_result = sink
+        .init(
+            &build_plain_pub_key(&source_init_info.ke_key.pub_key),
+            &vec_to_identity(&source_init_info.identity),
+            &source_init_info.nonce,
+            source_init_info.version,
+        )
+        .expect("failed to init() with remote impl");
+    let sink_init_info = init_result.sessionInitiationInfo;
+    let sink_pub_key = extract_plain_pub_key(&sink_init_info.key.pubKey);
+
+    let sink_info = init_result.sessionInfo;
+    assert!(!sink_info.sessionId.is_empty());
+
+    // The AuthGraph core library will verify the session ID signature, but do it here too.
+    let sink_verification_key = local_source
+        .peer_verification_key_from_identity(&sink_init_info.identity.identity)
+        .expect("failed to get peer verification from identity");
+    local_source
+        .verify_signature_on_session_id(
+            &sink_verification_key,
+            &sink_info.sessionId,
+            &sink_info.signature.signature,
+        )
+        .expect("failed verification of signed session ID");
+
+    // Step 3: pass the sink's ECDH public key and other session info to the (local) source, so it
+    // can calculate the same pair of symmetric keys.
+    let source_info = local_source
+        .finish(
+            &sink_pub_key.plainPubKey,
+            &sink_init_info.identity.identity,
+            &sink_info.signature.signature,
+            &sink_init_info.nonce,
+            sink_init_info.version,
+            source_init_info.ke_key,
+        )
+        .expect("failed to finish() with local impl");
+    assert!(!source_info.session_id.is_empty());
+
+    // The AuthGraph core library will verify the session ID signature, but do it here too.
+    let source_verification_key = key::Identity::from_slice(&source_init_info.identity)
+        .expect("invalid identity CBOR")
+        .cert_chain
+        .root_key;
+    local_source
+        .verify_signature_on_session_id(
+            &source_verification_key,
+            &source_info.session_id,
+            &source_info.session_id_signature,
+        )
+        .expect("failed verification of signed session ID");
+
+    // Both ends should agree on the session ID.
+    assert_eq!(source_info.session_id, sink_info.sessionId);
+
+    // Step 4: pass the (local) source's session ID signature back to the sink, so it can check it
+    // and update the symmetric keys so they're marked as authentication complete.
+    let _sink_arcs = sink
+        .authenticationComplete(
+            &vec_to_signature(&source_info.session_id_signature),
+            &sink_info.sharedKeys,
+        )
+        .expect("failed to authenticationComplete() with remote sink");
+    // Decrypt and return the session keys.
+    let decrypted_shared_keys = local_source
+        .decipher_shared_keys_from_arcs(&source_info.shared_keys)
+        .expect("failed to decrypt shared key arcs")
+        .try_into();
+    let decrypted_shared_keys_array = match decrypted_shared_keys {
+        Ok(array) => array,
+        Err(_) => panic!("wrong number of decrypted shared key arcs"),
+    };
+    (decrypted_shared_keys_array, sink_info.sessionId)
+}
+
+/// Perform mainline AuthGraph key exchange with the provided sink, but provide an invalid
+/// session ID signature.
+pub fn test_corrupt_sig(
+    local_source: &mut ke::AuthGraphParticipant,
+    sink: binder::Strong<dyn IAuthGraphKeyExchange>,
+) {
+    // Step 1: create an ephemeral ECDH key at the (local) source.
+    let source_init_info = local_source
+        .create()
+        .expect("failed to create() with local impl");
+
+    // Step 2: pass the source's ECDH public key and other session info to the (remote) sink.
+    let init_result = sink
+        .init(
+            &build_plain_pub_key(&source_init_info.ke_key.pub_key),
+            &vec_to_identity(&source_init_info.identity),
+            &source_init_info.nonce,
+            source_init_info.version,
+        )
+        .expect("failed to init() with remote impl");
+    let sink_init_info = init_result.sessionInitiationInfo;
+    let sink_pub_key = extract_plain_pub_key(&sink_init_info.key.pubKey);
+
+    let sink_info = init_result.sessionInfo;
+    assert!(!sink_info.sessionId.is_empty());
+
+    // Step 3: pass the sink's ECDH public key and other session info to the (local) source, so it
+    // can calculate the same pair of symmetric keys.
+    let source_info = local_source
+        .finish(
+            &sink_pub_key.plainPubKey,
+            &sink_init_info.identity.identity,
+            &sink_info.signature.signature,
+            &sink_init_info.nonce,
+            sink_init_info.version,
+            source_init_info.ke_key,
+        )
+        .expect("failed to finish() with local impl");
+    assert!(!source_info.session_id.is_empty());
+
+    // Build a corrupted version of the (local) source's session ID signature.
+    let mut corrupt_signature = source_info.session_id_signature.clone();
+    let sig_len = corrupt_signature.len();
+    corrupt_signature[sig_len - 1] ^= 0x01;
+
+    // Step 4: pass the (local) source's **invalid** session ID signature back to the sink,
+    // which should reject it.
+    let result =
+        sink.authenticationComplete(&vec_to_signature(&corrupt_signature), &sink_info.sharedKeys);
+    let err = result.expect_err("expect failure with corrupt signature");
+    assert_eq!(
+        err,
+        binder::Status::new_service_specific_error(Error::INVALID_SIGNATURE.0, None)
+    );
+}
+
+/// Perform mainline AuthGraph key exchange with the provided sink, but provide an invalid
+/// Arc for the sink's key.
+pub fn test_corrupt_keys(
+    local_source: &mut ke::AuthGraphParticipant,
+    sink: binder::Strong<dyn IAuthGraphKeyExchange>,
+) {
+    // Step 1: create an ephemeral ECDH key at the (local) source.
+    let source_init_info = local_source
+        .create()
+        .expect("failed to create() with local impl");
+
+    // Step 2: pass the source's ECDH public key and other session info to the (remote) sink.
+    let init_result = sink
+        .init(
+            &build_plain_pub_key(&source_init_info.ke_key.pub_key),
+            &vec_to_identity(&source_init_info.identity),
+            &source_init_info.nonce,
+            source_init_info.version,
+        )
+        .expect("failed to init() with remote impl");
+    let sink_init_info = init_result.sessionInitiationInfo;
+    let sink_pub_key = extract_plain_pub_key(&sink_init_info.key.pubKey);
+
+    let sink_info = init_result.sessionInfo;
+    assert!(!sink_info.sessionId.is_empty());
+
+    // Step 3: pass the sink's ECDH public key and other session info to the (local) source, so it
+    // can calculate the same pair of symmetric keys.
+    let source_info = local_source
+        .finish(
+            &sink_pub_key.plainPubKey,
+            &sink_init_info.identity.identity,
+            &sink_info.signature.signature,
+            &sink_init_info.nonce,
+            sink_init_info.version,
+            source_init_info.ke_key,
+        )
+        .expect("failed to finish() with local impl");
+    assert!(!source_info.session_id.is_empty());
+
+    // Deliberately corrupt the sink's shared key Arcs before returning them
+    let mut corrupt_keys = sink_info.sharedKeys.clone();
+    let len0 = corrupt_keys[0].arc.len();
+    let len1 = corrupt_keys[1].arc.len();
+    corrupt_keys[0].arc[len0 - 1] ^= 0x01;
+    corrupt_keys[1].arc[len1 - 1] ^= 0x01;
+
+    // Step 4: pass the (local) source's session ID signature back to the sink, but with corrupted
+    // keys, which should be rejected.
+    let result = sink.authenticationComplete(
+        &vec_to_signature(&source_info.session_id_signature),
+        &corrupt_keys,
+    );
+    let err = result.expect_err("expect failure with corrupt keys");
+    assert_eq!(
+        err,
+        binder::Status::new_service_specific_error(Error::INVALID_SHARED_KEY_ARCS.0, None)
+    );
+}
diff --git a/security/authgraph/aidl/vts/functional/source.rs b/security/authgraph/aidl/vts/functional/source.rs
new file mode 100644
index 0000000..019e1e8
--- /dev/null
+++ b/security/authgraph/aidl/vts/functional/source.rs
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! VTS tests for sources
+use super::*;
+use authgraph_core::{key, keyexchange as ke};
+
+/// Run AuthGraph tests against the provided source, using a local test sink implementation.
+pub fn test(
+    local_sink: &mut ke::AuthGraphParticipant,
+    source: binder::Strong<dyn IAuthGraphKeyExchange>,
+) {
+    test_mainline(local_sink, source.clone());
+    test_corrupt_sig(local_sink, source.clone());
+    test_corrupt_key(local_sink, source);
+}
+
+/// Perform mainline AuthGraph key exchange with the provided source.
+/// Return the agreed AES keys in plaintext, together with the session ID.
+pub fn test_mainline(
+    local_sink: &mut ke::AuthGraphParticipant,
+    source: binder::Strong<dyn IAuthGraphKeyExchange>,
+) -> ([key::AesKey; 2], Vec<u8>) {
+    // Step 1: create an ephemeral ECDH key at the (remote) source.
+    let source_init_info = source
+        .create()
+        .expect("failed to create() with remote impl");
+    assert!(source_init_info.key.pubKey.is_some());
+    assert!(source_init_info.key.arcFromPBK.is_some());
+    let source_pub_key = extract_plain_pub_key(&source_init_info.key.pubKey);
+
+    // Step 2: pass the source's ECDH public key and other session info to the (local) sink.
+    let init_result = local_sink
+        .init(
+            &source_pub_key.plainPubKey,
+            &source_init_info.identity.identity,
+            &source_init_info.nonce,
+            source_init_info.version,
+        )
+        .expect("failed to init() with local impl");
+    let sink_init_info = init_result.session_init_info;
+    let sink_pub_key = sink_init_info
+        .ke_key
+        .pub_key
+        .expect("expect pub_key to be populated");
+
+    let sink_info = init_result.session_info;
+    assert!(!sink_info.session_id.is_empty());
+
+    // The AuthGraph core library will verify the session ID signature, but do it here too.
+    let sink_verification_key = key::Identity::from_slice(&sink_init_info.identity)
+        .expect("invalid identity CBOR")
+        .cert_chain
+        .root_key;
+    local_sink
+        .verify_signature_on_session_id(
+            &sink_verification_key,
+            &sink_info.session_id,
+            &sink_info.session_id_signature,
+        )
+        .expect("failed verification of signed session ID");
+
+    // Step 3: pass the sink's ECDH public key and other session info to the (remote) source, so it
+    // can calculate the same pair of symmetric keys.
+    let source_info = source
+        .finish(
+            &PubKey::PlainKey(PlainPubKey {
+                plainPubKey: sink_pub_key,
+            }),
+            &Identity {
+                identity: sink_init_info.identity,
+            },
+            &vec_to_signature(&sink_info.session_id_signature),
+            &sink_init_info.nonce,
+            sink_init_info.version,
+            &source_init_info.key,
+        )
+        .expect("failed to finish() with remote impl");
+    assert!(!source_info.sessionId.is_empty());
+
+    // The AuthGraph core library will verify the session ID signature, but do it here too.
+    let source_verification_key = local_sink
+        .peer_verification_key_from_identity(&source_init_info.identity.identity)
+        .expect("failed to get peer verification from identity");
+    local_sink
+        .verify_signature_on_session_id(
+            &source_verification_key,
+            &source_info.sessionId,
+            &source_info.signature.signature,
+        )
+        .expect("failed verification of signed session ID");
+
+    // Both ends should agree on the session ID.
+    assert_eq!(source_info.sessionId, sink_info.session_id);
+
+    // Step 4: pass the (remote) source's session ID signature back to the sink, so it can check it
+    // and update the symmetric keys so they're marked as authentication complete.
+    let sink_arcs = local_sink
+        .authentication_complete(&source_info.signature.signature, sink_info.shared_keys)
+        .expect("failed to authenticationComplete() with local sink");
+    // Decrypt and return the session keys.
+    let decrypted_shared_keys = local_sink
+        .decipher_shared_keys_from_arcs(&sink_arcs)
+        .expect("failed to decrypt shared key arcs")
+        .try_into();
+    let decrypted_shared_keys_array = match decrypted_shared_keys {
+        Ok(array) => array,
+        Err(_) => panic!("wrong number of decrypted shared key arcs"),
+    };
+    (decrypted_shared_keys_array, source_info.sessionId)
+}
+
+/// Perform mainline AuthGraph key exchange with the provided source, but provide an invalid session
+/// ID signature.
+pub fn test_corrupt_sig(
+    local_sink: &mut ke::AuthGraphParticipant,
+    source: binder::Strong<dyn IAuthGraphKeyExchange>,
+) {
+    // Step 1: create an ephemeral ECDH key at the (remote) source.
+    let source_init_info = source
+        .create()
+        .expect("failed to create() with remote impl");
+    assert!(source_init_info.key.pubKey.is_some());
+    assert!(source_init_info.key.arcFromPBK.is_some());
+    let source_pub_key = extract_plain_pub_key(&source_init_info.key.pubKey);
+
+    // Step 2: pass the source's ECDH public key and other session info to the (local) sink.
+    let init_result = local_sink
+        .init(
+            &source_pub_key.plainPubKey,
+            &source_init_info.identity.identity,
+            &source_init_info.nonce,
+            source_init_info.version,
+        )
+        .expect("failed to init() with local impl");
+    let sink_init_info = init_result.session_init_info;
+    let sink_pub_key = sink_init_info
+        .ke_key
+        .pub_key
+        .expect("expect pub_key to be populated");
+    let sink_info = init_result.session_info;
+    assert!(!sink_info.session_id.is_empty());
+
+    // Deliberately corrupt the sink's session ID signature.
+    let mut corrupt_signature = sink_info.session_id_signature.clone();
+    let sig_len = corrupt_signature.len();
+    corrupt_signature[sig_len - 1] ^= 0x01;
+
+    // Step 3: pass the sink's ECDH public key and other session info to the (remote) source, so it
+    // can calculate the same pair of symmetric keys.
+    let result = source.finish(
+        &PubKey::PlainKey(PlainPubKey {
+            plainPubKey: sink_pub_key,
+        }),
+        &Identity {
+            identity: sink_init_info.identity,
+        },
+        &vec_to_signature(&corrupt_signature),
+        &sink_init_info.nonce,
+        sink_init_info.version,
+        &source_init_info.key,
+    );
+    let err = result.expect_err("expect failure with corrupt signature");
+    assert_eq!(
+        err,
+        binder::Status::new_service_specific_error(Error::INVALID_SIGNATURE.0, None)
+    );
+}
+
+/// Perform mainline AuthGraph key exchange with the provided source, but give it back
+/// a corrupted key.
+pub fn test_corrupt_key(
+    local_sink: &mut ke::AuthGraphParticipant,
+    source: binder::Strong<dyn IAuthGraphKeyExchange>,
+) {
+    // Step 1: create an ephemeral ECDH key at the (remote) source.
+    let source_init_info = source
+        .create()
+        .expect("failed to create() with remote impl");
+    assert!(source_init_info.key.pubKey.is_some());
+    assert!(source_init_info.key.arcFromPBK.is_some());
+    let source_pub_key = extract_plain_pub_key(&source_init_info.key.pubKey);
+
+    // Step 2: pass the source's ECDH public key and other session info to the (local) sink.
+    let init_result = local_sink
+        .init(
+            &source_pub_key.plainPubKey,
+            &source_init_info.identity.identity,
+            &source_init_info.nonce,
+            source_init_info.version,
+        )
+        .expect("failed to init() with local impl");
+    let sink_init_info = init_result.session_init_info;
+    let sink_pub_key = sink_init_info
+        .ke_key
+        .pub_key
+        .expect("expect pub_key to be populated");
+
+    let sink_info = init_result.session_info;
+    assert!(!sink_info.session_id.is_empty());
+
+    // The AuthGraph core library will verify the session ID signature, but do it here too.
+    let sink_verification_key = key::Identity::from_slice(&sink_init_info.identity)
+        .expect("invalid identity CBOR")
+        .cert_chain
+        .root_key;
+    local_sink
+        .verify_signature_on_session_id(
+            &sink_verification_key,
+            &sink_info.session_id,
+            &sink_info.session_id_signature,
+        )
+        .expect("failed verification of signed session ID");
+
+    // Deliberately corrupt the source's encrypted key.
+    let mut corrupt_key = source_init_info.key.clone();
+    match &mut corrupt_key.arcFromPBK {
+        Some(a) => {
+            let len = a.arc.len();
+            a.arc[len - 1] ^= 0x01;
+        }
+        None => panic!("no arc data"),
+    }
+
+    // Step 3: pass the sink's ECDH public key and other session info to the (remote) source, but
+    // give it back a corrupted version of its own key.
+    let result = source.finish(
+        &PubKey::PlainKey(PlainPubKey {
+            plainPubKey: sink_pub_key,
+        }),
+        &Identity {
+            identity: sink_init_info.identity,
+        },
+        &vec_to_signature(&sink_info.session_id_signature),
+        &sink_init_info.nonce,
+        sink_init_info.version,
+        &corrupt_key,
+    );
+
+    let err = result.expect_err("expect failure with corrupt key");
+    assert!(
+        err == binder::Status::new_service_specific_error(Error::INVALID_KE_KEY.0, None)
+            || err
+                == binder::Status::new_service_specific_error(
+                    Error::INVALID_PRIV_KEY_ARC_IN_KEY.0,
+                    None
+                )
+    );
+}
diff --git a/security/authgraph/default/Android.bp b/security/authgraph/default/Android.bp
index 9de3bc1..7894477 100644
--- a/security/authgraph/default/Android.bp
+++ b/security/authgraph/default/Android.bp
@@ -22,20 +22,39 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
+rust_library {
+    name: "libauthgraph_nonsecure",
+    crate_name: "authgraph_nonsecure",
+    defaults: [
+        "authgraph_use_latest_hal_aidl_rust",
+    ],
+    vendor_available: true,
+    rustlibs: [
+        "libandroid_logger",
+        "libauthgraph_boringssl",
+        "libauthgraph_core",
+        "libauthgraph_hal",
+        "libbinder_rs",
+        "liblibc",
+        "liblog_rust",
+    ],
+    srcs: ["src/lib.rs"],
+
+}
+
 rust_binary {
     name: "android.hardware.security.authgraph-service.nonsecure",
     relative_install_path: "hw",
     vendor: true,
-    init_rc: ["authgraph.rc"],
-    vintf_fragments: ["authgraph.xml"],
+    installable: false, // install com.android.hardware.security.authgraph
     defaults: [
         "authgraph_use_latest_hal_aidl_rust",
     ],
+    prefer_rlib: true,
     rustlibs: [
         "libandroid_logger",
-        "libauthgraph_core",
-        "libauthgraph_boringssl",
         "libauthgraph_hal",
+        "libauthgraph_nonsecure",
         "libbinder_rs",
         "liblibc",
         "liblog_rust",
@@ -44,3 +63,51 @@
         "src/main.rs",
     ],
 }
+
+rust_fuzz {
+    name: "android.hardware.authgraph-service.nonsecure_fuzzer",
+    rustlibs: [
+        "libauthgraph_hal",
+        "libauthgraph_nonsecure",
+        "libbinder_random_parcel_rs",
+        "libbinder_rs",
+    ],
+    srcs: ["src/fuzzer.rs"],
+    fuzz_config: {
+        cc: [
+            "drysdale@google.com",
+            "hasinitg@google.com",
+        ],
+    },
+}
+
+prebuilt_etc {
+    name: "authgraph.xml",
+    src: "authgraph.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "authgraph.rc",
+    src: "authgraph.rc",
+    installable: false,
+}
+
+apex {
+    name: "com.android.hardware.security.authgraph",
+    manifest: "apex_manifest.json",
+    file_contexts: "apex_file_contexts",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    vendor: true,
+    updatable: false,
+
+    binaries: [
+        "android.hardware.security.authgraph-service.nonsecure",
+    ],
+    prebuilts: [
+        "authgraph.rc",
+        "authgraph.xml",
+    ],
+}
diff --git a/security/authgraph/default/apex_file_contexts b/security/authgraph/default/apex_file_contexts
new file mode 100644
index 0000000..9a54613
--- /dev/null
+++ b/security/authgraph/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                          u:object_r:vendor_file:s0
+/etc(/.*)?                                      u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.security\.authgraph-service\.nonsecure  u:object_r:hal_authgraph_default_exec:s0
diff --git a/security/authgraph/default/apex_manifest.json b/security/authgraph/default/apex_manifest.json
new file mode 100644
index 0000000..0723846
--- /dev/null
+++ b/security/authgraph/default/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.security.authgraph",
+    "version": 1
+}
\ No newline at end of file
diff --git a/security/authgraph/default/authgraph.rc b/security/authgraph/default/authgraph.rc
index 0222994..2d07542 100644
--- a/security/authgraph/default/authgraph.rc
+++ b/security/authgraph/default/authgraph.rc
@@ -1,4 +1,4 @@
-service vendor.authgraph /vendor/bin/hw/android.hardware.security.authgraph-service.nonsecure
+service vendor.authgraph /apex/com.android.hardware.security.authgraph/bin/hw/android.hardware.security.authgraph-service.nonsecure
     interface aidl android.hardware.security.authgraph.IAuthGraph/nonsecure
     class hal
     user nobody
diff --git a/security/authgraph/default/src/fuzzer.rs b/security/authgraph/default/src/fuzzer.rs
new file mode 100644
index 0000000..387d72f
--- /dev/null
+++ b/security/authgraph/default/src/fuzzer.rs
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#![allow(missing_docs)]
+#![no_main]
+extern crate libfuzzer_sys;
+
+use authgraph_hal::service::AuthGraphService;
+use authgraph_nonsecure::LocalTa;
+use binder_random_parcel_rs::fuzz_service;
+use libfuzzer_sys::fuzz_target;
+
+fuzz_target!(|data: &[u8]| {
+    let local_ta = LocalTa::new().expect("Failed to create an AuthGraph local TA.");
+    let service = AuthGraphService::new_as_binder(local_ta);
+    fuzz_service(&mut service.as_binder(), data);
+});
diff --git a/security/authgraph/default/src/lib.rs b/security/authgraph/default/src/lib.rs
new file mode 100644
index 0000000..1d6ffb3
--- /dev/null
+++ b/security/authgraph/default/src/lib.rs
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Common functionality for non-secure/testing instance of AuthGraph.
+
+use authgraph_boringssl as boring;
+use authgraph_core::{
+    error, keyexchange,
+    ta::{AuthGraphTa, Role},
+};
+use authgraph_hal::channel::SerializedChannel;
+use log::error;
+use std::cell::RefCell;
+use std::rc::Rc;
+use std::sync::{mpsc, Mutex};
+
+/// Implementation of the AuthGraph TA that runs locally in-process (and which is therefore
+/// insecure).
+pub struct LocalTa {
+    channels: Mutex<Channels>,
+}
+
+struct Channels {
+    in_tx: mpsc::Sender<Vec<u8>>,
+    out_rx: mpsc::Receiver<Vec<u8>>,
+}
+
+impl LocalTa {
+    /// Create a new instance.
+    pub fn new() -> Result<Self, error::Error> {
+        // Create a pair of channels to communicate with the TA thread.
+        let (in_tx, in_rx) = mpsc::channel();
+        let (out_tx, out_rx) = mpsc::channel();
+
+        // The TA code expects to run single threaded, so spawn a thread to run it in.
+        std::thread::spawn(move || {
+            let mut ta = AuthGraphTa::new(
+                keyexchange::AuthGraphParticipant::new(
+                    boring::crypto_trait_impls(),
+                    Rc::new(RefCell::new(boring::test_device::AgDevice::default())),
+                    keyexchange::MAX_OPENED_SESSIONS,
+                )
+                .expect("failed to create AG participant"),
+                Role::Both,
+            );
+            // Loop forever processing request messages.
+            loop {
+                let req_data: Vec<u8> = match in_rx.recv() {
+                    Ok(data) => data,
+                    Err(_) => {
+                        error!("local TA failed to receive request!");
+                        break;
+                    }
+                };
+                let rsp_data = ta.process(&req_data);
+                match out_tx.send(rsp_data) {
+                    Ok(_) => {}
+                    Err(_) => {
+                        error!("local TA failed to send out response");
+                        break;
+                    }
+                }
+            }
+            error!("local TA terminating!");
+        });
+        Ok(Self {
+            channels: Mutex::new(Channels { in_tx, out_rx }),
+        })
+    }
+}
+
+impl SerializedChannel for LocalTa {
+    const MAX_SIZE: usize = usize::MAX;
+
+    fn execute(&self, req_data: &[u8]) -> binder::Result<Vec<u8>> {
+        // Serialize across both request and response.
+        let channels = self.channels.lock().unwrap();
+        channels
+            .in_tx
+            .send(req_data.to_vec())
+            .expect("failed to send in request");
+        Ok(channels.out_rx.recv().expect("failed to receive response"))
+    }
+}
diff --git a/security/authgraph/default/src/main.rs b/security/authgraph/default/src/main.rs
index 2112e58..ced7567 100644
--- a/security/authgraph/default/src/main.rs
+++ b/security/authgraph/default/src/main.rs
@@ -22,18 +22,9 @@
 //! expose an entrypoint that allowed retrieval of the specific IAuthGraphKeyExchange instance that
 //! is correlated with the component).
 
-use android_hardware_security_authgraph::aidl::android::hardware::security::authgraph::{
-    Arc::Arc, IAuthGraphKeyExchange::BnAuthGraphKeyExchange,
-    IAuthGraphKeyExchange::IAuthGraphKeyExchange, Identity::Identity, KeInitResult::KeInitResult,
-    Key::Key, PubKey::PubKey, SessionIdSignature::SessionIdSignature, SessionInfo::SessionInfo,
-    SessionInitiationInfo::SessionInitiationInfo,
-};
-use authgraph_boringssl as boring;
-use authgraph_core::{key::MillisecondsSinceEpoch, keyexchange as ke, traits};
-use authgraph_hal::{err_to_binder, Innto, TryInnto};
+use authgraph_hal::service;
+use authgraph_nonsecure::LocalTa;
 use log::{error, info};
-use std::ffi::CString;
-use std::sync::Mutex;
 
 static SERVICE_NAME: &str = "android.hardware.security.authgraph.IAuthGraphKeyExchange";
 static SERVICE_INSTANCE: &str = "nonsecure";
@@ -73,7 +64,8 @@
     binder::ProcessState::start_thread_pool();
 
     // Register the service
-    let service = AuthGraphService::new_as_binder();
+    let local_ta = LocalTa::new().map_err(|e| format!("Failed to create the TA because: {e:?}"))?;
+    let service = service::AuthGraphService::new_as_binder(local_ta);
     let service_name = format!("{}/{}", SERVICE_NAME, SERVICE_INSTANCE);
     binder::add_service(&service_name, service.as_binder()).map_err(|e| {
         format!(
@@ -87,141 +79,3 @@
     info!("AuthGraph HAL service is terminating."); // should not reach here
     Ok(())
 }
-
-/// Non-secure implementation of the AuthGraph key exchange service.
-struct AuthGraphService {
-    imp: Mutex<traits::TraitImpl>,
-}
-
-impl AuthGraphService {
-    /// Create a new instance.
-    fn new() -> Self {
-        Self {
-            imp: Mutex::new(traits::TraitImpl {
-                aes_gcm: Box::new(boring::BoringAes),
-                ecdh: Box::new(boring::BoringEcDh),
-                ecdsa: Box::new(boring::BoringEcDsa),
-                hmac: Box::new(boring::BoringHmac),
-                hkdf: Box::new(boring::BoringHkdf),
-                sha256: Box::new(boring::BoringSha256),
-                rng: Box::new(boring::BoringRng),
-                device: Box::<boring::test_device::AgDevice>::default(),
-                clock: Some(Box::new(StdClock)),
-            }),
-        }
-    }
-
-    /// Create a new instance wrapped in a proxy object.
-    pub fn new_as_binder() -> binder::Strong<dyn IAuthGraphKeyExchange> {
-        BnAuthGraphKeyExchange::new_binder(Self::new(), binder::BinderFeatures::default())
-    }
-}
-
-impl binder::Interface for AuthGraphService {}
-
-/// Extract (and require) an unsigned public key as bytes from a [`PubKey`].
-fn unsigned_pub_key(pub_key: &PubKey) -> binder::Result<&[u8]> {
-    match pub_key {
-        PubKey::PlainKey(key) => Ok(&key.plainPubKey),
-        PubKey::SignedKey(_) => Err(binder::Status::new_exception(
-            binder::ExceptionCode::ILLEGAL_ARGUMENT,
-            Some(&CString::new("expected unsigned public key").unwrap()),
-        )),
-    }
-}
-
-/// This nonsecure implementation of the AuthGraph HAL interface directly calls the AuthGraph
-/// reference implementation library code; a real implementation requires the AuthGraph
-/// code to run in a secure environment, not within Android.
-impl IAuthGraphKeyExchange for AuthGraphService {
-    fn create(&self) -> binder::Result<SessionInitiationInfo> {
-        info!("create()");
-        let mut imp = self.imp.lock().unwrap();
-        let info = ke::create(&mut *imp).map_err(err_to_binder)?;
-        Ok(info.innto())
-    }
-    fn init(
-        &self,
-        peer_pub_key: &PubKey,
-        peer_id: &Identity,
-        peer_nonce: &[u8],
-        peer_version: i32,
-    ) -> binder::Result<KeInitResult> {
-        info!("init(v={peer_version})");
-        let mut imp = self.imp.lock().unwrap();
-        let peer_pub_key = unsigned_pub_key(peer_pub_key)?;
-        let result = ke::init(
-            &mut *imp,
-            peer_pub_key,
-            &peer_id.identity,
-            &peer_nonce,
-            peer_version,
-        )
-        .map_err(err_to_binder)?;
-        Ok(result.innto())
-    }
-
-    fn finish(
-        &self,
-        peer_pub_key: &PubKey,
-        peer_id: &Identity,
-        peer_signature: &SessionIdSignature,
-        peer_nonce: &[u8],
-        peer_version: i32,
-        own_key: &Key,
-    ) -> binder::Result<SessionInfo> {
-        info!("finish(v={peer_version})");
-        let mut imp = self.imp.lock().unwrap();
-        let peer_pub_key = unsigned_pub_key(peer_pub_key)?;
-        let own_key: Key = own_key.clone();
-        let own_key: authgraph_core::key::Key = own_key.try_innto()?;
-        let session_info = ke::finish(
-            &mut *imp,
-            peer_pub_key,
-            &peer_id.identity,
-            &peer_signature.signature,
-            &peer_nonce,
-            peer_version,
-            own_key,
-        )
-        .map_err(err_to_binder)?;
-        Ok(session_info.innto())
-    }
-
-    fn authenticationComplete(
-        &self,
-        peer_signature: &SessionIdSignature,
-        shared_keys: &[Arc; 2],
-    ) -> binder::Result<[Arc; 2]> {
-        info!("authComplete()");
-        let mut imp = self.imp.lock().unwrap();
-        let shared_keys = [shared_keys[0].arc.clone(), shared_keys[1].arc.clone()];
-        let arcs = ke::authentication_complete(&mut *imp, &peer_signature.signature, shared_keys)
-            .map_err(err_to_binder)?;
-        Ok(arcs.map(|arc| Arc { arc }))
-    }
-}
-
-/// Monotonic clock.
-#[derive(Default)]
-pub struct StdClock;
-
-impl traits::MonotonicClock for StdClock {
-    fn now(&self) -> authgraph_core::key::MillisecondsSinceEpoch {
-        let mut time = libc::timespec {
-            tv_sec: 0,  // libc::time_t
-            tv_nsec: 0, // libc::c_long
-        };
-        let rc =
-        // Safety: `time` is a valid structure.
-            unsafe { libc::clock_gettime(libc::CLOCK_BOOTTIME, &mut time as *mut libc::timespec) };
-        if rc < 0 {
-            log::warn!("failed to get time!");
-            return MillisecondsSinceEpoch(0);
-        }
-        // The types in `libc::timespec` may be different on different architectures,
-        // so allow conversion to `i64`.
-        #[allow(clippy::unnecessary_cast)]
-        MillisecondsSinceEpoch((time.tv_sec as i64 * 1000) + (time.tv_nsec as i64 / 1000 / 1000))
-    }
-}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
index aa7bf28..be29f59 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
@@ -974,8 +974,8 @@
      * time in milliseconds.  This value is used when generating attestation or self signed
      * certificates.  ErrorCode::MISSING_NOT_BEFORE must be returned if this tag is not provided if
      * this tag is not provided to generateKey or importKey.  For importWrappedKey, there is no way
-     * to specify the value of this tag for the wrapped key, so a value of 0 must be used for
-     * certificate generation.
+     * to specify the value of this tag for a wrapped asymmetric key, so a value of 0 is suggested
+     * for certificate generation.
      */
     CERTIFICATE_NOT_BEFORE = TagType.DATE | 1008,
 
@@ -983,8 +983,9 @@
      * Tag::CERTIFICATE_NOT_AFTER the end of the validity of the certificate in UNIX epoch time in
      * milliseconds.  This value is used when generating attestation or self signed certificates.
      * ErrorCode::MISSING_NOT_AFTER must be returned if this tag is not provided to generateKey or
-     * importKey.  For importWrappedKey, there is no way to specify the value of this tag for the
-     * wrapped key, so a value of 253402300799000 is used for certificate generation.
+     * importKey.  For importWrappedKey, there is no way to specify the value of this tag for a
+     * wrapped asymmetric key, so a value of 253402300799000 is suggested for certificate
+     * generation.
      */
     CERTIFICATE_NOT_AFTER = TagType.DATE | 1009,
 
diff --git a/security/keymint/aidl/vts/functional/KeyBlobUpgradeTest.cpp b/security/keymint/aidl/vts/functional/KeyBlobUpgradeTest.cpp
index 7ccd246..c2509b8 100644
--- a/security/keymint/aidl/vts/functional/KeyBlobUpgradeTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyBlobUpgradeTest.cpp
@@ -258,7 +258,8 @@
 
                 if (upgraded_keyblob.empty()) {
                     std::cerr << "Keyblob '" << name << "' did not require upgrade\n";
-                    EXPECT_TRUE(!expectUpgrade) << "Keyblob '" << name << "' unexpectedly upgraded";
+                    EXPECT_FALSE(expectUpgrade)
+                            << "Keyblob '" << name << "' unexpectedly left as-is";
                 } else {
                     // Ensure the old format keyblob is deleted (so any secure deletion data is
                     // cleaned up).
@@ -275,8 +276,7 @@
                     save_keyblob(subdir, name, upgraded_keyblob, key_characteristics);
                     // Cert file is left unchanged.
                     std::cerr << "Keyblob '" << name << "' upgraded\n";
-                    EXPECT_TRUE(expectUpgrade)
-                            << "Keyblob '" << name << "' unexpectedly left as-is";
+                    EXPECT_TRUE(expectUpgrade) << "Keyblob '" << name << "' unexpectedly upgraded";
                 }
             }
         }
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 822770d..d3f6ae3 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -1792,6 +1792,12 @@
     std::string empty_boot_key(32, '\0');
     std::string verified_boot_key_str((const char*)verified_boot_key.data(),
                                       verified_boot_key.size());
+    if (get_vsr_api_level() >= __ANDROID_API_V__) {
+        // The attestation should contain the SHA-256 hash of the verified boot
+        // key.  However, this was not checked for earlier versions of the KeyMint
+        // HAL so only be strict for VSR-V and above.
+        EXPECT_LE(verified_boot_key.size(), 32);
+    }
     EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0);
     if (!strcmp(property_value, "green")) {
         EXPECT_EQ(verified_boot_state, VerifiedBoot::VERIFIED);
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index a8f17dd..a2e20dc 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -4123,13 +4123,13 @@
  * when the EC_CURVE is not explicitly specified.
  */
 TEST_P(ImportKeyTest, EcdsaSuccessCurveNotSpecified) {
-    if (AidlVersion() < 4) {
+    if (get_vsr_api_level() < __ANDROID_API_V__) {
         /*
-         * The KeyMint spec before V4 was not clear as to whether EC_CURVE was optional on import of
-         * EC keys. However, this was not checked at the time so we can only be strict about
-         * checking this for implementations of KeyMint version 4 and above.
+         * The KeyMint spec was previously not clear as to whether EC_CURVE was optional on import
+         * of EC keys. However, this was not checked at the time so we can only be strict about
+         * checking this for implementations at VSR-V or later.
          */
-        GTEST_SKIP() << "Skipping EC_CURVE on import only strict since KeyMint v4";
+        GTEST_SKIP() << "Skipping EC_CURVE on import only strict >= VSR-V";
     }
 
     ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
@@ -8796,10 +8796,11 @@
 
 }  // namespace aidl::android::hardware::security::keymint::test
 
+using aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase;
+
 int main(int argc, char** argv) {
     std::cout << "Testing ";
-    auto halInstances =
-            aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase::build_params();
+    auto halInstances = KeyMintAidlTestBase::build_params();
     std::cout << "HAL instances:\n";
     for (auto& entry : halInstances) {
         std::cout << "    " << entry << '\n';
@@ -8809,12 +8810,10 @@
     for (int i = 1; i < argc; ++i) {
         if (argv[i][0] == '-') {
             if (std::string(argv[i]) == "--arm_deleteAllKeys") {
-                aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase::
-                        arm_deleteAllKeys = true;
+                KeyMintAidlTestBase::arm_deleteAllKeys = true;
             }
             if (std::string(argv[i]) == "--dump_attestations") {
-                aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase::
-                        dump_Attestations = true;
+                KeyMintAidlTestBase::dump_Attestations = true;
             } else {
                 std::cout << "NOT dumping attestations" << std::endl;
             }
@@ -8829,8 +8828,7 @@
                     std::cerr << "Missing argument for --keyblob_dir\n";
                     return 1;
                 }
-                aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase::keyblob_dir =
-                        std::string(argv[i + 1]);
+                KeyMintAidlTestBase::keyblob_dir = std::string(argv[i + 1]);
                 ++i;
             }
             if (std::string(argv[i]) == "--expect_upgrade") {
@@ -8839,11 +8837,17 @@
                     return 1;
                 }
                 std::string arg = argv[i + 1];
-                aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase::
-                        expect_upgrade =
-                                arg == "yes"
-                                        ? true
-                                        : (arg == "no" ? false : std::optional<bool>(std::nullopt));
+                KeyMintAidlTestBase::expect_upgrade =
+                        arg == "yes" ? true
+                                     : (arg == "no" ? false : std::optional<bool>(std::nullopt));
+                if (KeyMintAidlTestBase::expect_upgrade.has_value()) {
+                    std::cout << "expect_upgrade = "
+                              << (KeyMintAidlTestBase::expect_upgrade.value() ? "true" : "false")
+                              << std::endl;
+                } else {
+                    std::cerr << "Error! Option --expect_upgrade " << arg << " unrecognized"
+                              << std::endl;
+                }
                 ++i;
             }
         }
diff --git a/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
index c9a156d..9f7322a 100644
--- a/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
+++ b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
@@ -114,6 +114,12 @@
         const auto& vbKey = rot->asArray()->get(pos++);
         ASSERT_TRUE(vbKey);
         ASSERT_TRUE(vbKey->asBstr());
+        if (get_vsr_api_level() >= __ANDROID_API_V__) {
+            // The attestation should contain the SHA-256 hash of the verified boot
+            // key.  However, this not was checked for earlier versions of the KeyMint
+            // HAL so only be strict for VSR-V and above.
+            ASSERT_LE(vbKey->asBstr()->value().size(), 32);
+        }
 
         const auto& deviceLocked = rot->asArray()->get(pos++);
         ASSERT_TRUE(deviceLocked);
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 79189a1..b8c69eb 100644
--- a/security/keymint/support/include/remote_prov/remote_prov_utils.h
+++ b/security/keymint/support/include/remote_prov/remote_prov_utils.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <memory>
+#include <string>
 #include <vector>
 #include "aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h"
 
@@ -129,8 +130,8 @@
  *     "name": <string>
  *   }
  */
-JsonOutput jsonEncodeCsrWithBuild(const std::string instance_name,
-                                  const cppbor::Array& csr);
+JsonOutput jsonEncodeCsrWithBuild(const std::string& instance_name, const cppbor::Array& csr,
+                                  const std::string& serialno_prop);
 
 /**
  * Parses a DeviceInfo structure from the given CBOR data. The parsed data is then validated to
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
index 34f7ce4..a830041 100644
--- a/security/keymint/support/remote_prov_utils.cpp
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -337,9 +337,9 @@
     return result;
 }
 
-JsonOutput jsonEncodeCsrWithBuild(const std::string instance_name, const cppbor::Array& csr) {
+JsonOutput jsonEncodeCsrWithBuild(const std::string& instance_name, const cppbor::Array& csr,
+                                  const std::string& serialno_prop) {
     const std::string kFingerprintProp = "ro.build.fingerprint";
-    const std::string kSerialNoProp = "ro.serialno";
 
     if (!::android::base::WaitForPropertyCreation(kFingerprintProp)) {
         return JsonOutput::Error("Unable to read build fingerprint");
@@ -364,7 +364,7 @@
     Json::Value json(Json::objectValue);
     json["name"] = instance_name;
     json["build_fingerprint"] = ::android::base::GetProperty(kFingerprintProp, /*default=*/"");
-    json["serialno"] = ::android::base::GetProperty(kSerialNoProp, /*default=*/"");
+    json["serialno"] = ::android::base::GetProperty(serialno_prop, /*default=*/"");
     json["csr"] = base64.data();  // Boring writes a NUL-terminated c-string
 
     Json::StreamWriterBuilder factory;
@@ -520,6 +520,15 @@
                    std::to_string(info.versionNumber) + ").";
         }
     }
+    // Bypasses the device info validation since the device info in AVF is currently
+    // empty. Check b/299256925 for more information.
+    //
+    // TODO(b/300911665): This check is temporary and will be replaced once the markers
+    // on the DICE chain become available. We need to determine if the CSR is from the
+    // RKP VM using the markers on the DICE chain.
+    if (info.uniqueId == "AVF Remote Provisioning 1") {
+        return std::move(parsed);
+    }
 
     std::string error;
     std::string tmp;
@@ -969,7 +978,7 @@
             return hwtrust::DiceChain::Kind::kVsr13;
         case __ANDROID_API_U__:
             return hwtrust::DiceChain::Kind::kVsr14;
-        case __ANDROID_API_V__:
+        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);
diff --git a/security/keymint/support/remote_prov_utils_test.cpp b/security/keymint/support/remote_prov_utils_test.cpp
index eaaba45..630f7bb 100644
--- a/security/keymint/support/remote_prov_utils_test.cpp
+++ b/security/keymint/support/remote_prov_utils_test.cpp
@@ -182,10 +182,11 @@
 }
 
 TEST(RemoteProvUtilsTest, JsonEncodeCsr) {
+    const std::string kSerialNoProp = "ro.serialno";
     cppbor::Array array;
     array.add(1);
 
-    auto [json, error] = jsonEncodeCsrWithBuild(std::string("test"), array);
+    auto [json, error] = jsonEncodeCsrWithBuild(std::string("test"), array, kSerialNoProp);
 
     ASSERT_TRUE(error.empty()) << error;
 
diff --git a/security/rkp/README.md b/security/rkp/README.md
index 15ea817..2d00b83 100644
--- a/security/rkp/README.md
+++ b/security/rkp/README.md
@@ -190,3 +190,30 @@
 *   [RpcHardwareInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl)
 *   [DeviceInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl)
 
+### Support for Android Virtualization Framework
+
+The Android Virtualization Framwork (AVF) relies on RKP to provision keys for VMs. A
+privileged vm, the RKP VM, is reponsible for generating and managing the keys for client
+VMs that run virtualized workloads. See the following for more background information on the
+RKP VM:
+*    [rkp-vm](https://android.googlesource.com/platform/packages/modules/Virtualization/+/main/service_vm/README.md#rkp-vm-remote-key-provisioning-virtual-machine)
+*    [rkp-service](https://source.android.com/docs/core/ota/modular-system/remote-key-provisioning#stack-architecture)
+
+It is important to distinquish the RKP VM from other components, such as KeyMint. An
+[RKP VM marker](https://pigweed.googlesource.com/open-dice/+/HEAD/docs/android.md#configuration-descriptor)
+(key `-70006) is used for this purpose. The existence or absence of this marker is used to
+identify the type of component decribed by a given DICE chain.
+
+The following describes which certificate types may be request based on the RKP VM marker:
+1. "rkp-vm": If a DICE chain has zero or more certificates without the RKP VM
+   marker followed by one or more certificates with the marker, then that chain
+   describes an RKP VM. If there are further certificates without the RKP VM
+   marker, then the chain does not describe an RKP VM.
+
+   Implementations must include the first RKP VM marker as early as possible
+   after the point of divergence between TEE and non-TEE components in the DICE
+   chain, prior to loading the Android Bootloader (ABL).
+2. "widevine" or "keymint": If there are no certificates with the RKP VM
+   marker then it describes a TEE component.
+3. None: Any component described by a DICE chain that does not match the above
+   two categories.
diff --git a/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequestV2.cddl b/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequestV2.cddl
index 61404d4..3c43238 100644
--- a/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequestV2.cddl
+++ b/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequestV2.cddl
@@ -14,8 +14,9 @@
 ; be extended without requiring a version bump of the HAL. Custom certificate types may
 ; be used, but the provisioning server may reject the request for an unknown certificate
 ; type. The currently defined certificate types are:
-;  - "widevine"
-;  - "keymint"
+;  * "widevine" -- Widevine content protection system
+;  * "keymint"  -- KeyMint HAL
+;  * "rkp-vm"   -- See "Support for Android Virtualization Framework" in the README.md file.
 CertificateType = tstr
 
 KeysToSign = [ * PublicKey ]   ; Please see PublicKey.cddl for the PublicKey definition.
@@ -112,6 +113,7 @@
     ? -70003 : int / tstr,                   ; Component version
     ? -70004 : null,                         ; Resettable
     ? -70005 : uint,                         ; Security version
+    ? -70006 : null,                         ; RKP VM marker
 }
 
 ; Each entry in the DICE chain is a DiceChainEntryPayload signed by the key from the previous
diff --git a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index 62463eb..68b966c 100644
--- a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -55,6 +55,8 @@
 
 constexpr uint8_t MIN_CHALLENGE_SIZE = 0;
 constexpr uint8_t MAX_CHALLENGE_SIZE = 64;
+const string RKP_VM_INSTANCE_NAME =
+        "android.hardware.security.keymint.IRemotelyProvisionedComponent/avf";
 
 #define INSTANTIATE_REM_PROV_AIDL_TEST(name)                                         \
     GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(name);                             \
@@ -181,7 +183,12 @@
             provisionable_ = IRemotelyProvisionedComponent::fromBinder(binder);
         }
         ASSERT_NE(provisionable_, nullptr);
-        ASSERT_TRUE(provisionable_->getHardwareInfo(&rpcHardwareInfo).isOk());
+        auto status = provisionable_->getHardwareInfo(&rpcHardwareInfo);
+        if (GetParam() == RKP_VM_INSTANCE_NAME &&
+            status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+            GTEST_SKIP() << "The RKP VM is not supported on this system.";
+        }
+        ASSERT_TRUE(status.isOk());
     }
 
     static vector<string> build_params() {
@@ -207,7 +214,11 @@
         ASSERT_NE(rpc, nullptr);
 
         RpcHardwareInfo hwInfo;
-        ASSERT_TRUE(rpc->getHardwareInfo(&hwInfo).isOk());
+        auto status = rpc->getHardwareInfo(&hwInfo);
+        if (hal == RKP_VM_INSTANCE_NAME && status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+            GTEST_SKIP() << "The RKP VM is not supported on this system.";
+        }
+        ASSERT_TRUE(status.isOk());
 
         if (hwInfo.versionNumber >= VERSION_WITH_UNIQUE_ID_SUPPORT) {
             ASSERT_TRUE(hwInfo.uniqueId);
@@ -391,7 +402,7 @@
         for (auto& key : keysToSign_) {
             bytevec privateKeyBlob;
             auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &key, &privateKeyBlob);
-            ASSERT_TRUE(status.isOk()) << status.getMessage();
+            ASSERT_TRUE(status.isOk()) << status.getDescription();
 
             vector<uint8_t> payload_value;
             check_maced_pubkey(key, testMode, &payload_value);
@@ -436,7 +447,7 @@
         auto status = provisionable_->generateCertificateRequest(
                 testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
                 &protectedData, &keysToSignMac);
-        ASSERT_TRUE(status.isOk()) << status.getMessage();
+        ASSERT_TRUE(status.isOk()) << status.getDescription();
 
         auto result = verifyProductionProtectedData(
                 deviceInfo, cppbor::Array(), keysToSignMac, protectedData, testEekChain_, eekId_,
@@ -461,7 +472,7 @@
     auto status = provisionable_->generateCertificateRequest(
             testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
             &protectedData, &keysToSignMac);
-    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    ASSERT_TRUE(status.isOk()) << status.getDescription();
 
     auto firstBcc = verifyProductionProtectedData(
             deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData, testEekChain_,
@@ -471,7 +482,7 @@
     status = provisionable_->generateCertificateRequest(
             testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
             &protectedData, &keysToSignMac);
-    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    ASSERT_TRUE(status.isOk()) << status.getDescription();
 
     auto secondBcc = verifyProductionProtectedData(
             deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData, testEekChain_,
@@ -521,7 +532,7 @@
         auto status = provisionable_->generateCertificateRequest(
                 testMode, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo, &protectedData,
                 &keysToSignMac);
-        ASSERT_TRUE(status.isOk()) << status.getMessage();
+        ASSERT_TRUE(status.isOk()) << status.getDescription();
 
         auto result = verifyProductionProtectedData(
                 deviceInfo, cborKeysToSign_, keysToSignMac, protectedData, testEekChain_, eekId_,
@@ -565,7 +576,7 @@
     auto status = provisionable_->generateCertificateRequest(
             testMode, {keyWithCorruptMac}, testEekChain_.chain, challenge_, &deviceInfo,
             &protectedData, &keysToSignMac);
-    ASSERT_FALSE(status.isOk()) << status.getMessage();
+    ASSERT_FALSE(status.isOk()) << status.getDescription();
     EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
 }
 
@@ -585,7 +596,7 @@
     auto status = provisionable_->generateCertificateRequest(
             testMode, {keyWithCorruptMac}, getProdEekChain(rpcHardwareInfo.supportedEekCurve),
             challenge_, &deviceInfo, &protectedData, &keysToSignMac);
-    ASSERT_FALSE(status.isOk()) << status.getMessage();
+    ASSERT_FALSE(status.isOk()) << status.getDescription();
     EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
 }
 
@@ -711,7 +722,7 @@
         auto challenge = randomBytes(size);
         auto status =
                 provisionable_->generateCertificateRequestV2({} /* keysToSign */, challenge, &csr);
-        ASSERT_TRUE(status.isOk()) << status.getMessage();
+        ASSERT_TRUE(status.isOk()) << status.getDescription();
 
         auto result = verifyProductionCsr(cppbor::Array(), csr, provisionable_.get(), challenge);
         ASSERT_TRUE(result) << result.message();
@@ -732,7 +743,7 @@
         SCOPED_TRACE(testing::Message() << "challenge[" << size << "]");
         auto challenge = randomBytes(size);
         auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge, &csr);
-        ASSERT_TRUE(status.isOk()) << status.getMessage();
+        ASSERT_TRUE(status.isOk()) << status.getDescription();
 
         auto result = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge);
         ASSERT_TRUE(result) << result.message();
@@ -747,7 +758,7 @@
 
     auto status = provisionable_->generateCertificateRequestV2(
             /* keysToSign */ {}, randomBytes(MAX_CHALLENGE_SIZE + 1), &csr);
-    EXPECT_FALSE(status.isOk()) << status.getMessage();
+    EXPECT_FALSE(status.isOk()) << status.getDescription();
     EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_FAILED);
 }
 
@@ -762,13 +773,13 @@
     bytevec csr;
 
     auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
-    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    ASSERT_TRUE(status.isOk()) << status.getDescription();
 
     auto firstCsr = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
     ASSERT_TRUE(firstCsr) << firstCsr.message();
 
     status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
-    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    ASSERT_TRUE(status.isOk()) << status.getDescription();
 
     auto secondCsr = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
     ASSERT_TRUE(secondCsr) << secondCsr.message();
@@ -786,7 +797,7 @@
     bytevec csr;
 
     auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
-    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    ASSERT_TRUE(status.isOk()) << status.getDescription();
 
     auto result = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
     ASSERT_TRUE(result) << result.message();
@@ -804,7 +815,7 @@
     bytevec csr;
     auto status =
             provisionable_->generateCertificateRequestV2({keyWithCorruptMac}, challenge_, &csr);
-    ASSERT_FALSE(status.isOk()) << status.getMessage();
+    ASSERT_FALSE(status.isOk()) << status.getDescription();
     EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
 }
 
@@ -818,7 +829,7 @@
     auto status = provisionable_->generateCertificateRequest(
             false /* testMode */, {} /* keysToSign */, {} /* EEK chain */, challenge_, &deviceInfo,
             &protectedData, &keysToSignMac);
-    ASSERT_FALSE(status.isOk()) << status.getMessage();
+    ASSERT_FALSE(status.isOk()) << status.getDescription();
     EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_REMOVED);
 }
 
@@ -832,7 +843,7 @@
     auto status = provisionable_->generateCertificateRequest(
             true /* testMode */, {} /* keysToSign */, {} /* EEK chain */, challenge_, &deviceInfo,
             &protectedData, &keysToSignMac);
-    ASSERT_FALSE(status.isOk()) << status.getMessage();
+    ASSERT_FALSE(status.isOk()) << status.getDescription();
     EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_REMOVED);
 }
 
@@ -916,7 +927,7 @@
     bytevec csr;
     irpcStatus =
             provisionable_->generateCertificateRequestV2({} /* keysToSign */, challenge_, &csr);
-    ASSERT_TRUE(irpcStatus.isOk()) << irpcStatus.getMessage();
+    ASSERT_TRUE(irpcStatus.isOk()) << irpcStatus.getDescription();
 
     auto result = verifyProductionCsr(cppbor::Array(), csr, provisionable_.get(), challenge_);
     ASSERT_TRUE(result) << result.message();
diff --git a/security/secretkeeper/OWNERS b/security/secretkeeper/OWNERS
new file mode 100644
index 0000000..acf4c6c
--- /dev/null
+++ b/security/secretkeeper/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 867125
+
+alanstokes@google.com
+drysdale@google.com
+hasinitg@google.com
+shikhapanwar@google.com
diff --git a/security/secretkeeper/aidl/Android.bp b/security/secretkeeper/aidl/Android.bp
new file mode 100644
index 0000000..ac923ca
--- /dev/null
+++ b/security/secretkeeper/aidl/Android.bp
@@ -0,0 +1,84 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+aidl_interface {
+    name: "android.hardware.security.secretkeeper",
+    vendor_available: true,
+    srcs: ["android/hardware/security/secretkeeper/*.aidl"],
+    imports: [
+        "android.hardware.security.authgraph-V1",
+    ],
+    stability: "vintf",
+    frozen: false,
+    backend: {
+        java: {
+            enabled: false,
+        },
+        ndk: {
+            enabled: true,
+        },
+        rust: {
+            enabled: true,
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.virt",
+            ],
+        },
+    },
+}
+
+// cc_defaults that includes the latest Secretkeeper AIDL library.
+// Modules that depend on Secretkeeper directly can include this cc_defaults to avoid
+// managing dependency versions explicitly.
+cc_defaults {
+    name: "secretkeeper_use_latest_hal_aidl_ndk_static",
+    static_libs: [
+        "android.hardware.security.secretkeeper-V1-ndk",
+    ],
+}
+
+cc_defaults {
+    name: "secretkeeper_use_latest_hal_aidl_ndk_shared",
+    shared_libs: [
+        "android.hardware.security.secretkeeper-V1-ndk",
+    ],
+}
+
+cc_defaults {
+    name: "secretkeeper_use_latest_hal_aidl_cpp_static",
+    static_libs: [
+        "android.hardware.security.secretkeeper-V1-cpp",
+    ],
+}
+
+cc_defaults {
+    name: "secretkeeper_use_latest_hal_aidl_cpp_shared",
+    shared_libs: [
+        "android.hardware.security.secretkeeper-V1-cpp",
+    ],
+}
+
+// A rust_defaults that includes the latest Secretkeeper AIDL library.
+// Modules that depend on Secretkeeper directly can include this rust_defaults to avoid
+// managing dependency versions explicitly.
+rust_defaults {
+    name: "secretkeeper_use_latest_hal_aidl_rust",
+    rustlibs: [
+        "android.hardware.security.secretkeeper-V1-rust",
+    ],
+}
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ISecretkeeper.aidl b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ISecretkeeper.aidl
new file mode 100644
index 0000000..8ce37cd
--- /dev/null
+++ b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ISecretkeeper.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.security.secretkeeper;
+@VintfStability
+interface ISecretkeeper {
+  android.hardware.security.authgraph.IAuthGraphKeyExchange getAuthGraphKe();
+  byte[] processSecretManagementRequest(in byte[] request);
+  void deleteIds(in android.hardware.security.secretkeeper.SecretId[] ids);
+  void deleteAll();
+  const int ERROR_UNKNOWN_KEY_ID = 1;
+  const int ERROR_INTERNAL_ERROR = 2;
+  const int ERROR_REQUEST_MALFORMED = 3;
+}
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/SecretId.aidl b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/SecretId.aidl
new file mode 100644
index 0000000..9887066
--- /dev/null
+++ b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/SecretId.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.security.secretkeeper;
+/* @hide */
+@VintfStability
+parcelable SecretId {
+  byte[64] id;
+}
diff --git a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl
new file mode 100644
index 0000000..b07dba8
--- /dev/null
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.secretkeeper;
+
+import android.hardware.security.authgraph.IAuthGraphKeyExchange;
+import android.hardware.security.secretkeeper.SecretId;
+
+@VintfStability
+/**
+ * Secretkeeper service definition.
+ *
+ * An ISecretkeeper instance provides secure storage of secrets on behalf of other components in
+ * Android, in particular for protected virtual machine instances. From the perspective of security
+ * privilege, Secretkeeper must be implemented in an environment with privilege higher than any of
+ * its clients. Since AVF based protected Virtual Machines are one set of its clients, the
+ * implementation of ISecretkeeper should live in a secure environment, such as:
+ * - A trusted execution environment such as ARM TrustZone.
+ * - A completely separate, purpose-built and certified secure CPU.
+ *
+ */
+interface ISecretkeeper {
+    const int ERROR_UNKNOWN_KEY_ID = 1;
+    const int ERROR_INTERNAL_ERROR = 2;
+    const int ERROR_REQUEST_MALFORMED = 3;
+
+    /**
+     * Retrieve the instance of the `IAuthGraphKeyExchange` HAL that should be used for shared
+     * session key establishment. These keys are used to perform encryption of messages as
+     * described in SecretManagement.cddl, allowing the client and Secretkeeper to have a
+     * cryptographically secure channel. In the key exchange protocol the client acts as P1
+     * (source) and Secretkeeper as P2 (sink). The interface returned here can be used to invoke
+     * methods on the sink.
+     *
+     * The client's identity is its DICE chain; Secretkeeper's identity is a
+     * per-boot key pair.
+     */
+    IAuthGraphKeyExchange getAuthGraphKe();
+
+    /**
+     * processSecretManagementRequest method is used for interacting with the Secret Management API
+     *
+     * Secret Management API: The clients can use this API to store (& get) 32 bytes of data.
+     * The API is a CBOR based protocol, which follows request/response model.
+     * See SecretManagement.cddl for the API spec.
+     *
+     * Further, the requests (from client) & responses (from service) must be encrypted into
+     * ProtectedRequestPacket & ProtectedResponsePacket using symmetric keys agreed between
+     * the client & service. This cryptographic protection is required because the messages are
+     * ferried via Android, which is allowed to be outside the TCB of clients (for example protected
+     * Virtual Machines). For this, service (& client) must implement the AuthGraph key exchange
+     * protocol to establish a secure channel between them.
+     *
+     * If an encrypted response cannot be generated, then a service-specific Binder error using one
+     * of the ERROR_ codes above will be returned.
+     *
+     * Secretkeeper database should guarantee the following properties:
+     *
+     * 1. Confidentiality: No entity (of security privilege lower than Secretkeeper) should
+     *    be able to get a client's data in clear.
+     *
+     * 2. Integrity: The data is protected against malicious Android OS tampering with database.
+     *    ie, if Android (userspace & kernel) tampers with the client's secret, the Secretkeeper
+     *    service must be able to detect it & return error when clients requests for their secrets.
+     *    Note: the integrity requirements also include Antirollback protection ie, reverting the
+     *    database into an old state should be detected.
+     *
+     * 3. The data is persistent across device boot.
+     *    Note: Denial of service is not in scope. A malicious Android may be able to delete data,
+     *    but for ideal Android, the data should be persistent.
+     *
+     * @param CBOR-encoded ProtectedRequestPacket. See SecretManagement.cddl for its definition.
+     * @return CBOR-encoded ProtectedResponsePacket. See SecretManagement.cddl for its definition
+     */
+    byte[] processSecretManagementRequest(in byte[] request);
+
+    /**
+     * Delete the data corresponding to a collection of IDs.
+     *
+     * Note that unlike `processSecretManagementRequest`, the contents of this method are in
+     * plaintext, and no client authentication is required.
+     *
+     * @param Secret identifiers to delete.
+     */
+    void deleteIds(in SecretId[] ids);
+
+    /**
+     * Delete data of all clients.
+     */
+    void deleteAll();
+}
diff --git a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretId.aidl b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretId.aidl
new file mode 100644
index 0000000..b17917f
--- /dev/null
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretId.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.secretkeeper;
+
+/**
+ * SecretId contains an identifier for a secret held by Secretkeeper.
+ * @hide
+ */
+@VintfStability
+parcelable SecretId {
+    /**
+     * 64-byte identifier for a secret.
+     */
+    byte[64] id;
+}
diff --git a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl
new file mode 100644
index 0000000..6a824c9
--- /dev/null
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl
@@ -0,0 +1,116 @@
+; CDDL for the Secret Management API.
+
+; The input parameter to the `processSecretManagementRequest` operation in
+; `ISecretkeeper.aidl` is always an encrypted request message, CBOR-encoded as a
+; COSE_Encrypt0 object.  The encryption uses the first of the keys agreed using
+; the associated AuthGraph instance, referred to as `KeySourceToSink`. Additionally,
+; an external aad is used - RequestSeqNum.
+ProtectedRequestPacket = CryptoPayload<RequestPacket, KeySourceToSink, RequestSeqNum>
+
+CryptoPayload<Payload, Key, SeqNum> = [ ; COSE_Encrypt0 (untagged), [RFC 9052 s5.2]
+    protected: bstr .cbor {
+        1 : 3,                  ; Algorithm: AES-GCM mode w/ 256-bit key, 128-bit tag
+        4 : bstr                ; key identifier set to session ID produced
+                                ; by AuthGraph key exchange.
+    },
+    unprotected: {
+        5 : bstr .size 12       ; IV
+    },
+    ciphertext : bstr           ; AES-GCM-256(Key, bstr .cbor Payload)
+                                ; AAD for the encryption is CBOR-serialized
+                                ; Enc_structure (RFC 9052 s5.3) with SeqNum as the external_aad.
+]
+
+; Once decrypted, the request packet is an encoded CBOR array holding:
+; - An initial integer indicating which request is present.
+; - Subsequent objects holding the parameters for that specific request.
+RequestPacket =
+    [GetVersionOpcode, GetVersionParams] /
+    [StoreSecretOpcode, StoreSecretParams] /
+    [GetSecretOpcode, GetSecretParams]
+
+GetVersionOpcode = 1            ; Get version of the SecretManagement API
+StoreSecretOpcode = 2           ; Store a secret
+GetSecretOpcode = 3             ; Get the secret
+
+; Retrieve Secretkeeper version.
+GetVersionParams = ()
+
+; Store a secret identified by the given ID, with access to the secret policed
+; by the associated sealing policy.
+StoreSecretParams = (
+    id : SecretId,
+    secret : Secret,
+    sealing_policy : bstr .cbor DicePolicy,
+)
+
+; INCLUDE DicePolicy.cddl for: DicePolicy
+
+; Retrieve a secret identified by the given ID, policed according to the sealing
+; policy that was associated with the secret.  If successful, optionally also
+; update the sealing policy for the secret.
+GetSecretParams = (
+    id : SecretId,
+    ; Retrieving the value of a secret may optionally also update the sealing
+    ; policy associated with a secret.
+    updated_sealing_policy : bstr .cbor DicePolicy / nil,
+)
+
+SecretId = bstr .size 64        ; Unique identifier of the secret.
+Secret = bstr .size 32          ; The secret value.
+
+; A monotonically incrementing number is associated with each RequestPacket to prevent replay
+; of messages within a session. This starts with 0 and is incremented (by 1) for each request
+; in a session. Secretkeeper implementation must maintain an expected RequestSeqNum for each
+; session (increasing it by 1 for each SecretManagement request received). This will be used in
+; in decryption (external_aad).
+RequestSeqNum = bstr .cbor uint     ; Encoded in accordance with Core Deterministic Encoding
+                                    ; Requirements [RFC 8949 s4.2.1]
+
+; The return value from a successful `processSecretManagementRequest` operation is a
+; response message encrypted with the second of the keys agreed using the associated
+; AuthGraph instance, referred to as `KeySinkToSource`.
+ProtectedResponsePacket = CryptoPayload<ResponsePacket, KeySinkToSource, ResponseSeqNum>
+
+; Once decrypted, the inner response message is encoded as a CBOR array holding:
+; - An initial integer return code value.
+; - Subsequently:
+;    - If the return code is zero: result value(s).
+;    - If the return code is non-zero: an error message.
+ResponsePacket =
+    [0, Result] /
+    [error_code: ErrorCode, error_message: tstr]
+
+; An error code in the inner response message indicates a failure in
+; secret management processing.
+ErrorCode = &(
+    ; Use this as if no other error code can be used.
+    ErrorCode_UnexpectedServerError: 1,
+    ; Indicate the Request was malformed & hence couldnt be served.
+    ErrorCode_RequestMalformed: 2,
+    ; Requested Entry not found.
+    ErrorCode_EntryNotFound: 3,
+    ; Error happened while serialization or deserialization.
+    ErrorCode_SerializationError: 4,
+    ; Indicates that Dice Policy matching did not succeed & hence access not granted.
+    ErrorCode_DicePolicyError: 5,
+)
+
+; The particular result variant present is determined by which request
+; message was originally sent.
+Result = &(
+    GetVersionResult,
+    StoreSecretResult,
+    GetSecretResult,
+)
+
+GetVersionResult = (1)
+
+StoreSecretResult = ()
+
+GetSecretResult = (secret : Secret)
+
+; Analogous to RequestSeqNum, Secretkeeper must maintain ResponseSeqNum for each session.
+; This will be input to the encryption (ProtectedResponsePacket) as external_aad.
+ResponseSeqNum = bstr .cbor uint    ; Encoded in accordance with Core Deterministic Encoding
+                                    ; Requirements [RFC 8949 s4.2.1]
diff --git a/security/secretkeeper/aidl/vts/Android.bp b/security/secretkeeper/aidl/vts/Android.bp
new file mode 100644
index 0000000..7de9d6a
--- /dev/null
+++ b/security/secretkeeper/aidl/vts/Android.bp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_test {
+    name: "VtsSecretkeeperTargetTest",
+    srcs: ["secretkeeper_test_client.rs"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+    test_config: "AndroidTest.xml",
+    rustlibs: [
+        "libsecretkeeper_client",
+        "libsecretkeeper_comm_nostd",
+        "libsecretkeeper_core_nostd",
+        "android.hardware.security.secretkeeper-V1-rust",
+        "libauthgraph_boringssl",
+        "libauthgraph_core",
+        "libcoset",
+        "libauthgraph_vts_test",
+        "libbinder_rs",
+        "libcoset",
+        "liblog_rust",
+        "liblogger",
+    ],
+    require_root: true,
+}
diff --git a/security/secretkeeper/aidl/vts/AndroidTest.xml b/security/secretkeeper/aidl/vts/AndroidTest.xml
new file mode 100644
index 0000000..4fee78f
--- /dev/null
+++ b/security/secretkeeper/aidl/vts/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for Secretkeeper VTS tests.">
+  <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+  <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+    <option name="push-file" key="VtsSecretkeeperTargetTest" value="/data/local/tmp/VtsSecretkeeperTargetTest" />
+  </target_preparer>
+
+  <test class="com.android.tradefed.testtype.rust.RustBinaryTest" >
+    <option name="test-device-path" value="/data/local/tmp" />
+    <option name="module-name" value="VtsSecretkeeperTargetTest" />
+    <!-- Rust tests are run in parallel by default. Run these ones
+         single-threaded, so that one test's secrets don't affect
+         the behaviour of a different test. -->
+    <option name="native-test-flag" value="--test-threads=1" />
+  </test>
+</configuration>
diff --git a/security/secretkeeper/aidl/vts/rustfmt.toml b/security/secretkeeper/aidl/vts/rustfmt.toml
new file mode 120000
index 0000000..ed2086b
--- /dev/null
+++ b/security/secretkeeper/aidl/vts/rustfmt.toml
@@ -0,0 +1 @@
+../../../../../../build/soong/scripts/rustfmt.toml
\ No newline at end of file
diff --git a/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs b/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
new file mode 100644
index 0000000..c457d24
--- /dev/null
+++ b/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
@@ -0,0 +1,552 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#![cfg(test)]
+
+use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::ISecretkeeper::ISecretkeeper;
+use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::SecretId::SecretId;
+use authgraph_vts_test as ag_vts;
+use authgraph_boringssl as boring;
+use authgraph_core::key;
+use binder::StatusCode;
+use coset::{CborSerializable, CoseEncrypt0};
+use log::{info, warn};
+use secretkeeper_client::SkSession;
+use secretkeeper_core::cipher;
+use secretkeeper_comm::data_types::error::SecretkeeperError;
+use secretkeeper_comm::data_types::request::Request;
+use secretkeeper_comm::data_types::request_response_impl::{
+    GetVersionRequest, GetVersionResponse, GetSecretRequest, GetSecretResponse, StoreSecretRequest,
+    StoreSecretResponse };
+use secretkeeper_comm::data_types::{Id, Secret, SeqNum};
+use secretkeeper_comm::data_types::response::Response;
+use secretkeeper_comm::data_types::packet::{ResponsePacket, ResponseType};
+
+const SECRETKEEPER_SERVICE: &str = "android.hardware.security.secretkeeper.ISecretkeeper";
+const SECRETKEEPER_INSTANCES: [&'static str; 2] = ["default", "nonsecure"];
+const CURRENT_VERSION: u64 = 1;
+
+// TODO(b/291238565): This will change once libdice_policy switches to Explicit-key DiceCertChain
+// This is generated by patching libdice_policy such that it dumps an example dice chain &
+// a policy, such that the former matches the latter.
+const HYPOTHETICAL_DICE_POLICY: [u8; 43] = [
+    0x83, 0x01, 0x81, 0x83, 0x01, 0x80, 0xA1, 0x01, 0x00, 0x82, 0x83, 0x01, 0x81, 0x01, 0x73, 0x74,
+    0x65, 0x73, 0x74, 0x69, 0x6E, 0x67, 0x5F, 0x64, 0x69, 0x63, 0x65, 0x5F, 0x70, 0x6F, 0x6C, 0x69,
+    0x63, 0x79, 0x83, 0x02, 0x82, 0x03, 0x18, 0x64, 0x19, 0xE9, 0x75,
+];
+
+// Random bytes (of ID_SIZE/SECRET_SIZE) generated for tests.
+const ID_EXAMPLE: Id = Id([
+    0xF1, 0xB2, 0xED, 0x3B, 0xD1, 0xBD, 0xF0, 0x7D, 0xE1, 0xF0, 0x01, 0xFC, 0x61, 0x71, 0xD3, 0x42,
+    0xE5, 0x8A, 0xAF, 0x33, 0x6C, 0x11, 0xDC, 0xC8, 0x6F, 0xAE, 0x12, 0x5C, 0x26, 0x44, 0x6B, 0x86,
+    0xCC, 0x24, 0xFD, 0xBF, 0x91, 0x4A, 0x54, 0x84, 0xF9, 0x01, 0x59, 0x25, 0x70, 0x89, 0x38, 0x8D,
+    0x5E, 0xE6, 0x91, 0xDF, 0x68, 0x60, 0x69, 0x26, 0xBE, 0xFE, 0x79, 0x58, 0xF7, 0xEA, 0x81, 0x7D,
+]);
+const ID_EXAMPLE_2: Id = Id([
+    0x6A, 0xCC, 0xB1, 0xEB, 0xBB, 0xAB, 0xE3, 0xEA, 0x44, 0xBD, 0xDC, 0x75, 0x75, 0x7D, 0xC0, 0xE5,
+    0xC7, 0x86, 0x41, 0x56, 0x39, 0x66, 0x96, 0x10, 0xCB, 0x43, 0x10, 0x79, 0x03, 0xDC, 0xE6, 0x9F,
+    0x12, 0x2B, 0xEF, 0x28, 0x9C, 0x1E, 0x32, 0x46, 0x5F, 0xA3, 0xE7, 0x8D, 0x53, 0x63, 0xE8, 0x30,
+    0x5A, 0x17, 0x6F, 0xEF, 0x42, 0xD6, 0x58, 0x7A, 0xF0, 0xCB, 0xD4, 0x40, 0x58, 0x96, 0x32, 0xF4,
+]);
+const ID_NOT_STORED: Id = Id([
+    0x56, 0xD0, 0x4E, 0xAA, 0xC1, 0x7B, 0x55, 0x6B, 0xA0, 0x2C, 0x65, 0x43, 0x39, 0x0A, 0x6C, 0xE9,
+    0x1F, 0xD0, 0x0E, 0x20, 0x3E, 0xFB, 0xF5, 0xF9, 0x3F, 0x5B, 0x11, 0x1B, 0x18, 0x73, 0xF6, 0xBB,
+    0xAB, 0x9F, 0xF2, 0xD6, 0xBD, 0xBA, 0x25, 0x68, 0x22, 0x30, 0xF2, 0x1F, 0x90, 0x05, 0xF3, 0x64,
+    0xE7, 0xEF, 0xC6, 0xB6, 0xA0, 0x85, 0xC9, 0x40, 0x40, 0xF0, 0xB4, 0xB9, 0xD8, 0x28, 0xEE, 0x9C,
+]);
+const SECRET_EXAMPLE: Secret = Secret([
+    0xA9, 0x89, 0x97, 0xFE, 0xAE, 0x97, 0x55, 0x4B, 0x32, 0x35, 0xF0, 0xE8, 0x93, 0xDA, 0xEA, 0x24,
+    0x06, 0xAC, 0x36, 0x8B, 0x3C, 0x95, 0x50, 0x16, 0x67, 0x71, 0x65, 0x26, 0xEB, 0xD0, 0xC3, 0x98,
+]);
+
+fn get_connection() -> Option<(binder::Strong<dyn ISecretkeeper>, String)> {
+    // Initialize logging (which is OK to call multiple times).
+    logger::init(logger::Config::default().with_min_level(log::Level::Debug));
+
+    // Determine which instances are available.
+    let available = binder::get_declared_instances(SECRETKEEPER_SERVICE).unwrap_or_default();
+
+    // TODO: replace this with a parameterized set of tests that run for each available instance of
+    // ISecretkeeper (rather than having a fixed set of instance names to look for).
+    for instance in &SECRETKEEPER_INSTANCES {
+        if available.iter().find(|s| s == instance).is_none() {
+            // Skip undeclared instances.
+            continue;
+        }
+        let name = format!("{SECRETKEEPER_SERVICE}/{instance}");
+        match binder::get_interface(&name) {
+            Ok(sk) => {
+                info!("Running test against /{instance}");
+                return Some((sk, name));
+            }
+            Err(StatusCode::NAME_NOT_FOUND) => {
+                info!("No /{instance} instance of ISecretkeeper present");
+            }
+            Err(e) => {
+                panic!(
+                    "unexpected error while fetching connection to Secretkeeper {:?}",
+                    e
+                );
+            }
+        }
+    }
+    info!("no Secretkeeper instances in {SECRETKEEPER_INSTANCES:?} are declared and present");
+    None
+}
+
+/// Macro to perform test setup. Invokes `return` if no Secretkeeper instance available.
+macro_rules! setup_client {
+    {} => {
+        match SkClient::new() {
+            Some(sk) => sk,
+            None => {
+                warn!("Secretkeeper HAL is unavailable, skipping test");
+                return;
+            }
+        }
+    }
+}
+
+/// Secretkeeper client information.
+struct SkClient {
+    sk: binder::Strong<dyn ISecretkeeper>,
+    name: String,
+    session: SkSession,
+}
+
+impl Drop for SkClient {
+    fn drop(&mut self) {
+        // Delete any IDs that may be left over.
+        self.delete(&[&ID_EXAMPLE, &ID_EXAMPLE_2]);
+    }
+}
+
+impl SkClient {
+    fn new() -> Option<Self> {
+        let (sk, name) = get_connection()?;
+        Some(Self {
+            sk: sk.clone(),
+            name,
+            session: SkSession::new(sk).unwrap(),
+        })
+    }
+
+    /// This method is wrapper that use `SkSession::secret_management_request` which handles
+    /// encryption and decryption.
+    fn secret_management_request(&mut self, req_data: &[u8]) -> Vec<u8> {
+        self.session.secret_management_request(req_data).unwrap()
+    }
+
+    /// Unlike the method [`secret_management_request`], this method directly uses
+    /// `cipher::encrypt_message` & `cipher::decrypt_message`, allowing finer control of request
+    /// & response aad.
+    fn secret_management_request_custom_aad(
+        &self,
+        req_data: &[u8],
+        req_aad: &[u8],
+        expected_res_aad: &[u8],
+    ) -> Vec<u8> {
+        let aes_gcm = boring::BoringAes;
+        let rng = boring::BoringRng;
+        let request_bytes = cipher::encrypt_message(
+            &aes_gcm,
+            &rng,
+            self.session.encryption_key(),
+            self.session.session_id(),
+            &req_data,
+            req_aad,
+        )
+        .unwrap();
+
+        // Binder call!
+        let response_bytes = self
+            .sk
+            .processSecretManagementRequest(&request_bytes)
+            .unwrap();
+
+        let response_encrypt0 = CoseEncrypt0::from_slice(&response_bytes).unwrap();
+        cipher::decrypt_message(
+            &aes_gcm,
+            self.session.decryption_key(),
+            &response_encrypt0,
+            expected_res_aad,
+        )
+        .unwrap()
+    }
+
+    /// Helper method to store a secret.
+    fn store(&mut self, id: &Id, secret: &Secret) {
+        let store_request = StoreSecretRequest {
+            id: id.clone(),
+            secret: secret.clone(),
+            sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
+        };
+        let store_request = store_request.serialize_to_packet().to_vec().unwrap();
+
+        let store_response = self.secret_management_request(&store_request);
+        let store_response = ResponsePacket::from_slice(&store_response).unwrap();
+
+        assert_eq!(
+            store_response.response_type().unwrap(),
+            ResponseType::Success
+        );
+        // Really just checking that the response is indeed StoreSecretResponse
+        let _ = StoreSecretResponse::deserialize_from_packet(store_response).unwrap();
+    }
+
+    /// Helper method to get a secret.
+    fn get(&mut self, id: &Id) -> Option<Secret> {
+        let get_request = GetSecretRequest {
+            id: id.clone(),
+            updated_sealing_policy: None,
+        };
+        let get_request = get_request.serialize_to_packet().to_vec().unwrap();
+
+        let get_response = self.secret_management_request(&get_request);
+        let get_response = ResponsePacket::from_slice(&get_response).unwrap();
+
+        if get_response.response_type().unwrap() == ResponseType::Success {
+            let get_response = *GetSecretResponse::deserialize_from_packet(get_response).unwrap();
+            Some(Secret(get_response.secret.0))
+        } else {
+            // Only expect a not-found failure.
+            let err = *SecretkeeperError::deserialize_from_packet(get_response).unwrap();
+            assert_eq!(err, SecretkeeperError::EntryNotFound);
+            None
+        }
+    }
+
+    /// Helper method to delete secrets.
+    fn delete(&self, ids: &[&Id]) {
+        let ids: Vec<SecretId> = ids
+            .iter()
+            .map(|id| SecretId { id: id.0 })
+            .collect();
+        self.sk.deleteIds(&ids).unwrap();
+    }
+
+    /// Helper method to delete everything.
+    fn delete_all(&self) {
+        self.sk.deleteAll().unwrap();
+    }
+}
+
+/// Perform AuthGraph key exchange, returning the session keys and session ID.
+fn authgraph_key_exchange(sk: binder::Strong<dyn ISecretkeeper>) -> ([key::AesKey; 2], Vec<u8>) {
+    let sink = sk.getAuthGraphKe().expect("failed to get AuthGraph");
+    let mut source = ag_vts::test_ag_participant().expect("failed to create a local source");
+    ag_vts::sink::test_mainline(&mut source, sink)
+}
+
+/// Test that the AuthGraph instance returned by SecretKeeper correctly performs
+/// mainline key exchange against a local source implementation.
+#[test]
+fn authgraph_mainline() {
+    let (sk, _) = match get_connection() {
+        Some(sk) => sk,
+        None => {
+            warn!("Secretkeeper HAL is unavailable, skipping test");
+            return;
+        }
+    };
+    let (_aes_keys, _session_id) = authgraph_key_exchange(sk);
+}
+
+/// Test that the AuthGraph instance returned by SecretKeeper correctly rejects
+/// a corrupted session ID signature.
+#[test]
+fn authgraph_corrupt_sig() {
+    let (sk, _) = match get_connection() {
+        Some(sk) => sk,
+        None => {
+            warn!("Secretkeeper HAL is unavailable, skipping test");
+            return;
+        }
+    };
+    let sink = sk.getAuthGraphKe().expect("failed to get AuthGraph");
+    let mut source = ag_vts::test_ag_participant().expect("failed to create a local source");
+    ag_vts::sink::test_corrupt_sig(&mut source, sink);
+}
+
+/// Test that the AuthGraph instance returned by SecretKeeper correctly detects
+/// when corrupted keys are returned to it.
+#[test]
+fn authgraph_corrupt_keys() {
+    let (sk, _) = match get_connection() {
+        Some(sk) => sk,
+        None => {
+            warn!("Secretkeeper HAL is unavailable, skipping test");
+            return;
+        }
+    };
+    let sink = sk.getAuthGraphKe().expect("failed to get AuthGraph");
+    let mut source = ag_vts::test_ag_participant().expect("failed to create a local source");
+    ag_vts::sink::test_corrupt_keys(&mut source, sink);
+}
+
+// TODO(b/2797757): Add tests that match different HAL defined objects (like request/response)
+// with expected bytes.
+
+#[test]
+fn secret_management_get_version() {
+    let mut sk_client = setup_client!();
+
+    let request = GetVersionRequest {};
+    let request_packet = request.serialize_to_packet();
+    let request_bytes = request_packet.to_vec().unwrap();
+
+    let response_bytes = sk_client.secret_management_request(&request_bytes);
+
+    let response_packet = ResponsePacket::from_slice(&response_bytes).unwrap();
+    assert_eq!(
+        response_packet.response_type().unwrap(),
+        ResponseType::Success
+    );
+    let get_version_response =
+        *GetVersionResponse::deserialize_from_packet(response_packet).unwrap();
+    assert_eq!(get_version_response.version, CURRENT_VERSION);
+}
+
+#[test]
+fn secret_management_malformed_request() {
+    let mut sk_client = setup_client!();
+
+    let request = GetVersionRequest {};
+    let request_packet = request.serialize_to_packet();
+    let mut request_bytes = request_packet.to_vec().unwrap();
+
+    // Deform the request
+    request_bytes[0] = !request_bytes[0];
+
+    let response_bytes = sk_client.secret_management_request(&request_bytes);
+
+    let response_packet = ResponsePacket::from_slice(&response_bytes).unwrap();
+    assert_eq!(
+        response_packet.response_type().unwrap(),
+        ResponseType::Error
+    );
+    let err = *SecretkeeperError::deserialize_from_packet(response_packet).unwrap();
+    assert_eq!(err, SecretkeeperError::RequestMalformed);
+}
+
+#[test]
+fn secret_management_store_get_secret_found() {
+    let mut sk_client = setup_client!();
+
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
+
+    // Get the secret that was just stored
+    assert_eq!(sk_client.get(&ID_EXAMPLE), Some(SECRET_EXAMPLE));
+}
+
+#[test]
+fn secret_management_store_get_secret_not_found() {
+    let mut sk_client = setup_client!();
+
+    // Store a secret (corresponding to an id).
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
+
+    // Get the secret that was never stored
+    assert_eq!(sk_client.get(&ID_NOT_STORED), None);
+}
+
+#[test]
+fn secretkeeper_store_delete_ids() {
+    let mut sk_client = setup_client!();
+
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
+    sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE);
+    sk_client.delete(&[&ID_EXAMPLE]);
+
+    assert_eq!(sk_client.get(&ID_EXAMPLE), None);
+    assert_eq!(sk_client.get(&ID_EXAMPLE_2), Some(SECRET_EXAMPLE));
+
+    sk_client.delete(&[&ID_EXAMPLE_2]);
+
+    assert_eq!(sk_client.get(&ID_EXAMPLE), None);
+    assert_eq!(sk_client.get(&ID_EXAMPLE_2), None);
+}
+
+#[test]
+fn secretkeeper_store_delete_multiple_ids() {
+    let mut sk_client = setup_client!();
+
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
+    sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE);
+    sk_client.delete(&[&ID_EXAMPLE, &ID_EXAMPLE_2]);
+
+    assert_eq!(sk_client.get(&ID_EXAMPLE), None);
+    assert_eq!(sk_client.get(&ID_EXAMPLE_2), None);
+}
+
+#[test]
+fn secretkeeper_store_delete_duplicate_ids() {
+    let mut sk_client = setup_client!();
+
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
+    sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE);
+    // Delete the same secret twice.
+    sk_client.delete(&[&ID_EXAMPLE, &ID_EXAMPLE]);
+
+    assert_eq!(sk_client.get(&ID_EXAMPLE), None);
+    assert_eq!(sk_client.get(&ID_EXAMPLE_2), Some(SECRET_EXAMPLE));
+}
+
+#[test]
+fn secretkeeper_store_delete_nonexistent() {
+    let mut sk_client = setup_client!();
+
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
+    sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE);
+    sk_client.delete(&[&ID_NOT_STORED]);
+
+    assert_eq!(sk_client.get(&ID_EXAMPLE), Some(SECRET_EXAMPLE));
+    assert_eq!(sk_client.get(&ID_EXAMPLE_2), Some(SECRET_EXAMPLE));
+    assert_eq!(sk_client.get(&ID_NOT_STORED), None);
+}
+
+#[test]
+fn secretkeeper_store_delete_all() {
+    let mut sk_client = setup_client!();
+
+    if sk_client.name != "nonsecure" {
+        // Don't run deleteAll() on a secure device, as it might affect
+        // real secrets.
+        warn!("skipping deleteAll test due to real impl");
+        return;
+    }
+
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
+    sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE);
+
+    sk_client.delete_all();
+
+    assert_eq!(sk_client.get(&ID_EXAMPLE), None);
+    assert_eq!(sk_client.get(&ID_EXAMPLE_2), None);
+
+    // Store a new secret (corresponding to an id).
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
+
+    // Get the restored secret.
+    assert_eq!(sk_client.get(&ID_EXAMPLE), Some(SECRET_EXAMPLE));
+
+    // (Try to) Get the secret that was never stored
+    assert_eq!(sk_client.get(&ID_NOT_STORED), None);
+}
+
+// This test checks that Secretkeeper uses the expected [`RequestSeqNum`] as aad while
+// decrypting requests and the responses are encrypted with correct [`ResponseSeqNum`] for the
+// first few messages.
+#[test]
+fn secret_management_replay_protection_seq_num() {
+    let sk_client = setup_client!();
+    // Construct encoded request packets for the test
+    let (req_1, req_2, req_3) = construct_secret_management_requests();
+
+    // Lets now construct the seq_numbers(in request & expected in response)
+    let mut seq_a = SeqNum::new();
+    let [seq_0, seq_1, seq_2] = std::array::from_fn(|_| seq_a.get_then_increment().unwrap());
+
+    // Check first request/response is successful
+    let res = ResponsePacket::from_slice(
+        &sk_client.secret_management_request_custom_aad(&req_1, &seq_0, &seq_0),
+    )
+    .unwrap();
+    assert_eq!(res.response_type().unwrap(), ResponseType::Success);
+
+    // Check 2nd request/response is successful
+    let res = ResponsePacket::from_slice(
+        &sk_client.secret_management_request_custom_aad(&req_2, &seq_1, &seq_1),
+    )
+    .unwrap();
+    assert_eq!(res.response_type().unwrap(), ResponseType::Success);
+
+    // Check 3rd request/response is successful
+    let res = ResponsePacket::from_slice(
+        &sk_client.secret_management_request_custom_aad(&req_3, &seq_2, &seq_2),
+    )
+    .unwrap();
+    assert_eq!(res.response_type().unwrap(), ResponseType::Success);
+}
+
+// This test checks that Secretkeeper uses fresh [`RequestSeqNum`] & [`ResponseSeqNum`]
+// for new sessions.
+#[test]
+fn secret_management_replay_protection_seq_num_per_session() {
+    let sk_client = setup_client!();
+
+    // Construct encoded request packets for the test
+    let (req_1, _, _) = construct_secret_management_requests();
+
+    // Lets now construct the seq_number (in request & expected in response)
+    let mut seq_a = SeqNum::new();
+    let seq_0 = seq_a.get_then_increment().unwrap();
+    // Check first request/response is successful
+    let res = ResponsePacket::from_slice(
+        &sk_client.secret_management_request_custom_aad(&req_1, &seq_0, &seq_0),
+    )
+    .unwrap();
+    assert_eq!(res.response_type().unwrap(), ResponseType::Success);
+
+    // Start another session
+    let sk_client_diff = setup_client!();
+    // Check first request/response is with seq_0 is successful
+    let res = ResponsePacket::from_slice(
+        &sk_client_diff.secret_management_request_custom_aad(&req_1, &seq_0, &seq_0),
+    )
+    .unwrap();
+    assert_eq!(res.response_type().unwrap(), ResponseType::Success);
+}
+
+// This test checks that Secretkeeper rejects requests with out of order [`RequestSeqNum`]
+#[test]
+// TODO(b/317416663): This test fails, when HAL is not present in the device. Refactor to fix this.
+#[ignore]
+#[should_panic]
+fn secret_management_replay_protection_out_of_seq_req_not_accepted() {
+    let sk_client = setup_client!();
+
+    // Construct encoded request packets for the test
+    let (req_1, req_2, _) = construct_secret_management_requests();
+
+    // Lets now construct the seq_numbers(in request & expected in response)
+    let mut seq_a = SeqNum::new();
+    let [seq_0, seq_1, seq_2] = std::array::from_fn(|_| seq_a.get_then_increment().unwrap());
+
+    // Assume First request/response is successful
+    sk_client.secret_management_request_custom_aad(&req_1, &seq_0, &seq_0);
+
+    // Check 2nd request/response with skipped seq_num in request is a binder error
+    // This should panic!
+    sk_client.secret_management_request_custom_aad(&req_2, /*Skipping seq_1*/ &seq_2, &seq_1);
+}
+
+fn construct_secret_management_requests() -> (Vec<u8>, Vec<u8>, Vec<u8>) {
+    let version_request = GetVersionRequest {};
+    let version_request = version_request.serialize_to_packet().to_vec().unwrap();
+    let store_request = StoreSecretRequest {
+        id: ID_EXAMPLE,
+        secret: SECRET_EXAMPLE,
+        sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
+    };
+    let store_request = store_request.serialize_to_packet().to_vec().unwrap();
+    let get_request = GetSecretRequest {
+        id: ID_EXAMPLE,
+        updated_sealing_policy: None,
+    };
+    let get_request = get_request.serialize_to_packet().to_vec().unwrap();
+    (version_request, store_request, get_request)
+}
diff --git a/security/secretkeeper/default/Android.bp b/security/secretkeeper/default/Android.bp
new file mode 100644
index 0000000..1d75c74
--- /dev/null
+++ b/security/secretkeeper/default/Android.bp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_library {
+    name: "libsecretkeeper_nonsecure",
+    crate_name: "secretkeeper_nonsecure",
+    srcs: [
+        "src/lib.rs",
+    ],
+    vendor_available: true,
+    defaults: [
+        "authgraph_use_latest_hal_aidl_rust",
+    ],
+    rustlibs: [
+        "android.hardware.security.secretkeeper-V1-rust",
+        "libauthgraph_boringssl",
+        "libauthgraph_core",
+        "libauthgraph_hal",
+        "libbinder_rs",
+        "liblog_rust",
+        "libsecretkeeper_core_nostd",
+        "libsecretkeeper_comm_nostd",
+    ],
+}
+
+rust_binary {
+    name: "android.hardware.security.secretkeeper-service.nonsecure",
+    relative_install_path: "hw",
+    vendor: true,
+    installable: false, // install APEX
+    prefer_rlib: true,
+    defaults: [
+        "authgraph_use_latest_hal_aidl_rust",
+    ],
+    rustlibs: [
+        "android.hardware.security.secretkeeper-V1-rust",
+        "libandroid_logger",
+        "libbinder_rs",
+        "liblog_rust",
+        "libsecretkeeper_hal",
+        "libsecretkeeper_nonsecure",
+    ],
+    srcs: [
+        "src/main.rs",
+    ],
+}
+
+rust_fuzz {
+    name: "android.hardware.security.secretkeeper-service.nonsecure_fuzzer",
+    rustlibs: [
+        "libsecretkeeper_hal",
+        "libsecretkeeper_nonsecure",
+        "libbinder_random_parcel_rs",
+        "libbinder_rs",
+    ],
+    srcs: ["src/fuzzer.rs"],
+    fuzz_config: {
+        cc: [
+            "alanstokes@google.com",
+            "drysdale@google.com",
+            "shikhapanwar@google.com",
+        ],
+    },
+}
+
+prebuilt_etc {
+    name: "secretkeeper.rc",
+    src: "secretkeeper.rc",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "secretkeeper.xml",
+    src: "secretkeeper.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
+
+apex {
+    name: "com.android.hardware.security.secretkeeper",
+    manifest: "apex_manifest.json",
+    file_contexts: "apex_file_contexts",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    vendor: true,
+    updatable: false,
+
+    binaries: [
+        "android.hardware.security.secretkeeper-service.nonsecure",
+    ],
+    prebuilts: [
+        "secretkeeper.rc",
+        "secretkeeper.xml",
+    ],
+}
diff --git a/security/secretkeeper/default/apex_file_contexts b/security/secretkeeper/default/apex_file_contexts
new file mode 100644
index 0000000..71369a8
--- /dev/null
+++ b/security/secretkeeper/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                          u:object_r:vendor_file:s0
+/etc(/.*)?                                      u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.security\.secretkeeper-service\.nonsecure  u:object_r:hal_secretkeeper_default_exec:s0
diff --git a/security/secretkeeper/default/apex_manifest.json b/security/secretkeeper/default/apex_manifest.json
new file mode 100644
index 0000000..7287095
--- /dev/null
+++ b/security/secretkeeper/default/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.security.secretkeeper",
+    "version": 1
+}
\ No newline at end of file
diff --git a/security/secretkeeper/default/secretkeeper.rc b/security/secretkeeper/default/secretkeeper.rc
new file mode 100644
index 0000000..38ee50d
--- /dev/null
+++ b/security/secretkeeper/default/secretkeeper.rc
@@ -0,0 +1,5 @@
+service vendor.secretkeeper /apex/com.android.hardware.security.secretkeeper/bin/hw/android.hardware.security.secretkeeper-service.nonsecure
+    interface aidl android.hardware.security.secretkeeper.ISecretkeeper/nonsecure
+    class hal
+    user nobody
+    group nobody
diff --git a/security/secretkeeper/default/secretkeeper.xml b/security/secretkeeper/default/secretkeeper.xml
new file mode 100644
index 0000000..40aebe0
--- /dev/null
+++ b/security/secretkeeper/default/secretkeeper.xml
@@ -0,0 +1,28 @@
+<manifest version="1.0" type="device">
+<!--
+/*
+** Copyright 2022, 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.
+*/
+-->
+
+    <hal format="aidl">
+        <name>android.hardware.security.secretkeeper</name>
+        <version>1</version>
+        <interface>
+            <name>ISecretkeeper</name>
+            <instance>nonsecure</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/security/secretkeeper/default/src/fuzzer.rs b/security/secretkeeper/default/src/fuzzer.rs
new file mode 100644
index 0000000..914ebe6
--- /dev/null
+++ b/security/secretkeeper/default/src/fuzzer.rs
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#![allow(missing_docs)]
+#![no_main]
+extern crate libfuzzer_sys;
+
+use binder_random_parcel_rs::fuzz_service;
+use libfuzzer_sys::fuzz_target;
+use secretkeeper_hal::SecretkeeperService;
+use secretkeeper_nonsecure::{AuthGraphChannel, LocalTa, SecretkeeperChannel};
+use std::sync::{Arc, Mutex};
+
+fuzz_target!(|data: &[u8]| {
+    let ta = Arc::new(Mutex::new(LocalTa::new()));
+    let ag_channel = AuthGraphChannel(ta.clone());
+    let sk_channel = SecretkeeperChannel(ta.clone());
+
+    let service = SecretkeeperService::new_as_binder(sk_channel, ag_channel);
+    fuzz_service(&mut service.as_binder(), data);
+});
diff --git a/security/secretkeeper/default/src/lib.rs b/security/secretkeeper/default/src/lib.rs
new file mode 100644
index 0000000..412ad45
--- /dev/null
+++ b/security/secretkeeper/default/src/lib.rs
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Non-secure implementation of a local Secretkeeper TA.
+
+use authgraph_boringssl as boring;
+use authgraph_core::keyexchange::{AuthGraphParticipant, MAX_OPENED_SESSIONS};
+use authgraph_core::ta::{AuthGraphTa, Role};
+use authgraph_hal::channel::SerializedChannel;
+use log::error;
+use secretkeeper_core::ta::SecretkeeperTa;
+use std::cell::RefCell;
+use std::rc::Rc;
+use std::sync::mpsc;
+use std::sync::{Arc, Mutex};
+
+mod store;
+
+/// Implementation of the Secrekeeper TA that runs locally in-process (and which is therefore
+/// insecure).
+pub struct LocalTa {
+    in_tx: mpsc::Sender<Vec<u8>>,
+    out_rx: mpsc::Receiver<Vec<u8>>,
+}
+
+/// Prefix byte for messages intended for the AuthGraph TA.
+const AG_MESSAGE_PREFIX: u8 = 0x00;
+/// Prefix byte for messages intended for the Secretkeeper TA.
+const SK_MESSAGE_PREFIX: u8 = 0x01;
+
+impl LocalTa {
+    /// Create a new instance.
+    pub fn new() -> Self {
+        // Create a pair of channels to communicate with the TA thread.
+        let (in_tx, in_rx) = mpsc::channel();
+        let (out_tx, out_rx) = mpsc::channel();
+
+        // The TA code expects to run single threaded, so spawn a thread to run it in.
+        std::thread::spawn(move || {
+            let mut crypto_impls = boring::crypto_trait_impls();
+            let storage_impl = Box::new(store::InMemoryStore::default());
+            let sk_ta = Rc::new(RefCell::new(
+                SecretkeeperTa::new(&mut crypto_impls, storage_impl)
+                    .expect("Failed to create local Secretkeeper TA"),
+            ));
+            let mut ag_ta = AuthGraphTa::new(
+                AuthGraphParticipant::new(crypto_impls, sk_ta.clone(), MAX_OPENED_SESSIONS)
+                    .expect("Failed to create local AuthGraph TA"),
+                Role::Sink,
+            );
+
+            // Loop forever processing request messages.
+            loop {
+                let req_data: Vec<u8> = match in_rx.recv() {
+                    Ok(data) => data,
+                    Err(_) => {
+                        error!("local TA failed to receive request!");
+                        break;
+                    }
+                };
+                let rsp_data = match req_data[0] {
+                    AG_MESSAGE_PREFIX => ag_ta.process(&req_data[1..]),
+                    SK_MESSAGE_PREFIX => {
+                        // It's safe to `borrow_mut()` because this code is not a callback
+                        // from AuthGraph (the only other holder of an `Rc`), and so there
+                        // can be no live `borrow()`s in this (single) thread.
+                        sk_ta.borrow_mut().process(&req_data[1..])
+                    }
+                    prefix => panic!("unexpected messageprefix {prefix}!"),
+                };
+                match out_tx.send(rsp_data) {
+                    Ok(_) => {}
+                    Err(_) => {
+                        error!("local TA failed to send out response");
+                        break;
+                    }
+                }
+            }
+            error!("local TA terminating!");
+        });
+        Self { in_tx, out_rx }
+    }
+
+    fn execute_for(&mut self, prefix: u8, req_data: &[u8]) -> Vec<u8> {
+        let mut prefixed_req = Vec::with_capacity(req_data.len() + 1);
+        prefixed_req.push(prefix);
+        prefixed_req.extend_from_slice(req_data);
+        self.in_tx
+            .send(prefixed_req)
+            .expect("failed to send in request");
+        self.out_rx.recv().expect("failed to receive response")
+    }
+}
+
+pub struct AuthGraphChannel(pub Arc<Mutex<LocalTa>>);
+
+impl SerializedChannel for AuthGraphChannel {
+    const MAX_SIZE: usize = usize::MAX;
+    fn execute(&self, req_data: &[u8]) -> binder::Result<Vec<u8>> {
+        Ok(self
+            .0
+            .lock()
+            .unwrap()
+            .execute_for(AG_MESSAGE_PREFIX, req_data))
+    }
+}
+
+pub struct SecretkeeperChannel(pub Arc<Mutex<LocalTa>>);
+
+impl SerializedChannel for SecretkeeperChannel {
+    const MAX_SIZE: usize = usize::MAX;
+    fn execute(&self, req_data: &[u8]) -> binder::Result<Vec<u8>> {
+        Ok(self
+            .0
+            .lock()
+            .unwrap()
+            .execute_for(SK_MESSAGE_PREFIX, req_data))
+    }
+}
diff --git a/security/secretkeeper/default/src/main.rs b/security/secretkeeper/default/src/main.rs
new file mode 100644
index 0000000..436f9a7
--- /dev/null
+++ b/security/secretkeeper/default/src/main.rs
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Non-secure implementation of the Secretkeeper HAL.
+
+use log::{error, info, Level};
+use secretkeeper_hal::SecretkeeperService;
+use secretkeeper_nonsecure::{AuthGraphChannel, SecretkeeperChannel, LocalTa};
+use std::sync::{Arc, Mutex};
+use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::ISecretkeeper::{
+    BpSecretkeeper, ISecretkeeper,
+};
+
+fn main() {
+    // Initialize Android logging.
+    android_logger::init_once(
+        android_logger::Config::default()
+            .with_tag("NonSecureSecretkeeper")
+            .with_min_level(Level::Info)
+            .with_log_id(android_logger::LogId::System),
+    );
+    // Redirect panic messages to logcat.
+    std::panic::set_hook(Box::new(|panic_info| {
+        error!("{}", panic_info);
+    }));
+
+    let ta = Arc::new(Mutex::new(LocalTa::new()));
+    let ag_channel = AuthGraphChannel(ta.clone());
+    let sk_channel = SecretkeeperChannel(ta.clone());
+
+    let service = SecretkeeperService::new_as_binder(sk_channel, ag_channel);
+    let service_name = format!(
+        "{}/nonsecure",
+        <BpSecretkeeper as ISecretkeeper>::get_descriptor()
+    );
+    binder::add_service(&service_name, service.as_binder()).unwrap_or_else(|e| {
+        panic!("Failed to register service {service_name} because of {e:?}.",);
+    });
+    info!("Registered Binder service, joining threadpool.");
+    binder::ProcessState::join_thread_pool();
+}
diff --git a/security/secretkeeper/default/src/store.rs b/security/secretkeeper/default/src/store.rs
new file mode 100644
index 0000000..6c7dba1
--- /dev/null
+++ b/security/secretkeeper/default/src/store.rs
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! In-memory store for nonsecure Secretkeeper.
+
+use secretkeeper_comm::data_types::error::Error;
+use secretkeeper_core::store::KeyValueStore;
+use std::collections::HashMap;
+
+/// An in-memory implementation of [`KeyValueStore`]. Please note that this is entirely for testing
+/// purposes. Refer to the documentation of `PolicyGatedStorage` and Secretkeeper HAL for
+/// persistence requirements.
+#[derive(Default)]
+pub struct InMemoryStore(HashMap<Vec<u8>, Vec<u8>>);
+impl KeyValueStore for InMemoryStore {
+    fn store(&mut self, key: &[u8], val: &[u8]) -> Result<(), Error> {
+        // This will overwrite the value if key is already present.
+        let _ = self.0.insert(key.to_vec(), val.to_vec());
+        Ok(())
+    }
+
+    fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Error> {
+        let optional_val = self.0.get(key);
+        Ok(optional_val.cloned())
+    }
+
+    fn delete(&mut self, key: &[u8]) -> Result<(), Error> {
+        self.0.remove(key);
+        Ok(())
+    }
+
+    fn delete_all(&mut self) -> Result<(), Error> {
+        self.0.clear();
+        Ok(())
+    }
+}
diff --git a/sensors/aidl/default/Android.bp b/sensors/aidl/default/Android.bp
index 384ee97..e93c391 100644
--- a/sensors/aidl/default/Android.bp
+++ b/sensors/aidl/default/Android.bp
@@ -23,18 +23,6 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
-filegroup {
-    name: "sensors-default.rc",
-    srcs: ["sensors-default.rc"],
-}
-
-prebuilt_etc {
-    name: "sensors-default.xml",
-    src: "sensors-default.xml",
-    sub_dir: "vintf",
-    installable: false,
-}
-
 cc_library_static {
     name: "libsensorsexampleimpl",
     vendor: true,
@@ -59,21 +47,55 @@
 cc_binary {
     name: "android.hardware.sensors-service.example",
     relative_install_path: "hw",
-    init_rc: [":sensors-default.rc"],
-    vintf_fragments: [":sensors-default.xml"],
+    installable: false, // install APEX below
+
     vendor: true,
     shared_libs: [
-        "libbase",
         "libbinder_ndk",
-        "libfmq",
-        "libpower",
-        "libcutils",
         "liblog",
-        "libutils",
-        "android.hardware.sensors-V2-ndk",
     ],
     static_libs: [
+        "android.hardware.common-V2-ndk",
+        "android.hardware.common.fmq-V1-ndk",
+        "android.hardware.sensors-V2-ndk",
+        "android.system.suspend-V1-ndk",
+        "libbase",
+        "libcutils",
+        "libfmq",
+        "libpower",
         "libsensorsexampleimpl",
+        "libutils",
     ],
     srcs: ["main.cpp"],
 }
+
+prebuilt_etc {
+    name: "sensors-default.rc",
+    src: "sensors-default.rc",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "sensors-default.xml",
+    src: "sensors-default.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
+
+// Default vendor APEX for android.hardware.sensors.
+// Custom implementations may use override_apex based on this APEX.
+apex {
+    name: "com.android.hardware.sensors",
+    manifest: "apex_manifest.json",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    file_contexts: "file_contexts",
+    updatable: false,
+    vendor: true,
+
+    binaries: ["android.hardware.sensors-service.example"],
+    prebuilts: [
+        "sensors-default.rc", // init rc
+        "sensors-default.xml", // vintf fragment
+    ],
+}
diff --git a/sensors/aidl/default/apex/Android.bp b/sensors/aidl/default/apex/Android.bp
deleted file mode 100644
index 5482086..0000000
--- a/sensors/aidl/default/apex/Android.bp
+++ /dev/null
@@ -1,41 +0,0 @@
-package {
-    default_applicable_licenses: ["hardware_interfaces_license"],
-}
-
-genrule {
-    name: "com.android.hardware.sensors.rc-gen",
-    srcs: [":sensors-default.rc"],
-    out: ["com.android.hardware.sensors.rc"],
-    cmd: "sed -E 's/\\/vendor/\\/apex\\/com.android.hardware.sensors/' $(in) > $(out)",
-}
-
-prebuilt_etc {
-    name: "com.android.hardware.sensors.rc",
-    src: ":com.android.hardware.sensors.rc-gen",
-    installable: false,
-}
-
-// Default vendor APEX for android.hardware.sensors.
-// Custom implementations may use override_apex based on this APEX.
-apex {
-    name: "com.android.hardware.sensors",
-    manifest: "apex_manifest.json",
-    key: "com.android.hardware.key",
-    certificate: ":com.android.hardware.certificate",
-    file_contexts: "file_contexts",
-    updatable: false,
-    vendor: true,
-
-    binaries: ["android.hardware.sensors-service.example"],
-    prebuilts: [
-        "com.android.hardware.sensors.rc", // init rc
-        "sensors-default.xml", // vintf fragment
-        "android.hardware.sensor.ambient_temperature.prebuilt.xml",
-        "android.hardware.sensor.barometer.prebuilt.xml",
-        "android.hardware.sensor.gyroscope.prebuilt.xml",
-        "android.hardware.sensor.hinge_angle.prebuilt.xml",
-        "android.hardware.sensor.light.prebuilt.xml",
-        "android.hardware.sensor.proximity.prebuilt.xml",
-        "android.hardware.sensor.relative_humidity.prebuilt.xml",
-    ],
-}
diff --git a/sensors/aidl/default/apex/com.android.hardware.sensors.avbpubkey b/sensors/aidl/default/apex/com.android.hardware.sensors.avbpubkey
deleted file mode 100644
index 98dfb71..0000000
--- a/sensors/aidl/default/apex/com.android.hardware.sensors.avbpubkey
+++ /dev/null
Binary files differ
diff --git a/sensors/aidl/default/apex/com.android.hardware.sensors.pem b/sensors/aidl/default/apex/com.android.hardware.sensors.pem
deleted file mode 100644
index a2f1833..0000000
--- a/sensors/aidl/default/apex/com.android.hardware.sensors.pem
+++ /dev/null
@@ -1,51 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIJKAIBAAKCAgEArUwl9rjXtNrSqJ2rfEryTnVEte7uhZlsn42rXRHFZtuV8N03
-AKAFDDkhJIT+FqmVJLW1Whrno+goaKzA23BodZcSo/xOJuTopgQ/TVqIO2QZ2WUS
-1NiYT3+kydZgtBHhfS+ek9h6aTLgJUn/XBX2xgEA6kp/NkcLpGkqj9Xs7XUpG+n/
-KnyYg+/YFqooEKHTTi4dT9YgRblgzv5zhCKxjB9gqy8dmhwDTpbPGavNiMIZvnSs
-aQzXh7+UMwte+V4QdaEqonoVWm85vEh6rsPpvvmxvlkVnUstRWRwsvbA183gvwZg
-f7OmAgpVu0kEkSHpoJJWpDUhzxmTdxmwvmL92eCJqQUjvxLqak4uBt+epUgbgxcA
-nS7rNg6PsNlHhYl5wRArPP17iW/QK3qnoz8rKgJCtdxPPD13byA13eY9q+Fdwb2H
-uHxGu1iYlRxUAzptvb6pIED/v9MMw/g3yMJkR89WG+pBLbUXHko6H0qOVchYrd8C
-OtcGo7GBBPbJmj9ZGZDX7p5YBSdTZs8f9wWqJmXkfVR60zZE0dOnOchzL44c8oUh
-uwEZMee7Ae/2LfWnfIe5KBNTvvH1CzU8KbQUJJVbATbb3j/eYExgsbnk0WgFi6i4
-osuJZZmfC44tAg18gXozcji+xYuW3MIMV2+drdc3xXn7LXKn5JZCLVJ6n+cCAwEA
-AQKCAgATT6P/XVO0NJo67e75F8Tul0TD3U85FgKzuO66nUtZDekkgRIrAKnvVcJq
-tmM2FUmoYJNH6i2b5zfxiianjVwmlmIeYfQ3g1Slg12megsqSxpSTmAN1eELItcz
-Iq9+AWwWLiNGqF3jsSanIRrSoSPxppT6hrisTLhwZsO2aYlQYLjnAmlLy7yXHzf+
-NpHmYJISaTMc/Wh1PJYcGuC2fcM5MRntmX9799kqfcWwP6PUtIR347p+rk6qMuAJ
-3B+GPEQrR31fw6jzfed6Ir2BEhXPETYMVxMAhysRS4L/fl247pk30Dcao+NA4PPy
-vc1Devr0yLnc7IrK8DetkvBOFuvgl53gHPZ4f7ge2PQMPghwjBaFuXklcfY96PVw
-Yo/CyAN+VEANThFFcKUzovtHI6m3sNTlxE6F+AYvx5dE/WZKmE5/cYCSJ8bhLPJl
-G68VkdeNv0LMZ/7rf1OEWP/YWw/5/tQ7MJ0IO5GShjE2EAGG0SZgK8/fwHZZJFES
-oYVWlriGtGDfiYjPLqVIjdZI6iOo6BMQh6pl0TPIJpn3ODqtRy8gN3TMvG6VcTJy
-QE3Z+br7UsK4gXSw0+MNLC3VKhX2bjT5q9lVpVnLv4L7q1ad4kwHblFAo686ZbWt
-eKTUv7QTI3fFqYeZEgCqRBQZ3UoKyWOBg0MAbf26hZFTFFpbEQKCAQEA2JdW6wDM
-iO1haR168l497nUC382/f/fJA8vzFdJ7cHVM95Tx/5JNYNJSL30XDyux9RJNqnFu
-tByec4c5CVuX/Gv/B4Q++xaaI7OVT9hTl/aoTShObGRJGbVh8xZagb7on7dAfD6G
-1SzTaahxQT5neoiki13GvJ6teL+0ZbCxRDMfPyy79lRzH5d0mw+EQvtc0Vvkweyj
-zf/Mn0yMZHO19oCKjJo8QkciseOqaS2mpgtOiRDc01uuaFAcw6taiERrR86xK2Yl
-OowIx6Yu8n7jRyTGUfr2Oz97a/zDVMVRi3BuyePOyCD9PfUmoj9JyCFbQSS1Lq3N
-AWacnNwQpkDDiQKCAQEAzNQ3/hKhjrLyEm2ktQk1Tzyk4eGu/NElxSKM7uJTeU0k
-xxKuMNMQCJbZmklJKojVYZ0fsh6AyLEpBMV6mWTmVo0qA/A09jKD2tsKu52KGCMt
-vgrN4Gi5JJJACNbtpG7uSJstAYuUGYQSTuS/xCE+urgMVbWBTocsf0bEeEe0FRWX
-txhS/zdj6wspTd6lJ0SSahWG/BsV7990zaRDGYv0N1+SwF8/C0Ml99WbyRof6oP9
-jx0esKA+giWc5lSk+Ag2gpsTIH36aF53lQnDBZL3hqSgqP0ollKa9Uyjfmp65D1m
-TwoENrKnVNO5ZKteTM3SGQ+zsHxBPpinK7T2BPe77wKCAQBdS+Nu2ys/mDErnD1H
-hXzb6J9SVEg3ET8PWZzeO4pciMqcoxYS5qxaFn68Yf+60zGWxUmbL71l7CX80bSp
-6UBwxPxX+ok+kx/WXRbmC+MGRIN+qOwPGKu8XTtSAMD/voJpugAXBMADt4lhq+MN
-HZppV865Ea33tco3hyxn2VKic/rztYtJslrcstrRqD9qsufqbtD9D7gHljZIMCsR
-Yh5xjjEgG5f1XLr/MXhIUhfE0n4D4LWefZGE8W1Sg889f2tOxSPf8+H5dDSb+2Oh
-pTK1hIvA6H+ESfYaMAjbzRsxGz89y9lYr40mUSFRJj3b7TJnvy4ka00xW0f+8XRi
-iOcxAoIBAB0o8Te4i0t3akL5XQNw5if7qDWIHZNcaxYfjxTLH7sbIms825OT2KqA
-X0Y5vLLTfB1Dcym2cfsgTYiiXIvN84TK3/pjjgamtmLH4EVJbkl1aKOvghO6lPEB
-6R/ZCUfpiv7HKKcZqeHgDYMxyaMwYG/Ql+Dz0A7P66PK/VlqS9bclha43cf7qLvj
-gOPXGIf4mSeFHQxzBrJ5i3VjNzJB3GitsIS2ipEd5B/eRylgEL8gP07KhH38silx
-FV8tGbc95BS/4v8zMBz/peKP2zXF8Hs4oK6uK8MKy4i0emoa2pf3rcL+2A65bF0F
-L1WHmAszGf/7Xkd3yQoSTWpJfuTCJ/0CggEBAJjkBaEoiRYp0RBq1Ty0wa+xbPHp
-gAcpco+VC3T8uqniKBDrf5QsMDm7+P9IZRYrfgyy0KFeG4mHrTt61JgOLnhSTOyz
-EEChc8SOn6+vqMB36FmSSqVb6CdLEZhv5dtTzzHgyd3xS3cwga9Mf2SCoG/l34HJ
-XzfoQyLKvqF0kWOq/76k+kBM5QwWIGc2fVXcpJpWaAuPWKDQJnkvTcPp8XPyEADv
-z2YbSDDqqcwczX2DWepf2t2RU1fdyjS5wS6pNDvsuyd6gwUTQT1P5ODHbIdAwcdi
-5Gxui8voJmzvrfabIsN6H73ZS4Lw20ZB+ejYyiwxZcb0os45C1coicMJ9wQ=
------END RSA PRIVATE KEY-----
diff --git a/sensors/aidl/default/apex/com.android.hardware.sensors.pk8 b/sensors/aidl/default/apex/com.android.hardware.sensors.pk8
deleted file mode 100644
index 7a1cca0..0000000
--- a/sensors/aidl/default/apex/com.android.hardware.sensors.pk8
+++ /dev/null
Binary files differ
diff --git a/sensors/aidl/default/apex/com.android.hardware.sensors.x509.pem b/sensors/aidl/default/apex/com.android.hardware.sensors.x509.pem
deleted file mode 100644
index 20a06f9..0000000
--- a/sensors/aidl/default/apex/com.android.hardware.sensors.x509.pem
+++ /dev/null
@@ -1,34 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIF3TCCA8UCFAbIl4RS714WSLo4k64MHsINz4VEMA0GCSqGSIb3DQEBCwUAMIGp
-MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91
-bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEi
-MCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTElMCMGA1UEAwwcY29t
-LmFuZHJvaWQuaGFyZHdhcmUuc2Vuc29yczAgFw0yMTA5MDMxNjEyNDNaGA80NzU5
-MDczMTE2MTI0M1owgakxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlh
-MRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYD
-VQQLDAdBbmRyb2lkMSIwIAYJKoZIhvcNAQkBFhNhbmRyb2lkQGFuZHJvaWQuY29t
-MSUwIwYDVQQDDBxjb20uYW5kcm9pZC5oYXJkd2FyZS5zZW5zb3JzMIICIjANBgkq
-hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnluNTPcq4pDEeb5gEYszRYQCawq8czUY
-J+x2b0i7qO2wLidX45CX6BLZ9N7c5veoV3FvC1wMTRR6lGAyg7UbD80vVmPdmr6R
-vw2AdIqrghXinvAEv6gxQQPVQa8UHkCL4lULLXo2gdmoCBM8VJHihjO/2F8ZLsP/
-nKhYx9Nr6w9LEyalmHTkXOgNyrNprpbJwugdk3hDXbAK+j5nF9fsz/iWFoXnPuNe
-oqdWj21YhXKDAbewBXaM6l3qmTdGsVVJL4HmVURGUY2f2UZwMWTEjpy9UDzyfqqg
-CSdH1RLmGVAINyfNI3Zswo0CjnOCf0jW6mq9/6mfGYu8hBCrky/rOH8reDwYZTGe
-H6JbNj0dhEN5HzQcxGEQQ43L1nmH7XlnuPO0xPSsw5binPVuUvURivR3PSsFgpPl
-0Uche62XgLAXCXhNV2uUQtZLVFGug7JcGgS4O3GoKr6w35Q+W9SEXanXFMW6X+wN
-hkbhB4MDSuKTZrjEnZEyxMOLG8ILN9i7osa+yjWONTn9bZc6q3Y9jyu3u84o8kC8
-KDcvr8YZEL63nQsQXO44GiQmqBptuB+ehcAC6uRCKkY9tQ95EQ7laGQ3C85d3gPj
-NcGjT7SSuUir7n+LI9pZsotedd9+rGhiiyT8CM4sVWiYJFnA2UX/bsnkZyAOq9Po
-jz1aMdHc4wUCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEATEPN2SZk8pJc4DaWmhyR
-MUklzVeuN0J0Mij1mHuVmID7Q5IhBBXxtVmwRIo208rHSvFLAo7Z4FnuZCV3A/c9
-TlXT3S2t+iYG5eOyXSsoSc/uerJ7kIBcOe27qIrO9GwcK5CQlTaXP+CG1gbLp1nl
-IaqKAT+eb/ji5wmFxMI77wo3uKLPTCfpaptFNaYlRqvxiXdJsCZwCPgmCtXJUeeZ
-R/HKOA4PcS2QB+HwhYePY5kUJPwt6MwJEyno72oenfl49FrGHj0BzVmQ7KMfiYjZ
-eRSB2Wbo50xfiICkPlUcvWD8rRNg7N9CM/Q5O0MW3ivAe42aGap/8qfXUa+L5vu4
-9vaxgQvBVcPXE/pyeCYM8beB84Us+FOYPC7gIUhcctBqGYAQmHzp3sXvIg0DVxz7
-0aqolFGpjRFqbgheS9WRkDHFpYrhR1XMVOQjussHqWEyRcvliqeFlZr8+JNkJNi+
-lmGMdnEAWZs8PL0/AEf+8y0Nr/w0k3Y6IZCDcwpxbpJQOU5pAbkfUzEJHkxMfuvW
-ZshvqIMOaLWCGxZaxlbLRxWGuarWYzfmDY3n9TwJmAIUdMLiswv3UsCmLBJO1XGX
-SUWfgi4fyG1/phfzhdU3efMvmN+XT16/ykMrY8P5S+ghwK12IZ3DgTl0ooLFABUj
-zYeQ8LLz3SP9LNgeLnPP/po=
------END CERTIFICATE-----
diff --git a/sensors/aidl/default/apex/apex_manifest.json b/sensors/aidl/default/apex_manifest.json
similarity index 100%
rename from sensors/aidl/default/apex/apex_manifest.json
rename to sensors/aidl/default/apex_manifest.json
diff --git a/sensors/aidl/default/apex/file_contexts b/sensors/aidl/default/file_contexts
similarity index 100%
rename from sensors/aidl/default/apex/file_contexts
rename to sensors/aidl/default/file_contexts
diff --git a/sensors/aidl/default/multihal/Android.bp b/sensors/aidl/default/multihal/Android.bp
index a20d6d7..40cb2d9 100644
--- a/sensors/aidl/default/multihal/Android.bp
+++ b/sensors/aidl/default/multihal/Android.bp
@@ -45,11 +45,6 @@
         "HalProxyAidl.cpp",
         "ConvertUtils.cpp",
     ],
-    visibility: [
-        ":__subpackages__",
-        "//hardware/interfaces/sensors/aidl/multihal:__subpackages__",
-        "//hardware/interfaces/tests/extension/sensors:__subpackages__",
-    ],
     static_libs: [
         "android.hardware.sensors@1.0-convert",
         "android.hardware.sensors@2.X-multihal",
diff --git a/sensors/aidl/default/sensors-default.rc b/sensors/aidl/default/sensors-default.rc
index 96da85d..e0b0ef0 100644
--- a/sensors/aidl/default/sensors-default.rc
+++ b/sensors/aidl/default/sensors-default.rc
@@ -1,4 +1,4 @@
-service vendor.sensors-default /vendor/bin/hw/android.hardware.sensors-service.example
+service vendor.sensors-default /apex/com.android.hardware.sensors/bin/hw/android.hardware.sensors-service.example
     class hal
     user system
     group system
diff --git a/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp b/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
index 618acbb..be11b87 100644
--- a/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
+++ b/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
@@ -41,6 +41,7 @@
 using aidl::android::hardware::sensors::SensorInfo;
 using aidl::android::hardware::sensors::SensorStatus;
 using aidl::android::hardware::sensors::SensorType;
+using aidl::android::hardware::sensors::AdditionalInfo;
 using android::ProcessState;
 using std::chrono::duration_cast;
 
@@ -629,6 +630,15 @@
     Event additionalInfoEvent;
     additionalInfoEvent.sensorType = SensorType::ADDITIONAL_INFO;
     additionalInfoEvent.timestamp = android::elapsedRealtimeNano();
+    AdditionalInfo info;
+    info.type = AdditionalInfo::AdditionalInfoType::AINFO_BEGIN;
+    info.serial = 1;
+    AdditionalInfo::AdditionalInfoPayload::Int32Values infoData;
+    for (int32_t i = 0; i < 14; i++) {
+        infoData.values[i] = i;
+    }
+    info.payload.set<AdditionalInfo::AdditionalInfoPayload::Tag::dataInt32>(infoData);
+    additionalInfoEvent.payload.set<Event::EventPayload::Tag::additional>(info);
 
     Event injectedEvent;
     injectedEvent.timestamp = android::elapsedRealtimeNano();
diff --git a/soundtrigger/aidl/Android.bp b/soundtrigger/aidl/Android.bp
index 27d43d3..aa400c1 100644
--- a/soundtrigger/aidl/Android.bp
+++ b/soundtrigger/aidl/Android.bp
@@ -22,8 +22,8 @@
         "android/hardware/soundtrigger3/ISoundTriggerHwGlobalCallback.aidl",
     ],
     stability: "vintf",
-    imports: [
-        "android.media.soundtrigger.types-V1",
+    defaults: [
+        "latest_android_media_soundtrigger_types_import_interface",
     ],
     backend: {
         cpp: {
@@ -34,6 +34,7 @@
             sdk_version: "module_current",
         },
     },
+    frozen: false,
     versions_with_info: [
         {
             version: "1",
@@ -45,7 +46,7 @@
 }
 
 // Note: This should always be one version ahead of the last frozen version
-latest_android_hardware_soundtrigger3 = "android.hardware.soundtrigger3-V1"
+latest_android_hardware_soundtrigger3 = "android.hardware.soundtrigger3-V2"
 
 // Modules that depend on android.hardware.soundtrigger3 directly can include
 // the following java_defaults to avoid explicitly managing dependency versions
@@ -56,3 +57,10 @@
         latest_android_hardware_soundtrigger3 + "-java",
     ],
 }
+
+cc_defaults {
+    name: "latest_android_hardware_soundtrigger3_ndk_shared",
+    shared_libs: [
+        latest_android_hardware_soundtrigger3 + "-ndk",
+    ],
+}
diff --git a/tests/multithread/1.0/default/Multithread.h b/tests/multithread/1.0/default/Multithread.h
index 0d4a007..7df75cc 100644
--- a/tests/multithread/1.0/default/Multithread.h
+++ b/tests/multithread/1.0/default/Multithread.h
@@ -33,7 +33,7 @@
     std::condition_variable mCv;
     std::mutex mCvMutex;
 
-    static constexpr auto kTimeoutDuration = 100ms;
+    static constexpr auto kTimeoutDuration = 1000ms;
 };
 
 extern "C" IMultithread* HIDL_FETCH_IMultithread(const char* name);
diff --git a/tetheroffload/config/1.0/Android.bp b/tetheroffload/config/1.0/Android.bp
index 116c9b6..b5c4185 100644
--- a/tetheroffload/config/1.0/Android.bp
+++ b/tetheroffload/config/1.0/Android.bp
@@ -19,4 +19,8 @@
         "android.hidl.base@1.0",
     ],
     gen_java: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.tethering",
+    ],
 }
diff --git a/tetheroffload/control/1.0/Android.bp b/tetheroffload/control/1.0/Android.bp
index acb5ee8..6589ee2 100644
--- a/tetheroffload/control/1.0/Android.bp
+++ b/tetheroffload/control/1.0/Android.bp
@@ -21,4 +21,8 @@
         "android.hidl.base@1.0",
     ],
     gen_java: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.tethering",
+    ],
 }
diff --git a/threadnetwork/aidl/Android.bp b/threadnetwork/aidl/Android.bp
index c621b81..7e674e0 100644
--- a/threadnetwork/aidl/Android.bp
+++ b/threadnetwork/aidl/Android.bp
@@ -15,9 +15,6 @@
             apex_available: [
                 "//apex_available:platform",
                 "com.android.tethering",
-                // Keep the threadnetwork apex to make it buildable on udc-mainline-prod.
-                // TODO: remove it after moving ot-daemon into tethering.
-                "com.android.threadnetwork",
             ],
             min_sdk_version: "30",
         },
diff --git a/tv/hdmi/cec/aidl/default/HdmiCecMock.cpp b/tv/hdmi/cec/aidl/default/HdmiCecMock.cpp
index 0212e7e..8a3c6f0 100644
--- a/tv/hdmi/cec/aidl/default/HdmiCecMock.cpp
+++ b/tv/hdmi/cec/aidl/default/HdmiCecMock.cpp
@@ -36,6 +36,7 @@
     ALOGE("HdmiCecMock died");
     auto hdmiCecMock = static_cast<HdmiCecMock*>(cookie);
     hdmiCecMock->mCecThreadRun = false;
+    pthread_join(hdmiCecMock->mThreadId, NULL);
 }
 
 ScopedAStatus HdmiCecMock::addLogicalAddress(CecLogicalAddress addr, Result* _aidl_return) {
@@ -89,7 +90,9 @@
     mCallback = callback;
 
     if (callback != nullptr) {
-        AIBinder_linkToDeath(this->asBinder().get(), mDeathRecipient.get(), 0 /* cookie */);
+        mDeathRecipient =
+                ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(serviceDied));
+        AIBinder_linkToDeath(callback->asBinder().get(), mDeathRecipient.get(), this /* cookie */);
 
         mInputFile = open(CEC_MSG_IN_FIFO, O_RDWR | O_CLOEXEC);
         mOutputFile = open(CEC_MSG_OUT_FIFO, O_RDWR | O_CLOEXEC);
@@ -220,7 +223,7 @@
     int r = -1;
 
     // Open the input pipe
-    while (mInputFile < 0) {
+    while (mCecThreadRun && mInputFile < 0) {
         usleep(1000 * 1000);
         mInputFile = open(CEC_MSG_IN_FIFO, O_RDONLY | O_CLOEXEC);
     }
@@ -257,7 +260,15 @@
 HdmiCecMock::HdmiCecMock() {
     ALOGE("[halimp_aidl] Opening a virtual CEC HAL for testing and virtual machine.");
     mCallback = nullptr;
-    mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(serviceDied));
+    mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(nullptr);
+}
+
+HdmiCecMock::~HdmiCecMock() {
+    ALOGE("[halimp_aidl] HdmiCecMock shutting down.");
+    mCallback = nullptr;
+    mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(nullptr);
+    mCecThreadRun = false;
+    pthread_join(mThreadId, NULL);
 }
 
 }  // namespace implementation
diff --git a/tv/hdmi/cec/aidl/default/HdmiCecMock.h b/tv/hdmi/cec/aidl/default/HdmiCecMock.h
index aca0581..e78b1cf 100644
--- a/tv/hdmi/cec/aidl/default/HdmiCecMock.h
+++ b/tv/hdmi/cec/aidl/default/HdmiCecMock.h
@@ -40,6 +40,7 @@
 
 struct HdmiCecMock : public BnHdmiCec {
     HdmiCecMock();
+    ~HdmiCecMock();
     ::ndk::ScopedAStatus addLogicalAddress(CecLogicalAddress addr, Result* _aidl_return) override;
     ::ndk::ScopedAStatus clearLogicalAddress() override;
     ::ndk::ScopedAStatus enableAudioReturnChannel(int32_t portId, bool enable) override;
diff --git a/tv/hdmi/connection/aidl/default/HdmiConnectionMock.cpp b/tv/hdmi/connection/aidl/default/HdmiConnectionMock.cpp
index 8f4411b..954982e 100644
--- a/tv/hdmi/connection/aidl/default/HdmiConnectionMock.cpp
+++ b/tv/hdmi/connection/aidl/default/HdmiConnectionMock.cpp
@@ -15,12 +15,11 @@
  */
 
 #define LOG_TAG "android.hardware.tv.hdmi.connection"
+#include "HdmiConnectionMock.h"
 #include <android-base/logging.h>
 #include <fcntl.h>
 #include <utils/Log.h>
 
-#include "HdmiConnectionMock.h"
-
 using ndk::ScopedAStatus;
 
 namespace android {
@@ -34,6 +33,7 @@
     ALOGE("HdmiConnectionMock died");
     auto hdmi = static_cast<HdmiConnectionMock*>(cookie);
     hdmi->mHdmiThreadRun = false;
+    pthread_join(hdmi->mThreadId, NULL);
 }
 
 ScopedAStatus HdmiConnectionMock::getPortInfo(std::vector<HdmiPortInfo>* _aidl_return) {
@@ -55,12 +55,15 @@
 ScopedAStatus HdmiConnectionMock::setCallback(
         const std::shared_ptr<IHdmiConnectionCallback>& callback) {
     if (mCallback != nullptr) {
+        stopThread();
         mCallback = nullptr;
     }
-
     if (callback != nullptr) {
         mCallback = callback;
-        AIBinder_linkToDeath(this->asBinder().get(), mDeathRecipient.get(), 0 /* cookie */);
+        mDeathRecipient =
+                ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(serviceDied));
+
+        AIBinder_linkToDeath(callback->asBinder().get(), mDeathRecipient.get(), this /* cookie */);
 
         mInputFile = open(HDMI_MSG_IN_FIFO, O_RDWR | O_CLOEXEC);
         pthread_create(&mThreadId, NULL, __threadLoop, this);
@@ -153,7 +156,7 @@
     int r = -1;
 
     // Open the input pipe
-    while (mInputFile < 0) {
+    while (mHdmiThreadRun && mInputFile < 0) {
         usleep(1000 * 1000);
         mInputFile = open(HDMI_MSG_IN_FIFO, O_RDONLY | O_CLOEXEC);
     }
@@ -193,7 +196,21 @@
                      .physicalAddress = mPhysicalAddress};
     mPortConnectionStatus[0] = false;
     mHpdSignal[0] = HpdSignal::HDMI_HPD_PHYSICAL;
-    mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(serviceDied));
+    mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(nullptr);
+}
+
+void HdmiConnectionMock::stopThread() {
+    if (mCallback != nullptr) {
+        ALOGE("[halimp_aidl] HdmiConnectionMock shutting down.");
+        mCallback = nullptr;
+        mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(nullptr);
+        mHdmiThreadRun = false;
+        pthread_join(mThreadId, NULL);
+    }
+}
+
+HdmiConnectionMock::~HdmiConnectionMock() {
+    stopThread();
 }
 
 }  // namespace implementation
diff --git a/tv/hdmi/connection/aidl/default/HdmiConnectionMock.h b/tv/hdmi/connection/aidl/default/HdmiConnectionMock.h
index c013fdd..8c66f08 100644
--- a/tv/hdmi/connection/aidl/default/HdmiConnectionMock.h
+++ b/tv/hdmi/connection/aidl/default/HdmiConnectionMock.h
@@ -41,7 +41,7 @@
 
 struct HdmiConnectionMock : public BnHdmiConnection {
     HdmiConnectionMock();
-
+    ~HdmiConnectionMock();
     ::ndk::ScopedAStatus getPortInfo(std::vector<HdmiPortInfo>* _aidl_return) override;
     ::ndk::ScopedAStatus isConnected(int32_t portId, bool* _aidl_return) override;
     ::ndk::ScopedAStatus setCallback(
@@ -56,6 +56,7 @@
     void threadLoop();
     int readMessageFromFifo(unsigned char* buf, int msgCount);
     void handleHotplugMessage(unsigned char* msgBuf);
+    void stopThread();
 
   private:
     static void serviceDied(void* cookie);
diff --git a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
index fccd2ed..3d60e89 100644
--- a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
+++ b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
@@ -35,6 +35,7 @@
     ASSERT_TRUE(mFrontendTests.setFrontendCallback());
     ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
     ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+    mFrontendTests.setDemux(demux);
     mFilterTests.setDemux(demux);
     ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.config1_0.type,
                                                filterConf.config1_0.bufferSize));
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
index 3664b6c..766814f 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
@@ -48,6 +48,7 @@
     ASSERT_TRUE(mFrontendTests.setFrontendCallback());
     ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
     ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+    mFrontendTests.setDemux(demux);
     mFilterTests.setDemux(demux);
     ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize));
     ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId_64bit(filterId));
@@ -1197,6 +1198,10 @@
     vector<ScanHardwareConnections> scan_configs = generateScanConfigurations();
     for (auto& configuration : scan_configs) {
         scan = configuration;
+        // Skip test if the frontend implementation doesn't support blind scan
+        if (!frontendMap[scan.frontendId].supportBlindScan) {
+            continue;
+        }
         mFrontendTests.scanTest(frontendMap[scan.frontendId], FrontendScanType::SCAN_BLIND);
     }
 }
@@ -1221,6 +1226,10 @@
     vector<ScanHardwareConnections> scan_configs = generateScanConfigurations();
     for (auto& configuration : scan_configs) {
         scan = configuration;
+        // Skip test if the frontend implementation doesn't support blind scan
+        if (!frontendMap[scan.frontendId].supportBlindScan) {
+            continue;
+        }
         mFrontendTests.scanTest(frontendMap[scan.frontendId], FrontendScanType::SCAN_BLIND);
     }
 }
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
index 516cb62..5c13ed0 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
@@ -612,6 +612,7 @@
     frontendMap[defaultFeId].isSoftwareFe = true;
     frontendMap[defaultFeId].canConnectToCiCam = true;
     frontendMap[defaultFeId].ciCamId = 0;
+    frontendMap[defaultFeId].supportBlindScan = true;
     FrontendDvbtSettings dvbt;
     dvbt.transmissionMode = FrontendDvbtTransmissionMode::MODE_8K_E;
     frontendMap[defaultFeId].settings.set<FrontendSettings::Tag::dvbt>(dvbt);
diff --git a/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h b/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
index 9517520..5ffb38f 100644
--- a/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
+++ b/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
@@ -114,6 +114,7 @@
     FrontendSettings settings;
     vector<FrontendStatusType> tuneStatusTypes;
     vector<FrontendStatus> expectTuneStatuses;
+    bool supportBlindScan;
 };
 
 struct FilterConfig {
@@ -354,6 +355,11 @@
                 } else {
                     hasHwFe = true;
                 }
+                if (feConfig.hasSupportBlindScan()) {
+                    frontendMap[id].supportBlindScan = feConfig.getSupportBlindScan();
+                } else {
+                    frontendMap[id].supportBlindScan = true;
+                }
                 // TODO: b/182519645 complete the tune status config
                 frontendMap[id].tuneStatusTypes = types;
                 frontendMap[id].expectTuneStatuses = statuses;
diff --git a/tv/tuner/config/api/current.txt b/tv/tuner/config/api/current.txt
index dbd3486..ff2df90 100644
--- a/tv/tuner/config/api/current.txt
+++ b/tv/tuner/config/api/current.txt
@@ -369,6 +369,7 @@
     method @Nullable public android.media.tuner.testing.configuration.V1_0.IsdbsFrontendSettings getIsdbsFrontendSettings_optional();
     method @Nullable public android.media.tuner.testing.configuration.V1_0.IsdbtFrontendSettings getIsdbtFrontendSettings_optional();
     method @Nullable public java.math.BigInteger getRemoveOutputPid();
+    method @Nullable public boolean getSupportBlindScan();
     method @Nullable public android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum getType();
     method public void setAtscFrontendSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.AtscFrontendSettings);
     method public void setConnectToCicamId(@Nullable java.math.BigInteger);
@@ -381,6 +382,7 @@
     method public void setIsdbsFrontendSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.IsdbsFrontendSettings);
     method public void setIsdbtFrontendSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.IsdbtFrontendSettings);
     method public void setRemoveOutputPid(@Nullable java.math.BigInteger);
+    method public void setSupportBlindScan(@Nullable boolean);
     method public void setType(@Nullable android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum);
   }
 
diff --git a/tv/tuner/config/tuner_testing_dynamic_configuration.xsd b/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
index c51ac51..eafaca9 100644
--- a/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
+++ b/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
@@ -162,6 +162,7 @@
         <xs:attribute name="connectToCicamId" type="xs:nonNegativeInteger" use="optional"/>
         <xs:attribute name="removeOutputPid" type="xs:nonNegativeInteger" use="optional"/>
         <xs:attribute name="endFrequency" type="xs:nonNegativeInteger" use="optional"/>
+        <xs:attribute name="supportBlindScan" type="xs:boolean" use="optional"/>
     </xs:complexType>
 
     <!-- FILTER SESSION -->
diff --git a/uwb/aidl/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 21951b6..58919d1 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
@@ -46,6 +46,7 @@
   CCC_SUPPORTED_MAX_RANGING_SESSION_NUMBER = 0xA8,
   CCC_SUPPORTED_MIN_UWB_INITIATION_TIME_MS = 0xA9,
   CCC_PRIORITIZED_CHANNEL_LIST = 0xAA,
+  CCC_SUPPORTED_UWBS_MAX_PPM = 0xAB,
   RADAR_SUPPORT = 0xB0,
   SUPPORTED_AOA_RESULT_REQ_ANTENNA_INTERLEAVING = 0xE3,
   SUPPORTED_MIN_RANGING_INTERVAL_MS = 0xE4,
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
index 2141b5a..4df45b6 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -154,6 +154,11 @@
      */
     CCC_PRIORITIZED_CHANNEL_LIST = 0xAA,
 
+    /**
+     * Short (2-octet) value to indicate the UWBS Max Clock Skew PPM value.
+     */
+    CCC_SUPPORTED_UWBS_MAX_PPM = 0xAB,
+
     /*********************************************
      * RADAR specific
      ********************************************/
diff --git a/uwb/aidl/default/Android.bp b/uwb/aidl/default/Android.bp
index f9b79de..8af1678 100644
--- a/uwb/aidl/default/Android.bp
+++ b/uwb/aidl/default/Android.bp
@@ -24,6 +24,8 @@
         "libtokio_util",
         "libnix",
         "libanyhow",
+        "libpdl_runtime",
+        "libuwb_uci_packets",
     ],
     proc_macros: [
         "libasync_trait",
diff --git a/uwb/aidl/default/src/uwb_chip.rs b/uwb/aidl/default/src/uwb_chip.rs
index 2b8e481..d1c3c67 100644
--- a/uwb/aidl/default/src/uwb_chip.rs
+++ b/uwb/aidl/default/src/uwb_chip.rs
@@ -14,9 +14,11 @@
 
 use std::fs::{File, OpenOptions};
 use std::io::{self, Read, Write};
-use std::os::fd::AsRawFd;
 use std::os::unix::fs::OpenOptionsExt;
 
+use pdl_runtime::Packet;
+use uwb_uci_packets::{DeviceResetCmdBuilder, ResetConfig, UciControlPacket, UciControlPacketHal};
+
 enum State {
     Closed,
     Opened {
@@ -47,11 +49,37 @@
 impl State {
     /// Terminate the reader task.
     async fn close(&mut self) -> Result<()> {
-        if let State::Opened { ref mut token, ref callbacks, ref mut death_recipient, ref mut handle, .. } = *self {
+        if let State::Opened {
+            ref mut token,
+            ref callbacks,
+            ref mut death_recipient,
+            ref mut handle,
+            ref mut serial,
+        } = *self
+        {
             log::info!("waiting for task cancellation");
             callbacks.as_binder().unlink_to_death(death_recipient)?;
             token.cancel();
             handle.await.unwrap();
+            let packet: UciControlPacket = DeviceResetCmdBuilder {
+                reset_config: ResetConfig::UwbsReset,
+            }
+            .build()
+            .into();
+            // DeviceResetCmd need to be send to reset the device to stop all running
+            // activities on UWBS.
+            let packet_vec: Vec<UciControlPacketHal> = packet.into();
+            for hal_packet in packet_vec.into_iter() {
+                serial
+                    .write(&hal_packet.to_vec())
+                    .map(|written| written as i32)
+                    .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
+            }
+            consume_device_reset_rsp_and_ntf(
+                &mut serial
+                    .try_clone()
+                    .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?,
+            );
             log::info!("task successfully cancelled");
             callbacks.onHalEvent(UwbEvent::CLOSE_CPLT, UwbStatus::OK)?;
             *self = State::Closed;
@@ -60,14 +88,26 @@
     }
 }
 
-pub fn makeraw(file: File) -> io::Result<File> {
-    let fd = file.as_raw_fd();
+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();
 
-    // Configure the file descritpro as raw fd.
+    // Make sure received packets are the expected ones.
+    assert_eq!(&buffer[0..DEVICE_RESET_RSP.len()], &DEVICE_RESET_RSP);
+    assert_eq!(&buffer[DEVICE_RESET_RSP.len()..], &DEVICE_STATUS_NTF);
+}
+
+pub fn makeraw(file: File) -> io::Result<File> {
+    // Configure the file descriptor as raw fd.
     use nix::sys::termios::*;
-    let mut attrs = tcgetattr(fd)?;
+    let mut attrs = tcgetattr(&file)?;
     cfmakeraw(&mut attrs);
-    tcsetattr(fd, SetArg::TCSANOW, &attrs)?;
+    tcsetattr(&file, SetArg::TCSANOW, &attrs)?;
 
     Ok(file)
 }
@@ -212,7 +252,7 @@
 
         let mut state = self.state.lock().await;
 
-        if matches!(*state, State::Opened { .. }) {
+        if let State::Opened { .. } = *state {
             state.close().await
         } else {
             Err(binder::ExceptionCode::ILLEGAL_STATE.into())
diff --git a/wifi/aidl/default/aidl_struct_util.cpp b/wifi/aidl/default/aidl_struct_util.cpp
index 7bc2eeb..83e1193 100644
--- a/wifi/aidl/default/aidl_struct_util.cpp
+++ b/wifi/aidl/default/aidl_struct_util.cpp
@@ -887,6 +887,15 @@
     return true;
 }
 
+StaLinkLayerLinkStats::StaLinkState convertLegacyMlLinkStateToAidl(wifi_link_state state) {
+    if (state == wifi_link_state::WIFI_LINK_STATE_NOT_IN_USE) {
+        return StaLinkLayerLinkStats::StaLinkState::NOT_IN_USE;
+    } else if (state == wifi_link_state::WIFI_LINK_STATE_IN_USE) {
+        return StaLinkLayerLinkStats::StaLinkState::IN_USE;
+    }
+    return StaLinkLayerLinkStats::StaLinkState::UNKNOWN;
+}
+
 bool convertLegacyLinkLayerMlStatsToAidl(const legacy_hal::LinkLayerMlStats& legacy_ml_stats,
                                          StaLinkLayerStats* aidl_stats) {
     if (!aidl_stats) {
@@ -898,6 +907,7 @@
     for (const auto& link : legacy_ml_stats.links) {
         StaLinkLayerLinkStats linkStats = {};
         linkStats.linkId = link.stat.link_id;
+        linkStats.state = convertLegacyMlLinkStateToAidl(link.stat.state);
         linkStats.radioId = link.stat.radio;
         linkStats.frequencyMhz = link.stat.frequency;
         linkStats.beaconRx = link.stat.beacon_rx;
diff --git a/wifi/aidl/default/tests/aidl_struct_util_unit_tests.cpp b/wifi/aidl/default/tests/aidl_struct_util_unit_tests.cpp
index 5c334f8..995a13d 100644
--- a/wifi/aidl/default/tests/aidl_struct_util_unit_tests.cpp
+++ b/wifi/aidl/default/tests/aidl_struct_util_unit_tests.cpp
@@ -123,6 +123,9 @@
     // Add two radio stats
     legacy_ml_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
     legacy_ml_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
+    wifi_link_state states[sizeof(wifi_link_state)] = {wifi_link_state::WIFI_LINK_STATE_UNKNOWN,
+                                                       wifi_link_state::WIFI_LINK_STATE_NOT_IN_USE,
+                                                       wifi_link_state::WIFI_LINK_STATE_IN_USE};
     // Add two links.
     legacy_ml_stats.links.push_back(legacy_hal::LinkStats{});
     legacy_ml_stats.links.push_back(legacy_hal::LinkStats{});
@@ -133,6 +136,7 @@
         link.stat.beacon_rx = rand();
         // MLO link id: 0 - 15
         link.stat.link_id = rand() % 16;
+        link.stat.state = states[rand() % sizeof(states)];
         // Maximum number of radios is limited to 3 for testing.
         link.stat.radio = rand() % 4;
         link.stat.frequency = rand();
@@ -241,6 +245,18 @@
     int l = 0;
     for (legacy_hal::LinkStats& link : legacy_ml_stats.links) {
         EXPECT_EQ(link.stat.link_id, (uint8_t)converted.iface.links[l].linkId);
+        StaLinkLayerLinkStats::StaLinkState expectedState;
+        switch (link.stat.state) {
+            case wifi_link_state::WIFI_LINK_STATE_NOT_IN_USE:
+                expectedState = StaLinkLayerLinkStats::StaLinkState::NOT_IN_USE;
+                break;
+            case wifi_link_state::WIFI_LINK_STATE_IN_USE:
+                expectedState = StaLinkLayerLinkStats::StaLinkState::IN_USE;
+                break;
+            default:
+                expectedState = StaLinkLayerLinkStats::StaLinkState::UNKNOWN;
+        }
+        EXPECT_EQ(expectedState, converted.iface.links[l].state);
         EXPECT_EQ(link.stat.radio, converted.iface.links[l].radioId);
         EXPECT_EQ(link.stat.frequency, (uint32_t)converted.iface.links[l].frequencyMhz);
         EXPECT_EQ(link.stat.beacon_rx, (uint32_t)converted.iface.links[l].beaconRx);
diff --git a/wifi/aidl/default/wifi_chip.cpp b/wifi/aidl/default/wifi_chip.cpp
index 6dd9156..8265e5b 100644
--- a/wifi/aidl/default/wifi_chip.cpp
+++ b/wifi/aidl/default/wifi_chip.cpp
@@ -1452,14 +1452,24 @@
     if (legacy_status != legacy_hal::WIFI_SUCCESS) {
         LOG(ERROR) << "Failed to get SupportedRadioCombinations matrix from legacy HAL: "
                    << legacyErrorToString(legacy_status);
+        if (legacy_matrix != nullptr) {
+            free(legacy_matrix);
+        }
         return {aidl_combinations, createWifiStatusFromLegacyError(legacy_status)};
     }
 
     if (!aidl_struct_util::convertLegacyRadioCombinationsMatrixToAidl(legacy_matrix,
                                                                       &aidl_combinations)) {
         LOG(ERROR) << "Failed convertLegacyRadioCombinationsMatrixToAidl() ";
+        if (legacy_matrix != nullptr) {
+            free(legacy_matrix);
+        }
         return {aidl_combinations, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
     }
+
+    if (legacy_matrix != nullptr) {
+        free(legacy_matrix);
+    }
     return {aidl_combinations, ndk::ScopedAStatus::ok()};
 }
 
diff --git a/wifi/netlinkinterceptor/aidl/default/Android.bp b/wifi/netlinkinterceptor/aidl/default/Android.bp
index 5227e51..c3a0c03 100644
--- a/wifi/netlinkinterceptor/aidl/default/Android.bp
+++ b/wifi/netlinkinterceptor/aidl/default/Android.bp
@@ -25,8 +25,6 @@
 
 cc_binary {
     name: "android.hardware.net.nlinterceptor-service.default",
-    init_rc: ["nlinterceptor-default.rc"],
-    vintf_fragments: ["nlinterceptor-default.xml"],
     vendor: true,
     relative_install_path: "hw",
     defaults: ["nlinterceptor@defaults"],
@@ -45,4 +43,35 @@
         "service.cpp",
         "util.cpp",
     ],
+    installable: false, // installed in APEX
+}
+
+apex {
+    name: "com.android.hardware.net.nlinterceptor",
+    vendor: true,
+    manifest: "apex_manifest.json",
+    file_contexts: "apex_file_contexts",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    updatable: false,
+    binaries: [
+        "android.hardware.net.nlinterceptor-service.default",
+    ],
+    prebuilts: [
+        "nlinterceptor.rc",
+        "nlinterceptor.xml",
+    ],
+}
+
+prebuilt_etc {
+    name: "nlinterceptor.rc",
+    src: "nlinterceptor.rc",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "nlinterceptor.xml",
+    src: "nlinterceptor.xml",
+    sub_dir: "vintf",
+    installable: false,
 }
diff --git a/wifi/netlinkinterceptor/aidl/default/apex_file_contexts b/wifi/netlinkinterceptor/aidl/default/apex_file_contexts
new file mode 100644
index 0000000..6ee544c
--- /dev/null
+++ b/wifi/netlinkinterceptor/aidl/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                                          u:object_r:vendor_file:s0
+/etc(/.*)?                                                      u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.net\.nlinterceptor-service\.default	u:object_r:hal_nlinterceptor_default_exec:s0
diff --git a/wifi/netlinkinterceptor/aidl/default/apex_manifest.json b/wifi/netlinkinterceptor/aidl/default/apex_manifest.json
new file mode 100644
index 0000000..4ffeac5
--- /dev/null
+++ b/wifi/netlinkinterceptor/aidl/default/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.net.nlinterceptor",
+    "version": 1
+}
diff --git a/wifi/netlinkinterceptor/aidl/default/nlinterceptor-default.rc b/wifi/netlinkinterceptor/aidl/default/nlinterceptor-default.rc
deleted file mode 100644
index 353cb27..0000000
--- a/wifi/netlinkinterceptor/aidl/default/nlinterceptor-default.rc
+++ /dev/null
@@ -1,4 +0,0 @@
-service nlinterceptor /vendor/bin/hw/android.hardware.net.nlinterceptor-service.default
-    class hal
-    user root
-    group system inet
diff --git a/wifi/netlinkinterceptor/aidl/default/nlinterceptor.rc b/wifi/netlinkinterceptor/aidl/default/nlinterceptor.rc
new file mode 100644
index 0000000..ec9baa9
--- /dev/null
+++ b/wifi/netlinkinterceptor/aidl/default/nlinterceptor.rc
@@ -0,0 +1,4 @@
+service nlinterceptor /apex/com.android.hardware.net.nlinterceptor/bin/hw/android.hardware.net.nlinterceptor-service.default
+    class hal
+    user root
+    group system inet
diff --git a/wifi/netlinkinterceptor/aidl/default/nlinterceptor-default.xml b/wifi/netlinkinterceptor/aidl/default/nlinterceptor.xml
similarity index 100%
rename from wifi/netlinkinterceptor/aidl/default/nlinterceptor-default.xml
rename to wifi/netlinkinterceptor/aidl/default/nlinterceptor.xml