Merge "Add stride query"
diff --git a/audio/OWNERS b/audio/OWNERS
index ede448c..3671685 100644
--- a/audio/OWNERS
+++ b/audio/OWNERS
@@ -1 +1,4 @@
-per-file README.md = elaurent@google.com,mnaganov@google.com
+# Bug component: 48436
+
+elaurent@google.com
+mnaganov@google.com
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index 05c7649..e69306e 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -41,6 +41,7 @@
         "android/hardware/audio/common/SinkMetadata.aidl",
         "android/hardware/audio/common/SourceMetadata.aidl",
     ],
+    frozen: true,
     imports: [
         "android.media.audio.common.types-V2",
     ],
@@ -111,11 +112,14 @@
         "android/hardware/audio/core/AudioMode.aidl",
         "android/hardware/audio/core/AudioPatch.aidl",
         "android/hardware/audio/core/AudioRoute.aidl",
+        "android/hardware/audio/core/IBluetooth.aidl",
         "android/hardware/audio/core/IConfig.aidl",
         "android/hardware/audio/core/IModule.aidl",
         "android/hardware/audio/core/IStreamCallback.aidl",
+        "android/hardware/audio/core/IStreamCommon.aidl",
         "android/hardware/audio/core/IStreamIn.aidl",
         "android/hardware/audio/core/IStreamOut.aidl",
+        "android/hardware/audio/core/IStreamOutEventCallback.aidl",
         "android/hardware/audio/core/ITelephony.aidl",
         "android/hardware/audio/core/MicrophoneDynamicInfo.aidl",
         "android/hardware/audio/core/MicrophoneInfo.aidl",
@@ -123,11 +127,14 @@
         "android/hardware/audio/core/ModuleDebug.aidl",
         "android/hardware/audio/core/StreamDescriptor.aidl",
         "android/hardware/audio/core/SurroundSoundConfig.aidl",
+        "android/hardware/audio/core/VendorParameter.aidl",
     ],
     imports: [
         "android.hardware.common-V2",
         "android.hardware.common.fmq-V1",
         "android.hardware.audio.common-V1",
+        "android.hardware.audio.core.sounddose-V1",
+        "android.hardware.audio.effect-V1",
         "android.media.audio.common.types-V2",
     ],
     backend: {
@@ -165,12 +172,61 @@
     ],
 }
 
+// Used for the standalone sounddose HAL
+aidl_interface {
+    name: "android.hardware.audio.core.sounddose",
+    defaults: [
+        "android.hardware.audio_defaults",
+    ],
+    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: {
+            enabled: false,
+        },
+        java: {
+            sdk_version: "module_current",
+        },
+    },
+    versions_with_info: [
+        // IMPORTANT: Update latest_android_hardware_audio_core_sounddose every time you
+        // add the latest frozen version to versions_with_info
+    ],
+}
+
+// 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"
+
+// Modules that depend on android.hardware.audio.core.sounddose directly can include
+// the following cc_defaults to avoid explicitly managing dependency versions
+// across many scattered files.
+cc_defaults {
+    name: "latest_android_hardware_audio_core_sounddose_ndk_shared",
+    shared_libs: [
+        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 {
     name: "android.hardware.audio.effect",
     defaults: [
         "android.hardware.audio_defaults",
     ],
     srcs: [
+        "android/hardware/audio/effect/AcousticEchoCanceler.aidl",
+        "android/hardware/audio/effect/AutomaticGainControl.aidl",
         "android/hardware/audio/effect/BassBoost.aidl",
         "android/hardware/audio/effect/Capability.aidl",
         "android/hardware/audio/effect/CommandId.aidl",
@@ -184,6 +240,7 @@
         "android/hardware/audio/effect/IEffect.aidl",
         "android/hardware/audio/effect/IFactory.aidl",
         "android/hardware/audio/effect/LoudnessEnhancer.aidl",
+        "android/hardware/audio/effect/NoiseSuppression.aidl",
         "android/hardware/audio/effect/Parameter.aidl",
         "android/hardware/audio/effect/PresetReverb.aidl",
         "android/hardware/audio/effect/Processing.aidl",
diff --git a/audio/aidl/OWNERS b/audio/aidl/OWNERS
deleted file mode 100644
index f9a2d6b..0000000
--- a/audio/aidl/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 48436
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/aidl/TEST_MAPPING b/audio/aidl/TEST_MAPPING
index 484320f..a166e61 100644
--- a/audio/aidl/TEST_MAPPING
+++ b/audio/aidl/TEST_MAPPING
@@ -10,10 +10,40 @@
       "name": "VtsHalAudioEffectTargetTest"
     },
     {
+      "name": "VtsHalDownmixTargetTest"
+    },
+    {
+      "name": "VtsHalEnvironmentalReverbTargetTest"
+    },
+    {
       "name": "VtsHalEqualizerTargetTest"
     },
     {
+      "name": "VtsHalHapticGeneratorTargetTest"
+    },
+    {
       "name": "VtsHalLoudnessEnhancerTargetTest"
+    },
+    {
+      "name": "VtsHalPresetReverbTargetTest"
+    },
+    {
+      "name": "VtsHalVirtualizerTargetTest"
+    },
+    {
+      "name": "VtsHalVisualizerTargetTest"
+    },
+    {
+      "name": "VtsHalVolumeTargetTest"
+    },
+    {
+      "name": "VtsHalAECTargetTest"
+    },
+    {
+      "name": "VtsHalAGCTargetTest"
+    },
+    {
+      "name": "VtsHalNSTargetTest"
     }
   ]
 }
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/sounddose/ISoundDose.aidl b/audio/aidl/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/sounddose/ISoundDose.aidl
new file mode 100644
index 0000000..3b5d2d0
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/sounddose/ISoundDose.aidl
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.core.sounddose;
+@VintfStability
+interface ISoundDose {
+  void setOutputRs2(float rs2ValueDbA);
+  float getOutputRs2();
+  void registerSoundDoseCallback(in android.hardware.audio.core.sounddose.ISoundDose.IHalSoundDoseCallback callback);
+  const int DEFAULT_MAX_RS2 = 100;
+  const int MIN_RS2 = 80;
+  @VintfStability
+  interface IHalSoundDoseCallback {
+    oneway void onMomentaryExposureWarning(float currentDbA, in android.media.audio.common.AudioDevice audioDevice);
+    oneway void onNewMelValues(in android.hardware.audio.core.sounddose.ISoundDose.IHalSoundDoseCallback.MelRecord melRecord, in android.media.audio.common.AudioDevice audioDevice);
+    @VintfStability
+    parcelable MelRecord {
+      float[] melValues;
+      long timestamp;
+    }
+  }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IBluetooth.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IBluetooth.aidl
new file mode 100644
index 0000000..289c0c2
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IBluetooth.aidl
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.core;
+@VintfStability
+interface IBluetooth {
+  android.hardware.audio.core.IBluetooth.ScoConfig setScoConfig(in android.hardware.audio.core.IBluetooth.ScoConfig config);
+  android.hardware.audio.core.IBluetooth.HfpConfig setHfpConfig(in android.hardware.audio.core.IBluetooth.HfpConfig config);
+  @JavaDerive(equals=true, toString=true) @VintfStability
+  parcelable ScoConfig {
+    @nullable android.media.audio.common.Boolean isEnabled;
+    @nullable android.media.audio.common.Boolean isNrecEnabled;
+    android.hardware.audio.core.IBluetooth.ScoConfig.Mode mode = android.hardware.audio.core.IBluetooth.ScoConfig.Mode.UNSPECIFIED;
+    @nullable @utf8InCpp String debugName;
+    @VintfStability
+    enum Mode {
+      UNSPECIFIED = 0,
+      SCO = 1,
+      SCO_WB = 2,
+      SCO_SWB = 3,
+    }
+  }
+  @JavaDerive(equals=true, toString=true) @VintfStability
+  parcelable HfpConfig {
+    @nullable android.media.audio.common.Boolean isEnabled;
+    @nullable android.media.audio.common.Int sampleRate;
+    @nullable android.media.audio.common.Float volume;
+    const int VOLUME_MIN = 0;
+    const int VOLUME_MAX = 1;
+  }
+}
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 0c7ca27..4486b66 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
@@ -36,6 +36,7 @@
 interface IModule {
   void setModuleDebug(in android.hardware.audio.core.ModuleDebug debug);
   @nullable android.hardware.audio.core.ITelephony getTelephony();
+  @nullable android.hardware.audio.core.IBluetooth getBluetooth();
   android.media.audio.common.AudioPort connectExternalDevice(in android.media.audio.common.AudioPort templateIdAndAdditionalData);
   void disconnectExternalDevice(int portId);
   android.hardware.audio.core.AudioPatch[] getAudioPatches();
@@ -46,6 +47,7 @@
   android.hardware.audio.core.AudioRoute[] getAudioRoutesForAudioPort(int portId);
   android.hardware.audio.core.IModule.OpenInputStreamReturn openInputStream(in android.hardware.audio.core.IModule.OpenInputStreamArguments args);
   android.hardware.audio.core.IModule.OpenOutputStreamReturn openOutputStream(in android.hardware.audio.core.IModule.OpenOutputStreamArguments args);
+  android.hardware.audio.core.IModule.SupportedPlaybackRateFactors getSupportedPlaybackRateFactors();
   android.hardware.audio.core.AudioPatch setAudioPatch(in android.hardware.audio.core.AudioPatch requested);
   boolean setAudioPortConfig(in android.media.audio.common.AudioPortConfig requested, out android.media.audio.common.AudioPortConfig suggested);
   void resetAudioPatch(int patchId);
@@ -60,6 +62,12 @@
   void updateAudioMode(android.hardware.audio.core.AudioMode mode);
   void updateScreenRotation(android.hardware.audio.core.IModule.ScreenRotation rotation);
   void updateScreenState(boolean isTurnedOn);
+  @nullable android.hardware.audio.core.sounddose.ISoundDose getSoundDose();
+  int generateHwAvSyncId();
+  android.hardware.audio.core.VendorParameter[] getVendorParameters(in @utf8InCpp String[] ids);
+  void setVendorParameters(in android.hardware.audio.core.VendorParameter[] parameters, boolean async);
+  void addDeviceEffect(int portConfigId, in android.hardware.audio.effect.IEffect effect);
+  void removeDeviceEffect(int portConfigId, in android.hardware.audio.effect.IEffect effect);
   @VintfStability
   parcelable OpenInputStreamArguments {
     int portConfigId;
@@ -78,12 +86,20 @@
     @nullable android.media.audio.common.AudioOffloadInfo offloadInfo;
     long bufferSizeFrames;
     @nullable android.hardware.audio.core.IStreamCallback callback;
+    @nullable android.hardware.audio.core.IStreamOutEventCallback eventCallback;
   }
   @VintfStability
   parcelable OpenOutputStreamReturn {
     android.hardware.audio.core.IStreamOut stream;
     android.hardware.audio.core.StreamDescriptor desc;
   }
+  @VintfStability
+  parcelable SupportedPlaybackRateFactors {
+    float minSpeed;
+    float maxSpeed;
+    float minPitch;
+    float maxPitch;
+  }
   @Backing(type="int") @VintfStability
   enum ScreenRotation {
     DEG_0 = 0,
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamCommon.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamCommon.aidl
new file mode 100644
index 0000000..f0bf100
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamCommon.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.core;
+@VintfStability
+interface IStreamCommon {
+  void close();
+  void updateHwAvSyncId(int hwAvSyncId);
+  android.hardware.audio.core.VendorParameter[] getVendorParameters(in @utf8InCpp String[] ids);
+  void setVendorParameters(in android.hardware.audio.core.VendorParameter[] parameters, boolean async);
+  void addEffect(in android.hardware.audio.effect.IEffect effect);
+  void removeEffect(in android.hardware.audio.effect.IEffect effect);
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl
index e9c727f..1041943 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl
@@ -34,16 +34,20 @@
 package android.hardware.audio.core;
 @VintfStability
 interface IStreamIn {
-  void close();
+  android.hardware.audio.core.IStreamCommon getStreamCommon();
   android.hardware.audio.core.MicrophoneDynamicInfo[] getActiveMicrophones();
   android.hardware.audio.core.IStreamIn.MicrophoneDirection getMicrophoneDirection();
   void setMicrophoneDirection(android.hardware.audio.core.IStreamIn.MicrophoneDirection direction);
   float getMicrophoneFieldDimension();
   void setMicrophoneFieldDimension(float zoom);
   void updateMetadata(in android.hardware.audio.common.SinkMetadata sinkMetadata);
-  const int MIC_FIELD_DIMENSION_WIDE_ANGLE = -1;
+  float[] getHwGain();
+  void setHwGain(in float[] channelGains);
+  const int MIC_FIELD_DIMENSION_WIDE_ANGLE = (-1);
   const int MIC_FIELD_DIMENSION_NO_ZOOM = 0;
   const int MIC_FIELD_DIMENSION_MAX_ZOOM = 1;
+  const int HW_GAIN_MIN = 0;
+  const int HW_GAIN_MAX = 1;
   @Backing(type="int") @VintfStability
   enum MicrophoneDirection {
     UNSPECIFIED = 0,
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOut.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOut.aidl
index 3021d94..46acc11 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOut.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOut.aidl
@@ -34,6 +34,20 @@
 package android.hardware.audio.core;
 @VintfStability
 interface IStreamOut {
-  void close();
+  android.hardware.audio.core.IStreamCommon getStreamCommon();
   void updateMetadata(in android.hardware.audio.common.SourceMetadata sourceMetadata);
+  float[] getHwVolume();
+  void setHwVolume(in float[] channelVolumes);
+  float getAudioDescriptionMixLevel();
+  void setAudioDescriptionMixLevel(float leveldB);
+  android.media.audio.common.AudioDualMonoMode getDualMonoMode();
+  void setDualMonoMode(android.media.audio.common.AudioDualMonoMode mode);
+  android.media.audio.common.AudioLatencyMode[] getRecommendedLatencyModes();
+  void setLatencyMode(android.media.audio.common.AudioLatencyMode mode);
+  android.media.audio.common.AudioPlaybackRate getPlaybackRateParameters();
+  void setPlaybackRateParameters(in android.media.audio.common.AudioPlaybackRate playbackRate);
+  void selectPresentation(int presentationId, int programId);
+  const int HW_VOLUME_MIN = 0;
+  const int HW_VOLUME_MAX = 1;
+  const int AUDIO_DESCRIPTION_MIX_LEVEL_MAX = 48;
 }
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOutEventCallback.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOutEventCallback.aidl
new file mode 100644
index 0000000..31cf0b7
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOutEventCallback.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.core;
+@VintfStability
+interface IStreamOutEventCallback {
+  oneway void onCodecFormatChanged(in byte[] audioMetadata);
+  oneway void onRecommendedLatencyModeChanged(in android.media.audio.common.AudioLatencyMode[] modes);
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.aidl
index a8c58c1..77063df 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.aidl
@@ -36,4 +36,21 @@
 interface ITelephony {
   android.hardware.audio.core.AudioMode[] getSupportedAudioModes();
   void switchAudioMode(android.hardware.audio.core.AudioMode mode);
+  android.hardware.audio.core.ITelephony.TelecomConfig setTelecomConfig(in android.hardware.audio.core.ITelephony.TelecomConfig config);
+  @JavaDerive(equals=true, toString=true) @VintfStability
+  parcelable TelecomConfig {
+    @nullable android.media.audio.common.Float voiceVolume;
+    android.hardware.audio.core.ITelephony.TelecomConfig.TtyMode ttyMode = android.hardware.audio.core.ITelephony.TelecomConfig.TtyMode.UNSPECIFIED;
+    @nullable android.media.audio.common.Boolean isHacEnabled;
+    const int VOICE_VOLUME_MIN = 0;
+    const int VOICE_VOLUME_MAX = 1;
+    @Backing(type="int") @VintfStability
+    enum TtyMode {
+      UNSPECIFIED = (-1),
+      OFF = 0,
+      FULL = 1,
+      HCO = 2,
+      VCO = 3,
+    }
+  }
 }
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneInfo.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneInfo.aidl
index 68c7f88..b77afe3 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneInfo.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneInfo.aidl
@@ -37,15 +37,15 @@
   @utf8InCpp String id;
   android.media.audio.common.AudioDevice device;
   android.hardware.audio.core.MicrophoneInfo.Location location = android.hardware.audio.core.MicrophoneInfo.Location.UNKNOWN;
-  int group = -1;
-  int indexInTheGroup = -1;
+  int group = GROUP_UNKNOWN;
+  int indexInTheGroup = INDEX_IN_THE_GROUP_UNKNOWN;
   @nullable android.hardware.audio.core.MicrophoneInfo.Sensitivity sensitivity;
   android.hardware.audio.core.MicrophoneInfo.Directionality directionality = android.hardware.audio.core.MicrophoneInfo.Directionality.UNKNOWN;
   android.hardware.audio.core.MicrophoneInfo.FrequencyResponsePoint[] frequencyResponse;
   @nullable android.hardware.audio.core.MicrophoneInfo.Coordinate position;
   @nullable android.hardware.audio.core.MicrophoneInfo.Coordinate orientation;
-  const int GROUP_UNKNOWN = -1;
-  const int INDEX_IN_THE_GROUP_UNKNOWN = -1;
+  const int GROUP_UNKNOWN = (-1);
+  const int INDEX_IN_THE_GROUP_UNKNOWN = (-1);
   @Backing(type="int") @VintfStability
   enum Location {
     UNKNOWN = 0,
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl
index 3a4271b..a65d7b7 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl
@@ -39,12 +39,12 @@
   int frameSizeBytes;
   long bufferSizeFrames;
   android.hardware.audio.core.StreamDescriptor.AudioBuffer audio;
-  const int LATENCY_UNKNOWN = -1;
+  const int LATENCY_UNKNOWN = (-1);
   @FixedSize @VintfStability
   parcelable Position {
-    long frames = -1;
-    long timeNs = -1;
-    const long UNKNOWN = -1;
+    long frames = UNKNOWN;
+    long timeNs = UNKNOWN;
+    const long UNKNOWN = (-1);
   }
   @Backing(type="int") @VintfStability
   enum State {
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/VendorParameter.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/VendorParameter.aidl
new file mode 100644
index 0000000..bfe33ee
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/VendorParameter.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.core;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable VendorParameter {
+  @utf8InCpp String id;
+  ParcelableHolder ext;
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/AcousticEchoCanceler.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/AcousticEchoCanceler.aidl
new file mode 100644
index 0000000..1d51ade
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/AcousticEchoCanceler.aidl
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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 AcousticEchoCanceler {
+  android.hardware.audio.effect.VendorExtension vendor;
+  int echoDelayUs;
+  boolean mobileMode;
+  @VintfStability
+  union Id {
+    int vendorExtensionTag;
+    android.hardware.audio.effect.AcousticEchoCanceler.Tag commonTag;
+  }
+  @VintfStability
+  parcelable Capability {
+    ParcelableHolder extension;
+    int maxEchoDelayUs;
+    boolean supportMobileMode;
+  }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/AutomaticGainControl.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/AutomaticGainControl.aidl
new file mode 100644
index 0000000..39068d5
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/AutomaticGainControl.aidl
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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 AutomaticGainControl {
+  android.hardware.audio.effect.VendorExtension vendor;
+  int fixedDigitalGainMb;
+  android.hardware.audio.effect.AutomaticGainControl.LevelEstimator levelEstimator;
+  int saturationMarginMb;
+  @VintfStability
+  union Id {
+    int vendorExtensionTag;
+    android.hardware.audio.effect.AutomaticGainControl.Tag commonTag;
+  }
+  @VintfStability
+  parcelable Capability {
+    ParcelableHolder extension;
+    int maxFixedDigitalGainMb;
+    int maxSaturationMarginMb;
+  }
+  @Backing(type="int") @VintfStability
+  enum LevelEstimator {
+    RMS = 0,
+    PEAK = 1,
+  }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/BassBoost.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/BassBoost.aidl
index 09ad015..f8baa2a 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/BassBoost.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/BassBoost.aidl
@@ -36,8 +36,6 @@
 union BassBoost {
   android.hardware.audio.effect.VendorExtension vendor;
   int strengthPm;
-  const int MIN_PER_MILLE_STRENGTH = 0;
-  const int MAX_PER_MILLE_STRENGTH = 1000;
   @VintfStability
   union Id {
     int vendorExtensionTag;
@@ -46,6 +44,7 @@
   @VintfStability
   parcelable Capability {
     ParcelableHolder extension;
+    int maxStrengthPm;
     boolean strengthSupported;
   }
 }
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Capability.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Capability.aidl
index 60c88d3..28f77b3 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Capability.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Capability.aidl
@@ -35,6 +35,8 @@
 @VintfStability
 union Capability {
   android.hardware.audio.effect.VendorExtension vendorExtension;
+  android.hardware.audio.effect.AcousticEchoCanceler.Capability acousticEchoCanceler;
+  android.hardware.audio.effect.AutomaticGainControl.Capability automaticGainControl;
   android.hardware.audio.effect.BassBoost.Capability bassBoost;
   android.hardware.audio.effect.Downmix.Capability downmix;
   android.hardware.audio.effect.DynamicsProcessing.Capability dynamicsProcessing;
@@ -42,6 +44,7 @@
   android.hardware.audio.effect.Equalizer.Capability equalizer;
   android.hardware.audio.effect.HapticGenerator.Capability hapticGenerator;
   android.hardware.audio.effect.LoudnessEnhancer.Capability loudnessEnhancer;
+  android.hardware.audio.effect.NoiseSuppression.Capability noiseSuppression;
   android.hardware.audio.effect.PresetReverb.Capability presetReverb;
   android.hardware.audio.effect.Virtualizer.Capability virtualizer;
   android.hardware.audio.effect.Visualizer.Capability visualizer;
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/EnvironmentalReverb.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/EnvironmentalReverb.aidl
index fcf08c3..0e61932 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/EnvironmentalReverb.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/EnvironmentalReverb.aidl
@@ -44,6 +44,22 @@
   int diffusionPm;
   int densityPm;
   boolean bypass;
+  const int MIN_ROOM_LEVEL_MB = -6000;
+  const int MAX_ROOM_LEVEL_MB = 0;
+  const int MIN_ROOM_HF_LEVEL_MB = -4000;
+  const int MAX_ROOM_HF_LEVEL_MB = 0;
+  const int MIN_DECAY_TIME_MS = 100;
+  const int MAX_DECAY_TIME_MS = 20000;
+  const int MIN_DECAY_HF_RATIO_PM = 100;
+  const int MAX_DECAY_HF_RATIO_PM = 1000;
+  const int MIN_LEVEL_MB = -6000;
+  const int MAX_LEVEL_MB = 0;
+  const int MIN_DELAY_MS = 0;
+  const int MAX_DELAY_MS = 65;
+  const int MIN_DIFFUSION_PM = 0;
+  const int MAX_DIFFUSION_PM = 1000;
+  const int MIN_DENSITY_PM = 0;
+  const int MAX_DENSITY_PM = 1000;
   @VintfStability
   union Id {
     int vendorExtensionTag;
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl
index 40a8d72..959594b 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl
@@ -35,7 +35,7 @@
 @VintfStability
 union HapticGenerator {
   android.hardware.audio.effect.VendorExtension vendorExtension;
-  android.hardware.audio.effect.HapticGenerator.HapticScale hapticScale;
+  android.hardware.audio.effect.HapticGenerator.HapticScale[] hapticScales;
   android.hardware.audio.effect.HapticGenerator.VibratorInformation vibratorInfo;
   @VintfStability
   union Id {
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/NoiseSuppression.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/NoiseSuppression.aidl
new file mode 100644
index 0000000..223d95a
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/NoiseSuppression.aidl
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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 NoiseSuppression {
+  android.hardware.audio.effect.VendorExtension vendor;
+  android.hardware.audio.effect.NoiseSuppression.Level level;
+  @VintfStability
+  union Id {
+    int vendorExtensionTag;
+    android.hardware.audio.effect.NoiseSuppression.Tag commonTag;
+  }
+  @VintfStability
+  parcelable Capability {
+    ParcelableHolder extension;
+  }
+  @Backing(type="int") @VintfStability
+  enum Level {
+    LOW = 0,
+    MEDIUM = 1,
+    HIGH = 2,
+  }
+}
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 0635c13..eaa4bb1 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
@@ -43,6 +43,8 @@
   @VintfStability
   union Id {
     int vendorEffectTag;
+    android.hardware.audio.effect.AcousticEchoCanceler.Id acousticEchoCancelerTag;
+    android.hardware.audio.effect.AutomaticGainControl.Id automaticGainControlTag;
     android.hardware.audio.effect.BassBoost.Id bassBoostTag;
     android.hardware.audio.effect.Downmix.Id downmixTag;
     android.hardware.audio.effect.DynamicsProcessing.Id dynamicsProcessingTag;
@@ -50,6 +52,7 @@
     android.hardware.audio.effect.Equalizer.Id equalizerTag;
     android.hardware.audio.effect.HapticGenerator.Id hapticGeneratorTag;
     android.hardware.audio.effect.LoudnessEnhancer.Id loudnessEnhancerTag;
+    android.hardware.audio.effect.NoiseSuppression.Id noiseSuppressionTag;
     android.hardware.audio.effect.PresetReverb.Id presetReverbTag;
     android.hardware.audio.effect.Virtualizer.Id virtualizerTag;
     android.hardware.audio.effect.Visualizer.Id visualizerTag;
@@ -71,6 +74,8 @@
   @VintfStability
   union Specific {
     android.hardware.audio.effect.VendorExtension vendorEffect;
+    android.hardware.audio.effect.AcousticEchoCanceler acousticEchoCanceler;
+    android.hardware.audio.effect.AutomaticGainControl automaticGainControl;
     android.hardware.audio.effect.BassBoost bassBoost;
     android.hardware.audio.effect.Downmix downmix;
     android.hardware.audio.effect.DynamicsProcessing dynamicsProcessing;
@@ -78,6 +83,7 @@
     android.hardware.audio.effect.Equalizer equalizer;
     android.hardware.audio.effect.HapticGenerator hapticGenerator;
     android.hardware.audio.effect.LoudnessEnhancer loudnessEnhancer;
+    android.hardware.audio.effect.NoiseSuppression noiseSuppression;
     android.hardware.audio.effect.PresetReverb presetReverb;
     android.hardware.audio.effect.Virtualizer virtualizer;
     android.hardware.audio.effect.Visualizer visualizer;
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Processing.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Processing.aidl
index a779ae4..f6d6ee2 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Processing.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Processing.aidl
@@ -35,7 +35,7 @@
 @VintfStability
 parcelable Processing {
   android.hardware.audio.effect.Processing.Type type;
-  android.hardware.audio.effect.Descriptor.Identity[] ids;
+  android.hardware.audio.effect.Descriptor[] ids;
   @VintfStability
   union Type {
     android.media.audio.common.AudioStreamType streamType = android.media.audio.common.AudioStreamType.INVALID;
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Virtualizer.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Virtualizer.aidl
index d4fb9e0..9fdd692 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Virtualizer.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Virtualizer.aidl
@@ -44,6 +44,7 @@
   @VintfStability
   parcelable Capability {
     android.hardware.audio.effect.VendorExtension extension;
+    int maxStrengthPm;
     boolean strengthSupported;
   }
 }
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Visualizer.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Visualizer.aidl
index 9ee19f0..25f0b73 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Visualizer.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Visualizer.aidl
@@ -38,7 +38,7 @@
   android.hardware.audio.effect.VendorExtension vendor;
   android.hardware.audio.effect.Visualizer.GetOnlyParameters getOnlyParameters;
   android.hardware.audio.effect.Visualizer.SetOnlyParameters setOnlyParameters;
-  int captureSizeBytes;
+  int captureSamples;
   android.hardware.audio.effect.Visualizer.ScalingMode scalingMode;
   android.hardware.audio.effect.Visualizer.MeasurementMode measurementMode;
   @VintfStability
@@ -52,12 +52,12 @@
   parcelable Capability {
     android.hardware.audio.effect.VendorExtension extension;
     int maxLatencyMs;
-    android.hardware.audio.effect.Visualizer.CaptureSizeRange captureSizeRange;
+    android.hardware.audio.effect.Visualizer.CaptureSamplesRange captureSampleRange;
   }
   @VintfStability
-  parcelable CaptureSizeRange {
-    int minBytes;
-    int maxBytes;
+  parcelable CaptureSamplesRange {
+    int min;
+    int max;
   }
   @VintfStability
   enum ScalingMode {
@@ -72,7 +72,7 @@
   @VintfStability
   union GetOnlyParameters {
     android.hardware.audio.effect.Visualizer.GetOnlyParameters.Measurement measurement;
-    byte[] captureBytes;
+    byte[] captureSampleBuffer;
     @VintfStability
     parcelable Measurement {
       int rms;
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Volume.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Volume.aidl
index 8c836b0..6259cfb 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Volume.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Volume.aidl
@@ -45,6 +45,7 @@
   @VintfStability
   parcelable Capability {
     android.hardware.audio.effect.VendorExtension extension;
-    int maxLevel;
+    int minLevelDb;
+    int maxLevelDb;
   }
 }
diff --git a/audio/aidl/android/hardware/audio/core/IBluetooth.aidl b/audio/aidl/android/hardware/audio/core/IBluetooth.aidl
new file mode 100644
index 0000000..21ac8e2
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/IBluetooth.aidl
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ */
+
+package android.hardware.audio.core;
+
+import android.media.audio.common.Boolean;
+import android.media.audio.common.Float;
+import android.media.audio.common.Int;
+
+/**
+ * An instance of IBluetooth manages settings for the Hands-Free Profile (HFP)
+ * and the SCO Link. This interface is optional to implement and provide by the
+ * vendor. It needs to be provided only if the device actually supports BT SCO
+ * or HFP.
+ */
+@VintfStability
+interface IBluetooth {
+    @JavaDerive(equals=true, toString=true)
+    @VintfStability
+    parcelable ScoConfig {
+        /**
+         * Whether BT SCO is enabled. The client might need to disable it
+         * when another profile (for example, A2DP) is activated.
+         */
+        @nullable Boolean isEnabled;
+        /**
+         * Whether BT SCO Noise Reduction and Echo Cancellation are enabled.
+         */
+        @nullable Boolean isNrecEnabled;
+        @VintfStability enum Mode { UNSPECIFIED, SCO, SCO_WB, SCO_SWB }
+        /**
+         * If set, specifies the SCO mode to use:
+         *   regular, wide band (WB), or super wide band (SWB).
+         */
+        Mode mode = Mode.UNSPECIFIED;
+        /**
+         * The name of the BT SCO headset used for debugging purposes. Can be empty.
+         */
+        @nullable @utf8InCpp String debugName;
+    }
+
+    /**
+     * Set the configuration of Bluetooth SCO.
+     *
+     * In the provided parcelable, the client sets zero, one or more parameters
+     * which have to be updated on the HAL side. The parameters that are left
+     * unset must retain their current values. It is allowed to change
+     * parameters while the SCO profile is disabled (isEnabled.value == false).
+     *
+     * In the returned parcelable, all parameter fields known to the HAL module
+     * must be populated to their current values. If the SCO profile is
+     * currently disabled (isEnabled.value == false), the parameters must
+     * reflect the last values that were in use.
+     *
+     * The client can pass an uninitialized parcelable in order to retrieve the
+     * current configuration.
+     *
+     * @return The current configuration (after update). All fields known to
+     *         the HAL must be populated.
+     * @param config The configuration to set. Any number of fields may be left
+     *               uninitialized.
+     * @throws EX_UNSUPPORTED_OPERATION If BT SCO is not supported.
+     * @throws EX_ILLEGAL_ARGUMENT If the requested combination of parameter
+     *                             values is invalid.
+     */
+    ScoConfig setScoConfig(in ScoConfig config);
+
+    @JavaDerive(equals=true, toString=true)
+    @VintfStability
+    parcelable HfpConfig {
+        /**
+         * Whether BT HFP is enabled.
+         */
+        @nullable Boolean isEnabled;
+        /**
+         * The sample rate of BT HFP, in Hertz. Must be a positive number.
+         */
+        @nullable Int sampleRate;
+
+        const int VOLUME_MIN = 0;
+        const int VOLUME_MAX = 1;
+        /**
+         * The output volume of BT HFP. 1.0f means unity gain, 0.0f is muted,
+         * see VOLUME_* constants;
+         */
+        @nullable Float volume;
+    }
+
+    /**
+     * Set the configuration of Bluetooth HFP.
+     *
+     * In the provided parcelable, the client sets zero, one or more parameters
+     * which have to be updated on the HAL side. The parameters that are left
+     * unset must retain their current values. It is allowed to change
+     * parameters while the HFP profile is disabled (isEnabled.value == false).
+     *
+     * In the returned parcelable, all parameter fields known to the HAL module
+     * must be populated to their current values. If the HFP profile is
+     * currently disabled (isEnabled.value == false), the parameters must
+     * reflect the last values that were in use.
+     *
+     * The client can pass an uninitialized parcelable in order to retrieve the
+     * current configuration.
+     *
+     * @return The current configuration (after update). All fields known to
+     *         the HAL must be populated.
+     * @param config The configuration to set. Any number of fields may be left
+     *               uninitialized.
+     * @throws EX_UNSUPPORTED_OPERATION If BT HFP is not supported.
+     * @throws EX_ILLEGAL_ARGUMENT If the requested combination of parameter
+     *                             values is invalid.
+     */
+    HfpConfig setHfpConfig(in HfpConfig config);
+}
diff --git a/audio/aidl/android/hardware/audio/core/IModule.aidl b/audio/aidl/android/hardware/audio/core/IModule.aidl
index 786d5ee..7bc1b9c 100644
--- a/audio/aidl/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/android/hardware/audio/core/IModule.aidl
@@ -21,16 +21,22 @@
 import android.hardware.audio.core.AudioMode;
 import android.hardware.audio.core.AudioPatch;
 import android.hardware.audio.core.AudioRoute;
+import android.hardware.audio.core.IBluetooth;
 import android.hardware.audio.core.IStreamCallback;
 import android.hardware.audio.core.IStreamIn;
 import android.hardware.audio.core.IStreamOut;
+import android.hardware.audio.core.IStreamOutEventCallback;
 import android.hardware.audio.core.ITelephony;
 import android.hardware.audio.core.MicrophoneInfo;
 import android.hardware.audio.core.ModuleDebug;
 import android.hardware.audio.core.StreamDescriptor;
+import android.hardware.audio.core.VendorParameter;
+import android.hardware.audio.core.sounddose.ISoundDose;
+import android.hardware.audio.effect.IEffect;
 import android.media.audio.common.AudioOffloadInfo;
 import android.media.audio.common.AudioPort;
 import android.media.audio.common.AudioPortConfig;
+import android.media.audio.common.Float;
 
 /**
  * Each instance of IModule corresponds to a separate audio module. The system
@@ -81,6 +87,20 @@
     @nullable ITelephony getTelephony();
 
     /**
+     * Retrieve the interface to control Bluetooth SCO and HFP.
+     *
+     * If the HAL module supports either the SCO Link or Hands-Free Profile
+     * functionality (or both) for Bluetooth, it must return an instance of the
+     * IBluetooth interface. The same instance must be returned during the
+     * lifetime of the HAL module. If the HAL module does not support BT SCO and
+     * HFP, a null must be returned, without throwing any errors.
+     *
+     * @return An instance of the IBluetooth interface implementation.
+     * @throws EX_ILLEGAL_STATE If there was an error creating an instance.
+     */
+    @nullable IBluetooth getBluetooth();
+
+    /**
      * Set a device port of an external device into connected state.
      *
      * This method is used to inform the HAL module that an external device has
@@ -386,6 +406,8 @@
         long bufferSizeFrames;
         /** Client callback interface for the non-blocking output mode. */
         @nullable IStreamCallback callback;
+        /** Optional callback to notify client about stream events. */
+        @nullable IStreamOutEventCallback eventCallback;
     }
     @VintfStability
     parcelable OpenOutputStreamReturn {
@@ -395,6 +417,33 @@
     OpenOutputStreamReturn openOutputStream(in OpenOutputStreamArguments args);
 
     /**
+     * Get supported ranges of playback rate factors.
+     *
+     * See 'PlaybackRate' for the information on the playback rate parameters.
+     * This method provides supported ranges (inclusive) for the speed factor
+     * and the pitch factor.
+     *
+     * If the HAL module supports setting the playback rate, it is recommended
+     * to support speed and pitch factor values at least in the range from 0.5f
+     * to 2.0f.
+     *
+     * @throws EX_UNSUPPORTED_OPERATION If setting of playback rate parameters
+     *                                  is not supported by the module.
+     */
+    @VintfStability
+    parcelable SupportedPlaybackRateFactors {
+        /** The minimum allowed speed factor. */
+        float minSpeed;
+        /** The maximum allowed speed factor. */
+        float maxSpeed;
+        /** The minimum allowed pitch factor. */
+        float minPitch;
+        /** The maximum allowed pitch factor. */
+        float maxPitch;
+    }
+    SupportedPlaybackRateFactors getSupportedPlaybackRateFactors();
+
+    /**
      * Set an audio patch.
      *
      * This method creates new or updates an existing audio patch. If the
@@ -513,7 +562,8 @@
      * @throws EX_ILLEGAL_ARGUMENT If the port config can not be found by the ID.
      * @throws EX_ILLEGAL_STATE In the following cases:
      *                          - If the port config has a stream opened on it;
-     *                          - If the port config is used by a patch.
+     *                          - If the port config is used by a patch;
+     *                          - If the port config has an audio effect on it.
      */
     void resetAudioPortConfig(int portConfigId);
 
@@ -668,4 +718,92 @@
      * @param isTurnedOn True if the screen is turned on.
      */
     void updateScreenState(boolean isTurnedOn);
+
+    /**
+     * Retrieve the sound dose interface.
+     *
+     * If a device must comply to IEC62368-1 3rd edition audio safety requirements and is
+     * implementing audio offload decoding or other direct playback paths where volume control
+     * happens below the audio HAL, it must return an instance of the ISoundDose interface.
+     * The same instance must be returned during the lifetime of the HAL module.
+     * If the HAL module does not support sound dose, null must be returned, without throwing
+     * any errors.
+     *
+     * @return An instance of the ISoundDose interface implementation.
+     * @throws EX_ILLEGAL_STATE If there was an error creating an instance.
+     */
+    @nullable ISoundDose getSoundDose();
+
+    /**
+     * Generate a HW AV Sync identifier for a new audio session.
+     *
+     * Creates a new unique identifier which can be further used by the client
+     * for tagging input / output streams that belong to the same audio
+     * session and thus must use the same HW AV Sync timestamps sequence.
+     *
+     * HW AV Sync timestamps are used for "tunneled" I/O modes and thus
+     * are not mandatory.
+     *
+     * @throws EX_ILLEGAL_STATE If the identifier can not be provided at the moment.
+     * @throws EX_UNSUPPORTED_OPERATION If synchronization with HW AV Sync markers
+     *                                  is not supported.
+     */
+    int generateHwAvSyncId();
+
+    /**
+     * Get current values of vendor parameters.
+     *
+     * Return current values for the parameters corresponding to the provided ids.
+     *
+     * @param ids Ids of the parameters to retrieve values of.
+     * @return Current values of parameters, one per each id.
+     * @throws EX_ILLEGAL_ARGUMENT If the module does not recognize provided ids.
+     * @throws EX_ILLEGAL_STATE If parameter values can not be retrieved at the moment.
+     * @throws EX_UNSUPPORTED_OPERATION If the module does not support vendor parameters.
+     */
+    VendorParameter[] getVendorParameters(in @utf8InCpp String[] ids);
+    /**
+     * Set vendor parameters.
+     *
+     * Update values for provided vendor parameters. If the 'async' parameter
+     * is set to 'true', the implementation must return the control back without
+     * waiting for the application of parameters to complete.
+     *
+     * @param parameters Ids and values of parameters to set.
+     * @param async Whether to return from the method as early as possible.
+     * @throws EX_ILLEGAL_ARGUMENT If the module does not recognize provided parameters.
+     * @throws EX_ILLEGAL_STATE If parameters can not be set at the moment.
+     * @throws EX_UNSUPPORTED_OPERATION If the module does not support vendor parameters.
+     */
+    void setVendorParameters(in VendorParameter[] parameters, boolean async);
+
+    /**
+     * Apply an audio effect to a device port.
+     *
+     * The audio effect applies to all audio input or output on the specific
+     * configuration of the device audio port. The effect is inserted according
+     * to its insertion preference specified by the 'flags.insert' field of the
+     * EffectDescriptor.
+     *
+     * @param portConfigId The ID of the audio port config.
+     * @param effect The effect instance.
+     * @throws EX_ILLEGAL_ARGUMENT If the device port config can not be found by the ID,
+     *                             or the effect reference is invalid.
+     * @throws EX_UNSUPPORTED_OPERATION If the module does not support device port effects.
+     */
+    void addDeviceEffect(int portConfigId, in IEffect effect);
+
+    /**
+     * Stop applying an audio effect to a device port.
+     *
+     * Undo the action of the 'addDeviceEffect' method.
+     *
+     * @param portConfigId The ID of the audio port config.
+     * @param effect The effect instance.
+     * @throws EX_ILLEGAL_ARGUMENT If the device port config can not be found by the ID,
+     *                             or the effect reference is invalid, or the effect is
+     *                             not currently applied to the port config.
+     * @throws EX_UNSUPPORTED_OPERATION If the module does not support device port effects.
+     */
+    void removeDeviceEffect(int portConfigId, in IEffect effect);
 }
diff --git a/audio/aidl/android/hardware/audio/core/IStreamCommon.aidl b/audio/aidl/android/hardware/audio/core/IStreamCommon.aidl
new file mode 100644
index 0000000..533ef67
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/IStreamCommon.aidl
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ */
+
+package android.hardware.audio.core;
+
+import android.hardware.audio.core.VendorParameter;
+import android.hardware.audio.effect.IEffect;
+
+/**
+ * This interface contains operations that are common to input and output
+ * streams (IStreamIn and IStreamOut). The lifetime of the server-side
+ * implementation object is the same as of the "parent" IStreamIn/Out object.
+ * The client must release all references to this object together with
+ * references to the "parent" object.
+ */
+@VintfStability
+interface IStreamCommon {
+    /**
+     * Close the stream.
+     *
+     * Releases any resources allocated for this stream on the HAL module side.
+     * This includes the fast message queues and shared memories returned via
+     * the StreamDescriptor. Thus, the stream can not be operated anymore after
+     * it has been closed. The client needs to release the audio data I/O
+     * objects after the call to this method returns.
+     *
+     * Methods of IStream* interfaces throw EX_ILLEGAL_STATE for a closed stream.
+     *
+     * @throws EX_ILLEGAL_STATE If the stream has already been closed.
+     */
+    void close();
+
+    /**
+     * Update the HW AV Sync identifier for the stream.
+     *
+     * The argument to this method must be one of the identifiers previously
+     * returned by the 'IModule.generateHwAvSyncId' method. By tagging streams
+     * with the same identifier, the client indicates to the HAL that they all
+     * use the same HW AV Sync timestamps sequence.
+     *
+     * HW AV Sync timestamps are used for "tunneled" I/O modes and thus
+     * are not mandatory.
+     *
+     * @throws EX_ILLEGAL_ARGUMENT If the provided ID is unknown to the HAL module.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If synchronization with HW AV Sync markers
+     *                                  is not supported.
+     */
+    void updateHwAvSyncId(int hwAvSyncId);
+
+    /**
+     * Get current values of vendor parameters.
+     *
+     * Return current values for the parameters corresponding to the provided ids.
+     *
+     * @param ids Ids of the parameters to retrieve values of.
+     * @return Current values of parameters.
+     * @throws EX_ILLEGAL_ARGUMENT If the stream does not recognize provided ids.
+     * @throws EX_ILLEGAL_STATE If parameter values can not be retrieved at the moment.
+     * @throws EX_UNSUPPORTED_OPERATION If the stream does not support vendor parameters.
+     */
+    VendorParameter[] getVendorParameters(in @utf8InCpp String[] ids);
+    /**
+     * Set vendor parameters.
+     *
+     * Update values for provided vendor parameters. If the 'async' parameter
+     * is set to 'true', the implementation must return the control back without
+     * waiting for the application of parameters to complete.
+     *
+     * @param parameters Ids and values of parameters to set.
+     * @param async Whether to return from the method as early as possible.
+     * @throws EX_ILLEGAL_ARGUMENT If the stream does not recognize provided parameters.
+     * @throws EX_ILLEGAL_STATE If parameters can not be set at the moment.
+     * @throws EX_UNSUPPORTED_OPERATION If the stream does not support vendor parameters.
+     */
+    void setVendorParameters(in VendorParameter[] parameters, boolean async);
+
+    /**
+     * Apply an audio effect to the stream.
+     *
+     * This method is intended for the cases when the effect has an offload
+     * implementation, since software effects can be applied at the client side.
+     *
+     * @param effect The effect instance.
+     * @throws EX_ILLEGAL_ARGUMENT If the effect reference is invalid.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If the module does not support audio effects.
+     */
+    void addEffect(in IEffect effect);
+
+    /**
+     * Stop applying an audio effect to the stream.
+     *
+     * Undo the action of the 'addEffect' method.
+     *
+     * @param effect The effect instance.
+     * @throws EX_ILLEGAL_ARGUMENT If the effect reference is invalid, or the effect is
+     *                             not currently applied to the stream.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If the module does not support audio effects.
+     */
+    void removeEffect(in IEffect effect);
+}
diff --git a/audio/aidl/android/hardware/audio/core/IStreamIn.aidl b/audio/aidl/android/hardware/audio/core/IStreamIn.aidl
index 0b6e02c..c2b3633 100644
--- a/audio/aidl/android/hardware/audio/core/IStreamIn.aidl
+++ b/audio/aidl/android/hardware/audio/core/IStreamIn.aidl
@@ -17,6 +17,7 @@
 package android.hardware.audio.core;
 
 import android.hardware.audio.common.SinkMetadata;
+import android.hardware.audio.core.IStreamCommon;
 import android.hardware.audio.core.MicrophoneDynamicInfo;
 
 /**
@@ -25,19 +26,15 @@
 @VintfStability
 interface IStreamIn {
     /**
-     * Close the stream.
+     * Return the interface for common stream operations.
      *
-     * Releases any resources allocated for this stream on the HAL module side.
-     * This includes the fast message queues and shared memories returned via
-     * the StreamDescriptor. Thus, the stream can not be operated anymore after
-     * it has been closed. The client needs to release the audio data I/O
-     * objects after the call to this method returns.
+     * This method must always succeed. The implementation must
+     * return the same instance object for all subsequent calls to
+     * this method.
      *
-     * Methods of this interface throw EX_ILLEGAL_STATE for a closed stream.
-     *
-     * @throws EX_ILLEGAL_STATE If the stream has already been closed.
+     * @return The interface for common operations.
      */
-    void close();
+    IStreamCommon getStreamCommon();
 
     /**
      * Provides information on the microphones that are active for this stream.
@@ -134,4 +131,38 @@
      * @throws EX_ILLEGAL_STATE If the stream is closed.
      */
     void updateMetadata(in SinkMetadata sinkMetadata);
+
+    const int HW_GAIN_MIN = 0;
+    const int HW_GAIN_MAX = 1;
+    /**
+     * Retrieve current gain applied in hardware.
+     *
+     * In case when the HAL module has a gain controller, this method returns
+     * the current value of its gain for each input channel.
+     *
+     * The valid range for gain is [0.0f, 1.0f], where 1.0f corresponds to unity
+     * gain, 0.0f corresponds to full mute (see HW_GAIN_* constants).
+     *
+     * @return Current gain values for each input channel.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If hardware gain control is not supported.
+     */
+    float[] getHwGain();
+    /**
+     * Set gain applied in hardware.
+     *
+     * In case when the HAL module has a gain controller, this method sets the
+     * current value of its gain for each input channel.
+     *
+     * The valid range for gain is [0.0f, 1.0f], where 1.0f corresponds to unity
+     * gain, 0.0f corresponds to full mute (see HW_GAIN_* constants).
+     *
+     * @param gain Gain values for each input channel.
+     * @throws EX_ILLEGAL_ARGUMENT If the number of elements in the provided
+     *                             array does not match the channel count, or
+     *                             gain values are out of range.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If hardware gain control is not supported.
+     */
+    void setHwGain(in float[] channelGains);
 }
diff --git a/audio/aidl/android/hardware/audio/core/IStreamOut.aidl b/audio/aidl/android/hardware/audio/core/IStreamOut.aidl
index 9fdb37d..b60b0fd 100644
--- a/audio/aidl/android/hardware/audio/core/IStreamOut.aidl
+++ b/audio/aidl/android/hardware/audio/core/IStreamOut.aidl
@@ -17,6 +17,10 @@
 package android.hardware.audio.core;
 
 import android.hardware.audio.common.SourceMetadata;
+import android.hardware.audio.core.IStreamCommon;
+import android.media.audio.common.AudioDualMonoMode;
+import android.media.audio.common.AudioLatencyMode;
+import android.media.audio.common.AudioPlaybackRate;
 
 /**
  * This interface provides means for sending audio data to output devices.
@@ -24,19 +28,15 @@
 @VintfStability
 interface IStreamOut {
     /**
-     * Close the stream.
+     * Return the interface for common stream operations.
      *
-     * Releases any resources allocated for this stream on the HAL module side.
-     * This includes the fast message queues and shared memories returned via
-     * the StreamDescriptor. Thus, the stream can not be operated anymore after
-     * it has been closed. The client needs to release the audio data I/O
-     * objects after the call to this method returns.
+     * This method must always succeed. The implementation must
+     * return the same instance object for all subsequent calls to
+     * this method.
      *
-     * Methods of this interface throw EX_ILLEGAL_STATE for a closed stream.
-     *
-     * @throws EX_ILLEGAL_STATE If the stream has already been closed.
+     * @return The interface for common operations.
      */
-    void close();
+    IStreamCommon getStreamCommon();
 
     /**
      * Update stream metadata.
@@ -47,4 +47,182 @@
      * @throws EX_ILLEGAL_STATE If the stream is closed.
      */
     void updateMetadata(in SourceMetadata sourceMetadata);
+
+    const int HW_VOLUME_MIN = 0;
+    const int HW_VOLUME_MAX = 1;
+    /**
+     * Retrieve current attenuation applied in hardware.
+     *
+     * Hardware attenuation can be used in cases when the client can not, or is
+     * not allowed to modify the audio stream, for example because the stream is
+     * encoded.
+     *
+     * The valid range for attenuation is [0.0f, 1.0f], where 1.0f corresponds
+     * to unity gain, 0.0f corresponds to full mute (see HW_VOLUME_*
+     * constants). The returned array specifies attenuation for each output
+     * channel of the stream.
+     *
+     * Support of hardware volume control is optional.
+     *
+     * @return Current attenuation values for each output channel.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If hardware volume control is not supported.
+     */
+    float[] getHwVolume();
+    /**
+     * Set attenuation applied in hardware.
+     *
+     * Hardware attenuation can be used in cases when the client can not, or is
+     * not allowed to modify the audio stream, for example because the stream is
+     * encoded.
+     *
+     * The valid range for attenuation is [0.0f, 1.0f], where 1.0f corresponds
+     * to unity gain, 0.0f corresponds to full mute (see HW_VOLUME_* constants).
+     *
+     * Support of hardware volume control is optional.
+     *
+     * @param channelVolumes Attenuation values for each output channel.
+     * @throws EX_ILLEGAL_ARGUMENT If the number of elements in the provided
+     *                             array does not match the channel count, or
+     *                             attenuation values are out of range.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If hardware volume control is not supported.
+     */
+    void setHwVolume(in float[] channelVolumes);
+
+    // aidl: Constant of type float is not supported (b/251286924).
+    // const float AUDIO_DESCRIPTION_MIX_LEVEL_MIN = -Inf;
+    const int AUDIO_DESCRIPTION_MIX_LEVEL_MAX = 48;
+    /**
+     * Returns the Audio Description Mix level in dB.
+     *
+     * The level is applied to streams incorporating a secondary Audio
+     * Description stream. It specifies the relative level of mixing for
+     * the Audio Description with a reference to the Main Audio.
+     *
+     * The value of the relative level is in the range from negative infinity
+     * to +48, see AUDIO_DESCRIPTION_MIX_LEVEL_* constants.
+     *
+     * @return The current Audio Description Mix Level in dB.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If the information is unavailable.
+     */
+    float getAudioDescriptionMixLevel();
+    /**
+     * Sets the Audio Description Mix level in dB.
+     *
+     * For streams incorporating a secondary Audio Description stream the
+     * relative level of mixing of the Audio Description to the Main Audio is
+     * controlled by this method.
+     *
+     * The value of the relative level must be in the range from negative
+     * infinity to +48, see AUDIO_DESCRIPTION_MIX_LEVEL_* constants.
+     *
+     * @param leveldB Audio Description Mix Level in dB.
+     * @throws EX_ILLEGAL_ARGUMENT If the provided value is out of range.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If setting of this parameter is not supported.
+     */
+    void setAudioDescriptionMixLevel(float leveldB);
+
+    /**
+     * Returns the Dual Mono mode presentation setting.
+     *
+     * @return The current setting of Dual Mono mode.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If the information is unavailable.
+     */
+    AudioDualMonoMode getDualMonoMode();
+    /**
+     * Sets the Dual Mono mode presentation on the output device.
+     *
+     * The Dual Mono mode is generally applied to stereo audio streams
+     * where the left and right channels come from separate sources.
+     *
+     * @param mode Selected Dual Mono mode.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If setting of this parameter is not supported.
+     */
+    void setDualMonoMode(AudioDualMonoMode mode);
+
+    /**
+     * Retrieve supported latency modes.
+     *
+     * Indicates which latency modes are currently supported on this output
+     * stream. If the transport protocol (for example, Bluetooth A2DP) used by
+     * this output stream to reach the output device supports variable latency
+     * modes, the HAL indicates which modes are currently supported. The client
+     * can then call setLatencyMode() with one of the supported modes to select
+     * the desired operation mode.
+     *
+     * Implementation for this method is mandatory only on specific spatial
+     * audio streams indicated by AUDIO_OUTPUT_FLAG_SPATIALIZER flag if they can
+     * be routed to a BT classic sink.
+     *
+     * @return Currently supported latency modes.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If the information is unavailable.
+     */
+    AudioLatencyMode[] getRecommendedLatencyModes();
+    /**
+     * Sets the latency mode.
+     *
+     * The requested mode must be one of the modes returned by the
+     * 'getRecommendedLatencyModes()' method.
+     *
+     * Implementation for this method is mandatory only on specific spatial
+     * audio streams indicated by AUDIO_OUTPUT_FLAG_SPATIALIZER flag if they can
+     * be routed to a BT classic sink.
+     *
+     * @throws EX_ILLEGAL_ARGUMENT If the specified mode is not supported.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If setting of this parameter is not supported.
+     */
+    void setLatencyMode(AudioLatencyMode mode);
+
+    /**
+     * Retrieve current playback rate parameters.
+     *
+     * @return Current playback parameters.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If the information is unavailable.
+     */
+    AudioPlaybackRate getPlaybackRateParameters();
+    /**
+     * Set playback rate parameters.
+     *
+     * Sets the playback rate parameters that control playback behavior. This
+     * is normally used when playing encoded content and decoding is performed
+     * in hardware. Otherwise, the client can apply necessary transformations
+     * itself.
+     *
+     * The range of supported values for speed and pitch factors is provided by
+     * the 'IModule.getSupportedPlaybackRateFactors' method. Out of range speed
+     * and pitch values must not be rejected if the fallback mode is 'MUTE'.
+     *
+     * @param playbackRate Playback parameters to set.
+     * @throws EX_ILLEGAL_ARGUMENT If provided parameters are out of acceptable range.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If setting playback rate parameters
+     *                                  is not supported.
+     */
+    void setPlaybackRateParameters(in AudioPlaybackRate playbackRate);
+
+    /**
+     * Select presentation and program from for decoding.
+     *
+     * Selects a presentation for decoding from a next generation media stream
+     * (as defined per ETSI TS 103 190-2) and a program within the presentation.
+     * The client must obtain valid presentation and program IDs from the media
+     * stream on its own.
+     *
+     * @param presentationId Selected audio presentation.
+     * @param programId Refinement for the presentation.
+     * @throws EX_ILLEGAL_ARGUMENT If the HAL module is unable to locate
+     *                             the specified presentation or program in
+     *                             the media stream.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If presentation selection is not supported.
+     */
+    void selectPresentation(int presentationId, int programId);
 }
diff --git a/audio/aidl/android/hardware/audio/core/IStreamOutEventCallback.aidl b/audio/aidl/android/hardware/audio/core/IStreamOutEventCallback.aidl
new file mode 100644
index 0000000..75d7385
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/IStreamOutEventCallback.aidl
@@ -0,0 +1,168 @@
+/*
+ * 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.
+ */
+
+package android.hardware.audio.core;
+
+import android.media.audio.common.AudioLatencyMode;
+
+/**
+ * This interface provides means for asynchronous notification of the client
+ * by an output stream.
+ */
+@VintfStability
+oneway interface IStreamOutEventCallback {
+    /**
+     * Codec format changed notification.
+     *
+     * onCodecFormatChanged returns an AudioMetadata object in read-only
+     * ByteString format.  It represents the most recent codec format decoded by
+     * a HW audio decoder.
+     *
+     * Codec format is an optional message from HW audio decoders. It serves to
+     * notify the application about the codec format and audio objects contained
+     * within the compressed audio stream for control, informational,
+     * and display purposes.
+     *
+     * audioMetadata ByteString is convertible to an AudioMetadata object
+     * through both a C++ and a C API present in Metadata.h [1], or through a
+     * Java API present in AudioMetadata.java [2].
+     *
+     * The ByteString format is a stable format used for parcelling
+     * (marshalling) across JNI, AIDL, and HIDL interfaces.  The test for R
+     * compatibility for native marshalling is TEST(metadata_tests,
+     * compatibility_R) [3]. The test for R compatibility for JNI marshalling
+     * is android.media.cts.AudioMetadataTest#testCompatibilityR [4].
+     *
+     * Android R defined keys are as follows [2]:
+     * "bitrate", int32
+     * "channel-mask", int32
+     * "mime", string
+     * "sample-rate", int32
+     * "bit-width", int32
+     * "has-atmos", int32
+     * "audio-encoding", int32
+     *
+     * Android S in addition adds the following keys:
+     * "presentation-id", int32
+     * "program-id", int32
+     * "presentation-content-classifier", int32
+     *    presentation-content-classifier key values can be referenced from
+     *    frameworks/base/media/java/android/media/AudioPresentation.java
+     *    i.e. AudioPresentation.ContentClassifier
+     *    It can contain any of the below values
+     *    CONTENT_UNKNOWN   = -1,
+     *    CONTENT_MAIN      =  0,
+     *    CONTENT_MUSIC_AND_EFFECTS = 1,
+     *    CONTENT_VISUALLY_IMPAIRED = 2,
+     *    CONTENT_HEARING_IMPAIRED  = 3,
+     *    CONTENT_DIALOG = 4,
+     *    CONTENT_COMMENTARY = 5,
+     *    CONTENT_EMERGENCY = 6,
+     *    CONTENT_VOICEOVER = 7
+     * "presentation-language", string  // represents ISO 639-2 (three letter code)
+     *
+     * Parceling Format:
+     * All values are native endian order. [1]
+     *
+     * using type_size_t = uint32_t;
+     * using index_size_t = uint32_t;
+     * using datum_size_t = uint32_t;
+     *
+     * Permitted type indexes are
+     * TYPE_NONE = 0, // Reserved
+     * TYPE_INT32 = 1,
+     * TYPE_INT64 = 2,
+     * TYPE_FLOAT = 3,
+     * TYPE_DOUBLE = 4,
+     * TYPE_STRING = 5,
+     * TYPE_DATA = 6,  // A data table of <String, Datum>
+     *
+     * Datum = {
+     *           (type_size_t)  Type (the type index from type_as_value<T>.)
+     *           (datum_size_t) Size (size of the Payload)
+     *           (byte string)  Payload<Type>
+     *         }
+     *
+     * The data is specified in native endian order. Since the size of the
+     * Payload is always present, unknown types may be skipped.
+     *
+     * Payload<Fixed-size Primitive_Value>
+     * [ sizeof(Primitive_Value) in raw bytes ]
+     *
+     * Example of Payload<Int32> of 123:
+     * Payload<Int32>
+     * [ value of 123                   ] =  0x7b 0x00 0x00 0x00       123
+     *
+     * Payload<String>
+     * [ (index_size_t) length, not including zero terminator.]
+     * [ (length) raw bytes ]
+     *
+     * Example of Payload<String> of std::string("hi"):
+     * [ (index_size_t) length          ] = 0x02 0x00 0x00 0x00        2 strlen("hi")
+     * [ raw bytes "hi"                 ] = 0x68 0x69                  "hi"
+     *
+     * Payload<Data>
+     * [ (index_size_t) entries ]
+     * [ raw bytes   (entry 1) Key   (Payload<String>)
+     *                         Value (Datum)
+     *                ...  (until #entries) ]
+     *
+     * Example of Payload<Data> of {{"hello", "world"},
+     *                              {"value", (int32_t)1000}};
+     * [ (index_size_t) #entries        ] = 0x02 0x00 0x00 0x00        2 entries
+     *    Key (Payload<String>)
+     *    [ index_size_t length         ] = 0x05 0x00 0x00 0x00        5 strlen("hello")
+     *    [ raw bytes "hello"           ] = 0x68 0x65 0x6c 0x6c 0x6f   "hello"
+     *    Value (Datum)
+     *    [ (type_size_t) type          ] = 0x05 0x00 0x00 0x00        5 (TYPE_STRING)
+     *    [ (datum_size_t) size         ] = 0x09 0x00 0x00 0x00        sizeof(index_size_t) +
+     *                                                                 strlen("world")
+     *       Payload<String>
+     *       [ (index_size_t) length    ] = 0x05 0x00 0x00 0x00        5 strlen("world")
+     *       [ raw bytes "world"        ] = 0x77 0x6f 0x72 0x6c 0x64   "world"
+     *    Key (Payload<String>)
+     *    [ index_size_t length         ] = 0x05 0x00 0x00 0x00        5 strlen("value")
+     *    [ raw bytes "value"           ] = 0x76 0x61 0x6c 0x75 0x65   "value"
+     *    Value (Datum)
+     *    [ (type_size_t) type          ] = 0x01 0x00 0x00 0x00        1 (TYPE_INT32)
+     *    [ (datum_size_t) size         ] = 0x04 0x00 0x00 0x00        4 sizeof(int32_t)
+     *        Payload<Int32>
+     *        [ raw bytes 1000          ] = 0xe8 0x03 0x00 0x00        1000
+     *
+     * The contents of audioMetadata is a Payload<Data>.
+     * An implementation dependent detail is that the Keys are always
+     * stored sorted, so the byte string representation generated is unique.
+     *
+     * Vendor keys are allowed for informational and debugging purposes.
+     * Vendor keys should consist of the vendor company name followed
+     * by a dot; for example, "vendorCompany.someVolume" [2].
+     *
+     * [1] system/media/audio_utils/include/audio_utils/Metadata.h
+     * [2] frameworks/base/media/java/android/media/AudioMetadata.java
+     * [3] system/media/audio_utils/tests/metadata_tests.cpp
+     * [4] cts/tests/tests/media/src/android/media/cts/AudioMetadataTest.java
+     *
+     * @param audioMetadata A buffer containing decoded format changes
+     *     reported by codec. The buffer contains data that can be transformed
+     *     to audio metadata, which is a C++ object based map.
+     */
+    void onCodecFormatChanged(in byte[] audioMetadata);
+
+    /**
+     * Called with the new list of supported latency modes when a change occurs.
+     */
+    void onRecommendedLatencyModeChanged(in AudioLatencyMode[] modes);
+}
diff --git a/audio/aidl/android/hardware/audio/core/ITelephony.aidl b/audio/aidl/android/hardware/audio/core/ITelephony.aidl
index a872c7c..a817032 100644
--- a/audio/aidl/android/hardware/audio/core/ITelephony.aidl
+++ b/audio/aidl/android/hardware/audio/core/ITelephony.aidl
@@ -17,6 +17,8 @@
 package android.hardware.audio.core;
 
 import android.hardware.audio.core.AudioMode;
+import android.media.audio.common.Boolean;
+import android.media.audio.common.Float;
 
 /**
  * An instance of ITelephony manages settings which are specific to voice calls
@@ -53,4 +55,75 @@
      * @throws EX_ILLEGAL_STATE If there was an error during switching.
      */
     void switchAudioMode(AudioMode mode);
+
+    @JavaDerive(equals=true, toString=true)
+    @VintfStability
+    parcelable TelecomConfig {
+        const int VOICE_VOLUME_MIN = 0;
+        const int VOICE_VOLUME_MAX = 1;
+        /**
+         * Volume of a voice call. 1.0f means unity gain, 0.0f is muted,
+         * see VOLUME_* constants.
+         */
+        @nullable Float voiceVolume;
+        /**
+         * The current mode of teletypewritter (TTY).
+         */
+        @VintfStability
+        @Backing(type="int")
+        enum TtyMode {
+            /**
+             * The default uninitialized value.
+             */
+            UNSPECIFIED = -1,
+            /**
+             * TTY mode is off.
+             */
+            OFF = 0,
+            /**
+             * TTY mode is on. The speaker is off and the microphone is muted. The
+             * user will communicate with the remote party by sending and receiving
+             * text messages.
+             */
+            FULL = 1,
+            /**
+             * TTY mode is in hearing carryover mode (HCO). The microphone is muted
+             * but the speaker is on. The user will communicate with the remote
+             * party by sending text messages and hearing an audible reply.
+             */
+            HCO = 2,
+            /**
+             * TTY mode is in voice carryover mode (VCO). The speaker is off but the
+             * microphone is still on. User will communicate with the remote party
+             * by speaking and receiving text message replies.
+             */
+            VCO = 3,
+        }
+        TtyMode ttyMode = TtyMode.UNSPECIFIED;
+        /**
+         * Whether Hearing Aid Compatibility - Telecoil (HAC-T) mode is enabled.
+         */
+        @nullable Boolean isHacEnabled;
+    }
+
+    /**
+     * Set the configuration of the telephony audio.
+     *
+     * In the provided parcelable, the client sets zero, one or more parameters
+     * which have to be updated on the HAL side. The parameters that are left
+     * unset must retain their current values.
+     *
+     * In the returned parcelable, all parameter fields known to the HAL module
+     * must be populated to their current values.The client can pass an
+     * uninitialized parcelable in order to retrieve the current configuration.
+     *
+     * @return The current configuration (after update). All fields known to
+     *         the HAL must be populated.
+     * @param config The configuration to set. Any number of fields may be left
+     *               uninitialized.
+     * @throws EX_UNSUPPORTED_OPERATION If telephony is not supported.
+     * @throws EX_ILLEGAL_ARGUMENT If the requested combination of parameter
+     *                             values is invalid.
+     */
+    TelecomConfig setTelecomConfig(in TelecomConfig config);
 }
diff --git a/audio/aidl/android/hardware/audio/core/VendorParameter.aidl b/audio/aidl/android/hardware/audio/core/VendorParameter.aidl
new file mode 100644
index 0000000..206bd9d
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/VendorParameter.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+package android.hardware.audio.core;
+
+/**
+ * Vendor parameters are used as a lightweight way to pass vendor-specific
+ * configuration data back and forth between the HAL and vendor's extension
+ * to the Android framework, without the need to extend audio interfaces
+ * from AOSP.
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable VendorParameter {
+    /**
+     * Vendor-generated unique ID of the parameter. In order to avoid
+     * collisions, vendors must use a vendor-specific prefix for parameter
+     * ids. The Android framework always passes ids as-is, without any attempt
+     * to parse their content.
+     */
+    @utf8InCpp String id;
+    /**
+     * The payload of the parameter.
+     */
+    ParcelableHolder ext;
+}
diff --git a/audio/aidl/android/hardware/audio/core/sounddose/ISoundDose.aidl b/audio/aidl/android/hardware/audio/core/sounddose/ISoundDose.aidl
new file mode 100644
index 0000000..953ab62
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/sounddose/ISoundDose.aidl
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+package android.hardware.audio.core.sounddose;
+
+import android.media.audio.common.AudioDevice;
+
+/**
+ * This interface provides functions related to sound exposure control required for compliance to
+ * EN/IEC 62368-1 3rd edition. Implementing this interface is mandatory for devices for which
+ * compliance to this standard is mandated and implementing audio offload decoding or other direct
+ * playback paths where volume control happens below the audio HAL.
+ */
+@VintfStability
+interface ISoundDose {
+    /**
+     * Max value in dBA used for momentary exposure warnings as defined by IEC62368-1
+     * 3rd edition. This value represents the default RS2 value.
+     */
+    const int DEFAULT_MAX_RS2 = 100;
+    /** Min value of the RS2 threshold in dBA as defined by IEC62368-1 3rd edition. */
+    const int MIN_RS2 = 80;
+
+    /**
+     * Sets the RS2 value used for momentary exposure warnings. Default value is
+     * DEFAULT_MAX_RS2 as specified in IEC62368-1 3rd edition.
+     *
+     * @param rs2ValueDbA custom RS2 value to use. Must not be higher than DEFAULT_MAX_RS2
+     * @throws EX_ILLEGAL_ARGUMENT if rs2ValueDbA is greater than DEFAULT_MAX_RS2 or lower
+     *                             than 80dBA
+     */
+    void setOutputRs2(float rs2ValueDbA);
+
+    /**
+     * Gets the RS2 value used for momentary exposure warnings.
+     *
+     * @return the RS2 value in dBA
+     */
+    float getOutputRs2();
+
+    /**
+     * Registers the HAL callback for sound dose computation. If sound dose is supported
+     * the MEL values and exposure notifications will be received through this callback
+     * only. The internal framework MEL computation will be disabled.
+     * It is not possible to unregister the callback. The HAL is responsible to provide
+     * the MEL values throughout its lifecycle.
+     * This method should only be called once (no updates allowed) with a valid callback.
+     *
+     * @param callback to use when new updates are available for sound dose
+     * @throws EX_ILLEGAL_STATE if the method is called more than once
+     * @throws EX_ILLEGAL_ARGUMENT if the passed callback is null
+     */
+    void registerSoundDoseCallback(in IHalSoundDoseCallback callback);
+
+    @VintfStability
+    oneway interface IHalSoundDoseCallback {
+        /**
+         * Called whenever the current MEL value exceeds the set RS2 value.
+         *
+         * @param currentDbA the current MEL value which exceeds the RS2 value
+         * @param audioDevice the audio device where the MEL exposure warning was recorded
+         */
+        void onMomentaryExposureWarning(float currentDbA, in AudioDevice audioDevice);
+
+        @VintfStability
+        parcelable MelRecord {
+            /**
+             * Array of continuously recorded MEL values >= RS1 (1 per second).
+             * First value in the array was recorded at 'timestamp'.
+             */
+            float[] melValues;
+            /**
+             * Corresponds to the time in seconds when the first MEL entry in melValues
+             * was recorded. The timestamp values have to be consistent throughout all
+             * audio ports, equal timestamp values will be aggregated.
+             */
+            long timestamp;
+        }
+
+        /**
+         * Provides a MelRecord containing continuous MEL values sorted by timestamp.
+         * Note that all the MEL values originate from the audio device specified by audioDevice.
+         * In case values from multiple devices need to be reported, the caller should execute
+         * this callback once for every device.
+         *
+         * @param melRecord contains the MEL values used for CSD
+         * @param audioDevice the audio device where the MEL values were recorded
+         */
+        void onNewMelValues(in MelRecord melRecord, in AudioDevice audioDevice);
+    }
+}
diff --git a/audio/aidl/android/hardware/audio/effect/AcousticEchoCanceler.aidl b/audio/aidl/android/hardware/audio/effect/AcousticEchoCanceler.aidl
new file mode 100644
index 0000000..19d60b6
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/AcousticEchoCanceler.aidl
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.VendorExtension;
+
+/**
+ * Acoustic Echo Canceler (AEC) is an audio pre-processor which removes the contribution of the
+ * signal received from the remote party from the captured audio signal.
+ *
+ * All parameters defined in union AcousticEchoCanceler must be gettable and settable. The
+ * capabilities defined in AcousticEchoCanceler.Capability can only acquired with
+ * IEffect.getDescriptor() and not settable.
+ */
+@VintfStability
+union AcousticEchoCanceler {
+    /**
+     * Effect parameter tag to identify the parameters for getParameter().
+     */
+    @VintfStability
+    union Id {
+        int vendorExtensionTag;
+        AcousticEchoCanceler.Tag commonTag;
+    }
+
+    /**
+     * Vendor AEC implementation definition for additional parameters.
+     */
+    VendorExtension vendor;
+
+    /**
+     * Capability supported by AEC implementation.
+     */
+    @VintfStability
+    parcelable Capability {
+        /**
+         * AEC capability extension, vendor can use this extension in case existing capability
+         * definition not enough.
+         */
+        ParcelableHolder extension;
+
+        /**
+         * Maximum AEC echo delay in microseconds supported.
+         */
+        int maxEchoDelayUs;
+        /**
+         * If AEC mobile mode was supported by the AEC implementation.
+         */
+        boolean supportMobileMode;
+    }
+
+    /**
+     * The AEC echo delay in microseconds.
+     * Must never be negative, and not larger than maxEchoDelayUs in capability.
+     */
+    int echoDelayUs;
+    /**
+     * If AEC mobile mode enabled.
+     * Can only be false if AEC implementation indicate not support mobile mode by set
+     * supportMobileMode to false in capability.
+     */
+    boolean mobileMode;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/AutomaticGainControl.aidl b/audio/aidl/android/hardware/audio/effect/AutomaticGainControl.aidl
new file mode 100644
index 0000000..e82a564
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/AutomaticGainControl.aidl
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.VendorExtension;
+
+/**
+ * Automatic Gain Control (AGC) is an audio pre-processor which automatically normalizes the output
+ * of the captured signal by boosting or lowering input from the microphone to match a preset level
+ * so that the output signal level is virtually constant. AGC can be used by applications where the
+ * input signal dynamic range is not important but where a constant strong capture level is desired.
+ *
+ * All parameters defined in union AutomaticGainControl must be gettable and settable. The
+ * capabilities defined in AutomaticGainControl.Capability can only acquired with
+ * IEffect.getDescriptor() and not settable.
+ */
+@VintfStability
+union AutomaticGainControl {
+    /**
+     * Effect parameter tag to identify the parameters for getParameter().
+     */
+    @VintfStability
+    union Id {
+        int vendorExtensionTag;
+        AutomaticGainControl.Tag commonTag;
+    }
+
+    /**
+     * Vendor AutomaticGainControl implementation definition for additional parameters.
+     */
+    VendorExtension vendor;
+
+    /**
+     * Capability supported by AutomaticGainControl implementation.
+     */
+    @VintfStability
+    parcelable Capability {
+        /**
+         * AutomaticGainControl capability extension, vendor can use this extension in case existing
+         * capability definition not enough.
+         */
+        ParcelableHolder extension;
+        /**
+         * Max fixed digital gain supported by AGC implementation in millibel.
+         */
+        int maxFixedDigitalGainMb;
+        /**
+         * Max fixed saturation margin supported by AGC implementation in millibel.
+         */
+        int maxSaturationMarginMb;
+    }
+
+    @VintfStability
+    @Backing(type="int")
+    enum LevelEstimator {
+        /* Use Root Mean Square level estimator*/
+        RMS = 0,
+        /* Use Peak level estimator*/
+        PEAK = 1,
+    }
+
+    /**
+     * The AGC fixed digital gain in millibel.
+     * Must never be negative, and not larger than maxFixedDigitalGainMb in capability.
+     */
+    int fixedDigitalGainMb;
+    /*
+     * Adaptive digital level estimator.
+     */
+    LevelEstimator levelEstimator;
+    /**
+     * The AGC saturation margin in millibel.
+     * Must never be negative, and not larger than maxSaturationMarginMb in capability.
+     */
+    int saturationMarginMb;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/BassBoost.aidl b/audio/aidl/android/hardware/audio/effect/BassBoost.aidl
index 9e5d8aa..6a94242 100644
--- a/audio/aidl/android/hardware/audio/effect/BassBoost.aidl
+++ b/audio/aidl/android/hardware/audio/effect/BassBoost.aidl
@@ -52,6 +52,10 @@
          */
         ParcelableHolder extension;
         /**
+         * Maximum possible per mille strength.
+         */
+        int maxStrengthPm;
+        /**
          * Indicates whether setting strength is supported. False value indicates only one strength
          * is supported and setParameter() method will return EX_ILLEGAL_ARGUMENT.
          */
@@ -59,23 +63,14 @@
     }
 
     /**
-     * Minimal possible per mille strength.
-     */
-    const int MIN_PER_MILLE_STRENGTH = 0;
-
-    /**
-     * Maximum possible per mille strength.
-     */
-    const int MAX_PER_MILLE_STRENGTH = 1000;
-
-    /**
      * The per mille strength of the bass boost effect.
      *
      * If the implementation does not support per mille accuracy for setting the strength, it is
      * allowed to round the given strength to the nearest supported value. In this case {@link
      * #IEffect.getParameter()} method should return the rounded value that was actually set.
      *
-     * The valid range for strength is [0, 1000].
+     * The value of the strength must be non-negative and not exceed the value specified by
+     * the 'maxStrengthPm' capability.
      */
     int strengthPm;
 }
diff --git a/audio/aidl/android/hardware/audio/effect/Capability.aidl b/audio/aidl/android/hardware/audio/effect/Capability.aidl
index 4149783..30780e6 100644
--- a/audio/aidl/android/hardware/audio/effect/Capability.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Capability.aidl
@@ -16,6 +16,8 @@
 
 package android.hardware.audio.effect;
 
+import android.hardware.audio.effect.AcousticEchoCanceler;
+import android.hardware.audio.effect.AutomaticGainControl;
 import android.hardware.audio.effect.BassBoost;
 import android.hardware.audio.effect.Downmix;
 import android.hardware.audio.effect.DynamicsProcessing;
@@ -23,6 +25,7 @@
 import android.hardware.audio.effect.Equalizer;
 import android.hardware.audio.effect.HapticGenerator;
 import android.hardware.audio.effect.LoudnessEnhancer;
+import android.hardware.audio.effect.NoiseSuppression;
 import android.hardware.audio.effect.PresetReverb;
 import android.hardware.audio.effect.VendorExtension;
 import android.hardware.audio.effect.Virtualizer;
@@ -49,6 +52,8 @@
     /**
      * Effect capabilities.
      */
+    AcousticEchoCanceler.Capability acousticEchoCanceler;
+    AutomaticGainControl.Capability automaticGainControl;
     BassBoost.Capability bassBoost;
     Downmix.Capability downmix;
     DynamicsProcessing.Capability dynamicsProcessing;
@@ -56,6 +61,7 @@
     Equalizer.Capability equalizer;
     HapticGenerator.Capability hapticGenerator;
     LoudnessEnhancer.Capability loudnessEnhancer;
+    NoiseSuppression.Capability noiseSuppression;
     PresetReverb.Capability presetReverb;
     Virtualizer.Capability virtualizer;
     Visualizer.Capability visualizer;
diff --git a/audio/aidl/android/hardware/audio/effect/EnvironmentalReverb.aidl b/audio/aidl/android/hardware/audio/effect/EnvironmentalReverb.aidl
index 3df0d27..81c0dde 100644
--- a/audio/aidl/android/hardware/audio/effect/EnvironmentalReverb.aidl
+++ b/audio/aidl/android/hardware/audio/effect/EnvironmentalReverb.aidl
@@ -56,37 +56,109 @@
     }
 
     /**
+     * Minimal possible room level in millibels.
+     */
+    const int MIN_ROOM_LEVEL_MB = -6000;
+    /**
+     * Maximum possible room level in millibels.
+     */
+    const int MAX_ROOM_LEVEL_MB = 0;
+    /**
      * Room level apply to the reverb effect in millibels.
      */
     int roomLevelMb;
+
+    /**
+     * Minimal possible room hf level in millibels.
+     */
+    const int MIN_ROOM_HF_LEVEL_MB = -4000;
+    /**
+     * Maximum possible room hf level in millibels.
+     */
+    const int MAX_ROOM_HF_LEVEL_MB = 0;
     /**
      * Room HF level apply to the reverb effect in millibels.
      */
     int roomHfLevelMb;
+
+    /**
+     * Minimal possible decay time in milliseconds.
+     */
+    const int MIN_DECAY_TIME_MS = 100;
+    /**
+     * Maximum possible decay time in milliseconds.
+     */
+    const int MAX_DECAY_TIME_MS = 20000;
     /**
      * Delay time apply to the reverb effect in milliseconds.
      */
     int decayTimeMs;
+
+    /**
+     * Minimal possible per mille decay hf ratio.
+     */
+    const int MIN_DECAY_HF_RATIO_PM = 100;
+    /**
+     * Maximum possible per mille decay hf ratio.
+     */
+    const int MAX_DECAY_HF_RATIO_PM = 1000;
     /**
      * HF decay ratio in permilles.
      */
     int decayHfRatioPm;
+
+    /**
+     * Minimal possible room level in millibels.
+     */
+    const int MIN_LEVEL_MB = -6000;
+    /**
+     * Maximum possible room level in millibels.
+     */
+    const int MAX_LEVEL_MB = 0;
     /**
      * Reverb level in millibels.
      */
     int levelMb;
+
+    /**
+     * Minimal possible delay time in milliseconds.
+     */
+    const int MIN_DELAY_MS = 0;
+    /**
+     * Maximum possible delay time in milliseconds.
+     */
+    const int MAX_DELAY_MS = 65;
     /**
      * Reverb delay in milliseconds.
      */
     int delayMs;
+
+    /**
+     * Minimal possible per mille diffusion.
+     */
+    const int MIN_DIFFUSION_PM = 0;
+    /**
+     * Maximum possible per mille diffusion.
+     */
+    const int MAX_DIFFUSION_PM = 1000;
     /**
      * Diffusion in permilles.
      */
     int diffusionPm;
+
+    /**
+     * Minimal possible per mille density.
+     */
+    const int MIN_DENSITY_PM = 0;
+    /**
+     * Maximum possible per mille density.
+     */
+    const int MAX_DENSITY_PM = 1000;
     /**
      * Density in permilles.
      */
     int densityPm;
+
     /**
      * Bypass reverb and copy input to output if set to true.
      */
diff --git a/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl b/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl
index 944155f..3063ee3 100644
--- a/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl
+++ b/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl
@@ -90,6 +90,6 @@
         float maxAmplitude;
     }
 
-    HapticScale hapticScale;
+    HapticScale[] hapticScales;
     VibratorInformation vibratorInfo;
 }
diff --git a/audio/aidl/android/hardware/audio/effect/IEffect.aidl b/audio/aidl/android/hardware/audio/effect/IEffect.aidl
index 3b957d7..6097f34 100644
--- a/audio/aidl/android/hardware/audio/effect/IEffect.aidl
+++ b/audio/aidl/android/hardware/audio/effect/IEffect.aidl
@@ -34,12 +34,10 @@
         /**
          * One of Binder STATUS_* statuses:
          *  - STATUS_OK: the command has completed successfully;
-         *  - STATUS_BAD_VALUE: invalid value in the 'Command' structure;
-         *  - STATUS_INVALID_OPERATION: the mix port is not connected
-         *                              to any producer or consumer, thus
-         *                              positions can not be reported;
-         *  - STATUS_NOT_ENOUGH_DATA: a read or write error has
-         *                            occurred for the 'audio.fmq' queue;
+         *  - STATUS_BAD_VALUE: invalid parameters or state detected in effects;
+         *  - STATUS_INVALID_OPERATION: an internal error happens in effect audio buffer processing;
+         *  - STATUS_NOT_ENOUGH_DATA: a read or write error has occurred for the 'inputDataMQ' or
+         * 'outputDataMQ';
          *
          */
         int status;
diff --git a/audio/aidl/android/hardware/audio/effect/NoiseSuppression.aidl b/audio/aidl/android/hardware/audio/effect/NoiseSuppression.aidl
new file mode 100644
index 0000000..946fa87
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/NoiseSuppression.aidl
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.VendorExtension;
+
+/**
+ * Noise suppression (NS) is an audio pre-processor which removes background noise from the captured
+ * signal. The component of the signal considered as noise can be either stationary (car/airplane
+ * engine, AC system) or non-stationary (other peoples conversations, car horn) for more advanced
+ * implementations.
+ *
+ * All parameters defined in union NoiseSuppression must be gettable and settable. The capabilities
+ * defined in NoiseSuppression.Capability can only acquired with IEffect.getDescriptor() and not
+ * settable.
+ */
+@VintfStability
+union NoiseSuppression {
+    /**
+     * Effect parameter tag to identify the parameters for getParameter().
+     */
+    @VintfStability
+    union Id {
+        int vendorExtensionTag;
+        NoiseSuppression.Tag commonTag;
+    }
+
+    /**
+     * Vendor NoiseSuppression implementation definition for additional parameters.
+     */
+    VendorExtension vendor;
+
+    /**
+     * Capability supported by NoiseSuppression implementation.
+     */
+    @VintfStability
+    parcelable Capability {
+        /**
+         * NoiseSuppression capability extension, vendor can use this extension in case existing
+         * capability definition not enough.
+         */
+        ParcelableHolder extension;
+    }
+
+    /**
+     * Different level of Noise Suppression to set.
+     * As an example, webrtc have NsConfig::SuppressionLevel::k6dB applied for LOW level noise
+     * suppression, NsConfig::SuppressionLevel::k12dB for MEDIUM, and
+     * NsConfig::SuppressionLevel::k18dB for HIGH.
+     */
+    @VintfStability @Backing(type="int") enum Level { LOW, MEDIUM, HIGH }
+
+    /**
+     * The NS level.
+     */
+    Level level;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/Parameter.aidl b/audio/aidl/android/hardware/audio/effect/Parameter.aidl
index d7a6a27..1c001d2 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.effect.AcousticEchoCanceler;
+import android.hardware.audio.effect.AutomaticGainControl;
 import android.hardware.audio.effect.BassBoost;
 import android.hardware.audio.effect.Downmix;
 import android.hardware.audio.effect.DynamicsProcessing;
@@ -23,6 +25,7 @@
 import android.hardware.audio.effect.Equalizer;
 import android.hardware.audio.effect.HapticGenerator;
 import android.hardware.audio.effect.LoudnessEnhancer;
+import android.hardware.audio.effect.NoiseSuppression;
 import android.hardware.audio.effect.PresetReverb;
 import android.hardware.audio.effect.VendorExtension;
 import android.hardware.audio.effect.Virtualizer;
@@ -71,6 +74,8 @@
          *  effectInstance.getParameter(id, &param);
          *
          */
+        AcousticEchoCanceler.Id acousticEchoCancelerTag;
+        AutomaticGainControl.Id automaticGainControlTag;
         BassBoost.Id bassBoostTag;
         Downmix.Id downmixTag;
         DynamicsProcessing.Id dynamicsProcessingTag;
@@ -78,6 +83,7 @@
         Equalizer.Id equalizerTag;
         HapticGenerator.Id hapticGeneratorTag;
         LoudnessEnhancer.Id loudnessEnhancerTag;
+        NoiseSuppression.Id noiseSuppressionTag;
         PresetReverb.Id presetReverbTag;
         Virtualizer.Id virtualizerTag;
         Visualizer.Id visualizerTag;
@@ -149,6 +155,8 @@
     @VintfStability
     union Specific {
         VendorExtension vendorEffect;
+        AcousticEchoCanceler acousticEchoCanceler;
+        AutomaticGainControl automaticGainControl;
         BassBoost bassBoost;
         Downmix downmix;
         DynamicsProcessing dynamicsProcessing;
@@ -156,6 +164,7 @@
         Equalizer equalizer;
         HapticGenerator hapticGenerator;
         LoudnessEnhancer loudnessEnhancer;
+        NoiseSuppression noiseSuppression;
         PresetReverb presetReverb;
         Virtualizer virtualizer;
         Visualizer visualizer;
diff --git a/audio/aidl/android/hardware/audio/effect/Processing.aidl b/audio/aidl/android/hardware/audio/effect/Processing.aidl
index ef32e8c..cb77350 100644
--- a/audio/aidl/android/hardware/audio/effect/Processing.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Processing.aidl
@@ -38,7 +38,7 @@
      */
     Type type;
     /**
-     * List of effect identities for this processing.
+     * List of effect descriptors for this processing.
      */
-    Descriptor.Identity[] ids;
+    Descriptor[] ids;
 }
diff --git a/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl b/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl
index 9d039bc..5f385a6 100644
--- a/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl
@@ -53,6 +53,10 @@
          */
         VendorExtension extension;
         /**
+         * Maximum possible per mille strength.
+         */
+        int maxStrengthPm;
+        /**
          * Indicates whether setting strength is supported. False value indicates only one strength
          * is supported and setParameter() method will always return EX_ILLEGAL_ARGUMENT.
          */
@@ -66,7 +70,8 @@
      * allowed to round the given strength to the nearest supported value. In this case {@link
      * #IEffect.getParameter()} method should return the rounded value that was actually set.
      *
-     * The valid range for strength is [0, 1000].
+     * The value of the strength must be non-negative and not exceed the value specified by
+     * the 'maxStrengthPm' capability.
      */
     int strengthPm;
 }
diff --git a/audio/aidl/android/hardware/audio/effect/Visualizer.aidl b/audio/aidl/android/hardware/audio/effect/Visualizer.aidl
index 4c1b71a..dfe29c8 100644
--- a/audio/aidl/android/hardware/audio/effect/Visualizer.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Visualizer.aidl
@@ -63,16 +63,16 @@
         /**
          *  Capture size range.
          */
-        CaptureSizeRange captureSizeRange;
+        CaptureSamplesRange captureSampleRange;
     }
 
     /**
-     * Supported capture size range in bytes.
+     * Supported capture size range in samples.
      */
     @VintfStability
-    parcelable CaptureSizeRange {
-        int minBytes;
-        int maxBytes;
+    parcelable CaptureSamplesRange {
+        int min;
+        int max;
     }
 
     /**
@@ -131,9 +131,9 @@
         Measurement measurement;
 
         /**
-         * Gets the latest PCM capture, size of returned vector equals to @c captureSize.
+         * Get the latest captureSamples of PCM samples (8 bits per sample).
          */
-        byte[] captureBytes;
+        byte[] captureSampleBuffer;
     }
     GetOnlyParameters getOnlyParameters;
 
@@ -152,10 +152,10 @@
     SetOnlyParameters setOnlyParameters;
 
     /**
-     * Current capture size in bytes. The capture size must be a power of 2 in the range
+     * Current capture size in number of samples. The capture size must be inside
      * Capability.captureSizeRange.
      */
-    int captureSizeBytes;
+    int captureSamples;
     /**
      * Visualizer capture mode
      */
diff --git a/audio/aidl/android/hardware/audio/effect/Volume.aidl b/audio/aidl/android/hardware/audio/effect/Volume.aidl
index a3ce2f6..5033881 100644
--- a/audio/aidl/android/hardware/audio/effect/Volume.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Volume.aidl
@@ -52,13 +52,18 @@
         VendorExtension extension;
 
         /**
-         * Volume strength supported in dB.
+         * Minimum Volume level supported in dB.
          */
-        int maxLevel;
+        int minLevelDb;
+
+        /**
+         * Maximum Volume level supported in dB.
+         */
+        int maxLevelDb;
     }
 
     /**
-     * Current level in dB.
+     * Current level in dB with supported minimum and maximum level specified in capability.
      */
     int levelDb;
     /**
diff --git a/audio/aidl/common/include/Utils.h b/audio/aidl/common/include/Utils.h
index 990cff9..8f0c986 100644
--- a/audio/aidl/common/include/Utils.h
+++ b/audio/aidl/common/include/Utils.h
@@ -48,7 +48,8 @@
 }
 
 constexpr size_t getChannelCount(
-        const ::aidl::android::media::audio::common::AudioChannelLayout& layout) {
+        const ::aidl::android::media::audio::common::AudioChannelLayout& layout,
+        int32_t mask = std::numeric_limits<int32_t>::max()) {
     using Tag = ::aidl::android::media::audio::common::AudioChannelLayout::Tag;
     switch (layout.getTag()) {
         case Tag::none:
@@ -56,11 +57,11 @@
         case Tag::invalid:
             return 0;
         case Tag::indexMask:
-            return __builtin_popcount(layout.get<Tag::indexMask>());
+            return __builtin_popcount(layout.get<Tag::indexMask>() & mask);
         case Tag::layoutMask:
-            return __builtin_popcount(layout.get<Tag::layoutMask>());
+            return __builtin_popcount(layout.get<Tag::layoutMask>() & mask);
         case Tag::voiceMask:
-            return __builtin_popcount(layout.get<Tag::voiceMask>());
+            return __builtin_popcount(layout.get<Tag::voiceMask>() & mask);
     }
     return 0;
 }
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index f2cebbf..6f23636 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -29,6 +29,29 @@
     ],
 }
 
+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_static {
     name: "libaudioserviceexampleimpl",
     defaults: [
@@ -39,10 +62,12 @@
     export_include_dirs: ["include"],
     srcs: [
         "AudioPolicyConfigXmlConverter.cpp",
+        "Bluetooth.cpp",
         "Config.cpp",
         "Configuration.cpp",
         "EngineConfigXmlConverter.cpp",
         "Module.cpp",
+        "SoundDose.cpp",
         "Stream.cpp",
         "Telephony.cpp",
     ],
@@ -71,6 +96,7 @@
     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",
     ],
     static_libs: [
@@ -125,17 +151,21 @@
     vintf_fragments: ["android.hardware.audio.effect.service-aidl.xml"],
     defaults: ["aidlaudioeffectservice_defaults"],
     shared_libs: [
+        "libaecsw",
+        "libagcsw",
         "libbassboostsw",
         "libbundleaidl",
+        "libdownmixaidl",
         "libdynamicsprocessingsw",
         "libenvreverbsw",
         "libequalizersw",
-        "libhapticgeneratorsw",
-        "libloudnessenhancersw",
+        "libhapticgeneratoraidl",
+        "libloudnessenhanceraidl",
+        "libnssw",
         "libpresetreverbsw",
         "libtinyxml2",
         "libvirtualizersw",
-        "libvisualizersw",
+        "libvisualizeraidl",
         "libvolumesw",
     ],
     srcs: [
diff --git a/audio/aidl/default/Bluetooth.cpp b/audio/aidl/default/Bluetooth.cpp
new file mode 100644
index 0000000..38e0c21
--- /dev/null
+++ b/audio/aidl/default/Bluetooth.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "AHAL_Bluetooth"
+#include <android-base/logging.h>
+
+#include "core-impl/Bluetooth.h"
+
+using aidl::android::media::audio::common::Boolean;
+using aidl::android::media::audio::common::Float;
+using aidl::android::media::audio::common::Int;
+
+namespace aidl::android::hardware::audio::core {
+
+Bluetooth::Bluetooth() {
+    mScoConfig.isEnabled = Boolean{false};
+    mScoConfig.isNrecEnabled = Boolean{false};
+    mScoConfig.mode = ScoConfig::Mode::SCO;
+    mHfpConfig.isEnabled = Boolean{false};
+    mHfpConfig.sampleRate = Int{8000};
+    mHfpConfig.volume = Float{HfpConfig::VOLUME_MAX};
+}
+
+ndk::ScopedAStatus Bluetooth::setScoConfig(const ScoConfig& in_config, ScoConfig* _aidl_return) {
+    if (in_config.isEnabled.has_value()) {
+        mScoConfig.isEnabled = in_config.isEnabled;
+    }
+    if (in_config.isNrecEnabled.has_value()) {
+        mScoConfig.isNrecEnabled = in_config.isNrecEnabled;
+    }
+    if (in_config.mode != ScoConfig::Mode::UNSPECIFIED) {
+        mScoConfig.mode = in_config.mode;
+    }
+    if (in_config.debugName.has_value()) {
+        mScoConfig.debugName = in_config.debugName;
+    }
+    *_aidl_return = mScoConfig;
+    LOG(DEBUG) << __func__ << ": received " << in_config.toString() << ", returning "
+               << _aidl_return->toString();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Bluetooth::setHfpConfig(const HfpConfig& in_config, HfpConfig* _aidl_return) {
+    if (in_config.sampleRate.has_value() && in_config.sampleRate.value().value <= 0) {
+        LOG(ERROR) << __func__ << ": invalid sample rate: " << in_config.sampleRate.value().value;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    if (in_config.volume.has_value() && (in_config.volume.value().value < HfpConfig::VOLUME_MIN ||
+                                         in_config.volume.value().value > HfpConfig::VOLUME_MAX)) {
+        LOG(ERROR) << __func__ << ": invalid volume: " << in_config.volume.value().value;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+
+    if (in_config.isEnabled.has_value()) {
+        mHfpConfig.isEnabled = in_config.isEnabled;
+    }
+    if (in_config.sampleRate.has_value()) {
+        mHfpConfig.sampleRate = in_config.sampleRate;
+    }
+    if (in_config.volume.has_value()) {
+        mHfpConfig.volume = in_config.volume;
+    }
+    *_aidl_return = mHfpConfig;
+    LOG(DEBUG) << __func__ << ": received " << in_config.toString() << ", returning "
+               << _aidl_return->toString();
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/EffectFactory.cpp b/audio/aidl/default/EffectFactory.cpp
index 7ae9a66..3b40ae0 100644
--- a/audio/aidl/default/EffectFactory.cpp
+++ b/audio/aidl/default/EffectFactory.cpp
@@ -40,12 +40,13 @@
 }
 
 Factory::~Factory() {
-    if (auto count = mEffectUuidMap.size()) {
+    if (auto count = mEffectMap.size()) {
         LOG(ERROR) << __func__ << " remaining " << count
                    << " effect instances not destroyed indicating resource leak!";
-        for (const auto& it : mEffectUuidMap) {
+        for (const auto& it : mEffectMap) {
             if (auto spEffect = it.first.lock()) {
-                LOG(ERROR) << __func__ << " erase remaining instance UUID " << it.second.toString();
+                LOG(ERROR) << __func__ << " erase remaining instance UUID "
+                           << it.second.first.toString();
                 destroyEffectImpl(spEffect);
             }
         }
@@ -109,9 +110,10 @@
             return ndk::ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
         }
         *_aidl_return = effectSp;
-        AIBinder_setMinSchedulerPolicy(effectSp->asBinder().get(), SCHED_NORMAL,
-                                       ANDROID_PRIORITY_AUDIO);
-        mEffectUuidMap[std::weak_ptr<IEffect>(effectSp)] = in_impl_uuid;
+        ndk::SpAIBinder effectBinder = effectSp->asBinder();
+        AIBinder_setMinSchedulerPolicy(effectBinder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
+        mEffectMap[std::weak_ptr<IEffect>(effectSp)] =
+                std::make_pair(in_impl_uuid, std::move(effectBinder));
         LOG(DEBUG) << __func__ << ": instance " << effectSp.get() << " created successfully";
         return ndk::ScopedAStatus::ok();
     } else {
@@ -123,9 +125,9 @@
 
 ndk::ScopedAStatus Factory::destroyEffectImpl(const std::shared_ptr<IEffect>& in_handle) {
     std::weak_ptr<IEffect> wpHandle(in_handle);
-    // find UUID with key (std::weak_ptr<IEffect>)
-    if (auto uuidIt = mEffectUuidMap.find(wpHandle); uuidIt != mEffectUuidMap.end()) {
-        auto& uuid = uuidIt->second;
+    // find the effect entry with key (std::weak_ptr<IEffect>)
+    if (auto effectIt = mEffectMap.find(wpHandle); effectIt != mEffectMap.end()) {
+        auto& uuid = effectIt->second.first;
         // find implementation library with UUID
         if (auto libIt = mEffectLibMap.find(uuid); libIt != mEffectLibMap.end()) {
             auto& interface = std::get<kMapEntryInterfaceIndex>(libIt->second);
@@ -136,7 +138,7 @@
             LOG(ERROR) << __func__ << ": UUID " << uuid.toString() << " does not exist in libMap!";
             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
         }
-        mEffectUuidMap.erase(uuidIt);
+        mEffectMap.erase(effectIt);
         return ndk::ScopedAStatus::ok();
     } else {
         LOG(ERROR) << __func__ << ": instance " << in_handle << " does not exist!";
@@ -146,9 +148,9 @@
 
 // go over the map and cleanup all expired weak_ptrs.
 void Factory::cleanupEffectMap() {
-    for (auto it = mEffectUuidMap.begin(); it != mEffectUuidMap.end();) {
+    for (auto it = mEffectMap.begin(); it != mEffectMap.end();) {
         if (nullptr == it->first.lock()) {
-            it = mEffectUuidMap.erase(it);
+            it = mEffectMap.erase(it);
         } else {
             ++it;
         }
diff --git a/audio/aidl/default/EffectImpl.cpp b/audio/aidl/default/EffectImpl.cpp
index 139f262..b24ca63 100644
--- a/audio/aidl/default/EffectImpl.cpp
+++ b/audio/aidl/default/EffectImpl.cpp
@@ -21,6 +21,7 @@
 
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::State;
+using aidl::android::media::audio::common::PcmType;
 
 extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
     State state;
@@ -40,6 +41,10 @@
                                     const std::optional<Parameter::Specific>& specific,
                                     OpenEffectReturn* ret) {
     LOG(DEBUG) << __func__;
+    // effect only support 32bits float
+    RETURN_IF(common.input.base.format.pcm != common.output.base.format.pcm ||
+                      common.input.base.format.pcm != PcmType::FLOAT_32_BIT,
+              EX_ILLEGAL_ARGUMENT, "dataMustBe32BitsFloat");
     RETURN_OK_IF(mState != State::INIT);
     auto context = createContext(common);
     RETURN_IF(!context, EX_NULL_POINTER, "createContextFailed");
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index 47d6fa4..e8b5bfc 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -25,12 +25,15 @@
 #include <aidl/android/media/audio/common/AudioInputFlags.h>
 #include <aidl/android/media/audio/common/AudioOutputFlags.h>
 
+#include "core-impl/Bluetooth.h"
 #include "core-impl/Module.h"
+#include "core-impl/SoundDose.h"
 #include "core-impl/Telephony.h"
 #include "core-impl/utils.h"
 
 using aidl::android::hardware::audio::common::SinkMetadata;
 using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::hardware::audio::core::sounddose::ISoundDose;
 using aidl::android::media::audio::common::AudioChannelLayout;
 using aidl::android::media::audio::common::AudioDevice;
 using aidl::android::media::audio::common::AudioFormatDescription;
@@ -315,7 +318,8 @@
 ndk::ScopedAStatus Module::getTelephony(std::shared_ptr<ITelephony>* _aidl_return) {
     if (mTelephony == nullptr) {
         mTelephony = ndk::SharedRefBase::make<Telephony>();
-        AIBinder_setMinSchedulerPolicy(mTelephony->asBinder().get(), SCHED_NORMAL,
+        mTelephonyBinder = mTelephony->asBinder();
+        AIBinder_setMinSchedulerPolicy(mTelephonyBinder.get(), SCHED_NORMAL,
                                        ANDROID_PRIORITY_AUDIO);
     }
     *_aidl_return = mTelephony;
@@ -323,6 +327,18 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Module::getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) {
+    if (mBluetooth == nullptr) {
+        mBluetooth = ndk::SharedRefBase::make<Bluetooth>();
+        mBluetoothBinder = mBluetooth->asBinder();
+        AIBinder_setMinSchedulerPolicy(mBluetoothBinder.get(), SCHED_NORMAL,
+                                       ANDROID_PRIORITY_AUDIO);
+    }
+    *_aidl_return = mBluetooth;
+    LOG(DEBUG) << __func__ << ": returning instance of IBluetooth: " << _aidl_return->get();
+    return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus Module::connectExternalDevice(const AudioPort& in_templateIdAndAdditionalData,
                                                  AudioPort* _aidl_return) {
     const int32_t templateId = in_templateIdAndAdditionalData.id;
@@ -530,13 +546,15 @@
         return status;
     }
     context.fillDescriptor(&_aidl_return->desc);
-    auto stream = ndk::SharedRefBase::make<StreamIn>(in_args.sinkMetadata, std::move(context),
-                                                     mConfig->microphones);
-    if (auto status = stream->init(); !status.isOk()) {
+    std::shared_ptr<StreamIn> stream;
+    if (auto status = StreamIn::createInstance(in_args.sinkMetadata, std::move(context),
+                                               mConfig->microphones, &stream);
+        !status.isOk()) {
         return status;
     }
-    AIBinder_setMinSchedulerPolicy(stream->asBinder().get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
     StreamWrapper streamWrapper(stream);
+    AIBinder_setMinSchedulerPolicy(streamWrapper.getBinder().get(), SCHED_NORMAL,
+                                   ANDROID_PRIORITY_AUDIO);
     auto patchIt = mPatches.find(in_args.portConfigId);
     if (patchIt != mPatches.end()) {
         streamWrapper.setStreamIsConnected(findConnectedDevices(in_args.portConfigId));
@@ -581,13 +599,15 @@
         return status;
     }
     context.fillDescriptor(&_aidl_return->desc);
-    auto stream = ndk::SharedRefBase::make<StreamOut>(in_args.sourceMetadata, std::move(context),
-                                                      in_args.offloadInfo);
-    if (auto status = stream->init(); !status.isOk()) {
+    std::shared_ptr<StreamOut> stream;
+    if (auto status = StreamOut::createInstance(in_args.sourceMetadata, std::move(context),
+                                                in_args.offloadInfo, &stream);
+        !status.isOk()) {
         return status;
     }
-    AIBinder_setMinSchedulerPolicy(stream->asBinder().get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
     StreamWrapper streamWrapper(stream);
+    AIBinder_setMinSchedulerPolicy(streamWrapper.getBinder().get(), SCHED_NORMAL,
+                                   ANDROID_PRIORITY_AUDIO);
     auto patchIt = mPatches.find(in_args.portConfigId);
     if (patchIt != mPatches.end()) {
         streamWrapper.setStreamIsConnected(findConnectedDevices(in_args.portConfigId));
@@ -597,6 +617,13 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Module::getSupportedPlaybackRateFactors(
+        SupportedPlaybackRateFactors* _aidl_return) {
+    LOG(DEBUG) << __func__;
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
 ndk::ScopedAStatus Module::setAudioPatch(const AudioPatch& in_requested, AudioPatch* _aidl_return) {
     LOG(DEBUG) << __func__ << ": requested patch " << in_requested.toString();
     if (in_requested.sourcePortConfigIds.empty()) {
@@ -931,4 +958,60 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Module::getSoundDose(std::shared_ptr<ISoundDose>* _aidl_return) {
+    if (mSoundDose == nullptr) {
+        mSoundDose = ndk::SharedRefBase::make<sounddose::SoundDose>();
+        mSoundDoseBinder = mSoundDose->asBinder();
+        AIBinder_setMinSchedulerPolicy(mSoundDoseBinder.get(), SCHED_NORMAL,
+                                       ANDROID_PRIORITY_AUDIO);
+    }
+    *_aidl_return = mSoundDose;
+    LOG(DEBUG) << __func__ << ": returning instance of ISoundDose: " << _aidl_return->get();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::generateHwAvSyncId(int32_t* _aidl_return) {
+    LOG(DEBUG) << __func__;
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Module::getVendorParameters(const std::vector<std::string>& in_ids,
+                                               std::vector<VendorParameter>* _aidl_return) {
+    LOG(DEBUG) << __func__ << ": id count: " << in_ids.size();
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Module::setVendorParameters(const std::vector<VendorParameter>& in_parameters,
+                                               bool in_async) {
+    LOG(DEBUG) << __func__ << ": parameter count " << in_parameters.size()
+               << ", async: " << in_async;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Module::addDeviceEffect(
+        int32_t in_portConfigId,
+        const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) {
+    if (in_effect == nullptr) {
+        LOG(DEBUG) << __func__ << ": port id " << in_portConfigId << ", null effect";
+    } else {
+        LOG(DEBUG) << __func__ << ": port id " << in_portConfigId << ", effect Binder "
+                   << in_effect->asBinder().get();
+    }
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Module::removeDeviceEffect(
+        int32_t in_portConfigId,
+        const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) {
+    if (in_effect == nullptr) {
+        LOG(DEBUG) << __func__ << ": port id " << in_portConfigId << ", null effect";
+    } else {
+        LOG(DEBUG) << __func__ << ": port id " << in_portConfigId << ", effect Binder "
+                   << in_effect->asBinder().get();
+    }
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/SoundDose.cpp b/audio/aidl/default/SoundDose.cpp
new file mode 100644
index 0000000..be9f93a
--- /dev/null
+++ b/audio/aidl/default/SoundDose.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "AHAL_SoundDose"
+
+#include "core-impl/SoundDose.h"
+
+#include <android-base/logging.h>
+
+namespace aidl::android::hardware::audio::core::sounddose {
+
+ndk::ScopedAStatus SoundDose::setOutputRs2(float in_rs2ValueDbA) {
+    if (in_rs2ValueDbA < MIN_RS2 || in_rs2ValueDbA > DEFAULT_MAX_RS2) {
+        LOG(ERROR) << __func__ << ": RS2 value is invalid: " << in_rs2ValueDbA;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+
+    mRs2Value = in_rs2ValueDbA;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus SoundDose::getOutputRs2(float* _aidl_return) {
+    *_aidl_return = mRs2Value;
+    LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus SoundDose::registerSoundDoseCallback(
+        const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>& in_callback) {
+    if (in_callback.get() == nullptr) {
+        LOG(ERROR) << __func__ << ": Callback is nullptr";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    if (mCallback != nullptr) {
+        LOG(ERROR) << __func__ << ": Sound dose callback was already registered";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+
+    mCallback = in_callback;
+    LOG(DEBUG) << __func__ << ": Registered sound dose callback ";
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::audio::core::sounddose
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index be5887c..a490a2a 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "AHAL_Stream"
 #include <android-base/logging.h>
+#include <android/binder_ibinder_platform.h>
 #include <utils/SystemClock.h>
 
 #include <Utils.h>
@@ -26,7 +27,10 @@
 using aidl::android::hardware::audio::common::SinkMetadata;
 using aidl::android::hardware::audio::common::SourceMetadata;
 using aidl::android::media::audio::common::AudioDevice;
+using aidl::android::media::audio::common::AudioDualMonoMode;
+using aidl::android::media::audio::common::AudioLatencyMode;
 using aidl::android::media::audio::common::AudioOffloadInfo;
+using aidl::android::media::audio::common::AudioPlaybackRate;
 using android::hardware::audio::common::getChannelCount;
 using android::hardware::audio::common::getFrameSizeInBytes;
 
@@ -486,7 +490,7 @@
 }
 
 template <class Metadata, class StreamWorker>
-StreamCommon<Metadata, StreamWorker>::~StreamCommon() {
+StreamCommonImpl<Metadata, StreamWorker>::~StreamCommonImpl() {
     if (!isClosed()) {
         LOG(ERROR) << __func__ << ": stream was not closed prior to destruction, resource leak";
         stopWorker();
@@ -495,7 +499,74 @@
 }
 
 template <class Metadata, class StreamWorker>
-ndk::ScopedAStatus StreamCommon<Metadata, StreamWorker>::close() {
+void StreamCommonImpl<Metadata, StreamWorker>::createStreamCommon(
+        const std::shared_ptr<StreamCommonInterface>& delegate) {
+    if (mCommon != nullptr) {
+        LOG(FATAL) << __func__ << ": attempting to create the common interface twice";
+    }
+    mCommon = ndk::SharedRefBase::make<StreamCommon>(delegate);
+    mCommonBinder = mCommon->asBinder();
+    AIBinder_setMinSchedulerPolicy(mCommonBinder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
+}
+
+template <class Metadata, class StreamWorker>
+ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::getStreamCommon(
+        std::shared_ptr<IStreamCommon>* _aidl_return) {
+    if (mCommon == nullptr) {
+        LOG(FATAL) << __func__ << ": the common interface was not created";
+    }
+    *_aidl_return = mCommon;
+    LOG(DEBUG) << __func__ << ": returning " << _aidl_return->get()->asBinder().get();
+    return ndk::ScopedAStatus::ok();
+}
+
+template <class Metadata, class StreamWorker>
+ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::updateHwAvSyncId(
+        int32_t in_hwAvSyncId) {
+    LOG(DEBUG) << __func__ << ": id " << in_hwAvSyncId;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+template <class Metadata, class StreamWorker>
+ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::getVendorParameters(
+        const std::vector<std::string>& in_ids, std::vector<VendorParameter>* _aidl_return) {
+    LOG(DEBUG) << __func__ << ": id count: " << in_ids.size();
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+template <class Metadata, class StreamWorker>
+ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::setVendorParameters(
+        const std::vector<VendorParameter>& in_parameters, bool in_async) {
+    LOG(DEBUG) << __func__ << ": parameters count " << in_parameters.size()
+               << ", async: " << in_async;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+template <class Metadata, class StreamWorker>
+ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::addEffect(
+        const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) {
+    if (in_effect == nullptr) {
+        LOG(DEBUG) << __func__ << ": null effect";
+    } else {
+        LOG(DEBUG) << __func__ << ": effect Binder" << in_effect->asBinder().get();
+    }
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+template <class Metadata, class StreamWorker>
+ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::removeEffect(
+        const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) {
+    if (in_effect == nullptr) {
+        LOG(DEBUG) << __func__ << ": null effect";
+    } else {
+        LOG(DEBUG) << __func__ << ": effect Binder" << in_effect->asBinder().get();
+    }
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+template <class Metadata, class StreamWorker>
+ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::close() {
     LOG(DEBUG) << __func__;
     if (!isClosed()) {
         stopWorker();
@@ -512,7 +583,7 @@
 }
 
 template <class Metadata, class StreamWorker>
-void StreamCommon<Metadata, StreamWorker>::stopWorker() {
+void StreamCommonImpl<Metadata, StreamWorker>::stopWorker() {
     if (auto commandMQ = mContext.getCommandMQ(); commandMQ != nullptr) {
         LOG(DEBUG) << __func__ << ": asking the worker to exit...";
         auto cmd = StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::halReservedExit>(
@@ -529,7 +600,8 @@
 }
 
 template <class Metadata, class StreamWorker>
-ndk::ScopedAStatus StreamCommon<Metadata, StreamWorker>::updateMetadata(const Metadata& metadata) {
+ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::updateMetadata(
+        const Metadata& metadata) {
     LOG(DEBUG) << __func__;
     if (!isClosed()) {
         mMetadata = metadata;
@@ -539,6 +611,20 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
 }
 
+// static
+ndk::ScopedAStatus StreamIn::createInstance(const common::SinkMetadata& sinkMetadata,
+                                            StreamContext context,
+                                            const std::vector<MicrophoneInfo>& microphones,
+                                            std::shared_ptr<StreamIn>* result) {
+    auto stream = ndk::SharedRefBase::make<StreamIn>(sinkMetadata, std::move(context), microphones);
+    if (auto status = stream->init(); !status.isOk()) {
+        return status;
+    }
+    stream->createStreamCommon(stream);
+    *result = std::move(stream);
+    return ndk::ScopedAStatus::ok();
+}
+
 namespace {
 static std::map<AudioDevice, std::string> transformMicrophones(
         const std::vector<MicrophoneInfo>& microphones) {
@@ -549,9 +635,9 @@
 }
 }  // namespace
 
-StreamIn::StreamIn(const SinkMetadata& sinkMetadata, StreamContext context,
+StreamIn::StreamIn(const SinkMetadata& sinkMetadata, StreamContext&& context,
                    const std::vector<MicrophoneInfo>& microphones)
-    : StreamCommon<SinkMetadata, StreamInWorker>(sinkMetadata, std::move(context)),
+    : StreamCommonImpl<SinkMetadata, StreamInWorker>(sinkMetadata, std::move(context)),
       mMicrophones(transformMicrophones(microphones)) {
     LOG(DEBUG) << __func__;
 }
@@ -597,11 +683,99 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
-StreamOut::StreamOut(const SourceMetadata& sourceMetadata, StreamContext context,
+ndk::ScopedAStatus StreamIn::getHwGain(std::vector<float>* _aidl_return) {
+    LOG(DEBUG) << __func__;
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamIn::setHwGain(const std::vector<float>& in_channelGains) {
+    LOG(DEBUG) << __func__ << ": gains " << ::android::internal::ToString(in_channelGains);
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+// static
+ndk::ScopedAStatus StreamOut::createInstance(const SourceMetadata& sourceMetadata,
+                                             StreamContext context,
+                                             const std::optional<AudioOffloadInfo>& offloadInfo,
+                                             std::shared_ptr<StreamOut>* result) {
+    auto stream =
+            ndk::SharedRefBase::make<StreamOut>(sourceMetadata, std::move(context), offloadInfo);
+    if (auto status = stream->init(); !status.isOk()) {
+        return status;
+    }
+    stream->createStreamCommon(stream);
+    *result = std::move(stream);
+    return ndk::ScopedAStatus::ok();
+}
+
+StreamOut::StreamOut(const SourceMetadata& sourceMetadata, StreamContext&& context,
                      const std::optional<AudioOffloadInfo>& offloadInfo)
-    : StreamCommon<SourceMetadata, StreamOutWorker>(sourceMetadata, std::move(context)),
+    : StreamCommonImpl<SourceMetadata, StreamOutWorker>(sourceMetadata, std::move(context)),
       mOffloadInfo(offloadInfo) {
     LOG(DEBUG) << __func__;
 }
 
+ndk::ScopedAStatus StreamOut::getHwVolume(std::vector<float>* _aidl_return) {
+    LOG(DEBUG) << __func__;
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::setHwVolume(const std::vector<float>& in_channelVolumes) {
+    LOG(DEBUG) << __func__ << ": gains " << ::android::internal::ToString(in_channelVolumes);
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::getAudioDescriptionMixLevel(float* _aidl_return) {
+    LOG(DEBUG) << __func__;
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::setAudioDescriptionMixLevel(float in_leveldB) {
+    LOG(DEBUG) << __func__ << ": description mix level " << in_leveldB;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::getDualMonoMode(AudioDualMonoMode* _aidl_return) {
+    LOG(DEBUG) << __func__;
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::setDualMonoMode(AudioDualMonoMode in_mode) {
+    LOG(DEBUG) << __func__ << ": dual mono mode " << toString(in_mode);
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::getRecommendedLatencyModes(
+        std::vector<AudioLatencyMode>* _aidl_return) {
+    LOG(DEBUG) << __func__;
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::setLatencyMode(AudioLatencyMode in_mode) {
+    LOG(DEBUG) << __func__ << ": latency mode " << toString(in_mode);
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::getPlaybackRateParameters(AudioPlaybackRate* _aidl_return) {
+    LOG(DEBUG) << __func__;
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::setPlaybackRateParameters(const AudioPlaybackRate& in_playbackRate) {
+    LOG(DEBUG) << __func__ << ": " << in_playbackRate.toString();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::selectPresentation(int32_t in_presentationId, int32_t in_programId) {
+    LOG(DEBUG) << __func__ << ": presentationId " << in_presentationId << ", programId "
+               << in_programId;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/Telephony.cpp b/audio/aidl/default/Telephony.cpp
index 1854b35..d873178 100644
--- a/audio/aidl/default/Telephony.cpp
+++ b/audio/aidl/default/Telephony.cpp
@@ -20,8 +20,17 @@
 
 #include "core-impl/Telephony.h"
 
+using aidl::android::media::audio::common::Boolean;
+using aidl::android::media::audio::common::Float;
+
 namespace aidl::android::hardware::audio::core {
 
+Telephony::Telephony() {
+    mTelecomConfig.voiceVolume = Float{TelecomConfig::VOICE_VOLUME_MAX};
+    mTelecomConfig.ttyMode = TelecomConfig::TtyMode::OFF;
+    mTelecomConfig.isHacEnabled = Boolean{false};
+}
+
 ndk::ScopedAStatus Telephony::getSupportedAudioModes(std::vector<AudioMode>* _aidl_return) {
     *_aidl_return = mSupportedAudioModes;
     LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return);
@@ -38,4 +47,28 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
+ndk::ScopedAStatus Telephony::setTelecomConfig(const TelecomConfig& in_config,
+                                               TelecomConfig* _aidl_return) {
+    if (in_config.voiceVolume.has_value() &&
+        (in_config.voiceVolume.value().value < TelecomConfig::VOICE_VOLUME_MIN ||
+         in_config.voiceVolume.value().value > TelecomConfig::VOICE_VOLUME_MAX)) {
+        LOG(ERROR) << __func__
+                   << ": voice volume value is invalid: " << in_config.voiceVolume.value().value;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    if (in_config.voiceVolume.has_value()) {
+        mTelecomConfig.voiceVolume = in_config.voiceVolume;
+    }
+    if (in_config.ttyMode != TelecomConfig::TtyMode::UNSPECIFIED) {
+        mTelecomConfig.ttyMode = in_config.ttyMode;
+    }
+    if (in_config.isHacEnabled.has_value()) {
+        mTelecomConfig.isHacEnabled = in_config.isHacEnabled;
+    }
+    *_aidl_return = mTelecomConfig;
+    LOG(DEBUG) << __func__ << ": received " << in_config.toString() << ", returning "
+               << _aidl_return->toString();
+    return ndk::ScopedAStatus::ok();
+}
+
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
new file mode 100644
index 0000000..7f06013
--- /dev/null
+++ b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
@@ -0,0 +1,194 @@
+/*
+ * 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.
+ */
+
+#include <algorithm>
+#include <cstddef>
+#include <memory>
+#define LOG_TAG "AHAL_AcousticEchoCancelerSw"
+#include <Utils.h>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "AcousticEchoCancelerSw.h"
+
+using aidl::android::hardware::audio::effect::AcousticEchoCancelerSw;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kAcousticEchoCancelerSwImplUUID;
+using aidl::android::media::audio::common::AudioUuid;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+                                           std::shared_ptr<IEffect>* instanceSpp) {
+    if (!in_impl_uuid || *in_impl_uuid != kAcousticEchoCancelerSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (instanceSpp) {
+        *instanceSpp = ndk::SharedRefBase::make<AcousticEchoCancelerSw>();
+        LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
+        return EX_NONE;
+    } else {
+        LOG(ERROR) << __func__ << " invalid input parameter!";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+}
+
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+    if (!in_impl_uuid || *in_impl_uuid != kAcousticEchoCancelerSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    *_aidl_return = AcousticEchoCancelerSw::kDescriptor;
+    LOG(ERROR) << __func__ << "xxx " << _aidl_return->toString();
+    return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+const std::string AcousticEchoCancelerSw::kEffectName = "AcousticEchoCancelerSw";
+const AcousticEchoCanceler::Capability AcousticEchoCancelerSw::kCapability = {
+        .maxEchoDelayUs = 500, .supportMobileMode = false};
+const Descriptor AcousticEchoCancelerSw::kDescriptor = {
+        .common = {.id = {.type = kAcousticEchoCancelerTypeUUID,
+                          .uuid = kAcousticEchoCancelerSwImplUUID,
+                          .proxy = std::nullopt},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::FIRST,
+                             .volume = Flags::Volume::CTRL},
+                   .name = AcousticEchoCancelerSw::kEffectName,
+                   .implementor = "The Android Open Source Project"},
+        .capability = Capability::make<Capability::acousticEchoCanceler>(
+                AcousticEchoCancelerSw::kCapability)};
+
+ndk::ScopedAStatus AcousticEchoCancelerSw::getDescriptor(Descriptor* _aidl_return) {
+    LOG(DEBUG) << __func__ << kDescriptor.toString();
+    *_aidl_return = kDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AcousticEchoCancelerSw::setParameterSpecific(
+        const Parameter::Specific& specific) {
+    RETURN_IF(Parameter::Specific::acousticEchoCanceler != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+              "EffectNotSupported");
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    auto& param = specific.get<Parameter::Specific::acousticEchoCanceler>();
+    auto tag = param.getTag();
+
+    switch (tag) {
+        case AcousticEchoCanceler::echoDelayUs: {
+            RETURN_IF(mContext->setEchoDelay(param.get<AcousticEchoCanceler::echoDelayUs>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "echoDelayNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        case AcousticEchoCanceler::mobileMode: {
+            RETURN_IF(true == param.get<AcousticEchoCanceler::mobileMode>(), EX_ILLEGAL_ARGUMENT,
+                      "SettingmobileModeSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "AcousticEchoCancelerTagNotSupported");
+        }
+    }
+}
+
+ndk::ScopedAStatus AcousticEchoCancelerSw::getParameterSpecific(const Parameter::Id& id,
+                                                                Parameter::Specific* specific) {
+    auto tag = id.getTag();
+    RETURN_IF(Parameter::Id::acousticEchoCancelerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+    auto specificId = id.get<Parameter::Id::acousticEchoCancelerTag>();
+    auto specificIdTag = specificId.getTag();
+    switch (specificIdTag) {
+        case AcousticEchoCanceler::Id::commonTag:
+            return getParameterAcousticEchoCanceler(
+                    specificId.get<AcousticEchoCanceler::Id::commonTag>(), specific);
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "AcousticEchoCancelerTagNotSupported");
+    }
+}
+
+ndk::ScopedAStatus AcousticEchoCancelerSw::getParameterAcousticEchoCanceler(
+        const AcousticEchoCanceler::Tag& tag, Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    AcousticEchoCanceler param;
+    switch (tag) {
+        case AcousticEchoCanceler::echoDelayUs: {
+            param.set<AcousticEchoCanceler::echoDelayUs>(mContext->getEchoDelay());
+            break;
+        }
+        case AcousticEchoCanceler::mobileMode: {
+            param.set<AcousticEchoCanceler::mobileMode>(false);
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "AcousticEchoCancelerTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::acousticEchoCanceler>(param);
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> AcousticEchoCancelerSw::createContext(
+        const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+    } else {
+        mContext = std::make_shared<AcousticEchoCancelerSwContext>(1 /* statusFmqDepth */, common);
+    }
+    return mContext;
+}
+
+std::shared_ptr<EffectContext> AcousticEchoCancelerSw::getContext() {
+    return mContext;
+}
+
+RetCode AcousticEchoCancelerSw::releaseContext() {
+    if (mContext) {
+        mContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status AcousticEchoCancelerSw::effectProcessImpl(float* in, float* out, int samples) {
+    // TODO: get data buffer and process.
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+    for (int i = 0; i < samples; i++) {
+        *out++ = *in++;
+    }
+    return {STATUS_OK, samples, samples};
+}
+
+RetCode AcousticEchoCancelerSwContext::setEchoDelay(int echoDelayUs) {
+    if (echoDelayUs < 0 || echoDelayUs > AcousticEchoCancelerSw::kCapability.maxEchoDelayUs) {
+        LOG(DEBUG) << __func__ << " illegal delay " << echoDelayUs;
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+    mEchoDelayUs = echoDelayUs;
+    return RetCode::SUCCESS;
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.h b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.h
new file mode 100644
index 0000000..5f1bc46
--- /dev/null
+++ b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+#include <cstdlib>
+#include <memory>
+
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class AcousticEchoCancelerSwContext final : public EffectContext {
+  public:
+    AcousticEchoCancelerSwContext(int statusDepth, const Parameter::Common& common)
+        : EffectContext(statusDepth, common) {
+        LOG(DEBUG) << __func__;
+    }
+
+    RetCode setEchoDelay(int echoDelayUs);
+    int getEchoDelay() const { return mEchoDelayUs; }
+
+  private:
+    int mEchoDelayUs = 0;
+};
+
+class AcousticEchoCancelerSw final : public EffectImpl {
+  public:
+    static const std::string kEffectName;
+    static const bool kStrengthSupported;
+    static const AcousticEchoCanceler::Capability kCapability;
+    static const Descriptor kDescriptor;
+    AcousticEchoCancelerSw() { LOG(DEBUG) << __func__; }
+    ~AcousticEchoCancelerSw() {
+        cleanUp();
+        LOG(DEBUG) << __func__;
+    }
+
+    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:
+    std::shared_ptr<AcousticEchoCancelerSwContext> mContext;
+    ndk::ScopedAStatus getParameterAcousticEchoCanceler(const AcousticEchoCanceler::Tag& tag,
+                                                        Parameter::Specific* specific);
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/acousticEchoCanceler/Android.bp b/audio/aidl/default/acousticEchoCanceler/Android.bp
new file mode 100644
index 0000000..b2e2682
--- /dev/null
+++ b/audio/aidl/default/acousticEchoCanceler/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+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: "libaecsw",
+    defaults: [
+        "aidlaudioeffectservice_defaults",
+        "latest_android_media_audio_common_types_ndk_shared",
+        "latest_android_hardware_audio_effect_ndk_shared",
+    ],
+    srcs: [
+        "AcousticEchoCancelerSw.cpp",
+        ":effectCommonFile",
+    ],
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
+    ],
+}
diff --git a/audio/aidl/default/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml
index f4ac8fe..9670e9c 100644
--- a/audio/aidl/default/audio_effects_config.xml
+++ b/audio/aidl/default/audio_effects_config.xml
@@ -28,16 +28,20 @@
          name of a library .so file on the target device.
     -->
     <libraries>
+        <library name="aecsw" path="libaecsw.so"/>
+        <library name="agcsw" path="libagcsw.so"/>
         <library name="bassboostsw" path="libbassboostsw.so"/>
         <library name="bundle" path="libbundleaidl.so"/>
+        <library name="downmix" path="libdownmixaidl.so"/>
         <library name="dynamics_processingsw" path="libdynamicsprocessingsw.so"/>
         <library name="equalizersw" path="libequalizersw.so"/>
-        <library name="haptic_generatorsw" path="libhapticgeneratorsw.so"/>
-        <library name="loudness_enhancersw" path="libloudnessenhancersw.so"/>
+        <library name="haptic_generator" path="libhapticgeneratoraidl.so"/>
+        <library name="loudness_enhancer" path="libloudnessenhanceraidl.so"/>
+        <library name="nssw" path="libnssw.so"/>
         <library name="env_reverbsw" path="libenvreverbsw.so"/>
         <library name="preset_reverbsw" path="libpresetreverbsw.so"/>
         <library name="virtualizersw" path="libvirtualizersw.so"/>
-        <library name="visualizersw" path="libvisualizersw.so"/>
+        <library name="visualizer" path="libvisualizeraidl.so"/>
         <library name="volumesw" path="libvolumesw.so"/>
     </libraries>
 
@@ -61,15 +65,25 @@
     -->
 
     <effects>
-        <effect name="bassboost" library="bassboostsw" uuid="fa8181f2-588b-11ed-9b6a-0242ac120002"/>
+        <effect name="acoustic_echo_canceler" library="aecsw" uuid="bb392ec0-8d4d-11e0-a896-0002a5d5c51b"/>
+        <effect name="automatic_gain_control" library="agcsw" uuid="89f38e65-d4d2-4d64-ad0e-2b3e799ea886"/>
+        <effectProxy name="bassboost" uuid="14804144-a5ee-4d24-aa88-0002a5d5c51b">
+            <libsw library="bassboostsw" uuid="fa8181f2-588b-11ed-9b6a-0242ac120002"/>
+            <libsw library="bundle" uuid="8631f300-72e2-11df-b57e-0002a5d5c51b"/>
+        </effectProxy>
+        <effect name="downmix" library="downmix" uuid="93f04452-e4fe-41cc-91f9-e475b6d1d69f"/>
         <effect name="dynamics_processing" library="dynamics_processingsw" uuid="fa818d78-588b-11ed-9b6a-0242ac120002"/>
-        <effect name="haptic_generator" library="haptic_generatorsw" uuid="fa819110-588b-11ed-9b6a-0242ac120002"/>
-        <effect name="loudness_enhancer" library="loudness_enhancersw" uuid="fa819610-588b-11ed-9b6a-0242ac120002"/>
+        <effect name="haptic_generator" library="haptic_generator" uuid="97c4acd1-8b82-4f2f-832e-c2fe5d7a9931"/>
+        <effect name="loudness_enhancer" library="loudness_enhancer" uuid="fa415329-2034-4bea-b5dc-5b381c8d1e2c"/>
         <effect name="env_reverb" library="env_reverbsw" uuid="fa819886-588b-11ed-9b6a-0242ac120002"/>
+        <effect name="noise_suppression" library="nssw" uuid="c06c8400-8e06-11e0-9cb6-0002a5d5c51b"/>
         <effect name="preset_reverb" library="preset_reverbsw" uuid="fa8199c6-588b-11ed-9b6a-0242ac120002"/>
-        <effect name="virtualizer" library="virtualizersw" uuid="fa819d86-588b-11ed-9b6a-0242ac120002"/>
-        <effect name="visualizer" library="visualizersw" uuid="fa81a0f6-588b-11ed-9b6a-0242ac120002"/>
-        <effect name="volume" library="volumesw" uuid="fa81a718-588b-11ed-9b6a-0242ac120002"/>
+        <effectProxy name="virtualizer" uuid="d3467faa-acc7-4d34-acaf-0002a5d5c51b">
+            <libsw library="virtualizersw" uuid="fa819d86-588b-11ed-9b6a-0242ac120002"/>
+            <libsw library="bundle" uuid="1d4033c0-8557-11df-9f2d-0002a5d5c51b"/>
+        </effectProxy>
+        <effect name="visualizer" library="visualizer" uuid="d069d9e0-8329-11df-9168-0002a5d5c51b"/>
+        <effect name="volume" library="bundle" uuid="119341a0-8469-11df-81f9-0002a5d5c51b"/>
         <effectProxy name="equalizer" uuid="c8e70ecd-48ca-456e-8a4f-0002a5d5c51b">
             <libsw library="equalizersw" uuid="0bed4300-847d-11df-bb17-0002a5d5c51b"/>
             <libsw library="bundle" uuid="ce772f20-847d-11df-bb17-0002a5d5c51b"/>
diff --git a/audio/aidl/default/automaticGainControl/Android.bp b/audio/aidl/default/automaticGainControl/Android.bp
new file mode 100644
index 0000000..4899b39
--- /dev/null
+++ b/audio/aidl/default/automaticGainControl/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+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: "libagcsw",
+    defaults: [
+        "aidlaudioeffectservice_defaults",
+        "latest_android_media_audio_common_types_ndk_shared",
+        "latest_android_hardware_audio_effect_ndk_shared",
+    ],
+    srcs: [
+        "AutomaticGainControlSw.cpp",
+        ":effectCommonFile",
+    ],
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
+    ],
+}
diff --git a/audio/aidl/default/automaticGainControl/AutomaticGainControlSw.cpp b/audio/aidl/default/automaticGainControl/AutomaticGainControlSw.cpp
new file mode 100644
index 0000000..8c706ef
--- /dev/null
+++ b/audio/aidl/default/automaticGainControl/AutomaticGainControlSw.cpp
@@ -0,0 +1,234 @@
+/*
+ * 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.
+ */
+
+#include <algorithm>
+#include <cstddef>
+#include <memory>
+#define LOG_TAG "AHAL_AutomaticGainControlSw"
+#include <Utils.h>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "AutomaticGainControlSw.h"
+
+using aidl::android::hardware::audio::effect::AutomaticGainControlSw;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kAutomaticGainControlSwImplUUID;
+using aidl::android::media::audio::common::AudioUuid;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+                                           std::shared_ptr<IEffect>* instanceSpp) {
+    if (!in_impl_uuid || *in_impl_uuid != kAutomaticGainControlSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (instanceSpp) {
+        *instanceSpp = ndk::SharedRefBase::make<AutomaticGainControlSw>();
+        LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
+        return EX_NONE;
+    } else {
+        LOG(ERROR) << __func__ << " invalid input parameter!";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+}
+
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+    if (!in_impl_uuid || *in_impl_uuid != kAutomaticGainControlSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    *_aidl_return = AutomaticGainControlSw::kDescriptor;
+    return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+const std::string AutomaticGainControlSw::kEffectName = "AutomaticGainControlSw";
+const AutomaticGainControl::Capability AutomaticGainControlSw::kCapability = {
+        .maxFixedDigitalGainMb = 50000, .maxSaturationMarginMb = 10000};
+const Descriptor AutomaticGainControlSw::kDescriptor = {
+        .common = {.id = {.type = kAutomaticGainControlTypeUUID,
+                          .uuid = kAutomaticGainControlSwImplUUID,
+                          .proxy = std::nullopt},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::FIRST,
+                             .volume = Flags::Volume::CTRL},
+                   .name = AutomaticGainControlSw::kEffectName,
+                   .implementor = "The Android Open Source Project"},
+        .capability = Capability::make<Capability::automaticGainControl>(
+                AutomaticGainControlSw::kCapability)};
+
+ndk::ScopedAStatus AutomaticGainControlSw::getDescriptor(Descriptor* _aidl_return) {
+    LOG(DEBUG) << __func__ << kDescriptor.toString();
+    *_aidl_return = kDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AutomaticGainControlSw::setParameterSpecific(
+        const Parameter::Specific& specific) {
+    RETURN_IF(Parameter::Specific::automaticGainControl != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+              "EffectNotSupported");
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    auto& param = specific.get<Parameter::Specific::automaticGainControl>();
+    auto tag = param.getTag();
+
+    switch (tag) {
+        case AutomaticGainControl::fixedDigitalGainMb: {
+            RETURN_IF(mContext->setDigitalGain(
+                              param.get<AutomaticGainControl::fixedDigitalGainMb>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "digitalGainNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        case AutomaticGainControl::levelEstimator: {
+            RETURN_IF(
+                    mContext->setLevelEstimator(
+                            param.get<AutomaticGainControl::levelEstimator>()) != RetCode::SUCCESS,
+                    EX_ILLEGAL_ARGUMENT, "levelEstimatorNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        case AutomaticGainControl::saturationMarginMb: {
+            RETURN_IF(mContext->setSaturationMargin(
+                              param.get<AutomaticGainControl::saturationMarginMb>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "saturationMarginNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "AutomaticGainControlTagNotSupported");
+        }
+    }
+}
+
+ndk::ScopedAStatus AutomaticGainControlSw::getParameterSpecific(const Parameter::Id& id,
+                                                                Parameter::Specific* specific) {
+    auto tag = id.getTag();
+    RETURN_IF(Parameter::Id::automaticGainControlTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+    auto specificId = id.get<Parameter::Id::automaticGainControlTag>();
+    auto specificIdTag = specificId.getTag();
+    switch (specificIdTag) {
+        case AutomaticGainControl::Id::commonTag:
+            return getParameterAutomaticGainControl(
+                    specificId.get<AutomaticGainControl::Id::commonTag>(), specific);
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "AutomaticGainControlTagNotSupported");
+    }
+}
+
+ndk::ScopedAStatus AutomaticGainControlSw::getParameterAutomaticGainControl(
+        const AutomaticGainControl::Tag& tag, Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    AutomaticGainControl param;
+    switch (tag) {
+        case AutomaticGainControl::fixedDigitalGainMb: {
+            param.set<AutomaticGainControl::fixedDigitalGainMb>(mContext->getDigitalGain());
+            break;
+        }
+        case AutomaticGainControl::levelEstimator: {
+            param.set<AutomaticGainControl::levelEstimator>(mContext->getLevelEstimator());
+            break;
+        }
+        case AutomaticGainControl::saturationMarginMb: {
+            param.set<AutomaticGainControl::saturationMarginMb>(mContext->getSaturationMargin());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "AutomaticGainControlTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::automaticGainControl>(param);
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> AutomaticGainControlSw::createContext(
+        const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+    } else {
+        mContext = std::make_shared<AutomaticGainControlSwContext>(1 /* statusFmqDepth */, common);
+    }
+    return mContext;
+}
+
+std::shared_ptr<EffectContext> AutomaticGainControlSw::getContext() {
+    return mContext;
+}
+
+RetCode AutomaticGainControlSw::releaseContext() {
+    if (mContext) {
+        mContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status AutomaticGainControlSw::effectProcessImpl(float* in, float* out, int samples) {
+    // TODO: get data buffer and process.
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+    for (int i = 0; i < samples; i++) {
+        *out++ = *in++;
+    }
+    return {STATUS_OK, samples, samples};
+}
+
+RetCode AutomaticGainControlSwContext::setDigitalGain(int gain) {
+    if (gain < 0 || gain > AutomaticGainControlSw::kCapability.maxFixedDigitalGainMb) {
+        LOG(DEBUG) << __func__ << " illegal digital gain " << gain;
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+    mDigitalGain = gain;
+    return RetCode::SUCCESS;
+}
+
+int AutomaticGainControlSwContext::getDigitalGain() {
+    return mDigitalGain;
+}
+
+RetCode AutomaticGainControlSwContext::setLevelEstimator(
+        AutomaticGainControl::LevelEstimator levelEstimator) {
+    mLevelEstimator = levelEstimator;
+    return RetCode::SUCCESS;
+}
+
+AutomaticGainControl::LevelEstimator AutomaticGainControlSwContext::getLevelEstimator() {
+    return mLevelEstimator;
+}
+
+RetCode AutomaticGainControlSwContext::setSaturationMargin(int margin) {
+    if (margin < 0 || margin > AutomaticGainControlSw::kCapability.maxSaturationMarginMb) {
+        LOG(DEBUG) << __func__ << " illegal saturationMargin " << margin;
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+    mSaturationMargin = margin;
+    return RetCode::SUCCESS;
+}
+
+int AutomaticGainControlSwContext::getSaturationMargin() {
+    return mSaturationMargin;
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/automaticGainControl/AutomaticGainControlSw.h b/audio/aidl/default/automaticGainControl/AutomaticGainControlSw.h
new file mode 100644
index 0000000..2724835
--- /dev/null
+++ b/audio/aidl/default/automaticGainControl/AutomaticGainControlSw.h
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+#include <cstdlib>
+#include <memory>
+
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class AutomaticGainControlSwContext final : public EffectContext {
+  public:
+    AutomaticGainControlSwContext(int statusDepth, const Parameter::Common& common)
+        : EffectContext(statusDepth, common) {
+        LOG(DEBUG) << __func__;
+    }
+
+    RetCode setDigitalGain(int gain);
+    int getDigitalGain();
+    RetCode setLevelEstimator(AutomaticGainControl::LevelEstimator levelEstimator);
+    AutomaticGainControl::LevelEstimator getLevelEstimator();
+    RetCode setSaturationMargin(int margin);
+    int getSaturationMargin();
+
+  private:
+    int mDigitalGain = 0;
+    AutomaticGainControl::LevelEstimator mLevelEstimator =
+            AutomaticGainControl::LevelEstimator::RMS;
+    int mSaturationMargin = 0;
+};
+
+class AutomaticGainControlSw final : public EffectImpl {
+  public:
+    static const std::string kEffectName;
+    static const bool kStrengthSupported;
+    static const AutomaticGainControl::Capability kCapability;
+    static const Descriptor kDescriptor;
+    AutomaticGainControlSw() { LOG(DEBUG) << __func__; }
+    ~AutomaticGainControlSw() {
+        cleanUp();
+        LOG(DEBUG) << __func__;
+    }
+
+    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:
+    std::shared_ptr<AutomaticGainControlSwContext> mContext;
+    ndk::ScopedAStatus getParameterAutomaticGainControl(const AutomaticGainControl::Tag& tag,
+                                                        Parameter::Specific* specific);
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/bassboost/BassBoostSw.cpp b/audio/aidl/default/bassboost/BassBoostSw.cpp
index 61976c8..0c7ebe1 100644
--- a/audio/aidl/default/bassboost/BassBoostSw.cpp
+++ b/audio/aidl/default/bassboost/BassBoostSw.cpp
@@ -62,11 +62,12 @@
 
 const std::string BassBoostSw::kEffectName = "BassBoostSw";
 const bool BassBoostSw::kStrengthSupported = true;
-const BassBoost::Capability BassBoostSw::kCapability = {.strengthSupported = kStrengthSupported};
+const BassBoost::Capability BassBoostSw::kCapability = {.maxStrengthPm = 1000,
+                                                        .strengthSupported = kStrengthSupported};
 const Descriptor BassBoostSw::kDescriptor = {
         .common = {.id = {.type = kBassBoostTypeUUID,
                           .uuid = kBassBoostSwImplUUID,
-                          .proxy = std::nullopt},
+                          .proxy = kBassBoostProxyUUID},
                    .flags = {.type = Flags::Type::INSERT,
                              .insert = Flags::Insert::FIRST,
                              .volume = Flags::Volume::CTRL},
@@ -171,4 +172,14 @@
     return {STATUS_OK, samples, samples};
 }
 
+RetCode BassBoostSwContext::setBbStrengthPm(int strength) {
+    if (strength < 0 || strength > BassBoostSw::kCapability.maxStrengthPm) {
+        LOG(ERROR) << __func__ << " invalid strength: " << strength;
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+    // TODO : Add implementation to apply new strength
+    mStrength = strength;
+    return RetCode::SUCCESS;
+}
+
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/bassboost/BassBoostSw.h b/audio/aidl/default/bassboost/BassBoostSw.h
index 411b9c9..65c01c8 100644
--- a/audio/aidl/default/bassboost/BassBoostSw.h
+++ b/audio/aidl/default/bassboost/BassBoostSw.h
@@ -33,20 +33,11 @@
         LOG(DEBUG) << __func__;
     }
 
-    RetCode setBbStrengthPm(int strength) {
-        if (strength < BassBoost::MIN_PER_MILLE_STRENGTH ||
-            strength > BassBoost::MAX_PER_MILLE_STRENGTH) {
-            LOG(ERROR) << __func__ << " invalid strength: " << strength;
-            return RetCode::ERROR_ILLEGAL_PARAMETER;
-        }
-        // TODO : Add implementation to apply new strength
-        mStrength = strength;
-        return RetCode::SUCCESS;
-    }
+    RetCode setBbStrengthPm(int strength);
     int getBbStrengthPm() const { return mStrength; }
 
   private:
-    int mStrength;
+    int mStrength = 0;
 };
 
 class BassBoostSw final : public EffectImpl {
diff --git a/audio/aidl/default/config/audioPolicy/api/current.txt b/audio/aidl/default/config/audioPolicy/api/current.txt
index 5a8b970..ad79a0c 100644
--- a/audio/aidl/default/config/audioPolicy/api/current.txt
+++ b/audio/aidl/default/config/audioPolicy/api/current.txt
@@ -167,6 +167,7 @@
     method @NonNull public String getRawName();
     enum_constant public static final android.audio.policy.configuration.AudioEncapsulationType AUDIO_ENCAPSULATION_TYPE_IEC61937;
     enum_constant public static final android.audio.policy.configuration.AudioEncapsulationType AUDIO_ENCAPSULATION_TYPE_NONE;
+    enum_constant public static final android.audio.policy.configuration.AudioEncapsulationType AUDIO_ENCAPSULATION_TYPE_PCM;
   }
 
   public enum AudioFormat {
diff --git a/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd b/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
index ddaa122..301c969 100644
--- a/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
+++ b/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
@@ -576,6 +576,7 @@
         <xs:restriction base="xs:string">
             <xs:enumeration value="AUDIO_ENCAPSULATION_TYPE_NONE"/>
             <xs:enumeration value="AUDIO_ENCAPSULATION_TYPE_IEC61937"/>
+            <xs:enumeration value="AUDIO_ENCAPSULATION_TYPE_PCM"/>
         </xs:restriction>
     </xs:simpleType>
     <xs:complexType name="profile">
diff --git a/audio/aidl/default/downmix/Android.bp b/audio/aidl/default/downmix/Android.bp
new file mode 100644
index 0000000..230b2d8
--- /dev/null
+++ b/audio/aidl/default/downmix/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+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: "libdownmixsw",
+    defaults: [
+        "aidlaudioeffectservice_defaults",
+        "latest_android_media_audio_common_types_ndk_shared",
+        "latest_android_hardware_audio_effect_ndk_shared",
+    ],
+    srcs: [
+        "DownmixSw.cpp",
+        ":effectCommonFile",
+    ],
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
+    ],
+}
diff --git a/audio/aidl/default/downmix/DownmixSw.cpp b/audio/aidl/default/downmix/DownmixSw.cpp
new file mode 100644
index 0000000..7bb958d
--- /dev/null
+++ b/audio/aidl/default/downmix/DownmixSw.cpp
@@ -0,0 +1,170 @@
+/*
+ * 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.
+ */
+
+#include <cstddef>
+#define LOG_TAG "AHAL_DownmixSw"
+#include <Utils.h>
+#include <algorithm>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "DownmixSw.h"
+
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::DownmixSw;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kDownmixSwImplUUID;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::media::audio::common::AudioUuid;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+                                           std::shared_ptr<IEffect>* instanceSpp) {
+    if (!in_impl_uuid || *in_impl_uuid != kDownmixSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (instanceSpp) {
+        *instanceSpp = ndk::SharedRefBase::make<DownmixSw>();
+        LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
+        return EX_NONE;
+    } else {
+        LOG(ERROR) << __func__ << " invalid input parameter!";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+}
+
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+    if (!in_impl_uuid || *in_impl_uuid != kDownmixSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    *_aidl_return = DownmixSw::kDescriptor;
+    return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+const std::string DownmixSw::kEffectName = "DownmixSw";
+const Downmix::Capability DownmixSw::kCapability;
+const Descriptor DownmixSw::kDescriptor = {
+        .common = {.id = {.type = kDownmixTypeUUID,
+                          .uuid = kDownmixSwImplUUID,
+                          .proxy = std::nullopt},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::FIRST,
+                             .volume = Flags::Volume::CTRL},
+                   .name = kEffectName,
+                   .implementor = "The Android Open Source Project"},
+        .capability = Capability::make<Capability::downmix>(kCapability)};
+
+ndk::ScopedAStatus DownmixSw::getDescriptor(Descriptor* _aidl_return) {
+    LOG(DEBUG) << __func__ << kDescriptor.toString();
+    *_aidl_return = kDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus DownmixSw::setParameterSpecific(const Parameter::Specific& specific) {
+    RETURN_IF(Parameter::Specific::downmix != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+              "EffectNotSupported");
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    auto& dmParam = specific.get<Parameter::Specific::downmix>();
+    auto tag = dmParam.getTag();
+
+    switch (tag) {
+        case Downmix::type: {
+            RETURN_IF(mContext->setDmType(dmParam.get<Downmix::type>()) != RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setTypeFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "DownmixTagNotSupported");
+        }
+    }
+}
+
+ndk::ScopedAStatus DownmixSw::getParameterSpecific(const Parameter::Id& id,
+                                                   Parameter::Specific* specific) {
+    auto tag = id.getTag();
+    RETURN_IF(Parameter::Id::downmixTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+    auto dmId = id.get<Parameter::Id::downmixTag>();
+    auto dmIdTag = dmId.getTag();
+    switch (dmIdTag) {
+        case Downmix::Id::commonTag:
+            return getParameterDownmix(dmId.get<Downmix::Id::commonTag>(), specific);
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "DownmixTagNotSupported");
+    }
+}
+
+ndk::ScopedAStatus DownmixSw::getParameterDownmix(const Downmix::Tag& tag,
+                                                  Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    Downmix dmParam;
+    switch (tag) {
+        case Downmix::type: {
+            dmParam.set<Downmix::type>(mContext->getDmType());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "DownmixTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::downmix>(dmParam);
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> DownmixSw::createContext(const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+    } else {
+        mContext = std::make_shared<DownmixSwContext>(1 /* statusFmqDepth */, common);
+    }
+
+    return mContext;
+}
+
+std::shared_ptr<EffectContext> DownmixSw::getContext() {
+    return mContext;
+}
+
+RetCode DownmixSw::releaseContext() {
+    if (mContext) {
+        mContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status DownmixSw::effectProcessImpl(float* in, float* out, int samples) {
+    // TODO: get data buffer and process.
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+    for (int i = 0; i < samples; i++) {
+        *out++ = *in++;
+    }
+    return {STATUS_OK, samples, samples};
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/downmix/DownmixSw.h b/audio/aidl/default/downmix/DownmixSw.h
new file mode 100644
index 0000000..51546c1
--- /dev/null
+++ b/audio/aidl/default/downmix/DownmixSw.h
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+#include <cstdlib>
+#include <memory>
+
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class DownmixSwContext final : public EffectContext {
+  public:
+    DownmixSwContext(int statusDepth, const Parameter::Common& common)
+        : EffectContext(statusDepth, common) {
+        LOG(DEBUG) << __func__;
+    }
+
+    RetCode setDmType(Downmix::Type type) {
+        // TODO : Add implementation to apply new type
+        mType = type;
+        return RetCode::SUCCESS;
+    }
+    Downmix::Type getDmType() const { return mType; }
+
+  private:
+    Downmix::Type mType = Downmix::Type::STRIP;
+};
+
+class DownmixSw final : public EffectImpl {
+  public:
+    static const std::string kEffectName;
+    static const Downmix::Capability kCapability;
+    static const Descriptor kDescriptor;
+    DownmixSw() { LOG(DEBUG) << __func__; }
+    ~DownmixSw() {
+        cleanUp();
+        LOG(DEBUG) << __func__;
+    }
+
+    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 sample) override;
+
+  private:
+    std::shared_ptr<DownmixSwContext> mContext;
+
+    ndk::ScopedAStatus getParameterDownmix(const Downmix::Tag& tag, Parameter::Specific* specific);
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/envReverb/EnvReverbSw.cpp b/audio/aidl/default/envReverb/EnvReverbSw.cpp
index a107064..9d7159a 100644
--- a/audio/aidl/default/envReverb/EnvReverbSw.cpp
+++ b/audio/aidl/default/envReverb/EnvReverbSw.cpp
@@ -60,7 +60,8 @@
 namespace aidl::android::hardware::audio::effect {
 
 const std::string EnvReverbSw::kEffectName = "EnvReverbSw";
-const EnvironmentalReverb::Capability EnvReverbSw::kCapability;
+const EnvironmentalReverb::Capability EnvReverbSw::kCapability = {
+        .maxDecayTimeMs = EnvironmentalReverb::MAX_DECAY_TIME_MS};
 const Descriptor EnvReverbSw::kDescriptor = {
         .common = {.id = {.type = kEnvReverbTypeUUID,
                           .uuid = kEnvReverbSwImplUUID,
@@ -82,16 +83,140 @@
     RETURN_IF(Parameter::Specific::environmentalReverb != specific.getTag(), EX_ILLEGAL_ARGUMENT,
               "EffectNotSupported");
 
-    mSpecificParam = specific.get<Parameter::Specific::environmentalReverb>();
-    LOG(DEBUG) << __func__ << " success with: " << specific.toString();
-    return ndk::ScopedAStatus::ok();
+    auto& erParam = specific.get<Parameter::Specific::environmentalReverb>();
+    auto tag = erParam.getTag();
+
+    switch (tag) {
+        case EnvironmentalReverb::roomLevelMb: {
+            RETURN_IF(mContext->setErRoomLevel(erParam.get<EnvironmentalReverb::roomLevelMb>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setRoomLevelFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case EnvironmentalReverb::roomHfLevelMb: {
+            RETURN_IF(
+                    mContext->setErRoomHfLevel(erParam.get<EnvironmentalReverb::roomHfLevelMb>()) !=
+                            RetCode::SUCCESS,
+                    EX_ILLEGAL_ARGUMENT, "setRoomHfLevelFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case EnvironmentalReverb::decayTimeMs: {
+            RETURN_IF(mContext->setErDecayTime(erParam.get<EnvironmentalReverb::decayTimeMs>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setDecayTimeFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case EnvironmentalReverb::decayHfRatioPm: {
+            RETURN_IF(
+                    mContext->setErDecayHfRatio(
+                            erParam.get<EnvironmentalReverb::decayHfRatioPm>()) != RetCode::SUCCESS,
+                    EX_ILLEGAL_ARGUMENT, "setDecayHfRatioFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case EnvironmentalReverb::levelMb: {
+            RETURN_IF(mContext->setErLevel(erParam.get<EnvironmentalReverb::levelMb>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setLevelFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case EnvironmentalReverb::delayMs: {
+            RETURN_IF(mContext->setErDelay(erParam.get<EnvironmentalReverb::delayMs>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setDelayFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case EnvironmentalReverb::diffusionPm: {
+            RETURN_IF(mContext->setErDiffusion(erParam.get<EnvironmentalReverb::diffusionPm>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setDiffusionFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case EnvironmentalReverb::densityPm: {
+            RETURN_IF(mContext->setErDensity(erParam.get<EnvironmentalReverb::densityPm>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setDensityFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case EnvironmentalReverb::bypass: {
+            RETURN_IF(mContext->setErBypass(erParam.get<EnvironmentalReverb::bypass>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setBypassFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "EnvironmentalReverbTagNotSupported");
+        }
+    }
 }
 
 ndk::ScopedAStatus EnvReverbSw::getParameterSpecific(const Parameter::Id& id,
                                                      Parameter::Specific* specific) {
     auto tag = id.getTag();
     RETURN_IF(Parameter::Id::environmentalReverbTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
-    specific->set<Parameter::Specific::environmentalReverb>(mSpecificParam);
+    auto erId = id.get<Parameter::Id::environmentalReverbTag>();
+    auto erIdTag = erId.getTag();
+    switch (erIdTag) {
+        case EnvironmentalReverb::Id::commonTag:
+            return getParameterEnvironmentalReverb(erId.get<EnvironmentalReverb::Id::commonTag>(),
+                                                   specific);
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(erIdTag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "EnvironmentalReverbTagNotSupported");
+    }
+}
+
+ndk::ScopedAStatus EnvReverbSw::getParameterEnvironmentalReverb(const EnvironmentalReverb::Tag& tag,
+                                                                Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    EnvironmentalReverb erParam;
+    switch (tag) {
+        case EnvironmentalReverb::roomLevelMb: {
+            erParam.set<EnvironmentalReverb::roomLevelMb>(mContext->getErRoomLevel());
+            break;
+        }
+        case EnvironmentalReverb::roomHfLevelMb: {
+            erParam.set<EnvironmentalReverb::roomHfLevelMb>(mContext->getErRoomHfLevel());
+            break;
+        }
+        case EnvironmentalReverb::decayTimeMs: {
+            erParam.set<EnvironmentalReverb::decayTimeMs>(mContext->getErDecayTime());
+            break;
+        }
+        case EnvironmentalReverb::decayHfRatioPm: {
+            erParam.set<EnvironmentalReverb::decayHfRatioPm>(mContext->getErDecayHfRatio());
+            break;
+        }
+        case EnvironmentalReverb::levelMb: {
+            erParam.set<EnvironmentalReverb::levelMb>(mContext->getErLevel());
+            break;
+        }
+        case EnvironmentalReverb::delayMs: {
+            erParam.set<EnvironmentalReverb::delayMs>(mContext->getErDelay());
+            break;
+        }
+        case EnvironmentalReverb::diffusionPm: {
+            erParam.set<EnvironmentalReverb::diffusionPm>(mContext->getErDiffusion());
+            break;
+        }
+        case EnvironmentalReverb::densityPm: {
+            erParam.set<EnvironmentalReverb::densityPm>(mContext->getErDensity());
+            break;
+        }
+        case EnvironmentalReverb::bypass: {
+            erParam.set<EnvironmentalReverb::bypass>(mContext->getErBypass());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "EnvironmentalReverbTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::environmentalReverb>(erParam);
     return ndk::ScopedAStatus::ok();
 }
 
diff --git a/audio/aidl/default/envReverb/EnvReverbSw.h b/audio/aidl/default/envReverb/EnvReverbSw.h
index b8761a6..f521215 100644
--- a/audio/aidl/default/envReverb/EnvReverbSw.h
+++ b/audio/aidl/default/envReverb/EnvReverbSw.h
@@ -32,7 +32,120 @@
         : EffectContext(statusDepth, common) {
         LOG(DEBUG) << __func__;
     }
-    // TODO: add specific context here
+
+    RetCode setErRoomLevel(int roomLevel) {
+        if (roomLevel < EnvironmentalReverb::MIN_ROOM_LEVEL_MB ||
+            roomLevel > EnvironmentalReverb::MAX_ROOM_LEVEL_MB) {
+            LOG(ERROR) << __func__ << " invalid roomLevel: " << roomLevel;
+            return RetCode::ERROR_ILLEGAL_PARAMETER;
+        }
+        // TODO : Add implementation to apply new room level
+        mRoomLevel = roomLevel;
+        return RetCode::SUCCESS;
+    }
+    int getErRoomLevel() const { return mRoomLevel; }
+
+    RetCode setErRoomHfLevel(int roomHfLevel) {
+        if (roomHfLevel < EnvironmentalReverb::MIN_ROOM_HF_LEVEL_MB ||
+            roomHfLevel > EnvironmentalReverb::MAX_ROOM_HF_LEVEL_MB) {
+            LOG(ERROR) << __func__ << " invalid roomHfLevel: " << roomHfLevel;
+            return RetCode::ERROR_ILLEGAL_PARAMETER;
+        }
+        // TODO : Add implementation to apply new room HF level
+        mRoomHfLevel = roomHfLevel;
+        return RetCode::SUCCESS;
+    }
+    int getErRoomHfLevel() const { return mRoomHfLevel; }
+
+    RetCode setErDecayTime(int decayTime) {
+        if (decayTime < EnvironmentalReverb::MIN_DECAY_TIME_MS ||
+            decayTime > EnvironmentalReverb::MAX_DECAY_TIME_MS) {
+            LOG(ERROR) << __func__ << " invalid decayTime: " << decayTime;
+            return RetCode::ERROR_ILLEGAL_PARAMETER;
+        }
+        // TODO : Add implementation to apply new decay time
+        mDecayTime = decayTime;
+        return RetCode::SUCCESS;
+    }
+    int getErDecayTime() const { return mDecayTime; }
+
+    RetCode setErDecayHfRatio(int decayHfRatio) {
+        if (decayHfRatio < EnvironmentalReverb::MIN_DECAY_HF_RATIO_PM ||
+            decayHfRatio > EnvironmentalReverb::MAX_DECAY_HF_RATIO_PM) {
+            LOG(ERROR) << __func__ << " invalid decayHfRatio: " << decayHfRatio;
+            return RetCode::ERROR_ILLEGAL_PARAMETER;
+        }
+        // TODO : Add implementation to apply new decay HF ratio
+        mDecayHfRatio = decayHfRatio;
+        return RetCode::SUCCESS;
+    }
+    int getErDecayHfRatio() const { return mDecayHfRatio; }
+
+    RetCode setErLevel(int level) {
+        if (level < EnvironmentalReverb::MIN_LEVEL_MB ||
+            level > EnvironmentalReverb::MAX_LEVEL_MB) {
+            LOG(ERROR) << __func__ << " invalid level: " << level;
+            return RetCode::ERROR_ILLEGAL_PARAMETER;
+        }
+        // TODO : Add implementation to apply new level
+        mLevel = level;
+        return RetCode::SUCCESS;
+    }
+    int getErLevel() const { return mLevel; }
+
+    RetCode setErDelay(int delay) {
+        if (delay < EnvironmentalReverb::MIN_DELAY_MS ||
+            delay > EnvironmentalReverb::MAX_DELAY_MS) {
+            LOG(ERROR) << __func__ << " invalid delay: " << delay;
+            return RetCode::ERROR_ILLEGAL_PARAMETER;
+        }
+        // TODO : Add implementation to apply new delay
+        mDelay = delay;
+        return RetCode::SUCCESS;
+    }
+    int getErDelay() const { return mDelay; }
+
+    RetCode setErDiffusion(int diffusion) {
+        if (diffusion < EnvironmentalReverb::MIN_DIFFUSION_PM ||
+            diffusion > EnvironmentalReverb::MAX_DIFFUSION_PM) {
+            LOG(ERROR) << __func__ << " invalid diffusion: " << diffusion;
+            return RetCode::ERROR_ILLEGAL_PARAMETER;
+        }
+        // TODO : Add implementation to apply new diffusion
+        mDiffusion = diffusion;
+        return RetCode::SUCCESS;
+    }
+    int getErDiffusion() const { return mDiffusion; }
+
+    RetCode setErDensity(int density) {
+        if (density < EnvironmentalReverb::MIN_DENSITY_PM ||
+            density > EnvironmentalReverb::MAX_DENSITY_PM) {
+            LOG(ERROR) << __func__ << " invalid density: " << density;
+            return RetCode::ERROR_ILLEGAL_PARAMETER;
+        }
+        // TODO : Add implementation to apply new density
+        mDensity = density;
+        return RetCode::SUCCESS;
+    }
+    int getErDensity() const { return mDensity; }
+
+    RetCode setErBypass(bool bypass) {
+        // TODO : Add implementation to apply new bypass
+        mBypass = bypass;
+        return RetCode::SUCCESS;
+    }
+    bool getErBypass() const { return mBypass; }
+
+  private:
+    int mRoomLevel = EnvironmentalReverb::MIN_ROOM_LEVEL_MB;       // Default room level
+    int mRoomHfLevel = EnvironmentalReverb::MAX_ROOM_HF_LEVEL_MB;  // Default room hf level
+    int mDecayTime = 1000;                                         // Default decay time
+    int mDecayHfRatio = 500;                                       // Default decay hf ratio
+    int mLevel = EnvironmentalReverb::MIN_LEVEL_MB;                // Default level
+    int mDelay = 40;                                               // Default delay
+    int mDiffusion = EnvironmentalReverb::MAX_DIFFUSION_PM;        // Default diffusion
+    int mDensity = EnvironmentalReverb::MAX_DENSITY_PM;            // Default density
+    bool mBypass = false;                                          // Default bypass
 };
 
 class EnvReverbSw final : public EffectImpl {
@@ -60,7 +173,7 @@
 
   private:
     std::shared_ptr<EnvReverbSwContext> mContext;
-    /* parameters */
-    EnvironmentalReverb mSpecificParam;
+    ndk::ScopedAStatus getParameterEnvironmentalReverb(const EnvironmentalReverb::Tag& tag,
+                                                       Parameter::Specific* specific);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/equalizer/EqualizerSw.h b/audio/aidl/default/equalizer/EqualizerSw.h
index 81bcd7a..65a8002 100644
--- a/audio/aidl/default/equalizer/EqualizerSw.h
+++ b/audio/aidl/default/equalizer/EqualizerSw.h
@@ -53,8 +53,9 @@
                 LOG(ERROR) << __func__ << " index illegal, skip: " << it.index << " - "
                            << it.levelMb;
                 ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+            } else {
+                mBandLevels[it.index] = it.levelMb;
             }
-            mBandLevels[it.index] = it.levelMb;
         }
         return ret;
     }
diff --git a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
index 8004631..3c3b66f 100644
--- a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
+++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
@@ -84,16 +84,71 @@
 ndk::ScopedAStatus HapticGeneratorSw::setParameterSpecific(const Parameter::Specific& specific) {
     RETURN_IF(Parameter::Specific::hapticGenerator != specific.getTag(), EX_ILLEGAL_ARGUMENT,
               "EffectNotSupported");
-    mSpecificParam = specific.get<Parameter::Specific::hapticGenerator>();
-    LOG(DEBUG) << __func__ << " success with: " << specific.toString();
-    return ndk::ScopedAStatus::ok();
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    auto& hgParam = specific.get<Parameter::Specific::hapticGenerator>();
+    auto tag = hgParam.getTag();
+
+    switch (tag) {
+        case HapticGenerator::hapticScales: {
+            RETURN_IF(mContext->setHgHapticScales(hgParam.get<HapticGenerator::hapticScales>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "HapticScaleNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        case HapticGenerator::vibratorInfo: {
+            RETURN_IF(mContext->setHgVibratorInformation(
+                              hgParam.get<HapticGenerator::vibratorInfo>()) != RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "VibratorInfoNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "HapticGeneratorTagNotSupported");
+        }
+    }
 }
 
 ndk::ScopedAStatus HapticGeneratorSw::getParameterSpecific(const Parameter::Id& id,
                                                            Parameter::Specific* specific) {
     auto tag = id.getTag();
     RETURN_IF(Parameter::Id::hapticGeneratorTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
-    specific->set<Parameter::Specific::hapticGenerator>(mSpecificParam);
+    auto hgId = id.get<Parameter::Id::hapticGeneratorTag>();
+    auto hgIdTag = hgId.getTag();
+    switch (hgIdTag) {
+        case HapticGenerator::Id::commonTag:
+            return getParameterHapticGenerator(hgId.get<HapticGenerator::Id::commonTag>(),
+                                               specific);
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "HapticGeneratorTagNotSupported");
+    }
+}
+
+ndk::ScopedAStatus HapticGeneratorSw::getParameterHapticGenerator(const HapticGenerator::Tag& tag,
+                                                                  Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    HapticGenerator hgParam;
+    switch (tag) {
+        case HapticGenerator::hapticScales: {
+            hgParam.set<HapticGenerator::hapticScales>(mContext->getHgHapticScales());
+            break;
+        }
+        case HapticGenerator::vibratorInfo: {
+            hgParam.set<HapticGenerator::vibratorInfo>(mContext->getHgVibratorInformation());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "HapticGeneratorTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::hapticGenerator>(hgParam);
     return ndk::ScopedAStatus::ok();
 }
 
@@ -128,4 +183,20 @@
     return {STATUS_OK, samples, samples};
 }
 
+RetCode HapticGeneratorSwContext::setHgHapticScales(
+        const std::vector<HapticGenerator::HapticScale>& hapticScales) {
+    // Assume any audio track ID is valid
+    for (auto& it : hapticScales) {
+        mHapticScales[it.id] = it;
+    }
+    return RetCode::SUCCESS;
+}
+
+std::vector<HapticGenerator::HapticScale> HapticGeneratorSwContext::getHgHapticScales() const {
+    std::vector<HapticGenerator::HapticScale> result;
+    std::transform(mHapticScales.begin(), mHapticScales.end(), std::back_inserter(result),
+                   [](auto& scaleIt) { return scaleIt.second; });
+    return result;
+}
+
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
index bf01bfb..7159501 100644
--- a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
+++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
@@ -32,7 +32,27 @@
         : EffectContext(statusDepth, common) {
         LOG(DEBUG) << __func__;
     }
-    // TODO: add specific context here
+
+    RetCode setHgHapticScales(const std::vector<HapticGenerator::HapticScale>& hapticScales);
+    std::vector<HapticGenerator::HapticScale> getHgHapticScales() const;
+
+    RetCode setHgVibratorInformation(const HapticGenerator::VibratorInformation& vibratorInfo) {
+        // All float values are valid for resonantFrequencyHz, qFactor, maxAmplitude
+        mVibratorInformation = vibratorInfo;
+        return RetCode::SUCCESS;
+    }
+
+    HapticGenerator::VibratorInformation getHgVibratorInformation() const {
+        return mVibratorInformation;
+    }
+
+  private:
+    static constexpr float DEFAULT_RESONANT_FREQUENCY = 150.0f;
+    static constexpr float DEFAULT_Q_FACTOR = 1.0f;
+    static constexpr float DEFAULT_MAX_AMPLITUDE = 0.0f;
+    std::map<int /* trackID */, HapticGenerator::HapticScale> mHapticScales;
+    HapticGenerator::VibratorInformation mVibratorInformation = {
+            DEFAULT_RESONANT_FREQUENCY, DEFAULT_Q_FACTOR, DEFAULT_MAX_AMPLITUDE};
 };
 
 class HapticGeneratorSw final : public EffectImpl {
@@ -60,7 +80,8 @@
 
   private:
     std::shared_ptr<HapticGeneratorSwContext> mContext;
-    /* parameters */
-    HapticGenerator mSpecificParam;
+
+    ndk::ScopedAStatus getParameterHapticGenerator(const HapticGenerator::Tag& tag,
+                                                   Parameter::Specific* specific);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/core-impl/Bluetooth.h b/audio/aidl/default/include/core-impl/Bluetooth.h
new file mode 100644
index 0000000..f2e762d
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/Bluetooth.h
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/core/BnBluetooth.h>
+
+namespace aidl::android::hardware::audio::core {
+
+class Bluetooth : public BnBluetooth {
+  public:
+    Bluetooth();
+
+  private:
+    ndk::ScopedAStatus setScoConfig(const ScoConfig& in_config, ScoConfig* _aidl_return) override;
+    ndk::ScopedAStatus setHfpConfig(const HfpConfig& in_config, HfpConfig* _aidl_return) override;
+
+    ScoConfig mScoConfig;
+    HfpConfig mHfpConfig;
+};
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index 52fb54c..e9f43d8 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -39,6 +39,7 @@
     ndk::ScopedAStatus setModuleDebug(
             const ::aidl::android::hardware::audio::core::ModuleDebug& in_debug) override;
     ndk::ScopedAStatus getTelephony(std::shared_ptr<ITelephony>* _aidl_return) override;
+    ndk::ScopedAStatus getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) override;
     ndk::ScopedAStatus connectExternalDevice(
             const ::aidl::android::media::audio::common::AudioPort& in_templateIdAndAdditionalData,
             ::aidl::android::media::audio::common::AudioPort* _aidl_return) override;
@@ -66,6 +67,8 @@
                     in_args,
             ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn* _aidl_return)
             override;
+    ndk::ScopedAStatus getSupportedPlaybackRateFactors(
+            SupportedPlaybackRateFactors* _aidl_return) override;
     ndk::ScopedAStatus setAudioPatch(const AudioPatch& in_requested,
                                      AudioPatch* _aidl_return) override;
     ndk::ScopedAStatus setAudioPortConfig(
@@ -86,6 +89,20 @@
     ndk::ScopedAStatus updateScreenRotation(
             ::aidl::android::hardware::audio::core::IModule::ScreenRotation in_rotation) override;
     ndk::ScopedAStatus updateScreenState(bool in_isTurnedOn) override;
+    ndk::ScopedAStatus getSoundDose(std::shared_ptr<sounddose::ISoundDose>* _aidl_return) override;
+    ndk::ScopedAStatus generateHwAvSyncId(int32_t* _aidl_return) override;
+    ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_ids,
+                                           std::vector<VendorParameter>* _aidl_return) override;
+    ndk::ScopedAStatus setVendorParameters(const std::vector<VendorParameter>& in_parameters,
+                                           bool in_async) override;
+    ndk::ScopedAStatus addDeviceEffect(
+            int32_t in_portConfigId,
+            const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
+            override;
+    ndk::ScopedAStatus removeDeviceEffect(
+            int32_t in_portConfigId,
+            const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
+            override;
 
     void cleanUpPatch(int32_t patchId);
     ndk::ScopedAStatus createStreamContext(
@@ -111,9 +128,12 @@
     const Type mType;
     std::unique_ptr<internal::Configuration> mConfig;
     ModuleDebug mDebug;
-    // Since it is required to return the same instance of the ITelephony, even
-    // if the client has released it on its side, we need to hold it via a strong pointer.
+    // For the interfaces requiring to return the same instance, we need to hold them
+    // via a strong pointer. The binder token is retained for a call to 'setMinSchedulerPolicy'.
     std::shared_ptr<ITelephony> mTelephony;
+    ndk::SpAIBinder mTelephonyBinder;
+    std::shared_ptr<IBluetooth> mBluetooth;
+    ndk::SpAIBinder mBluetoothBinder;
     // ids of ports created at runtime via 'connectExternalDevice'.
     std::set<int32_t> mConnectedDevicePorts;
     Streams mStreams;
@@ -123,6 +143,8 @@
     bool mMasterMute = false;
     float mMasterVolume = 1.0f;
     bool mMicMute = false;
+    std::shared_ptr<sounddose::ISoundDose> mSoundDose;
+    ndk::SpAIBinder mSoundDoseBinder;
 };
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/SoundDose.h b/audio/aidl/default/include/core-impl/SoundDose.h
new file mode 100644
index 0000000..306aa04
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/SoundDose.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <mutex>
+
+#include <aidl/android/hardware/audio/core/sounddose/BnSoundDose.h>
+#include <aidl/android/media/audio/common/AudioDevice.h>
+
+using aidl::android::media::audio::common::AudioDevice;
+
+namespace aidl::android::hardware::audio::core::sounddose {
+
+class SoundDose : public BnSoundDose {
+  public:
+    SoundDose() : mRs2Value(DEFAULT_MAX_RS2){};
+
+    ndk::ScopedAStatus setOutputRs2(float in_rs2ValueDbA) override;
+    ndk::ScopedAStatus getOutputRs2(float* _aidl_return) override;
+    ndk::ScopedAStatus registerSoundDoseCallback(
+            const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>& in_callback) override;
+
+  private:
+    std::shared_ptr<ISoundDose::IHalSoundDoseCallback> mCallback;
+    float mRs2Value;
+};
+
+}  // namespace aidl::android::hardware::audio::core::sounddose
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index 7a07eeb..5abd4de 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -27,6 +27,7 @@
 #include <StreamWorker.h>
 #include <aidl/android/hardware/audio/common/SinkMetadata.h>
 #include <aidl/android/hardware/audio/common/SourceMetadata.h>
+#include <aidl/android/hardware/audio/core/BnStreamCommon.h>
 #include <aidl/android/hardware/audio/core/BnStreamIn.h>
 #include <aidl/android/hardware/audio/core/BnStreamOut.h>
 #include <aidl/android/hardware/audio/core/IStreamCallback.h>
@@ -197,10 +198,93 @@
 };
 using StreamOutWorker = ::android::hardware::audio::common::StreamWorker<StreamOutWorkerLogic>;
 
-template <class Metadata, class StreamWorker>
-class StreamCommon {
+// This provides a C++ interface with methods of the IStreamCommon Binder interface,
+// but intentionally does not inherit from it. This is needed to avoid inheriting
+// StreamIn and StreamOut from two Binder interface classes, as these parts of the class
+// will be reference counted separately.
+//
+// The implementation of these common methods is in the StreamCommonImpl template class.
+struct StreamCommonInterface {
+    virtual ~StreamCommonInterface() = default;
+    virtual ndk::ScopedAStatus close() = 0;
+    virtual ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) = 0;
+    virtual ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_ids,
+                                                   std::vector<VendorParameter>* _aidl_return) = 0;
+    virtual ndk::ScopedAStatus setVendorParameters(
+            const std::vector<VendorParameter>& in_parameters, bool in_async) = 0;
+    virtual ndk::ScopedAStatus addEffect(
+            const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>&
+                    in_effect) = 0;
+    virtual ndk::ScopedAStatus removeEffect(
+            const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>&
+                    in_effect) = 0;
+};
+
+class StreamCommon : public BnStreamCommon {
   public:
-    ndk::ScopedAStatus close();
+    explicit StreamCommon(const std::shared_ptr<StreamCommonInterface>& delegate)
+        : mDelegate(delegate) {}
+
+  private:
+    ndk::ScopedAStatus close() override {
+        auto delegate = mDelegate.lock();
+        return delegate != nullptr ? delegate->close()
+                                   : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) override {
+        auto delegate = mDelegate.lock();
+        return delegate != nullptr ? delegate->updateHwAvSyncId(in_hwAvSyncId)
+                                   : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_ids,
+                                           std::vector<VendorParameter>* _aidl_return) override {
+        auto delegate = mDelegate.lock();
+        return delegate != nullptr ? delegate->getVendorParameters(in_ids, _aidl_return)
+                                   : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    ndk::ScopedAStatus setVendorParameters(const std::vector<VendorParameter>& in_parameters,
+                                           bool in_async) override {
+        auto delegate = mDelegate.lock();
+        return delegate != nullptr ? delegate->setVendorParameters(in_parameters, in_async)
+                                   : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    ndk::ScopedAStatus addEffect(
+            const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
+            override {
+        auto delegate = mDelegate.lock();
+        return delegate != nullptr ? delegate->addEffect(in_effect)
+                                   : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    ndk::ScopedAStatus removeEffect(
+            const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
+            override {
+        auto delegate = mDelegate.lock();
+        return delegate != nullptr ? delegate->removeEffect(in_effect)
+                                   : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    // It is possible that on the client side the proxy for IStreamCommon will outlive
+    // the IStream* instance, and the server side IStream* instance will get destroyed
+    // while this IStreamCommon instance is still alive.
+    std::weak_ptr<StreamCommonInterface> mDelegate;
+};
+
+template <class Metadata, class StreamWorker>
+class StreamCommonImpl : public StreamCommonInterface {
+  public:
+    ndk::ScopedAStatus close() override;
+    ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) override;
+    ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_ids,
+                                           std::vector<VendorParameter>* _aidl_return) override;
+    ndk::ScopedAStatus setVendorParameters(const std::vector<VendorParameter>& in_parameters,
+                                           bool in_async) override;
+    ndk::ScopedAStatus addEffect(
+            const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
+            override;
+    ndk::ScopedAStatus removeEffect(
+            const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
+            override;
+
+    ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return);
     ndk::ScopedAStatus init() {
         return mWorker.start(StreamWorker::kThreadName, ANDROID_PRIORITY_AUDIO)
                        ? ndk::ScopedAStatus::ok()
@@ -215,23 +299,26 @@
     ndk::ScopedAStatus updateMetadata(const Metadata& metadata);
 
   protected:
-    StreamCommon(const Metadata& metadata, StreamContext context)
+    StreamCommonImpl(const Metadata& metadata, StreamContext&& context)
         : mMetadata(metadata), mContext(std::move(context)), mWorker(mContext) {}
-    ~StreamCommon();
+    ~StreamCommonImpl();
     void stopWorker();
+    void createStreamCommon(const std::shared_ptr<StreamCommonInterface>& delegate);
 
+    std::shared_ptr<StreamCommon> mCommon;
+    ndk::SpAIBinder mCommonBinder;
     Metadata mMetadata;
     StreamContext mContext;
     StreamWorker mWorker;
     std::vector<::aidl::android::media::audio::common::AudioDevice> mConnectedDevices;
 };
 
-class StreamIn
-    : public StreamCommon<::aidl::android::hardware::audio::common::SinkMetadata, StreamInWorker>,
-      public BnStreamIn {
-    ndk::ScopedAStatus close() override {
-        return StreamCommon<::aidl::android::hardware::audio::common::SinkMetadata,
-                            StreamInWorker>::close();
+class StreamIn : public StreamCommonImpl<::aidl::android::hardware::audio::common::SinkMetadata,
+                                         StreamInWorker>,
+                 public BnStreamIn {
+    ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override {
+        return StreamCommonImpl<::aidl::android::hardware::audio::common::SinkMetadata,
+                                StreamInWorker>::getStreamCommon(_aidl_return);
     }
     ndk::ScopedAStatus getActiveMicrophones(
             std::vector<MicrophoneDynamicInfo>* _aidl_return) override;
@@ -241,46 +328,92 @@
     ndk::ScopedAStatus setMicrophoneFieldDimension(float in_zoom) override;
     ndk::ScopedAStatus updateMetadata(const ::aidl::android::hardware::audio::common::SinkMetadata&
                                               in_sinkMetadata) override {
-        return StreamCommon<::aidl::android::hardware::audio::common::SinkMetadata,
-                            StreamInWorker>::updateMetadata(in_sinkMetadata);
+        return StreamCommonImpl<::aidl::android::hardware::audio::common::SinkMetadata,
+                                StreamInWorker>::updateMetadata(in_sinkMetadata);
     }
+    ndk::ScopedAStatus getHwGain(std::vector<float>* _aidl_return) override;
+    ndk::ScopedAStatus setHwGain(const std::vector<float>& in_channelGains) override;
 
   public:
-    StreamIn(const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
-             StreamContext context, const std::vector<MicrophoneInfo>& microphones);
+    static ndk::ScopedAStatus createInstance(
+            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
+            StreamContext context, const std::vector<MicrophoneInfo>& microphones,
+            std::shared_ptr<StreamIn>* result);
 
   private:
+    friend class ndk::SharedRefBase;
+    StreamIn(const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
+             StreamContext&& context, const std::vector<MicrophoneInfo>& microphones);
+    void createStreamCommon(const std::shared_ptr<StreamIn>& myPtr) {
+        StreamCommonImpl<::aidl::android::hardware::audio::common::SinkMetadata,
+                         StreamInWorker>::createStreamCommon(myPtr);
+    }
+
     const std::map<::aidl::android::media::audio::common::AudioDevice, std::string> mMicrophones;
 };
 
-class StreamOut : public StreamCommon<::aidl::android::hardware::audio::common::SourceMetadata,
-                                      StreamOutWorker>,
+class StreamOut : public StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata,
+                                          StreamOutWorker>,
                   public BnStreamOut {
-    ndk::ScopedAStatus close() override {
-        return StreamCommon<::aidl::android::hardware::audio::common::SourceMetadata,
-                            StreamOutWorker>::close();
+    ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override {
+        return StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata,
+                                StreamOutWorker>::getStreamCommon(_aidl_return);
     }
     ndk::ScopedAStatus updateMetadata(
             const ::aidl::android::hardware::audio::common::SourceMetadata& in_sourceMetadata)
             override {
-        return StreamCommon<::aidl::android::hardware::audio::common::SourceMetadata,
-                            StreamOutWorker>::updateMetadata(in_sourceMetadata);
+        return StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata,
+                                StreamOutWorker>::updateMetadata(in_sourceMetadata);
     }
+    ndk::ScopedAStatus getHwVolume(std::vector<float>* _aidl_return) override;
+    ndk::ScopedAStatus setHwVolume(const std::vector<float>& in_channelVolumes) override;
+    ndk::ScopedAStatus getAudioDescriptionMixLevel(float* _aidl_return) override;
+    ndk::ScopedAStatus setAudioDescriptionMixLevel(float in_leveldB) override;
+    ndk::ScopedAStatus getDualMonoMode(
+            ::aidl::android::media::audio::common::AudioDualMonoMode* _aidl_return) override;
+    ndk::ScopedAStatus setDualMonoMode(
+            ::aidl::android::media::audio::common::AudioDualMonoMode in_mode) override;
+    ndk::ScopedAStatus getRecommendedLatencyModes(
+            std::vector<::aidl::android::media::audio::common::AudioLatencyMode>* _aidl_return)
+            override;
+    ndk::ScopedAStatus setLatencyMode(
+            ::aidl::android::media::audio::common::AudioLatencyMode in_mode) override;
+    ndk::ScopedAStatus getPlaybackRateParameters(
+            ::aidl::android::media::audio::common::AudioPlaybackRate* _aidl_return) override;
+    ndk::ScopedAStatus setPlaybackRateParameters(
+            const ::aidl::android::media::audio::common::AudioPlaybackRate& in_playbackRate)
+            override;
+    ndk::ScopedAStatus selectPresentation(int32_t in_presentationId, int32_t in_programId) override;
 
   public:
-    StreamOut(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
-              StreamContext context,
-              const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
-                      offloadInfo);
+    static ndk::ScopedAStatus createInstance(
+            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
+            StreamContext context,
+            const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
+                    offloadInfo,
+            std::shared_ptr<StreamOut>* result);
 
   private:
+    friend class ndk::SharedRefBase;
+    StreamOut(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
+              StreamContext&& context,
+              const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
+                      offloadInfo);
+    void createStreamCommon(const std::shared_ptr<StreamOut>& myPtr) {
+        StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata,
+                         StreamOutWorker>::createStreamCommon(myPtr);
+    }
+
     std::optional<::aidl::android::media::audio::common::AudioOffloadInfo> mOffloadInfo;
 };
 
 class StreamWrapper {
   public:
-    explicit StreamWrapper(std::shared_ptr<StreamIn> streamIn) : mStream(streamIn) {}
-    explicit StreamWrapper(std::shared_ptr<StreamOut> streamOut) : mStream(streamOut) {}
+    explicit StreamWrapper(const std::shared_ptr<StreamIn>& streamIn)
+        : mStream(streamIn), mStreamBinder(streamIn->asBinder()) {}
+    explicit StreamWrapper(const std::shared_ptr<StreamOut>& streamOut)
+        : mStream(streamOut), mStreamBinder(streamOut->asBinder()) {}
+    ndk::SpAIBinder getBinder() const { return mStreamBinder; }
     bool isStreamOpen() const {
         return std::visit(
                 [](auto&& ws) -> bool {
@@ -301,6 +434,7 @@
 
   private:
     std::variant<std::weak_ptr<StreamIn>, std::weak_ptr<StreamOut>> mStream;
+    ndk::SpAIBinder mStreamBinder;
 };
 
 class Streams {
diff --git a/audio/aidl/default/include/core-impl/Telephony.h b/audio/aidl/default/include/core-impl/Telephony.h
index 597f3d6..0936172 100644
--- a/audio/aidl/default/include/core-impl/Telephony.h
+++ b/audio/aidl/default/include/core-impl/Telephony.h
@@ -23,12 +23,18 @@
 namespace aidl::android::hardware::audio::core {
 
 class Telephony : public BnTelephony {
+  public:
+    Telephony();
+
   private:
     ndk::ScopedAStatus getSupportedAudioModes(std::vector<AudioMode>* _aidl_return) override;
     ndk::ScopedAStatus switchAudioMode(AudioMode in_mode) override;
+    ndk::ScopedAStatus setTelecomConfig(const TelecomConfig& in_config,
+                                        TelecomConfig* _aidl_return) override;
 
     const std::vector<AudioMode> mSupportedAudioModes = {::ndk::enum_range<AudioMode>().begin(),
                                                          ::ndk::enum_range<AudioMode>().end()};
+    TelecomConfig mTelecomConfig;
 };
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/effect-impl/EffectContext.h b/audio/aidl/default/include/effect-impl/EffectContext.h
index 95645d5..1f39db0 100644
--- a/audio/aidl/default/include/effect-impl/EffectContext.h
+++ b/audio/aidl/default/include/effect-impl/EffectContext.h
@@ -72,13 +72,11 @@
 
     float* getWorkBuffer() { return static_cast<float*>(mWorkBuffer.data()); }
 
-    // reset buffer status by abandon all data and status in FMQ
+    // reset buffer status by abandon input data in FMQ
     void resetBuffer() {
         auto buffer = static_cast<float*>(mWorkBuffer.data());
         std::vector<IEffect::Status> status(mStatusMQ->availableToRead());
         mInputMQ->read(buffer, mInputMQ->availableToRead());
-        mOutputMQ->read(buffer, mOutputMQ->availableToRead());
-        mStatusMQ->read(status.data(), mStatusMQ->availableToRead());
     }
 
     void dupeFmq(IEffect::OpenEffectReturn* effectRet) {
diff --git a/audio/aidl/default/include/effect-impl/EffectUUID.h b/audio/aidl/default/include/effect-impl/EffectUUID.h
index 7709eab..6eec29e 100644
--- a/audio/aidl/default/include/effect-impl/EffectUUID.h
+++ b/audio/aidl/default/include/effect-impl/EffectUUID.h
@@ -33,6 +33,30 @@
 static const AudioUuid kEffectZeroUuid = {
         static_cast<int32_t>(0x0), 0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
 
+// 7b491460-8d4d-11e0-bd61-0002a5d5c51b.
+static const AudioUuid kAcousticEchoCancelerTypeUUID = {static_cast<int32_t>(0x7b491460),
+                                                        0x8d4d,
+                                                        0x11e0,
+                                                        0xbd61,
+                                                        {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// bb392ec0-8d4d-11e0-a896-0002a5d5c51b
+static const AudioUuid kAcousticEchoCancelerSwImplUUID = {static_cast<int32_t>(0xbb392ec0),
+                                                          0x8d4d,
+                                                          0x11e0,
+                                                          0xa896,
+                                                          {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// 0xae3c653b-be18-4ab8-8938-418f0a7f06ac
+static const AudioUuid kAutomaticGainControlTypeUUID = {static_cast<int32_t>(0xae3c653b),
+                                                        0xbe18,
+                                                        0x4ab8,
+                                                        0x8938,
+                                                        {0x41, 0x8f, 0x0a, 0x7f, 0x06, 0xac}};
+// 89f38e65-d4d2-4d64-ad0e-2b3e799ea886
+static const AudioUuid kAutomaticGainControlSwImplUUID = {static_cast<int32_t>(0x89f38e65),
+                                                          0xd4d2,
+                                                          0x4d64,
+                                                          0xad0e,
+                                                          {0x2b, 0x3e, 0x79, 0x9e, 0xa8, 0x86}};
 // 0634f220-ddd4-11db-a0fc-0002a5d5c51b
 static const AudioUuid kBassBoostTypeUUID = {static_cast<int32_t>(0x0634f220),
                                              0xddd4,
@@ -45,6 +69,18 @@
                                                0x11ed,
                                                0x9b6a,
                                                {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 8631f300-72e2-11df-b57e-0002a5d5c51b
+static const AudioUuid kBassBoostBundleImplUUID = {static_cast<int32_t>(0x8631f300),
+                                                   0x72e2,
+                                                   0x11df,
+                                                   0xb57e,
+                                                   {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// 14804144-a5ee-4d24-aa88-0002a5d5c51b
+static const AudioUuid kBassBoostProxyUUID = {static_cast<int32_t>(0x14804144),
+                                              0xa5ee,
+                                              0x4d24,
+                                              0xaa88,
+                                              {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
 // fa81862a-588b-11ed-9b6a-0242ac120002
 static const AudioUuid kDownmixTypeUUID = {static_cast<int32_t>(0xfa81862a),
                                            0x588b,
@@ -57,6 +93,12 @@
                                              0x11ed,
                                              0x9b6a,
                                              {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 93f04452-e4fe-41cc-91f9-e475b6d1d69f
+static const AudioUuid kDownmixImplUUID = {static_cast<int32_t>(0x93f04452),
+                                           0xe4fe,
+                                           0x41cc,
+                                           0x91f9,
+                                           {0xe4, 0x75, 0xb6, 0xd1, 0xd6, 0x9f}};
 // 0bed4300-ddd6-11db-8f34-0002a5d5c51b.
 static const AudioUuid kEqualizerTypeUUID = {static_cast<int32_t>(0x0bed4300),
                                              0xddd6,
@@ -105,6 +147,12 @@
                                                      0x11ed,
                                                      0x9b6a,
                                                      {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 97c4acd1-8b82-4f2f-832e-c2fe5d7a9931
+static const AudioUuid kHapticGeneratorImplUUID = {static_cast<int32_t>(0x97c4acd1),
+                                                   0x8b82,
+                                                   0x4f2f,
+                                                   0x832e,
+                                                   {0xc2, 0xfe, 0x5d, 0x7a, 0x99, 0x31}};
 // fe3199be-aed0-413f-87bb-11260eb63cf1
 static const AudioUuid kLoudnessEnhancerTypeUUID = {static_cast<int32_t>(0xfe3199be),
                                                     0xaed0,
@@ -117,6 +165,12 @@
                                                       0x11ed,
                                                       0x9b6a,
                                                       {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// fa415329-2034-4bea-b5dc-5b381c8d1e2c
+static const AudioUuid kLoudnessEnhancerImplUUID = {static_cast<int32_t>(0xfa415329),
+                                                    0x2034,
+                                                    0x4bea,
+                                                    0xb5dc,
+                                                    {0x5b, 0x38, 0x1c, 0x8d, 0x1e, 0x2c}};
 // c2e5d5f0-94bd-4763-9cac-4e234d06839e
 static const AudioUuid kEnvReverbTypeUUID = {static_cast<int32_t>(0xc2e5d5f0),
                                              0x94bd,
@@ -129,6 +183,18 @@
                                                0x11ed,
                                                0x9b6a,
                                                {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 58b4b260-8e06-11e0-aa8e-0002a5d5c51b
+static const AudioUuid kNoiseSuppressionTypeUUID = {static_cast<int32_t>(0x58b4b260),
+                                                    0x8e06,
+                                                    0x11e0,
+                                                    0xaa8e,
+                                                    {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// c06c8400-8e06-11e0-9cb6-0002a5d5c51b
+static const AudioUuid kNoiseSuppressionSwImplUUID = {static_cast<int32_t>(0xc06c8400),
+                                                      0x8e06,
+                                                      0x11e0,
+                                                      0x9cb6,
+                                                      {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
 // 47382d60-ddd8-11db-bf3a-0002a5d5c51b
 static const AudioUuid kPresetReverbTypeUUID = {static_cast<int32_t>(0x47382d60),
                                                 0xddd8,
@@ -153,6 +219,18 @@
                                                  0x11ed,
                                                  0x9b6a,
                                                  {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 1d4033c0-8557-11df-9f2d-0002a5d5c51b
+static const AudioUuid kVirtualizerBundleImplUUID = {static_cast<int32_t>(0x1d4033c0),
+                                                     0x8557,
+                                                     0x11df,
+                                                     0x9f2d,
+                                                     {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// d3467faa-acc7-4d34-acaf-0002a5d5c51b
+static const AudioUuid kVirtualizerProxyUUID = {static_cast<int32_t>(0xd3467faa),
+                                                0xacc7,
+                                                0x4d34,
+                                                0xacaf,
+                                                {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
 // fa819f3e-588b-11ed-9b6a-0242ac120002
 static const AudioUuid kVisualizerTypeUUID = {static_cast<int32_t>(0xfa819f3e),
                                               0x588b,
@@ -165,6 +243,13 @@
                                                 0x11ed,
                                                 0x9b6a,
                                                 {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// d069d9e0-8329-11df-9168-0002a5d5c51b
+// {0xd069d9e0, 0x8329, 0x11df, 0x9168, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+static const AudioUuid kVisualizerImplUUID = {static_cast<int32_t>(0xd069d9e0),
+                                              0x8329,
+                                              0x11df,
+                                              0x9168,
+                                              {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
 // fa81a2b8-588b-11ed-9b6a-0242ac120002
 static const AudioUuid kVolumeTypeUUID = {static_cast<int32_t>(0xfa81a2b8),
                                           0x588b,
@@ -177,6 +262,12 @@
                                             0x11ed,
                                             0x9b6a,
                                             {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 119341a0-8469-11df-81f9-0002a5d5c51b
+static const AudioUuid kVolumeBundleImplUUID = {static_cast<int32_t>(0x119341a0),
+                                                0x8469,
+                                                0x11df,
+                                                0x81f9,
+                                                {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
 
 /**
  * @brief A map between effect name and effect type UUID.
@@ -184,6 +275,8 @@
  * We need this map is because existing audio_effects.xml don't have a type UUID defined.
  */
 static const std::map<const std::string /* effect type */, const AudioUuid&> kUuidNameTypeMap = {
+        {"acoustic_echo_canceler", kAcousticEchoCancelerTypeUUID},
+        {"automatic_gain_control", kAutomaticGainControlTypeUUID},
         {"bassboost", kBassBoostTypeUUID},
         {"downmix", kDownmixTypeUUID},
         {"dynamics_processing", kDynamicsProcessingTypeUUID},
@@ -191,6 +284,7 @@
         {"haptic_generator", kHapticGeneratorTypeUUID},
         {"loudness_enhancer", kLoudnessEnhancerTypeUUID},
         {"env_reverb", kEnvReverbTypeUUID},
+        {"noise_suppression", kNoiseSuppressionTypeUUID},
         {"preset_reverb", kPresetReverbTypeUUID},
         {"reverb_env_aux", kEnvReverbTypeUUID},
         {"reverb_env_ins", kEnvReverbTypeUUID},
diff --git a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
index 5903276..04bd1bb 100644
--- a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
+++ b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
@@ -96,9 +96,8 @@
 
     std::map<aidl::android::media::audio::common::AudioUuid /* implUUID */, DlEntry> mEffectLibMap;
 
-    std::map<std::weak_ptr<IEffect>, aidl::android::media::audio::common::AudioUuid,
-             std::owner_less<>>
-            mEffectUuidMap;
+    typedef std::pair<aidl::android::media::audio::common::AudioUuid, ndk::SpAIBinder> EffectEntry;
+    std::map<std::weak_ptr<IEffect>, EffectEntry, std::owner_less<>> mEffectMap;
 
     ndk::ScopedAStatus destroyEffectImpl(const std::shared_ptr<IEffect>& in_handle);
     void cleanupEffectMap();
diff --git a/audio/aidl/default/main.cpp b/audio/aidl/default/main.cpp
index b11af4e..b66c134 100644
--- a/audio/aidl/default/main.cpp
+++ b/audio/aidl/default/main.cpp
@@ -16,6 +16,7 @@
 
 #include <cstdlib>
 #include <ctime>
+#include <utility>
 
 #include <android-base/logging.h>
 #include <android/binder_ibinder_platform.h>
@@ -44,19 +45,17 @@
     CHECK_EQ(STATUS_OK, status);
 
     // Make modules
-    auto moduleDefault = ndk::SharedRefBase::make<Module>(Module::Type::DEFAULT);
-    const std::string moduleDefaultName = std::string() + Module::descriptor + "/default";
-    AIBinder_setMinSchedulerPolicy(moduleDefault->asBinder().get(), SCHED_NORMAL,
-                                   ANDROID_PRIORITY_AUDIO);
-    status = AServiceManager_addService(moduleDefault->asBinder().get(), moduleDefaultName.c_str());
-    CHECK_EQ(STATUS_OK, status);
-
-    auto moduleRSubmix = ndk::SharedRefBase::make<Module>(Module::Type::R_SUBMIX);
-    const std::string moduleRSubmixName = std::string() + Module::descriptor + "/r_submix";
-    AIBinder_setMinSchedulerPolicy(moduleRSubmix->asBinder().get(), SCHED_NORMAL,
-                                   ANDROID_PRIORITY_AUDIO);
-    status = AServiceManager_addService(moduleRSubmix->asBinder().get(), moduleRSubmixName.c_str());
-    CHECK_EQ(STATUS_OK, status);
+    auto createModule = [](Module::Type type, const std::string& instance) {
+        auto module = ndk::SharedRefBase::make<Module>(type);
+        ndk::SpAIBinder moduleBinder = module->asBinder();
+        const std::string moduleName = std::string(Module::descriptor).append("/").append(instance);
+        AIBinder_setMinSchedulerPolicy(moduleBinder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
+        binder_status_t status = AServiceManager_addService(moduleBinder.get(), moduleName.c_str());
+        CHECK_EQ(STATUS_OK, status);
+        return std::make_pair(module, moduleBinder);
+    };
+    auto modules = {createModule(Module::Type::DEFAULT, "default"),
+                    createModule(Module::Type::R_SUBMIX, "r_submix")};
 
     ABinderProcess_joinThreadPool();
     return EXIT_FAILURE;  // should not reach
diff --git a/audio/aidl/default/noiseSuppression/Android.bp b/audio/aidl/default/noiseSuppression/Android.bp
new file mode 100644
index 0000000..581d4bf
--- /dev/null
+++ b/audio/aidl/default/noiseSuppression/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+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: "libnssw",
+    defaults: [
+        "aidlaudioeffectservice_defaults",
+        "latest_android_media_audio_common_types_ndk_shared",
+        "latest_android_hardware_audio_effect_ndk_shared",
+    ],
+    srcs: [
+        "NoiseSuppressionSw.cpp",
+        ":effectCommonFile",
+    ],
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
+    ],
+}
diff --git a/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp
new file mode 100644
index 0000000..a36cfe0
--- /dev/null
+++ b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ */
+
+#include <algorithm>
+#include <cstddef>
+#include <memory>
+#define LOG_TAG "AHAL_NoiseSuppressionSw"
+#include <Utils.h>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "NoiseSuppressionSw.h"
+
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kNoiseSuppressionSwImplUUID;
+using aidl::android::hardware::audio::effect::NoiseSuppressionSw;
+using aidl::android::media::audio::common::AudioUuid;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+                                           std::shared_ptr<IEffect>* instanceSpp) {
+    if (!in_impl_uuid || *in_impl_uuid != kNoiseSuppressionSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (instanceSpp) {
+        *instanceSpp = ndk::SharedRefBase::make<NoiseSuppressionSw>();
+        LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
+        return EX_NONE;
+    } else {
+        LOG(ERROR) << __func__ << " invalid input parameter!";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+}
+
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+    if (!in_impl_uuid || *in_impl_uuid != kNoiseSuppressionSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    *_aidl_return = NoiseSuppressionSw::kDescriptor;
+    return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+const std::string NoiseSuppressionSw::kEffectName = "NoiseSuppressionSw";
+const NoiseSuppression::Capability NoiseSuppressionSw::kCapability;
+const Descriptor NoiseSuppressionSw::kDescriptor = {
+        .common = {.id = {.type = kNoiseSuppressionTypeUUID,
+                          .uuid = kNoiseSuppressionSwImplUUID,
+                          .proxy = std::nullopt},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::FIRST,
+                             .volume = Flags::Volume::CTRL},
+                   .name = NoiseSuppressionSw::kEffectName,
+                   .implementor = "The Android Open Source Project"},
+        .capability =
+                Capability::make<Capability::noiseSuppression>(NoiseSuppressionSw::kCapability)};
+
+ndk::ScopedAStatus NoiseSuppressionSw::getDescriptor(Descriptor* _aidl_return) {
+    LOG(DEBUG) << __func__ << kDescriptor.toString();
+    *_aidl_return = kDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus NoiseSuppressionSw::setParameterSpecific(const Parameter::Specific& specific) {
+    RETURN_IF(Parameter::Specific::noiseSuppression != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+              "EffectNotSupported");
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    auto& param = specific.get<Parameter::Specific::noiseSuppression>();
+    auto tag = param.getTag();
+
+    switch (tag) {
+        case NoiseSuppression::level: {
+            RETURN_IF(mContext->setLevel(param.get<NoiseSuppression::level>()) != RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "levelSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "NoiseSuppressionTagNotSupported");
+        }
+    }
+}
+
+ndk::ScopedAStatus NoiseSuppressionSw::getParameterSpecific(const Parameter::Id& id,
+                                                            Parameter::Specific* specific) {
+    auto tag = id.getTag();
+    RETURN_IF(Parameter::Id::noiseSuppressionTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+    auto specificId = id.get<Parameter::Id::noiseSuppressionTag>();
+    auto specificIdTag = specificId.getTag();
+    switch (specificIdTag) {
+        case NoiseSuppression::Id::commonTag:
+            return getParameterNoiseSuppression(specificId.get<NoiseSuppression::Id::commonTag>(),
+                                                specific);
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "NoiseSuppressionTagNotSupported");
+    }
+}
+
+ndk::ScopedAStatus NoiseSuppressionSw::getParameterNoiseSuppression(
+        const NoiseSuppression::Tag& tag, Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    NoiseSuppression param;
+    switch (tag) {
+        case NoiseSuppression::level: {
+            param.set<NoiseSuppression::level>(mContext->getLevel());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "NoiseSuppressionTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::noiseSuppression>(param);
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> NoiseSuppressionSw::createContext(const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+    } else {
+        mContext = std::make_shared<NoiseSuppressionSwContext>(1 /* statusFmqDepth */, common);
+    }
+    return mContext;
+}
+
+std::shared_ptr<EffectContext> NoiseSuppressionSw::getContext() {
+    return mContext;
+}
+
+RetCode NoiseSuppressionSw::releaseContext() {
+    if (mContext) {
+        mContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status NoiseSuppressionSw::effectProcessImpl(float* in, float* out, int samples) {
+    // TODO: get data buffer and process.
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+    for (int i = 0; i < samples; i++) {
+        *out++ = *in++;
+    }
+    return {STATUS_OK, samples, samples};
+}
+
+RetCode NoiseSuppressionSwContext::setLevel(NoiseSuppression::Level level) {
+    mLevel = level;
+    return RetCode::SUCCESS;
+}
+
+NoiseSuppression::Level NoiseSuppressionSwContext::getLevel() {
+    return mLevel;
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.h b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.h
new file mode 100644
index 0000000..f39d8e5
--- /dev/null
+++ b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+#include <cstdlib>
+#include <memory>
+
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class NoiseSuppressionSwContext final : public EffectContext {
+  public:
+    NoiseSuppressionSwContext(int statusDepth, const Parameter::Common& common)
+        : EffectContext(statusDepth, common) {
+        LOG(DEBUG) << __func__;
+    }
+
+    RetCode setLevel(NoiseSuppression::Level level);
+    NoiseSuppression::Level getLevel();
+
+  private:
+    NoiseSuppression::Level mLevel = NoiseSuppression::Level::LOW;
+};
+
+class NoiseSuppressionSw final : public EffectImpl {
+  public:
+    static const std::string kEffectName;
+    static const bool kStrengthSupported;
+    static const NoiseSuppression::Capability kCapability;
+    static const Descriptor kDescriptor;
+    NoiseSuppressionSw() { LOG(DEBUG) << __func__; }
+    ~NoiseSuppressionSw() {
+        cleanUp();
+        LOG(DEBUG) << __func__;
+    }
+
+    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:
+    std::shared_ptr<NoiseSuppressionSwContext> mContext;
+    ndk::ScopedAStatus getParameterNoiseSuppression(const NoiseSuppression::Tag& tag,
+                                                    Parameter::Specific* specific);
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/presetReverb/PresetReverbSw.cpp b/audio/aidl/default/presetReverb/PresetReverbSw.cpp
index 1b9d614..d038596 100644
--- a/audio/aidl/default/presetReverb/PresetReverbSw.cpp
+++ b/audio/aidl/default/presetReverb/PresetReverbSw.cpp
@@ -21,6 +21,7 @@
 #include <unordered_set>
 
 #include <android-base/logging.h>
+#include <android/binder_enums.h>
 #include <fmq/AidlMessageQueue.h>
 
 #include "PresetReverbSw.h"
@@ -60,7 +61,13 @@
 namespace aidl::android::hardware::audio::effect {
 
 const std::string PresetReverbSw::kEffectName = "PresetReverbSw";
-const PresetReverb::Capability PresetReverbSw::kCapability;
+
+const std::vector<PresetReverb::Presets> kSupportedPresets{
+        ndk::enum_range<PresetReverb::Presets>().begin(),
+        ndk::enum_range<PresetReverb::Presets>().end()};
+
+const PresetReverb::Capability PresetReverbSw::kCapability = {.supportedPresets =
+                                                                      kSupportedPresets};
 const Descriptor PresetReverbSw::kDescriptor = {
         .common = {.id = {.type = kPresetReverbTypeUUID,
                           .uuid = kPresetReverbSwImplUUID,
@@ -82,16 +89,59 @@
     RETURN_IF(Parameter::Specific::presetReverb != specific.getTag(), EX_ILLEGAL_ARGUMENT,
               "EffectNotSupported");
 
-    mSpecificParam = specific.get<Parameter::Specific::presetReverb>();
-    LOG(DEBUG) << __func__ << " success with: " << specific.toString();
-    return ndk::ScopedAStatus::ok();
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    auto& prParam = specific.get<Parameter::Specific::presetReverb>();
+    auto tag = prParam.getTag();
+
+    switch (tag) {
+        case PresetReverb::preset: {
+            RETURN_IF(
+                    mContext->setPRPreset(prParam.get<PresetReverb::preset>()) != RetCode::SUCCESS,
+                    EX_ILLEGAL_ARGUMENT, "setPresetFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "PresetReverbTagNotSupported");
+        }
+    }
 }
 
 ndk::ScopedAStatus PresetReverbSw::getParameterSpecific(const Parameter::Id& id,
                                                         Parameter::Specific* specific) {
     auto tag = id.getTag();
     RETURN_IF(Parameter::Id::presetReverbTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
-    specific->set<Parameter::Specific::presetReverb>(mSpecificParam);
+    auto prId = id.get<Parameter::Id::presetReverbTag>();
+    auto prIdTag = prId.getTag();
+    switch (prIdTag) {
+        case PresetReverb::Id::commonTag:
+            return getParameterPresetReverb(prId.get<PresetReverb::Id::commonTag>(), specific);
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "PresetReverbTagNotSupported");
+    }
+}
+
+ndk::ScopedAStatus PresetReverbSw::getParameterPresetReverb(const PresetReverb::Tag& tag,
+                                                            Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    PresetReverb prParam;
+    switch (tag) {
+        case PresetReverb::preset: {
+            prParam.set<PresetReverb::preset>(mContext->getPRPreset());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "PresetReverbTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::presetReverb>(prParam);
     return ndk::ScopedAStatus::ok();
 }
 
diff --git a/audio/aidl/default/presetReverb/PresetReverbSw.h b/audio/aidl/default/presetReverb/PresetReverbSw.h
index 43ed36e..eb1d80a 100644
--- a/audio/aidl/default/presetReverb/PresetReverbSw.h
+++ b/audio/aidl/default/presetReverb/PresetReverbSw.h
@@ -32,7 +32,15 @@
         : EffectContext(statusDepth, common) {
         LOG(DEBUG) << __func__;
     }
-    // TODO: add specific context here
+    RetCode setPRPreset(PresetReverb::Presets preset) {
+        // TODO : Add implementation to modify Presets
+        mPreset = preset;
+        return RetCode::SUCCESS;
+    }
+    PresetReverb::Presets getPRPreset() const { return mPreset; }
+
+  private:
+    PresetReverb::Presets mPreset = PresetReverb::Presets::NONE;
 };
 
 class PresetReverbSw final : public EffectImpl {
@@ -60,7 +68,8 @@
 
   private:
     std::shared_ptr<PresetReverbSwContext> mContext;
-    /* parameters */
-    PresetReverb mSpecificParam;
+
+    ndk::ScopedAStatus getParameterPresetReverb(const PresetReverb::Tag& tag,
+                                                Parameter::Specific* specific);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.cpp b/audio/aidl/default/virtualizer/VirtualizerSw.cpp
index faa630e..cc51937 100644
--- a/audio/aidl/default/virtualizer/VirtualizerSw.cpp
+++ b/audio/aidl/default/virtualizer/VirtualizerSw.cpp
@@ -60,11 +60,13 @@
 namespace aidl::android::hardware::audio::effect {
 
 const std::string VirtualizerSw::kEffectName = "VirtualizerSw";
-const Virtualizer::Capability VirtualizerSw::kCapability;
+const bool VirtualizerSw::kStrengthSupported = true;
+const Virtualizer::Capability VirtualizerSw::kCapability = {
+        .maxStrengthPm = 1000, .strengthSupported = kStrengthSupported};
 const Descriptor VirtualizerSw::kDescriptor = {
         .common = {.id = {.type = kVirtualizerTypeUUID,
                           .uuid = kVirtualizerSwImplUUID,
-                          .proxy = std::nullopt},
+                          .proxy = kVirtualizerProxyUUID},
                    .flags = {.type = Flags::Type::INSERT,
                              .insert = Flags::Insert::FIRST,
                              .volume = Flags::Volume::CTRL},
@@ -82,16 +84,60 @@
     RETURN_IF(Parameter::Specific::virtualizer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
               "EffectNotSupported");
 
-    mSpecificParam = specific.get<Parameter::Specific::virtualizer>();
-    LOG(DEBUG) << __func__ << " success with: " << specific.toString();
-    return ndk::ScopedAStatus::ok();
+    auto& vrParam = specific.get<Parameter::Specific::virtualizer>();
+    auto tag = vrParam.getTag();
+
+    switch (tag) {
+        case Virtualizer::strengthPm: {
+            RETURN_IF(!kStrengthSupported, EX_ILLEGAL_ARGUMENT, "SettingStrengthNotSupported");
+
+            RETURN_IF(mContext->setVrStrength(vrParam.get<Virtualizer::strengthPm>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "strengthPmNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "VirtualizerTagNotSupported");
+        }
+    }
 }
 
 ndk::ScopedAStatus VirtualizerSw::getParameterSpecific(const Parameter::Id& id,
                                                        Parameter::Specific* specific) {
     auto tag = id.getTag();
     RETURN_IF(Parameter::Id::virtualizerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
-    specific->set<Parameter::Specific::virtualizer>(mSpecificParam);
+    auto vrId = id.get<Parameter::Id::virtualizerTag>();
+    auto vrIdTag = vrId.getTag();
+    switch (vrIdTag) {
+        case Virtualizer::Id::commonTag:
+            return getParameterVirtualizer(vrId.get<Virtualizer::Id::commonTag>(), specific);
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "VirtualizerTagNotSupported");
+    }
+}
+
+ndk::ScopedAStatus VirtualizerSw::getParameterVirtualizer(const Virtualizer::Tag& tag,
+                                                          Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    Virtualizer vrParam;
+    switch (tag) {
+        case Virtualizer::strengthPm: {
+            vrParam.set<Virtualizer::strengthPm>(mContext->getVrStrength());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "VirtualizerTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::virtualizer>(vrParam);
     return ndk::ScopedAStatus::ok();
 }
 
@@ -126,4 +172,14 @@
     return {STATUS_OK, samples, samples};
 }
 
+RetCode VirtualizerSwContext::setVrStrength(int strength) {
+    if (strength < 0 || strength > VirtualizerSw::kCapability.maxStrengthPm) {
+        LOG(ERROR) << __func__ << " invalid strength: " << strength;
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+    // TODO : Add implementation to apply new strength
+    mStrength = strength;
+    return RetCode::SUCCESS;
+}
+
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.h b/audio/aidl/default/virtualizer/VirtualizerSw.h
index 4a05678..0f294cd 100644
--- a/audio/aidl/default/virtualizer/VirtualizerSw.h
+++ b/audio/aidl/default/virtualizer/VirtualizerSw.h
@@ -32,12 +32,17 @@
         : EffectContext(statusDepth, common) {
         LOG(DEBUG) << __func__;
     }
-    // TODO: add specific context here
+    RetCode setVrStrength(int strength);
+    int getVrStrength() const { return mStrength; }
+
+  private:
+    int mStrength = 0;
 };
 
 class VirtualizerSw final : public EffectImpl {
   public:
     static const std::string kEffectName;
+    static const bool kStrengthSupported;
     static const Virtualizer::Capability kCapability;
     static const Descriptor kDescriptor;
     VirtualizerSw() { LOG(DEBUG) << __func__; }
@@ -60,7 +65,8 @@
 
   private:
     std::shared_ptr<VirtualizerSwContext> mContext;
-    /* parameters */
-    Virtualizer mSpecificParam;
+
+    ndk::ScopedAStatus getParameterVirtualizer(const Virtualizer::Tag& tag,
+                                               Parameter::Specific* specific);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/visualizer/VisualizerSw.cpp b/audio/aidl/default/visualizer/VisualizerSw.cpp
index b898c00..614988c 100644
--- a/audio/aidl/default/visualizer/VisualizerSw.cpp
+++ b/audio/aidl/default/visualizer/VisualizerSw.cpp
@@ -14,14 +14,9 @@
  * limitations under the License.
  */
 
-#include <cstddef>
 #define LOG_TAG "AHAL_VisualizerSw"
-#include <Utils.h>
-#include <algorithm>
-#include <unordered_set>
 
 #include <android-base/logging.h>
-#include <fmq/AidlMessageQueue.h>
 
 #include "VisualizerSw.h"
 
@@ -60,7 +55,13 @@
 namespace aidl::android::hardware::audio::effect {
 
 const std::string VisualizerSw::kEffectName = "VisualizerSw";
-const Visualizer::Capability VisualizerSw::kCapability;
+/* capabilities */
+const Visualizer::CaptureSamplesRange VisualizerSwContext::kCaptureSamplesRange = {
+        VisualizerSwContext::kMinCaptureSize, VisualizerSwContext::kMaxCaptureSize};
+const Visualizer::Capability VisualizerSw::kCapability = {
+        .maxLatencyMs = VisualizerSwContext::kMaxLatencyMs,
+        .captureSampleRange = VisualizerSwContext::kCaptureSamplesRange};
+
 const Descriptor VisualizerSw::kDescriptor = {
         .common = {.id = {.type = kVisualizerTypeUUID,
                           .uuid = kVisualizerSwImplUUID,
@@ -82,8 +83,53 @@
     RETURN_IF(Parameter::Specific::visualizer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
               "EffectNotSupported");
 
-    mSpecificParam = specific.get<Parameter::Specific::visualizer>();
-    LOG(DEBUG) << __func__ << " success with: " << specific.toString();
+    auto& vsParam = specific.get<Parameter::Specific::visualizer>();
+    auto tag = vsParam.getTag();
+
+    switch (tag) {
+        case Visualizer::captureSamples: {
+            RETURN_IF(mContext->setVsCaptureSize(vsParam.get<Visualizer::captureSamples>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "captureSizeNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        case Visualizer::scalingMode: {
+            RETURN_IF(mContext->setVsScalingMode(vsParam.get<Visualizer::scalingMode>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "scalingModeNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        case Visualizer::measurementMode: {
+            RETURN_IF(mContext->setVsMeasurementMode(vsParam.get<Visualizer::measurementMode>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "measurementModeNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        case Visualizer::setOnlyParameters: {
+            return setSetOnlyParameterVisualizer(vsParam.get<Visualizer::setOnlyParameters>());
+        }
+        case Visualizer::getOnlyParameters: {
+            LOG(ERROR) << __func__ << " unsupported settable getOnlyParam";
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "SetofGetOnlyParamsNotSupported");
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "VisualizerTagNotSupported");
+        }
+    }
+}
+
+ndk::ScopedAStatus VisualizerSw::setSetOnlyParameterVisualizer(
+        Visualizer::SetOnlyParameters setOnlyParam) {
+    auto tag = setOnlyParam.getTag();
+    RETURN_IF(Visualizer::SetOnlyParameters::latencyMs != tag, EX_ILLEGAL_ARGUMENT,
+              "SetOnlyParametersTagNotSupported");
+    RETURN_IF(
+            mContext->setVsLatency(setOnlyParam.get<Visualizer::SetOnlyParameters::latencyMs>()) !=
+                    RetCode::SUCCESS,
+            EX_ILLEGAL_ARGUMENT, "latencyNotSupported");
     return ndk::ScopedAStatus::ok();
 }
 
@@ -91,7 +137,76 @@
                                                       Parameter::Specific* specific) {
     auto tag = id.getTag();
     RETURN_IF(Parameter::Id::visualizerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
-    specific->set<Parameter::Specific::visualizer>(mSpecificParam);
+    auto vsId = id.get<Parameter::Id::visualizerTag>();
+    auto vsIdTag = vsId.getTag();
+    switch (vsIdTag) {
+        case Visualizer::Id::commonTag:
+            return getParameterVisualizer(vsId.get<Visualizer::Id::commonTag>(), specific);
+        case Visualizer::Id::getOnlyParamTag:
+            return getGetOnlyParameterVisualizer(vsId.get<Visualizer::Id::getOnlyParamTag>(),
+                                                 specific);
+        case Visualizer::Id::setOnlyParamTag: {
+            LOG(ERROR) << __func__ << " unsupported gettable setOnlyParam";
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "GetofSetOnlyParamsNotSupported");
+        }
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "VisualizerTagNotSupported");
+    }
+}
+ndk::ScopedAStatus VisualizerSw::getParameterVisualizer(const Visualizer::Tag& tag,
+                                                        Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    Visualizer vsParam;
+    switch (tag) {
+        case Visualizer::captureSamples: {
+            vsParam.set<Visualizer::captureSamples>(mContext->getVsCaptureSize());
+            break;
+        }
+        case Visualizer::scalingMode: {
+            vsParam.set<Visualizer::scalingMode>(mContext->getVsScalingMode());
+            break;
+        }
+        case Visualizer::measurementMode: {
+            vsParam.set<Visualizer::measurementMode>(mContext->getVsMeasurementMode());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "VisualizerTagNotSupported");
+        }
+    }
+    specific->set<Parameter::Specific::visualizer>(vsParam);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus VisualizerSw::getGetOnlyParameterVisualizer(
+        const Visualizer::GetOnlyParameters::Tag& tag, Parameter::Specific* specific) {
+    Visualizer::GetOnlyParameters getOnlyParam;
+    switch (tag) {
+        case Visualizer::GetOnlyParameters::measurement: {
+            getOnlyParam.set<Visualizer::GetOnlyParameters::measurement>(
+                    mContext->getVsMeasurement());
+            break;
+        }
+        case Visualizer::GetOnlyParameters::captureSampleBuffer: {
+            getOnlyParam.set<Visualizer::GetOnlyParameters::captureSampleBuffer>(
+                    mContext->getVsCaptureSampleBuffer());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "GetOnlyParameterTagNotSupported");
+        }
+    }
+    Visualizer vsParam;
+    vsParam.set<Visualizer::getOnlyParameters>(getOnlyParam);
+    specific->set<Parameter::Specific::visualizer>(vsParam);
     return ndk::ScopedAStatus::ok();
 }
 
@@ -126,4 +241,37 @@
     return {STATUS_OK, samples, samples};
 }
 
+RetCode VisualizerSwContext::setVsCaptureSize(int captureSize) {
+    if (captureSize < VisualizerSw::kCapability.captureSampleRange.min ||
+        captureSize > VisualizerSw::kCapability.captureSampleRange.max) {
+        LOG(ERROR) << __func__ << " invalid captureSize " << captureSize;
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+    // TODO : Add implementation to apply new captureSize
+    mCaptureSize = captureSize;
+    return RetCode::SUCCESS;
+}
+
+RetCode VisualizerSwContext::setVsScalingMode(Visualizer::ScalingMode scalingMode) {
+    // TODO : Add implementation to apply new scalingMode
+    mScalingMode = scalingMode;
+    return RetCode::SUCCESS;
+}
+
+RetCode VisualizerSwContext::setVsMeasurementMode(Visualizer::MeasurementMode measurementMode) {
+    // TODO : Add implementation to apply new measurementMode
+    mMeasurementMode = measurementMode;
+    return RetCode::SUCCESS;
+}
+
+RetCode VisualizerSwContext::setVsLatency(int latency) {
+    if (latency < 0 || latency > VisualizerSw::kCapability.maxLatencyMs) {
+        LOG(ERROR) << __func__ << " invalid latency " << latency;
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+    // TODO : Add implementation to modify latency
+    mLatency = latency;
+    return RetCode::SUCCESS;
+}
+
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/visualizer/VisualizerSw.h b/audio/aidl/default/visualizer/VisualizerSw.h
index 24b92dd..e9d46d7 100644
--- a/audio/aidl/default/visualizer/VisualizerSw.h
+++ b/audio/aidl/default/visualizer/VisualizerSw.h
@@ -17,9 +17,7 @@
 #pragma once
 
 #include <aidl/android/hardware/audio/effect/BnEffect.h>
-#include <fmq/AidlMessageQueue.h>
-#include <cstdlib>
-#include <memory>
+#include <vector>
 
 #include "effect-impl/EffectImpl.h"
 #include "effect-impl/EffectUUID.h"
@@ -28,11 +26,39 @@
 
 class VisualizerSwContext final : public EffectContext {
   public:
+    static const int kMinCaptureSize = 0x80;
+    static const int kMaxCaptureSize = 0x400;
+    static const int kMaxLatencyMs = 3000;
+    static const int kMaxCaptureBufSize = 0xffff;
+    static const Visualizer::CaptureSamplesRange kCaptureSamplesRange;
     VisualizerSwContext(int statusDepth, const Parameter::Common& common)
         : EffectContext(statusDepth, common) {
         LOG(DEBUG) << __func__;
+        mCaptureSampleBuffer.resize(kMaxCaptureBufSize);
+        fill(mCaptureSampleBuffer.begin(), mCaptureSampleBuffer.end(), 0x80);
     }
-    // TODO: add specific context here
+
+    RetCode setVsCaptureSize(int captureSize);
+    int getVsCaptureSize() const { return mCaptureSize; }
+
+    RetCode setVsScalingMode(Visualizer::ScalingMode scalingMode);
+    Visualizer::ScalingMode getVsScalingMode() const { return mScalingMode; }
+
+    RetCode setVsMeasurementMode(Visualizer::MeasurementMode measurementMode);
+    Visualizer::MeasurementMode getVsMeasurementMode() const { return mMeasurementMode; }
+
+    RetCode setVsLatency(int latency);
+
+    Visualizer::GetOnlyParameters::Measurement getVsMeasurement() const { return mMeasurement; }
+    std::vector<uint8_t> getVsCaptureSampleBuffer() const { return mCaptureSampleBuffer; }
+
+  private:
+    int mCaptureSize = kMaxCaptureSize;
+    Visualizer::ScalingMode mScalingMode = Visualizer::ScalingMode::NORMALIZED;
+    Visualizer::MeasurementMode mMeasurementMode = Visualizer::MeasurementMode::NONE;
+    int mLatency = 0;
+    const Visualizer::GetOnlyParameters::Measurement mMeasurement = {0, 0};
+    std::vector<uint8_t> mCaptureSampleBuffer;
 };
 
 class VisualizerSw final : public EffectImpl {
@@ -60,7 +86,11 @@
 
   private:
     std::shared_ptr<VisualizerSwContext> mContext;
-    /* parameters */
-    Visualizer mSpecificParam;
+
+    ndk::ScopedAStatus setSetOnlyParameterVisualizer(Visualizer::SetOnlyParameters setOnlyParam);
+    ndk::ScopedAStatus getParameterVisualizer(const Visualizer::Tag& tag,
+                                              Parameter::Specific* specific);
+    ndk::ScopedAStatus getGetOnlyParameterVisualizer(const Visualizer::GetOnlyParameters::Tag& tag,
+                                                     Parameter::Specific* specific);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/volume/VolumeSw.cpp b/audio/aidl/default/volume/VolumeSw.cpp
index 6fce16e..64301dc 100644
--- a/audio/aidl/default/volume/VolumeSw.cpp
+++ b/audio/aidl/default/volume/VolumeSw.cpp
@@ -60,7 +60,7 @@
 namespace aidl::android::hardware::audio::effect {
 
 const std::string VolumeSw::kEffectName = "VolumeSw";
-const Volume::Capability VolumeSw::kCapability;
+const Volume::Capability VolumeSw::kCapability = {.minLevelDb = -9600, .maxLevelDb = 0};
 const Descriptor VolumeSw::kDescriptor = {
         .common = {.id = {.type = kVolumeTypeUUID,
                           .uuid = kVolumeSwImplUUID,
@@ -82,16 +82,66 @@
     RETURN_IF(Parameter::Specific::volume != specific.getTag(), EX_ILLEGAL_ARGUMENT,
               "EffectNotSupported");
 
-    mSpecificParam = specific.get<Parameter::Specific::volume>();
-    LOG(DEBUG) << __func__ << " success with: " << specific.toString();
-    return ndk::ScopedAStatus::ok();
+    auto& volParam = specific.get<Parameter::Specific::volume>();
+    auto tag = volParam.getTag();
+
+    switch (tag) {
+        case Volume::levelDb: {
+            RETURN_IF(mContext->setVolLevel(volParam.get<Volume::levelDb>()) != RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "LevelNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        case Volume::mute: {
+            RETURN_IF(mContext->setVolMute(volParam.get<Volume::mute>()) != RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "MuteNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "VolumeTagNotSupported");
+        }
+    }
 }
 
 ndk::ScopedAStatus VolumeSw::getParameterSpecific(const Parameter::Id& id,
                                                   Parameter::Specific* specific) {
     auto tag = id.getTag();
     RETURN_IF(Parameter::Id::volumeTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
-    specific->set<Parameter::Specific::volume>(mSpecificParam);
+    auto volId = id.get<Parameter::Id::volumeTag>();
+    auto volIdTag = volId.getTag();
+    switch (volIdTag) {
+        case Volume::Id::commonTag:
+            return getParameterVolume(volId.get<Volume::Id::commonTag>(), specific);
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "VolumeTagNotSupported");
+    }
+}
+
+ndk::ScopedAStatus VolumeSw::getParameterVolume(const Volume::Tag& tag,
+                                                Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    Volume volParam;
+    switch (tag) {
+        case Volume::levelDb: {
+            volParam.set<Volume::levelDb>(mContext->getVolLevel());
+            break;
+        }
+        case Volume::mute: {
+            volParam.set<Volume::mute>(mContext->getVolMute());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "VolumeTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::volume>(volParam);
     return ndk::ScopedAStatus::ok();
 }
 
@@ -126,4 +176,20 @@
     return {STATUS_OK, samples, samples};
 }
 
+RetCode VolumeSwContext::setVolLevel(int level) {
+    if (level < VolumeSw::kCapability.minLevelDb || level > VolumeSw::kCapability.maxLevelDb) {
+        LOG(ERROR) << __func__ << " invalid level " << level;
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+    // TODO : Add implementation to apply new level
+    mLevel = level;
+    return RetCode::SUCCESS;
+}
+
+RetCode VolumeSwContext::setVolMute(bool mute) {
+    // TODO : Add implementation to modify mute
+    mMute = mute;
+    return RetCode::SUCCESS;
+}
+
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/volume/VolumeSw.h b/audio/aidl/default/volume/VolumeSw.h
index 3bd29b9..b6f6077 100644
--- a/audio/aidl/default/volume/VolumeSw.h
+++ b/audio/aidl/default/volume/VolumeSw.h
@@ -32,7 +32,18 @@
         : EffectContext(statusDepth, common) {
         LOG(DEBUG) << __func__;
     }
-    // TODO: add specific context here
+
+    RetCode setVolLevel(int level);
+
+    int getVolLevel() const { return mLevel; }
+
+    RetCode setVolMute(bool mute);
+
+    bool getVolMute() const { return mMute; }
+
+  private:
+    int mLevel = 0;
+    bool mMute = false;
 };
 
 class VolumeSw final : public EffectImpl {
@@ -60,7 +71,7 @@
 
   private:
     std::shared_ptr<VolumeSwContext> mContext;
-    /* parameters */
-    Volume mSpecificParam;
+
+    ndk::ScopedAStatus getParameterVolume(const Volume::Tag& tag, Parameter::Specific* specific);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/sounddose/Android.bp b/audio/aidl/sounddose/Android.bp
new file mode 100644
index 0000000..85d6e21
--- /dev/null
+++ b/audio/aidl/sounddose/Android.bp
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+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.audio.sounddose",
+    host_supported: true,
+    vendor_available: true,
+    stability: "vintf",
+    srcs: [
+        "android/hardware/audio/sounddose/ISoundDoseFactory.aidl",
+    ],
+    imports: [
+        latest_android_hardware_audio_core_sounddose,
+    ],
+    backend: {
+        // The C++ backend is disabled transitively due to use by core audio HAL.
+        cpp: {
+            enabled: false,
+        },
+        java: {
+            sdk_version: "module_current",
+        },
+    },
+    versions_with_info: [
+        // IMPORTANT: Update latest_android_hardware_audio_sounddose every time you
+        // add the latest frozen version to versions_with_info
+    ],
+}
+
+// Note: This should always be one version ahead of the last frozen version
+latest_android_hardware_audio_sounddose = "android.hardware.audio.sounddose-V1"
+
+// Modules that depend on android.hardware.audio.sounddose directly can include
+// the following cc_defaults to avoid explicitly managing dependency versions
+// across many scattered files.
+cc_defaults {
+    name: "latest_android_hardware_audio_sounddose_ndk_shared",
+    shared_libs: [
+        latest_android_hardware_audio_sounddose + "-ndk",
+    ],
+}
+
+cc_defaults {
+    name: "latest_android_hardware_audio_sounddose_ndk_static",
+    static_libs: [
+        latest_android_hardware_audio_sounddose + "-ndk",
+    ],
+}
diff --git a/audio/aidl/sounddose/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/ISoundDose.aidl b/audio/aidl/sounddose/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/ISoundDose.aidl
new file mode 100644
index 0000000..dff17e2
--- /dev/null
+++ b/audio/aidl/sounddose/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/ISoundDose.aidl
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.core;
+@VintfStability
+interface ISoundDose {
+  void setOutputRs2(float rs2ValueDbA);
+  float getOutputRs2();
+  void registerSoundDoseCallback(in android.hardware.audio.core.ISoundDose.IHalSoundDoseCallback callback);
+  const int DEFAULT_MAX_RS2 = 100;
+  @VintfStability
+  interface IHalSoundDoseCallback {
+    oneway void onMomentaryExposureWarning(float currentDbA, in android.media.audio.common.AudioDevice audioDevice);
+    oneway void onNewMelValues(in android.hardware.audio.core.ISoundDose.IHalSoundDoseCallback.MelRecord melRecord, in android.media.audio.common.AudioDevice audioDevice);
+    @VintfStability
+    parcelable MelRecord {
+      float[] melValues;
+      long timestamp;
+    }
+  }
+}
diff --git a/audio/aidl/sounddose/aidl_api/android.hardware.audio.sounddose/current/android/hardware/audio/sounddose/ISoundDoseFactory.aidl b/audio/aidl/sounddose/aidl_api/android.hardware.audio.sounddose/current/android/hardware/audio/sounddose/ISoundDoseFactory.aidl
new file mode 100644
index 0000000..148720c
--- /dev/null
+++ b/audio/aidl/sounddose/aidl_api/android.hardware.audio.sounddose/current/android/hardware/audio/sounddose/ISoundDoseFactory.aidl
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.sounddose;
+@VintfStability
+interface ISoundDoseFactory {
+  @nullable android.hardware.audio.core.sounddose.ISoundDose getSoundDose(in @utf8InCpp String module);
+}
diff --git a/audio/aidl/sounddose/android/hardware/audio/sounddose/ISoundDoseFactory.aidl b/audio/aidl/sounddose/android/hardware/audio/sounddose/ISoundDoseFactory.aidl
new file mode 100644
index 0000000..4079fe8
--- /dev/null
+++ b/audio/aidl/sounddose/android/hardware/audio/sounddose/ISoundDoseFactory.aidl
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+package android.hardware.audio.sounddose;
+
+import android.hardware.audio.core.sounddose.ISoundDose;
+
+/**
+ * This interface is used to provide an easy way to implement the ISoundDose interface
+ * without switching the audio HAL to AIDL. The implementation is intended as a workaround
+ * for the certification with IEC62368-1 3rd edition and EN50332-3.
+ * Note that this interface will be deprecated in favor of the audio AIDL HAL.
+ */
+@VintfStability
+interface ISoundDoseFactory {
+    /**
+     * Retrieve the sound dose interface for a given audio HAL module name.
+     *
+     * If a device must comply to IEC62368-1 3rd edition audio safety requirements and is
+     * implementing audio offload decoding or other direct playback paths where volume control
+     * happens below the audio HAL, it must return an instance of the ISoundDose interface.
+     * The same instance must be returned during the lifetime of the HAL module.
+     * If the HAL module does not support sound dose, null must be returned, without throwing
+     * any errors.
+     *
+     * @param module for which we trigger sound dose updates.
+     * @return An instance of the ISoundDose interface implementation.
+     * @throws EX_ILLEGAL_STATE If there was an error creating an instance.
+     */
+    @nullable ISoundDose getSoundDose(in @utf8InCpp String module);
+}
diff --git a/audio/aidl/sounddose/default/Android.bp b/audio/aidl/sounddose/default/Android.bp
new file mode 100644
index 0000000..bd770fa
--- /dev/null
+++ b/audio/aidl/sounddose/default/Android.bp
@@ -0,0 +1,46 @@
+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_defaults {
+    name: "aidlsounddoseservice_defaults",
+    vendor: true,
+    header_libs: [
+        "libsounddoseaidl_headers",
+    ],
+}
+
+cc_library {
+    name: "libsounddoseserviceexampleimpl",
+    defaults: [
+        "aidlsounddoseservice_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: [
+        "SoundDoseFactory.cpp",
+    ],
+    shared_libs: [
+        "libaudioservicesounddoseimpl",
+        "libbase",
+        "libbinder_ndk",
+    ],
+
+    visibility: [
+        "//hardware/interfaces/audio/common/all-versions/default/service",
+    ],
+}
+
+cc_library_headers {
+    name: "libsounddoseaidl_headers",
+    export_include_dirs: ["include"],
+    vendor_available: true,
+    host_supported: true,
+}
diff --git a/audio/aidl/sounddose/default/SoundDoseFactory.cpp b/audio/aidl/sounddose/default/SoundDoseFactory.cpp
new file mode 100644
index 0000000..83a592b
--- /dev/null
+++ b/audio/aidl/sounddose/default/SoundDoseFactory.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "AHAL_SoundDoseFactory"
+
+#include "SoundDoseFactory.h"
+
+#include <android-base/logging.h>
+#include <core-impl/SoundDose.h>
+
+namespace aidl::android::hardware::audio::sounddose {
+
+using ::aidl::android::hardware::audio::core::sounddose::SoundDose;
+
+ndk::ScopedAStatus SoundDoseFactory::getSoundDose(const std::string& in_module,
+                                                  std::shared_ptr<ISoundDose>* _aidl_return) {
+    auto soundDoseIt = mSoundDoseBinderMap.find(in_module);
+    if (soundDoseIt != mSoundDoseBinderMap.end()) {
+        *_aidl_return = ISoundDose::fromBinder(soundDoseIt->second);
+
+        LOG(DEBUG) << __func__
+                   << ": returning cached instance of ISoundDose: " << _aidl_return->get()
+                   << " for module " << in_module;
+        return ndk::ScopedAStatus::ok();
+    }
+
+    auto soundDose = ndk::SharedRefBase::make<SoundDose>();
+    mSoundDoseBinderMap[in_module] = soundDose->asBinder();
+    *_aidl_return = soundDose;
+
+    LOG(DEBUG) << __func__ << ": returning new instance of ISoundDose: " << _aidl_return->get()
+               << " for module " << in_module;
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::audio::sounddose
diff --git a/audio/aidl/sounddose/default/include/SoundDoseFactory.h b/audio/aidl/sounddose/default/include/SoundDoseFactory.h
new file mode 100644
index 0000000..ced4291
--- /dev/null
+++ b/audio/aidl/sounddose/default/include/SoundDoseFactory.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/core/sounddose/ISoundDose.h>
+#include <aidl/android/hardware/audio/sounddose/BnSoundDoseFactory.h>
+#include <android/binder_interface_utils.h>
+
+#include <unordered_map>
+
+namespace aidl::android::hardware::audio::sounddose {
+
+using ::aidl::android::hardware::audio::core::sounddose::ISoundDose;
+
+class SoundDoseFactory : public BnSoundDoseFactory {
+  public:
+    ndk::ScopedAStatus getSoundDose(const std::string& module,
+                                    std::shared_ptr<ISoundDose>* _aidl_return) override;
+
+  private:
+    std::unordered_map<std::string, ndk::SpAIBinder> mSoundDoseBinderMap;
+};
+
+}  // namespace aidl::android::hardware::audio::sounddose
diff --git a/audio/aidl/sounddose/vts/Android.bp b/audio/aidl/sounddose/vts/Android.bp
new file mode 100644
index 0000000..88be968
--- /dev/null
+++ b/audio/aidl/sounddose/vts/Android.bp
@@ -0,0 +1,36 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsHalSoundDoseFactoryTargetTest",
+    defaults: [
+        "latest_android_hardware_audio_core_sounddose_ndk_static",
+        "latest_android_hardware_audio_sounddose_ndk_static",
+        "latest_android_media_audio_common_types_ndk_static",
+        "use_libaidlvintf_gtest_helper_static",
+        "VtsHalTargetTestDefaults",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "libcutils",
+    ],
+    srcs: [
+        "VtsHalSoundDoseFactoryTargetTest.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-Wthread-safety",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/audio/aidl/sounddose/vts/TEST_MAPPING b/audio/aidl/sounddose/vts/TEST_MAPPING
new file mode 100644
index 0000000..bebeed9
--- /dev/null
+++ b/audio/aidl/sounddose/vts/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "VtsHalSoundDoseFactoryTargetTest"
+    }
+  ]
+}
diff --git a/audio/aidl/sounddose/vts/VtsHalSoundDoseFactoryTargetTest.cpp b/audio/aidl/sounddose/vts/VtsHalSoundDoseFactoryTargetTest.cpp
new file mode 100644
index 0000000..df35bae
--- /dev/null
+++ b/audio/aidl/sounddose/vts/VtsHalSoundDoseFactoryTargetTest.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "VtsHalSoundDose.Factory"
+#include <android-base/logging.h>
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/audio/sounddose/ISoundDoseFactory.h>
+#include <android/binder_manager.h>
+
+#include <memory>
+
+namespace android::hardware::audio::common::testing {
+
+namespace detail {
+
+inline ::testing::AssertionResult assertIsOk(const char* expr, const ::ndk::ScopedAStatus& status) {
+    if (status.isOk()) {
+        return ::testing::AssertionSuccess();
+    }
+    return ::testing::AssertionFailure()
+           << "Expected the transaction \'" << expr << "\' to succeed\n"
+           << "  but it has failed with: " << status;
+}
+
+}  // namespace detail
+
+}  // namespace android::hardware::audio::common::testing
+
+// Test that the transaction status 'isOk'
+#define EXPECT_IS_OK(ret) \
+    EXPECT_PRED_FORMAT1(::android::hardware::audio::common::testing::detail::assertIsOk, ret)
+
+using namespace android;
+
+using aidl::android::hardware::audio::core::sounddose::ISoundDose;
+using aidl::android::hardware::audio::sounddose::ISoundDoseFactory;
+
+class SoundDoseFactory : public testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override { ASSERT_NO_FATAL_FAILURE(ConnectToService(GetParam())); }
+
+    void TearDown() override {}
+
+    void ConnectToService(const std::string& interfaceName) {
+        ndk::SpAIBinder binder =
+                ndk::SpAIBinder(AServiceManager_waitForService(interfaceName.c_str()));
+        if (binder == nullptr) {
+            LOG(ERROR) << "Failed to get service " << interfaceName;
+        } else {
+            LOG(DEBUG) << "Succeeded to get service " << interfaceName;
+        }
+        soundDoseFactory = ISoundDoseFactory::fromBinder(binder);
+        ASSERT_NE(soundDoseFactory, nullptr);
+    }
+
+    std::shared_ptr<ISoundDoseFactory> soundDoseFactory;
+};
+
+TEST_P(SoundDoseFactory, GetSoundDoseForSameModule) {
+    const std::string module = "primary";
+
+    std::shared_ptr<ISoundDose> soundDose1;
+    EXPECT_IS_OK(soundDoseFactory->getSoundDose(module, &soundDose1));
+
+    if (soundDose1 == nullptr) {
+        LOG(WARNING) << "Primary module does not support sound dose";
+        return;
+    }
+
+    std::shared_ptr<ISoundDose> soundDose2;
+    EXPECT_IS_OK(soundDoseFactory->getSoundDose(module, &soundDose2));
+    EXPECT_NE(nullptr, soundDose2);
+    EXPECT_EQ(soundDose1->asBinder(), soundDose2->asBinder())
+            << "getSoundDose must return the same interface for the same module";
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        SoundDoseFactoryTest, SoundDoseFactory,
+        testing::ValuesIn(android::getAidlHalInstanceNames(ISoundDoseFactory::descriptor)),
+        android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SoundDoseFactory);
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index 068742d..becdf1b 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -24,6 +24,7 @@
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
         "libaudioaidlcommon",
+        "libaidlcommonsupport",
     ],
     header_libs: ["libaudioaidl_headers"],
     cflags: [
@@ -43,6 +44,7 @@
     defaults: [
         "VtsHalAudioTargetTestDefaults",
         "latest_android_hardware_audio_core_ndk_static",
+        "latest_android_hardware_audio_core_sounddose_ndk_static",
     ],
     shared_libs: [
         "libcutils",
@@ -73,13 +75,73 @@
 }
 
 cc_test {
+    name: "VtsHalDownmixTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalDownmixTargetTest.cpp"],
+}
+
+cc_test {
+    name: "VtsHalEnvironmentalReverbTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalEnvironmentalReverbTargetTest.cpp"],
+}
+
+cc_test {
     name: "VtsHalEqualizerTargetTest",
     defaults: ["VtsHalAudioTargetTestDefaults"],
     srcs: ["VtsHalEqualizerTargetTest.cpp"],
 }
 
 cc_test {
+    name: "VtsHalHapticGeneratorTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalHapticGeneratorTargetTest.cpp"],
+}
+
+cc_test {
     name: "VtsHalLoudnessEnhancerTargetTest",
     defaults: ["VtsHalAudioTargetTestDefaults"],
     srcs: ["VtsHalLoudnessEnhancerTargetTest.cpp"],
 }
+
+cc_test {
+    name: "VtsHalPresetReverbTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalPresetReverbTargetTest.cpp"],
+}
+
+cc_test {
+    name: "VtsHalVirtualizerTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalVirtualizerTargetTest.cpp"],
+}
+
+cc_test {
+    name: "VtsHalVisualizerTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalVisualizerTargetTest.cpp"],
+}
+
+cc_test {
+    name: "VtsHalVolumeTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalVolumeTargetTest.cpp"],
+}
+
+cc_test {
+    name: "VtsHalAECTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalAECTargetTest.cpp"],
+}
+
+cc_test {
+    name: "VtsHalAGCTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalAGCTargetTest.cpp"],
+}
+
+cc_test {
+    name: "VtsHalNSTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalNSTargetTest.cpp"],
+}
diff --git a/audio/aidl/vts/EffectFactoryHelper.h b/audio/aidl/vts/EffectFactoryHelper.h
index b649d9e..4add844 100644
--- a/audio/aidl/vts/EffectFactoryHelper.h
+++ b/audio/aidl/vts/EffectFactoryHelper.h
@@ -49,11 +49,11 @@
 
     std::shared_ptr<IFactory> GetFactory() const { return mEffectFactory; }
 
-    static std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>>
-    getAllEffectDescriptors(std::string serviceName, std::optional<AudioUuid> type = std::nullopt) {
+    static std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> getAllEffectDescriptors(
+            std::string serviceName, std::optional<AudioUuid> type = std::nullopt) {
         AudioHalBinderServiceUtil util;
         auto names = android::getAidlHalInstanceNames(serviceName);
-        std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>> result;
+        std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> result;
 
         for (const auto& name : names) {
             auto factory = IFactory::fromBinder(util.connectToService(name));
@@ -62,16 +62,14 @@
                     factory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &descs)
                             .isOk()) {
                     for (const auto& desc : descs) {
-                        const auto& id = desc.common.id;
-                        if (type.has_value() && id.type != type.value()) {
+                        if (type.has_value() && desc.common.id.type != type.value()) {
                             continue;
                         }
-                        result.emplace_back(factory, id);
+                        result.emplace_back(factory, desc);
                     }
                 }
             }
         }
-
         return result;
     }
 
diff --git a/audio/aidl/vts/EffectHelper.h b/audio/aidl/vts/EffectHelper.h
index 73a1f49..7222d4f 100644
--- a/audio/aidl/vts/EffectHelper.h
+++ b/audio/aidl/vts/EffectHelper.h
@@ -58,26 +58,34 @@
 class EffectHelper {
   public:
     static void create(std::shared_ptr<IFactory> factory, std::shared_ptr<IEffect>& effect,
-                       Descriptor::Identity id, binder_status_t status = EX_NONE) {
+                       Descriptor& desc, binder_status_t status = EX_NONE) {
         ASSERT_NE(factory, nullptr);
-        EXPECT_STATUS(status, factory->createEffect(id.uuid, &effect));
+        auto& id = desc.common.id;
+        ASSERT_STATUS(status, factory->createEffect(id.uuid, &effect));
         if (status == EX_NONE) {
             ASSERT_NE(effect, nullptr) << id.uuid.toString();
         }
     }
 
+    static void destroyIgnoreRet(std::shared_ptr<IFactory> factory,
+                                 std::shared_ptr<IEffect> effect) {
+        if (factory && effect) {
+            factory->destroyEffect(effect);
+        }
+    }
+
     static void destroy(std::shared_ptr<IFactory> factory, std::shared_ptr<IEffect> effect,
                         binder_status_t status = EX_NONE) {
         ASSERT_NE(factory, nullptr);
         ASSERT_NE(effect, nullptr);
-        EXPECT_STATUS(status, factory->destroyEffect(effect));
+        ASSERT_STATUS(status, factory->destroyEffect(effect));
     }
 
     static void open(std::shared_ptr<IEffect> effect, const Parameter::Common& common,
                      const std::optional<Parameter::Specific>& specific,
                      IEffect::OpenEffectReturn* ret, binder_status_t status = EX_NONE) {
         ASSERT_NE(effect, nullptr);
-        EXPECT_STATUS(status, effect->open(common, specific, ret));
+        ASSERT_STATUS(status, effect->open(common, specific, ret));
     }
 
     static void open(std::shared_ptr<IEffect> effect, int session = 0,
@@ -85,30 +93,40 @@
         ASSERT_NE(effect, nullptr);
         Parameter::Common common = EffectHelper::createParamCommon(session);
         IEffect::OpenEffectReturn ret;
-        open(effect, common, std::nullopt /* specific */, &ret, status);
+        ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, status));
     }
 
+    static void closeIgnoreRet(std::shared_ptr<IEffect> effect) {
+        if (effect) {
+            effect->close();
+        }
+    }
     static void close(std::shared_ptr<IEffect> effect, binder_status_t status = EX_NONE) {
         if (effect) {
-            EXPECT_STATUS(status, effect->close());
+            ASSERT_STATUS(status, effect->close());
         }
     }
     static void getDescriptor(std::shared_ptr<IEffect> effect, Descriptor& desc,
                               binder_status_t status = EX_NONE) {
         ASSERT_NE(effect, nullptr);
-        EXPECT_STATUS(status, effect->getDescriptor(&desc));
+        ASSERT_STATUS(status, effect->getDescriptor(&desc));
     }
     static void expectState(std::shared_ptr<IEffect> effect, State expectState,
                             binder_status_t status = EX_NONE) {
         ASSERT_NE(effect, nullptr);
         State state;
-        EXPECT_STATUS(status, effect->getState(&state));
-        EXPECT_EQ(expectState, state);
+        ASSERT_STATUS(status, effect->getState(&state));
+        ASSERT_EQ(expectState, state);
+    }
+    static void commandIgnoreRet(std::shared_ptr<IEffect> effect, CommandId command) {
+        if (effect) {
+            effect->command(command);
+        }
     }
     static void command(std::shared_ptr<IEffect> effect, CommandId command,
                         binder_status_t status = EX_NONE) {
         ASSERT_NE(effect, nullptr);
-        EXPECT_STATUS(status, effect->command(command));
+        ASSERT_STATUS(status, effect->command(command));
     }
     static void allocateInputData(const Parameter::Common common, std::unique_ptr<DataMQ>& mq,
                                   std::vector<float>& buffer) {
@@ -116,29 +134,29 @@
         auto frameSize = android::hardware::audio::common::getFrameSizeInBytes(
                 common.input.base.format, common.input.base.channelMask);
         const size_t floatsToWrite = mq->availableToWrite();
-        EXPECT_NE(0UL, floatsToWrite);
-        EXPECT_EQ(frameSize * common.input.frameCount, floatsToWrite * sizeof(float));
+        ASSERT_NE(0UL, floatsToWrite);
+        ASSERT_EQ(frameSize * common.input.frameCount, floatsToWrite * sizeof(float));
         buffer.resize(floatsToWrite);
         std::fill(buffer.begin(), buffer.end(), 0x5a);
     }
     static void writeToFmq(std::unique_ptr<DataMQ>& mq, const std::vector<float>& buffer) {
         const size_t available = mq->availableToWrite();
-        EXPECT_NE(0Ul, available);
+        ASSERT_NE(0Ul, available);
         auto bufferFloats = buffer.size();
         auto floatsToWrite = std::min(available, bufferFloats);
-        EXPECT_TRUE(mq->write(buffer.data(), floatsToWrite));
+        ASSERT_TRUE(mq->write(buffer.data(), floatsToWrite));
     }
     static void readFromFmq(std::unique_ptr<StatusMQ>& statusMq, size_t statusNum,
                             std::unique_ptr<DataMQ>& dataMq, size_t expectFloats,
                             std::vector<float>& buffer) {
         IEffect::Status status{};
-        EXPECT_TRUE(statusMq->readBlocking(&status, statusNum));
-        EXPECT_EQ(STATUS_OK, status.status);
+        ASSERT_TRUE(statusMq->readBlocking(&status, statusNum));
+        ASSERT_EQ(STATUS_OK, status.status);
         if (statusNum != 0) {
-            EXPECT_EQ(expectFloats, (unsigned)status.fmqProduced);
-            EXPECT_EQ(expectFloats, dataMq->availableToRead());
+            ASSERT_EQ(expectFloats, (unsigned)status.fmqProduced);
+            ASSERT_EQ(expectFloats, dataMq->availableToRead());
             if (expectFloats != 0) {
-                EXPECT_TRUE(dataMq->read(buffer.data(), expectFloats));
+                ASSERT_TRUE(dataMq->read(buffer.data(), expectFloats));
             }
         }
     }
diff --git a/audio/aidl/vts/TestUtils.h b/audio/aidl/vts/TestUtils.h
index 5e4d56a..4c1d42c 100644
--- a/audio/aidl/vts/TestUtils.h
+++ b/audio/aidl/vts/TestUtils.h
@@ -16,6 +16,8 @@
 
 #pragma once
 
+#include <algorithm>
+#include <initializer_list>
 #include <iostream>
 
 #include <android/binder_auto_utils.h>
@@ -45,6 +47,19 @@
            << "\n  but is has completed with: " << status;
 }
 
+template <typename T>
+inline ::testing::AssertionResult assertResult(const char* exp_expr, const char* act_expr,
+                                               const std::initializer_list<T>& expected,
+                                               const ::ndk::ScopedAStatus& status) {
+    if (std::find(expected.begin(), expected.end(), status.getExceptionCode()) != expected.end()) {
+        return ::testing::AssertionSuccess();
+    }
+    return ::testing::AssertionFailure() << "Expected the transaction \'" << act_expr
+                                         << "\' to complete with one of: " << exp_expr
+                                         << "\n  which is: " << ::testing::PrintToString(expected)
+                                         << "\n  but is has completed with: " << status;
+}
+
 }  // namespace detail
 
 }  // namespace android::hardware::audio::common::testing
diff --git a/audio/aidl/vts/VtsHalAECTargetTest.cpp b/audio/aidl/vts/VtsHalAECTargetTest.cpp
new file mode 100644
index 0000000..c3427c8
--- /dev/null
+++ b/audio/aidl/vts/VtsHalAECTargetTest.cpp
@@ -0,0 +1,218 @@
+/*
+ * 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.
+ */
+
+#include <Utils.h>
+#include <aidl/Vintf.h>
+#include <algorithm>
+#include <string>
+#include <unordered_set>
+
+#define LOG_TAG "VtsHalAECParamTest"
+
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::AcousticEchoCanceler;
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kAcousticEchoCancelerTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_ECHO_DELAY, PARAM_MOBILE_MODE };
+using AECParamTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
+                                     int /* echoDelayUs */, bool /* mobileMode */>;
+
+class AECParamTest : public ::testing::TestWithParam<AECParamTestParam>, public EffectHelper {
+  public:
+    AECParamTest()
+        : mEchoDelay(std::get<PARAM_ECHO_DELAY>(GetParam())),
+          mMobileMode(std::get<PARAM_MOBILE_MODE>(GetParam())) {
+        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() {
+        AcousticEchoCanceler aec = AcousticEchoCanceler::make<AcousticEchoCanceler::echoDelayUs>(0);
+        Parameter::Specific specific =
+                Parameter::Specific::make<Parameter::Specific::acousticEchoCanceler>(aec);
+        return specific;
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+
+    int mEchoDelay;
+    bool mMobileMode;
+
+    void SetAndGetParameters() {
+        for (auto& it : mTags) {
+            auto& tag = it.first;
+            auto& aec = it.second;
+
+            // validate parameter
+            Descriptor desc;
+            ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+            const bool valid = isTagInRange(tag, aec, desc);
+            const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+            // set parameter
+            Parameter expectParam;
+            Parameter::Specific specific;
+            specific.set<Parameter::Specific::acousticEchoCanceler>(aec);
+            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;
+                AcousticEchoCanceler::Id specificId;
+                specificId.set<AcousticEchoCanceler::Id::commonTag>(tag);
+                id.set<Parameter::Id::acousticEchoCancelerTag>(specificId);
+                EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+
+                EXPECT_EQ(expectParam, getParam) << "\nexpect:" << expectParam.toString()
+                                                 << "\ngetParam:" << getParam.toString();
+            }
+        }
+    }
+
+    void addEchoDelayParam(int delay) {
+        AcousticEchoCanceler aec;
+        aec.set<AcousticEchoCanceler::echoDelayUs>(delay);
+        mTags.push_back({AcousticEchoCanceler::echoDelayUs, aec});
+    }
+
+    void addMobileModeParam(bool mode) {
+        AcousticEchoCanceler aec;
+        aec.set<AcousticEchoCanceler::mobileMode>(mode);
+        mTags.push_back({AcousticEchoCanceler::mobileMode, aec});
+    }
+
+    bool isTagInRange(const AcousticEchoCanceler::Tag& tag, const AcousticEchoCanceler& aec,
+                      const Descriptor& desc) const {
+        const AcousticEchoCanceler::Capability& aecCap =
+                desc.capability.get<Capability::acousticEchoCanceler>();
+        switch (tag) {
+            case AcousticEchoCanceler::echoDelayUs: {
+                return isEchoDelayInRange(aecCap, aec.get<AcousticEchoCanceler::echoDelayUs>());
+            }
+            case AcousticEchoCanceler::mobileMode: {
+                bool mode = aec.get<AcousticEchoCanceler::mobileMode>();
+                return isMobileModeValid(aecCap, mode);
+            }
+            default:
+                return false;
+        }
+    }
+
+    bool isEchoDelayInRange(const AcousticEchoCanceler::Capability& cap, int delay) const {
+        return (delay >= 0 && delay <= cap.maxEchoDelayUs);
+    }
+
+    bool isMobileModeValid(const AcousticEchoCanceler::Capability& cap, bool mode) const {
+        if (cap.supportMobileMode) {
+            return true;
+        } else {
+            return mode == false;
+        }
+    }
+
+    static std::unordered_set<int> getEchoDelayTestValues() {
+        auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+                                                                     kAcousticEchoCancelerTypeUUID);
+        const auto max = std::max_element(
+                descList.begin(), descList.end(),
+                [](const std::pair<std::shared_ptr<IFactory>, Descriptor>& a,
+                   const std::pair<std::shared_ptr<IFactory>, Descriptor>& b) {
+                    return a.second.capability.get<Capability::acousticEchoCanceler>()
+                                   .maxEchoDelayUs <
+                           b.second.capability.get<Capability::acousticEchoCanceler>()
+                                   .maxEchoDelayUs;
+                });
+        if (max == descList.end()) {
+            return {0};
+        }
+        int maxDelay =
+                max->second.capability.get<Capability::acousticEchoCanceler>().maxEchoDelayUs;
+        return {-1, 0, maxDelay - 1, maxDelay, maxDelay + 1};
+    }
+    static std::unordered_set<bool> getMobileModeValues() { return {true, false}; }
+
+  private:
+    std::vector<std::pair<AcousticEchoCanceler::Tag, AcousticEchoCanceler>> mTags;
+    void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(AECParamTest, SetAndGetEchoDelay) {
+    EXPECT_NO_FATAL_FAILURE(addEchoDelayParam(mEchoDelay));
+    SetAndGetParameters();
+}
+
+TEST_P(AECParamTest, SetAndGetMobileMode) {
+    EXPECT_NO_FATAL_FAILURE(addMobileModeParam(mMobileMode));
+    SetAndGetParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        AECParamTest, AECParamTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kAcousticEchoCancelerTypeUUID)),
+                           testing::ValuesIn(AECParamTest::getEchoDelayTestValues()),
+                           testing::ValuesIn(AECParamTest::getMobileModeValues())),
+        [](const testing::TestParamInfo<AECParamTest::ParamType>& info) {
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string echoDelay = std::to_string(std::get<PARAM_ECHO_DELAY>(info.param));
+            std::string mobileMode = std::get<PARAM_MOBILE_MODE>(info.param) ? "true" : "false";
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_EchoDelay_" + echoDelay +
+                               "_MobileMode_" + mobileMode;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AECParamTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/audio/aidl/vts/VtsHalAGCTargetTest.cpp b/audio/aidl/vts/VtsHalAGCTargetTest.cpp
new file mode 100644
index 0000000..3448ae2
--- /dev/null
+++ b/audio/aidl/vts/VtsHalAGCTargetTest.cpp
@@ -0,0 +1,252 @@
+/*
+ * 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.
+ */
+
+#include <Utils.h>
+#include <aidl/Vintf.h>
+#include <android/binder_enums.h>
+#include <unordered_set>
+
+#define LOG_TAG "VtsHalAGCParamTest"
+
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::AutomaticGainControl;
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kAutomaticGainControlTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+
+enum ParamName {
+    PARAM_INSTANCE_NAME,
+    PARAM_DIGITAL_GAIN,
+    PARAM_SATURATION_MARGIN,
+    PARAM_LEVEL_ESTIMATOR
+};
+using AGCParamTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int /* gain */,
+                   int /* margin */, AutomaticGainControl::LevelEstimator>;
+
+class AGCParamTest : public ::testing::TestWithParam<AGCParamTestParam>, public EffectHelper {
+  public:
+    AGCParamTest()
+        : mGain(std::get<PARAM_DIGITAL_GAIN>(GetParam())),
+          mMargin(std::get<PARAM_SATURATION_MARGIN>(GetParam())),
+          mLevelEstimator(std::get<PARAM_LEVEL_ESTIMATOR>(GetParam())) {
+        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() {
+        AutomaticGainControl AGC =
+                AutomaticGainControl::make<AutomaticGainControl::fixedDigitalGainMb>(0);
+        Parameter::Specific specific =
+                Parameter::Specific::make<Parameter::Specific::automaticGainControl>(AGC);
+        return specific;
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+    int mGain;
+    int mMargin;
+    AutomaticGainControl::LevelEstimator mLevelEstimator;
+
+    void SetAndGetParameters() {
+        for (auto& it : mTags) {
+            auto& tag = it.first;
+            auto& AGC = it.second;
+
+            // validate parameter
+            Descriptor desc;
+            ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+            const bool valid = isTagInRange(tag, AGC, desc);
+            const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+            // set parameter
+            Parameter expectParam;
+            Parameter::Specific specific;
+            specific.set<Parameter::Specific::automaticGainControl>(AGC);
+            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;
+                AutomaticGainControl::Id specificId;
+                specificId.set<AutomaticGainControl::Id::commonTag>(tag);
+                id.set<Parameter::Id::automaticGainControlTag>(specificId);
+                EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+
+                EXPECT_EQ(expectParam, getParam) << "\nexpect:" << expectParam.toString()
+                                                 << "\ngetParam:" << getParam.toString();
+            }
+        }
+    }
+
+    void addDigitalGainParam(int gain) {
+        AutomaticGainControl AGC;
+        AGC.set<AutomaticGainControl::fixedDigitalGainMb>(gain);
+        mTags.push_back({AutomaticGainControl::fixedDigitalGainMb, AGC});
+    }
+    void addSaturationMarginParam(int margin) {
+        AutomaticGainControl AGC;
+        AGC.set<AutomaticGainControl::saturationMarginMb>(margin);
+        mTags.push_back({AutomaticGainControl::saturationMarginMb, AGC});
+    }
+    void addLevelEstimatorParam(AutomaticGainControl::LevelEstimator levelEstimator) {
+        AutomaticGainControl AGC;
+        AGC.set<AutomaticGainControl::levelEstimator>(levelEstimator);
+        mTags.push_back({AutomaticGainControl::levelEstimator, AGC});
+    }
+
+    bool isTagInRange(const AutomaticGainControl::Tag& tag, const AutomaticGainControl& AGC,
+                      const Descriptor& desc) const {
+        const AutomaticGainControl::Capability& AGCCap =
+                desc.capability.get<Capability::automaticGainControl>();
+        switch (tag) {
+            case AutomaticGainControl::fixedDigitalGainMb: {
+                auto gain = AGC.get<AutomaticGainControl::fixedDigitalGainMb>();
+                return gain >= 0 && gain <= AGCCap.maxFixedDigitalGainMb;
+            }
+            case AutomaticGainControl::levelEstimator: {
+                return true;
+            }
+            case AutomaticGainControl::saturationMarginMb: {
+                auto margin = AGC.get<AutomaticGainControl::saturationMarginMb>();
+                return margin >= 0 && margin <= AGCCap.maxSaturationMarginMb;
+            }
+            default:
+                return false;
+        }
+    }
+    static std::unordered_set<int> getDigitalGainValues() {
+        auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+                                                                     kAutomaticGainControlTypeUUID);
+        const auto max = std::max_element(
+                descList.begin(), descList.end(),
+                [](const std::pair<std::shared_ptr<IFactory>, Descriptor>& a,
+                   const std::pair<std::shared_ptr<IFactory>, Descriptor>& b) {
+                    return a.second.capability.get<Capability::automaticGainControl>()
+                                   .maxFixedDigitalGainMb <
+                           b.second.capability.get<Capability::automaticGainControl>()
+                                   .maxFixedDigitalGainMb;
+                });
+        if (max == descList.end()) {
+            return {0};
+        }
+        int maxGain = max->second.capability.get<Capability::automaticGainControl>()
+                              .maxFixedDigitalGainMb;
+        return {-1, 0, maxGain - 1, maxGain, maxGain + 1};
+    }
+    static std::unordered_set<int> getSaturationMarginValues() {
+        auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+                                                                     kAutomaticGainControlTypeUUID);
+        const auto max = std::max_element(
+                descList.begin(), descList.end(),
+                [](const std::pair<std::shared_ptr<IFactory>, Descriptor>& a,
+                   const std::pair<std::shared_ptr<IFactory>, Descriptor>& b) {
+                    return a.second.capability.get<Capability::automaticGainControl>()
+                                   .maxSaturationMarginMb <
+                           b.second.capability.get<Capability::automaticGainControl>()
+                                   .maxSaturationMarginMb;
+                });
+        if (max == descList.end()) {
+            return {0};
+        }
+        int maxMargin = max->second.capability.get<Capability::automaticGainControl>()
+                                .maxSaturationMarginMb;
+        return {-1, 0, maxMargin - 1, maxMargin, maxMargin + 1};
+    }
+    static std::unordered_set<AutomaticGainControl::LevelEstimator> getLevelEstimatorValues() {
+        return {ndk::enum_range<AutomaticGainControl::LevelEstimator>().begin(),
+                ndk::enum_range<AutomaticGainControl::LevelEstimator>().end()};
+    }
+
+  private:
+    std::vector<std::pair<AutomaticGainControl::Tag, AutomaticGainControl>> mTags;
+    void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(AGCParamTest, SetAndGetDigitalGainParam) {
+    EXPECT_NO_FATAL_FAILURE(addDigitalGainParam(mGain));
+    SetAndGetParameters();
+}
+
+TEST_P(AGCParamTest, SetAndGetSaturationMargin) {
+    EXPECT_NO_FATAL_FAILURE(addSaturationMarginParam(mMargin));
+    SetAndGetParameters();
+}
+
+TEST_P(AGCParamTest, SetAndGetLevelEstimator) {
+    EXPECT_NO_FATAL_FAILURE(addLevelEstimatorParam(mLevelEstimator));
+    SetAndGetParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        AGCParamTest, AGCParamTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kAutomaticGainControlTypeUUID)),
+                           testing::ValuesIn(AGCParamTest::getDigitalGainValues()),
+                           testing::ValuesIn(AGCParamTest::getSaturationMarginValues()),
+                           testing::ValuesIn(AGCParamTest::getLevelEstimatorValues())),
+        [](const testing::TestParamInfo<AGCParamTest::ParamType>& info) {
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string gain = std::to_string(std::get<PARAM_DIGITAL_GAIN>(info.param));
+            std::string estimator = aidl::android::hardware::audio::effect::toString(
+                    std::get<PARAM_LEVEL_ESTIMATOR>(info.param));
+            std::string margin =
+                    std::to_string(static_cast<int>(std::get<PARAM_SATURATION_MARGIN>(info.param)));
+
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_digital_gain_" + gain +
+                               "_level_estimator_" + estimator + "_margin_" + margin;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AGCParamTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
index 99771e6..8da475e 100644
--- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -37,6 +37,7 @@
 #include <aidl/android/hardware/audio/core/BnStreamCallback.h>
 #include <aidl/android/hardware/audio/core/IModule.h>
 #include <aidl/android/hardware/audio/core/ITelephony.h>
+#include <aidl/android/hardware/audio/core/sounddose/ISoundDose.h>
 #include <aidl/android/media/audio/common/AudioIoFlags.h>
 #include <aidl/android/media/audio/common/AudioOutputFlags.h>
 #include <android-base/chrono_utils.h>
@@ -55,7 +56,9 @@
 using aidl::android::hardware::audio::core::AudioMode;
 using aidl::android::hardware::audio::core::AudioPatch;
 using aidl::android::hardware::audio::core::AudioRoute;
+using aidl::android::hardware::audio::core::IBluetooth;
 using aidl::android::hardware::audio::core::IModule;
+using aidl::android::hardware::audio::core::IStreamCommon;
 using aidl::android::hardware::audio::core::IStreamIn;
 using aidl::android::hardware::audio::core::IStreamOut;
 using aidl::android::hardware::audio::core::ITelephony;
@@ -63,21 +66,29 @@
 using aidl::android::hardware::audio::core::MicrophoneInfo;
 using aidl::android::hardware::audio::core::ModuleDebug;
 using aidl::android::hardware::audio::core::StreamDescriptor;
+using aidl::android::hardware::audio::core::VendorParameter;
+using aidl::android::hardware::audio::core::sounddose::ISoundDose;
 using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
 using aidl::android::media::audio::common::AudioContentType;
 using aidl::android::media::audio::common::AudioDevice;
 using aidl::android::media::audio::common::AudioDeviceAddress;
 using aidl::android::media::audio::common::AudioDeviceType;
+using aidl::android::media::audio::common::AudioDualMonoMode;
 using aidl::android::media::audio::common::AudioFormatType;
 using aidl::android::media::audio::common::AudioIoFlags;
+using aidl::android::media::audio::common::AudioLatencyMode;
 using aidl::android::media::audio::common::AudioOutputFlags;
+using aidl::android::media::audio::common::AudioPlaybackRate;
 using aidl::android::media::audio::common::AudioPort;
 using aidl::android::media::audio::common::AudioPortConfig;
 using aidl::android::media::audio::common::AudioPortDeviceExt;
 using aidl::android::media::audio::common::AudioPortExt;
 using aidl::android::media::audio::common::AudioSource;
 using aidl::android::media::audio::common::AudioUsage;
+using aidl::android::media::audio::common::Float;
+using aidl::android::media::audio::common::Int;
 using aidl::android::media::audio::common::Void;
+using android::hardware::audio::common::getChannelCount;
 using android::hardware::audio::common::isBitPositionFlagSet;
 using android::hardware::audio::common::isTelephonyDeviceType;
 using android::hardware::audio::common::StreamLogic;
@@ -185,6 +196,29 @@
     AudioPortConfig mConfig;
 };
 
+template <typename T>
+void GenerateTestArrays(size_t validElementCount, T validMin, T validMax,
+                        std::vector<std::vector<T>>* validValues,
+                        std::vector<std::vector<T>>* invalidValues) {
+    validValues->emplace_back(validElementCount, validMin);
+    validValues->emplace_back(validElementCount, validMax);
+    validValues->emplace_back(validElementCount, (validMin + validMax) / 2.f);
+    if (validElementCount > 0) {
+        invalidValues->emplace_back(validElementCount - 1, validMin);
+    }
+    invalidValues->emplace_back(validElementCount + 1, validMin);
+    for (auto m : {-2, -1, 2}) {
+        const auto invalidMin = m * validMin;
+        if (invalidMin < validMin || invalidMin > validMax) {
+            invalidValues->emplace_back(validElementCount, invalidMin);
+        }
+        const auto invalidMax = m * validMax;
+        if (invalidMax < validMin || invalidMax > validMax) {
+            invalidValues->emplace_back(validElementCount, invalidMax);
+        }
+    }
+}
+
 template <typename PropType, class Instance, typename Getter, typename Setter>
 void TestAccessors(Instance* inst, Getter getter, Setter setter,
                    const std::vector<PropType>& validValues,
@@ -198,17 +232,68 @@
     ASSERT_TRUE(status.isOk()) << "Unexpected status from a getter: " << status;
     *isSupported = true;
     for (const auto v : validValues) {
-        EXPECT_IS_OK((inst->*setter)(v)) << "for valid value: " << v;
+        EXPECT_IS_OK((inst->*setter)(v)) << "for a valid value: " << ::testing::PrintToString(v);
         PropType currentValue{};
         EXPECT_IS_OK((inst->*getter)(&currentValue));
         EXPECT_EQ(v, currentValue);
     }
     for (const auto v : invalidValues) {
-        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, (inst->*setter)(v)) << "for invalid value: " << v;
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, (inst->*setter)(v))
+                << "for an invalid value: " << ::testing::PrintToString(v);
     }
     EXPECT_IS_OK((inst->*setter)(initialValue)) << "Failed to restore the initial value";
 }
 
+template <class Instance>
+void TestGetVendorParameters(Instance* inst, bool* isSupported) {
+    static const std::vector<std::vector<std::string>> kIdsLists = {{}, {"zero"}, {"one", "two"}};
+    static const auto kStatuses = {EX_ILLEGAL_ARGUMENT, EX_ILLEGAL_STATE, EX_UNSUPPORTED_OPERATION};
+    for (const auto& ids : kIdsLists) {
+        std::vector<VendorParameter> params;
+        if (ndk::ScopedAStatus status = inst->getVendorParameters(ids, &params); status.isOk()) {
+            EXPECT_EQ(ids.size(), params.size()) << "Size of the returned parameters list must "
+                                                 << "match the size of the provided ids list";
+            for (const auto& param : params) {
+                EXPECT_NE(ids.end(), std::find(ids.begin(), ids.end(), param.id))
+                        << "Returned parameter id \"" << param.id << "\" is unexpected";
+            }
+            for (const auto& id : ids) {
+                EXPECT_NE(params.end(),
+                          std::find_if(params.begin(), params.end(),
+                                       [&](const auto& param) { return param.id == id; }))
+                        << "Requested parameter with id \"" << id << "\" was not returned";
+            }
+        } else {
+            EXPECT_STATUS(kStatuses, status);
+            if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+                *isSupported = false;
+                return;
+            }
+        }
+    }
+    *isSupported = true;
+}
+
+template <class Instance>
+void TestSetVendorParameters(Instance* inst, bool* isSupported) {
+    static const auto kStatuses = {EX_NONE, EX_ILLEGAL_ARGUMENT, EX_ILLEGAL_STATE,
+                                   EX_UNSUPPORTED_OPERATION};
+    static const std::vector<std::vector<VendorParameter>> kParamsLists = {
+            {}, {VendorParameter{"zero"}}, {VendorParameter{"one"}, VendorParameter{"two"}}};
+    for (const auto& params : kParamsLists) {
+        ndk::ScopedAStatus status = inst->setVendorParameters(params, false);
+        if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+            *isSupported = false;
+            return;
+        }
+        EXPECT_STATUS(kStatuses, status)
+                << ::android::internal::ToString(params) << ", async: false";
+        EXPECT_STATUS(kStatuses, inst->setVendorParameters(params, true))
+                << ::android::internal::ToString(params) << ", async: true";
+    }
+    *isSupported = true;
+}
+
 // Can be used as a base for any test here, does not depend on the fixture GTest parameters.
 class AudioCoreModuleBase {
   public:
@@ -835,6 +920,13 @@
 template <typename Stream>
 class WithStream {
   public:
+    static ndk::ScopedAStatus callClose(std::shared_ptr<Stream> stream) {
+        std::shared_ptr<IStreamCommon> common;
+        ndk::ScopedAStatus status = stream->getStreamCommon(&common);
+        if (!status.isOk()) return status;
+        return common->close();
+    }
+
     WithStream() {}
     explicit WithStream(const AudioPortConfig& portConfig) : mPortConfig(portConfig) {}
     WithStream(const WithStream&) = delete;
@@ -842,7 +934,7 @@
     ~WithStream() {
         if (mStream != nullptr) {
             mContext.reset();
-            EXPECT_IS_OK(mStream->close()) << "port config id " << getPortId();
+            EXPECT_IS_OK(callClose(mStream)) << "port config id " << getPortId();
         }
     }
     void SetUpPortConfig(IModule* module) { ASSERT_NO_FATAL_FAILURE(mPortConfig.SetUp(module)); }
@@ -1626,6 +1718,149 @@
     EXPECT_IS_OK(module->updateScreenState(true));
 }
 
+TEST_P(AudioCoreModule, GenerateHwAvSyncId) {
+    const auto kStatuses = {EX_NONE, EX_ILLEGAL_STATE};
+    int32_t id1;
+    ndk::ScopedAStatus status = module->generateHwAvSyncId(&id1);
+    if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+        GTEST_SKIP() << "HW AV Sync is not supported";
+    }
+    EXPECT_STATUS(kStatuses, status);
+    if (status.isOk()) {
+        int32_t id2;
+        ASSERT_IS_OK(module->generateHwAvSyncId(&id2));
+        EXPECT_NE(id1, id2) << "HW AV Sync IDs must be unique";
+    }
+}
+
+TEST_P(AudioCoreModule, GetVendorParameters) {
+    bool isGetterSupported = false;
+    EXPECT_NO_FATAL_FAILURE(TestGetVendorParameters(module.get(), &isGetterSupported));
+    ndk::ScopedAStatus status = module->setVendorParameters({}, false);
+    EXPECT_EQ(isGetterSupported, status.getExceptionCode() != EX_UNSUPPORTED_OPERATION)
+            << "Support for getting and setting of vendor parameters must be consistent";
+    if (!isGetterSupported) {
+        GTEST_SKIP() << "Vendor parameters are not supported";
+    }
+}
+
+TEST_P(AudioCoreModule, SetVendorParameters) {
+    bool isSupported = false;
+    EXPECT_NO_FATAL_FAILURE(TestSetVendorParameters(module.get(), &isSupported));
+    if (!isSupported) {
+        GTEST_SKIP() << "Vendor parameters are not supported";
+    }
+}
+
+// See b/262930731. In the absence of offloaded effect implementations,
+// 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.
+TEST_P(AudioCoreModule, AddRemoveEffectInvalidArguments) {
+    ndk::ScopedAStatus addEffectStatus = module->addDeviceEffect(-1, nullptr);
+    ndk::ScopedAStatus removeEffectStatus = module->removeDeviceEffect(-1, nullptr);
+    if (addEffectStatus.getExceptionCode() != EX_UNSUPPORTED_OPERATION) {
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, addEffectStatus.getExceptionCode());
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, removeEffectStatus.getExceptionCode());
+    } else if (removeEffectStatus.getExceptionCode() != EX_UNSUPPORTED_OPERATION) {
+        GTEST_FAIL() << "addDeviceEffect and removeDeviceEffect must be either supported or "
+                     << "not supported together";
+    } else {
+        GTEST_SKIP() << "Offloaded effects not supported";
+    }
+    // Test rejection of a nullptr effect with a valid device port Id.
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    const auto configs = moduleConfig->getPortConfigsForAttachedDevicePorts();
+    for (const auto& config : configs) {
+        WithAudioPortConfig portConfig(config);
+        ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get()));
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->addDeviceEffect(portConfig.getId(), nullptr));
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->removeDeviceEffect(portConfig.getId(), nullptr));
+    }
+}
+
+class AudioCoreBluetooth : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam()));
+        ASSERT_IS_OK(module->getBluetooth(&bluetooth));
+    }
+
+    void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
+
+    std::shared_ptr<IBluetooth> bluetooth;
+};
+
+TEST_P(AudioCoreBluetooth, SameInstance) {
+    if (bluetooth == nullptr) {
+        GTEST_SKIP() << "Bluetooth is not supported";
+    }
+    std::shared_ptr<IBluetooth> bluetooth2;
+    EXPECT_IS_OK(module->getBluetooth(&bluetooth2));
+    ASSERT_NE(nullptr, bluetooth2.get());
+    EXPECT_EQ(bluetooth->asBinder(), bluetooth2->asBinder())
+            << "getBluetooth must return the same interface instance across invocations";
+}
+
+TEST_P(AudioCoreBluetooth, ScoConfig) {
+    static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
+    if (bluetooth == nullptr) {
+        GTEST_SKIP() << "Bluetooth is not supported";
+    }
+    ndk::ScopedAStatus status;
+    IBluetooth::ScoConfig scoConfig;
+    ASSERT_STATUS(kStatuses, status = bluetooth->setScoConfig({}, &scoConfig));
+    if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+        GTEST_SKIP() << "BT SCO is not supported";
+    }
+    EXPECT_TRUE(scoConfig.isEnabled.has_value());
+    EXPECT_TRUE(scoConfig.isNrecEnabled.has_value());
+    EXPECT_NE(IBluetooth::ScoConfig::Mode::UNSPECIFIED, scoConfig.mode);
+    IBluetooth::ScoConfig scoConfig2;
+    ASSERT_IS_OK(bluetooth->setScoConfig(scoConfig, &scoConfig2));
+    EXPECT_EQ(scoConfig, scoConfig2);
+}
+
+TEST_P(AudioCoreBluetooth, HfpConfig) {
+    static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
+    if (bluetooth == nullptr) {
+        GTEST_SKIP() << "Bluetooth is not supported";
+    }
+    ndk::ScopedAStatus status;
+    IBluetooth::HfpConfig hfpConfig;
+    ASSERT_STATUS(kStatuses, status = bluetooth->setHfpConfig({}, &hfpConfig));
+    if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+        GTEST_SKIP() << "BT HFP is not supported";
+    }
+    EXPECT_TRUE(hfpConfig.isEnabled.has_value());
+    EXPECT_TRUE(hfpConfig.sampleRate.has_value());
+    EXPECT_TRUE(hfpConfig.volume.has_value());
+    IBluetooth::HfpConfig hfpConfig2;
+    ASSERT_IS_OK(bluetooth->setHfpConfig(hfpConfig, &hfpConfig2));
+    EXPECT_EQ(hfpConfig, hfpConfig2);
+}
+
+TEST_P(AudioCoreBluetooth, HfpConfigInvalid) {
+    static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
+    if (bluetooth == nullptr) {
+        GTEST_SKIP() << "Bluetooth is not supported";
+    }
+    ndk::ScopedAStatus status;
+    IBluetooth::HfpConfig hfpConfig;
+    ASSERT_STATUS(kStatuses, status = bluetooth->setHfpConfig({}, &hfpConfig));
+    if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+        GTEST_SKIP() << "BT HFP is not supported";
+    }
+    EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+                  bluetooth->setHfpConfig({.sampleRate = Int{-1}}, &hfpConfig));
+    EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, bluetooth->setHfpConfig({.sampleRate = Int{0}}, &hfpConfig));
+    EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+                  bluetooth->setHfpConfig({.volume = Float{IBluetooth::HfpConfig::VOLUME_MIN - 1}},
+                                          &hfpConfig));
+    EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+                  bluetooth->setHfpConfig({.volume = Float{IBluetooth::HfpConfig::VOLUME_MAX + 1}},
+                                          &hfpConfig));
+}
+
 class AudioCoreTelephony : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
   public:
     void SetUp() override {
@@ -1638,6 +1873,17 @@
     std::shared_ptr<ITelephony> telephony;
 };
 
+TEST_P(AudioCoreTelephony, SameInstance) {
+    if (telephony == nullptr) {
+        GTEST_SKIP() << "Telephony is not supported";
+    }
+    std::shared_ptr<ITelephony> telephony2;
+    EXPECT_IS_OK(module->getTelephony(&telephony2));
+    ASSERT_NE(nullptr, telephony2.get());
+    EXPECT_EQ(telephony->asBinder(), telephony2->asBinder())
+            << "getTelephony must return the same interface instance across invocations";
+}
+
 TEST_P(AudioCoreTelephony, GetSupportedAudioModes) {
     if (telephony == nullptr) {
         GTEST_SKIP() << "Telephony is not supported";
@@ -1679,6 +1925,46 @@
     }
 }
 
+TEST_P(AudioCoreTelephony, TelecomConfig) {
+    static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
+    if (telephony == nullptr) {
+        GTEST_SKIP() << "Telephony is not supported";
+    }
+    ndk::ScopedAStatus status;
+    ITelephony::TelecomConfig telecomConfig;
+    ASSERT_STATUS(kStatuses, status = telephony->setTelecomConfig({}, &telecomConfig));
+    if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+        GTEST_SKIP() << "Telecom is not supported";
+    }
+    EXPECT_TRUE(telecomConfig.voiceVolume.has_value());
+    EXPECT_NE(ITelephony::TelecomConfig::TtyMode::UNSPECIFIED, telecomConfig.ttyMode);
+    EXPECT_TRUE(telecomConfig.isHacEnabled.has_value());
+    ITelephony::TelecomConfig telecomConfig2;
+    ASSERT_IS_OK(telephony->setTelecomConfig(telecomConfig, &telecomConfig2));
+    EXPECT_EQ(telecomConfig, telecomConfig2);
+}
+
+TEST_P(AudioCoreTelephony, TelecomConfigInvalid) {
+    static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
+    if (telephony == nullptr) {
+        GTEST_SKIP() << "Telephony is not supported";
+    }
+    ndk::ScopedAStatus status;
+    ITelephony::TelecomConfig telecomConfig;
+    ASSERT_STATUS(kStatuses, status = telephony->setTelecomConfig({}, &telecomConfig));
+    if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+        GTEST_SKIP() << "Telecom is not supported";
+    }
+    EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+                  telephony->setTelecomConfig(
+                          {.voiceVolume = Float{ITelephony::TelecomConfig::VOICE_VOLUME_MIN - 1}},
+                          &telecomConfig));
+    EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+                  telephony->setTelecomConfig(
+                          {.voiceVolume = Float{ITelephony::TelecomConfig::VOICE_VOLUME_MAX + 1}},
+                          &telecomConfig));
+}
+
 using CommandSequence = std::vector<StreamDescriptor::Command>;
 class StreamLogicDriverInvalidCommand : public StreamLogicDriver {
   public:
@@ -1731,6 +2017,23 @@
         ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
     }
 
+    void GetStreamCommon() {
+        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+        if (!portConfig.has_value()) {
+            GTEST_SKIP() << "No mix port for attached devices";
+        }
+        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));
+        std::shared_ptr<IStreamCommon> streamCommon2;
+        EXPECT_IS_OK(stream.get()->getStreamCommon(&streamCommon2));
+        ASSERT_NE(nullptr, streamCommon1);
+        ASSERT_NE(nullptr, streamCommon2);
+        EXPECT_EQ(streamCommon1->asBinder(), streamCommon2->asBinder())
+                << "getStreamCommon must return the same interface instance across invocations";
+    }
+
     void CloseTwice() {
         const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
         if (!portConfig.has_value()) {
@@ -1742,7 +2045,8 @@
             ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
             heldStream = stream.getSharedPointer();
         }
-        EXPECT_STATUS(EX_ILLEGAL_STATE, heldStream->close()) << "when closing the stream twice";
+        EXPECT_STATUS(EX_ILLEGAL_STATE, WithStream<Stream>::callClose(heldStream))
+                << "when closing the stream twice";
     }
 
     void OpenAllConfigs() {
@@ -1761,9 +2065,7 @@
         }
         WithStream<Stream> stream(portConfig.value());
         ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
-        // The buffer size of 1 frame should be impractically small, and thus
-        // less than any minimum buffer size suggested by any HAL.
-        for (long bufferSize : std::array<long, 4>{-1, 0, 1, std::numeric_limits<long>::max()}) {
+        for (long bufferSize : std::array<long, 3>{-1, 0, std::numeric_limits<long>::max()}) {
             EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, stream.SetUpNoChecks(module.get(), bufferSize))
                     << "for the buffer size " << bufferSize;
             EXPECT_EQ(nullptr, stream.get());
@@ -1847,6 +2149,136 @@
         EXPECT_NO_FATAL_FAILURE(SendInvalidCommandImpl(portConfig.value()));
     }
 
+    void UpdateHwAvSyncId() {
+        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+        if (!portConfig.has_value()) {
+            GTEST_SKIP() << "No mix port for attached devices";
+        }
+        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_NE(nullptr, streamCommon);
+        const auto kStatuses = {EX_NONE, EX_ILLEGAL_ARGUMENT, EX_ILLEGAL_STATE};
+        for (const auto id : {-100, -1, 0, 1, 100}) {
+            ndk::ScopedAStatus status = streamCommon->updateHwAvSyncId(id);
+            if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+                GTEST_SKIP() << "HW AV Sync is not supported";
+            }
+            EXPECT_STATUS(kStatuses, status) << "id: " << id;
+        }
+    }
+
+    void GetVendorParameters() {
+        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+        if (!portConfig.has_value()) {
+            GTEST_SKIP() << "No mix port for attached devices";
+        }
+        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_NE(nullptr, streamCommon);
+
+        bool isGetterSupported = false;
+        EXPECT_NO_FATAL_FAILURE(TestGetVendorParameters(module.get(), &isGetterSupported));
+        ndk::ScopedAStatus status = module->setVendorParameters({}, false);
+        EXPECT_EQ(isGetterSupported, status.getExceptionCode() != EX_UNSUPPORTED_OPERATION)
+                << "Support for getting and setting of vendor parameters must be consistent";
+        if (!isGetterSupported) {
+            GTEST_SKIP() << "Vendor parameters are not supported";
+        }
+    }
+
+    void SetVendorParameters() {
+        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+        if (!portConfig.has_value()) {
+            GTEST_SKIP() << "No mix port for attached devices";
+        }
+        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_NE(nullptr, streamCommon);
+
+        bool isSupported = false;
+        EXPECT_NO_FATAL_FAILURE(TestSetVendorParameters(module.get(), &isSupported));
+        if (!isSupported) {
+            GTEST_SKIP() << "Vendor parameters are not supported";
+        }
+    }
+
+    void HwGainHwVolume() {
+        const auto ports =
+                moduleConfig->getMixPorts(IOTraits<Stream>::is_input, false /*attachedOnly*/);
+        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));
+            std::vector<std::vector<float>> validValues, invalidValues;
+            bool isSupported = false;
+            if constexpr (IOTraits<Stream>::is_input) {
+                GenerateTestArrays<float>(getChannelCount(portConfig.value().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));
+            } else {
+                GenerateTestArrays<float>(getChannelCount(portConfig.value().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,
+                        validValues, invalidValues, &isSupported));
+            }
+            if (isSupported) atLeastOneSupports = true;
+        }
+        if (!atLeastOneSupports) {
+            GTEST_SKIP() << "Hardware gain / volume is not supported";
+        }
+    }
+
+    // See b/262930731. In the absence of offloaded effect implementations,
+    // 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, false /*attachedOnly*/);
+        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));
+            std::shared_ptr<IStreamCommon> streamCommon;
+            ASSERT_IS_OK(stream.get()->getStreamCommon(&streamCommon));
+            ASSERT_NE(nullptr, streamCommon);
+            ndk::ScopedAStatus addEffectStatus = streamCommon->addEffect(nullptr);
+            ndk::ScopedAStatus removeEffectStatus = streamCommon->removeEffect(nullptr);
+            if (addEffectStatus.getExceptionCode() != EX_UNSUPPORTED_OPERATION) {
+                EXPECT_EQ(EX_ILLEGAL_ARGUMENT, addEffectStatus.getExceptionCode());
+                EXPECT_EQ(EX_ILLEGAL_ARGUMENT, removeEffectStatus.getExceptionCode());
+                atLeastOneSupports = true;
+            } else if (removeEffectStatus.getExceptionCode() != EX_UNSUPPORTED_OPERATION) {
+                ADD_FAILURE() << "addEffect and removeEffect must be either supported or "
+                              << "not supported together";
+                atLeastOneSupports = true;
+            }
+        }
+        if (!atLeastOneSupports) {
+            GTEST_SKIP() << "Offloaded effects not supported";
+        }
+    }
+
     void OpenTwiceSamePortConfigImpl(const AudioPortConfig& portConfig) {
         WithStream<Stream> stream1(portConfig);
         ASSERT_NO_FATAL_FAILURE(stream1.SetUp(module.get(), kDefaultBufferSizeFrames));
@@ -1912,6 +2344,7 @@
     }
 
 TEST_IN_AND_OUT_STREAM(CloseTwice);
+TEST_IN_AND_OUT_STREAM(GetStreamCommon);
 TEST_IN_AND_OUT_STREAM(OpenAllConfigs);
 TEST_IN_AND_OUT_STREAM(OpenInvalidBufferSize);
 TEST_IN_AND_OUT_STREAM(OpenInvalidDirection);
@@ -1919,6 +2352,11 @@
 TEST_IN_AND_OUT_STREAM(OpenTwiceSamePortConfig);
 TEST_IN_AND_OUT_STREAM(ResetPortConfigWithOpenStream);
 TEST_IN_AND_OUT_STREAM(SendInvalidCommand);
+TEST_IN_AND_OUT_STREAM(UpdateHwAvSyncId);
+TEST_IN_AND_OUT_STREAM(GetVendorParameters);
+TEST_IN_AND_OUT_STREAM(SetVendorParameters);
+TEST_IN_AND_OUT_STREAM(HwGainHwVolume);
+TEST_IN_AND_OUT_STREAM(AddRemoveEffectInvalidArguments);
 
 namespace aidl::android::hardware::audio::core {
 std::ostream& operator<<(std::ostream& os, const IStreamIn::MicrophoneDirection& md) {
@@ -2091,6 +2529,191 @@
             << "when no async callback is provided for a non-blocking mix port";
 }
 
+TEST_P(AudioStreamOut, AudioDescriptionMixLevel) {
+    const auto ports = moduleConfig->getOutputMixPorts(false /*attachedOnly*/);
+    if (ports.empty()) {
+        GTEST_SKIP() << "No output mix ports";
+    }
+    bool atLeastOneSupports = 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));
+        bool isSupported = false;
+        EXPECT_NO_FATAL_FAILURE(
+                TestAccessors<float>(stream.get(), &IStreamOut::getAudioDescriptionMixLevel,
+                                     &IStreamOut::setAudioDescriptionMixLevel,
+                                     {IStreamOut::AUDIO_DESCRIPTION_MIX_LEVEL_MAX,
+                                      IStreamOut::AUDIO_DESCRIPTION_MIX_LEVEL_MAX - 1, 0,
+                                      -INFINITY /*IStreamOut::AUDIO_DESCRIPTION_MIX_LEVEL_MIN*/},
+                                     {IStreamOut::AUDIO_DESCRIPTION_MIX_LEVEL_MAX * 2,
+                                      IStreamOut::AUDIO_DESCRIPTION_MIX_LEVEL_MAX * 1.1f},
+                                     &isSupported));
+        if (isSupported) atLeastOneSupports = true;
+    }
+    if (!atLeastOneSupports) {
+        GTEST_SKIP() << "Audio description mix level is not supported";
+    }
+}
+
+TEST_P(AudioStreamOut, DualMonoMode) {
+    const auto ports = moduleConfig->getOutputMixPorts(false /*attachedOnly*/);
+    if (ports.empty()) {
+        GTEST_SKIP() << "No output mix ports";
+    }
+    bool atLeastOneSupports = 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));
+        bool isSupported = false;
+        EXPECT_NO_FATAL_FAILURE(TestAccessors<AudioDualMonoMode>(
+                stream.get(), &IStreamOut::getDualMonoMode, &IStreamOut::setDualMonoMode,
+                std::vector<AudioDualMonoMode>(enum_range<AudioDualMonoMode>().begin(),
+                                               enum_range<AudioDualMonoMode>().end()),
+                {}, &isSupported));
+        if (isSupported) atLeastOneSupports = true;
+    }
+    if (!atLeastOneSupports) {
+        GTEST_SKIP() << "Audio dual mono mode is not supported";
+    }
+}
+
+TEST_P(AudioStreamOut, LatencyMode) {
+    const auto ports = moduleConfig->getOutputMixPorts(false /*attachedOnly*/);
+    if (ports.empty()) {
+        GTEST_SKIP() << "No output mix ports";
+    }
+    bool atLeastOneSupports = 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));
+        std::vector<AudioLatencyMode> supportedModes;
+        ndk::ScopedAStatus status = stream.get()->getRecommendedLatencyModes(&supportedModes);
+        if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) continue;
+        atLeastOneSupports = true;
+        if (!status.isOk()) {
+            ADD_FAILURE() << "When latency modes are supported, getRecommendedLatencyModes "
+                          << "must succeed on a non-closed stream, but it failed with " << status;
+            continue;
+        }
+        std::set<AudioLatencyMode> unsupportedModes(enum_range<AudioLatencyMode>().begin(),
+                                                    enum_range<AudioLatencyMode>().end());
+        for (const auto mode : supportedModes) {
+            unsupportedModes.erase(mode);
+            ndk::ScopedAStatus status = stream.get()->setLatencyMode(mode);
+            if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+                ADD_FAILURE() << "When latency modes are supported, both getRecommendedLatencyModes"
+                              << " and setLatencyMode must be supported";
+            }
+            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));
+        }
+    }
+    if (!atLeastOneSupports) {
+        GTEST_SKIP() << "Audio latency modes are not supported";
+    }
+}
+
+TEST_P(AudioStreamOut, PlaybackRate) {
+    static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
+    const auto offloadMixPorts =
+            moduleConfig->getOffloadMixPorts(true /*attachedOnly*/, false /*singlePort*/);
+    if (offloadMixPorts.empty()) {
+        GTEST_SKIP()
+                << "No mix port for compressed offload that could be routed to attached devices";
+    }
+    ndk::ScopedAStatus status;
+    IModule::SupportedPlaybackRateFactors factors;
+    EXPECT_STATUS(kStatuses, status = module.get()->getSupportedPlaybackRateFactors(&factors));
+    if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+        GTEST_SKIP() << "Audio playback rate configuration is not supported";
+    }
+    EXPECT_LE(factors.minSpeed, factors.maxSpeed);
+    EXPECT_LE(factors.minPitch, factors.maxPitch);
+    EXPECT_LE(factors.minSpeed, 1.0f);
+    EXPECT_GE(factors.maxSpeed, 1.0f);
+    EXPECT_LE(factors.minPitch, 1.0f);
+    EXPECT_GE(factors.maxPitch, 1.0f);
+    constexpr auto tsDefault = AudioPlaybackRate::TimestretchMode::DEFAULT;
+    constexpr auto tsVoice = AudioPlaybackRate::TimestretchMode::VOICE;
+    constexpr auto fbFail = AudioPlaybackRate::TimestretchFallbackMode::FAIL;
+    constexpr auto fbMute = AudioPlaybackRate::TimestretchFallbackMode::MUTE;
+    const std::vector<AudioPlaybackRate> validValues = {
+            AudioPlaybackRate{1.0f, 1.0f, tsDefault, fbFail},
+            AudioPlaybackRate{1.0f, 1.0f, tsDefault, fbMute},
+            AudioPlaybackRate{factors.maxSpeed, factors.maxPitch, tsDefault, fbMute},
+            AudioPlaybackRate{factors.minSpeed, factors.minPitch, tsDefault, fbMute},
+            AudioPlaybackRate{1.0f, 1.0f, tsVoice, fbMute},
+            AudioPlaybackRate{1.0f, 1.0f, tsVoice, fbFail},
+            AudioPlaybackRate{factors.maxSpeed, factors.maxPitch, tsVoice, fbMute},
+            AudioPlaybackRate{factors.minSpeed, factors.minPitch, tsVoice, fbMute},
+            // Out of range speed / pitch values must not be rejected if the fallback mode is "mute"
+            AudioPlaybackRate{factors.maxSpeed * 2, factors.maxPitch * 2, tsDefault, fbMute},
+            AudioPlaybackRate{factors.minSpeed / 2, factors.minPitch / 2, tsDefault, fbMute},
+            AudioPlaybackRate{factors.maxSpeed * 2, factors.maxPitch * 2, tsVoice, fbMute},
+            AudioPlaybackRate{factors.minSpeed / 2, factors.minPitch / 2, tsVoice, fbMute},
+    };
+    const std::vector<AudioPlaybackRate> invalidValues = {
+            AudioPlaybackRate{factors.maxSpeed, factors.maxPitch * 2, tsDefault, fbFail},
+            AudioPlaybackRate{factors.maxSpeed * 2, factors.maxPitch, tsDefault, fbFail},
+            AudioPlaybackRate{factors.minSpeed, factors.minPitch / 2, tsDefault, fbFail},
+            AudioPlaybackRate{factors.minSpeed / 2, factors.minPitch, tsDefault, fbFail},
+            AudioPlaybackRate{factors.maxSpeed, factors.maxPitch * 2, tsVoice, fbFail},
+            AudioPlaybackRate{factors.maxSpeed * 2, factors.maxPitch, tsVoice, fbFail},
+            AudioPlaybackRate{factors.minSpeed, factors.minPitch / 2, tsVoice, fbFail},
+            AudioPlaybackRate{factors.minSpeed / 2, factors.minPitch, tsVoice, fbFail},
+            AudioPlaybackRate{1.0f, 1.0f, tsDefault,
+                              AudioPlaybackRate::TimestretchFallbackMode::SYS_RESERVED_CUT_REPEAT},
+            AudioPlaybackRate{1.0f, 1.0f, tsDefault,
+                              AudioPlaybackRate::TimestretchFallbackMode::SYS_RESERVED_DEFAULT},
+    };
+    bool atLeastOneSupports = false;
+    for (const auto& port : offloadMixPorts) {
+        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));
+        bool isSupported = false;
+        EXPECT_NO_FATAL_FAILURE(TestAccessors<AudioPlaybackRate>(
+                stream.get(), &IStreamOut::getPlaybackRateParameters,
+                &IStreamOut::setPlaybackRateParameters, validValues, invalidValues, &isSupported));
+        if (isSupported) atLeastOneSupports = true;
+    }
+    if (!atLeastOneSupports) {
+        GTEST_SKIP() << "Audio playback rate configuration is not supported";
+    }
+}
+
+TEST_P(AudioStreamOut, SelectPresentation) {
+    static const auto kStatuses = {EX_ILLEGAL_ARGUMENT, EX_UNSUPPORTED_OPERATION};
+    const auto offloadMixPorts =
+            moduleConfig->getOffloadMixPorts(true /*attachedOnly*/, false /*singlePort*/);
+    if (offloadMixPorts.empty()) {
+        GTEST_SKIP()
+                << "No mix port for compressed offload that could be routed to attached devices";
+    }
+    bool atLeastOneSupports = false;
+    for (const auto& port : offloadMixPorts) {
+        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));
+        ndk::ScopedAStatus status;
+        EXPECT_STATUS(kStatuses, status = stream.get()->selectPresentation(0, 0));
+        if (status.getExceptionCode() != EX_UNSUPPORTED_OPERATION) atLeastOneSupports = true;
+    }
+    if (!atLeastOneSupports) {
+        GTEST_SKIP() << "Presentation selection is not supported";
+    }
+}
+
 class StreamLogicDefaultDriver : public StreamLogicDriver {
   public:
     explicit StreamLogicDefaultDriver(std::shared_ptr<StateSequence> commands)
@@ -2468,10 +3091,111 @@
     }
 }
 
+class AudioCoreSoundDose : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
+  public:
+    class NoOpHalSoundDoseCallback : public ISoundDose::BnHalSoundDoseCallback {
+      public:
+        ndk::ScopedAStatus onMomentaryExposureWarning(float in_currentDbA,
+                                                      const AudioDevice& in_audioDevice) override;
+        ndk::ScopedAStatus onNewMelValues(
+                const ISoundDose::IHalSoundDoseCallback::MelRecord& in_melRecord,
+                const AudioDevice& in_audioDevice) override;
+    };
+
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam()));
+        ASSERT_IS_OK(module->getSoundDose(&soundDose));
+        callback = ndk::SharedRefBase::make<NoOpHalSoundDoseCallback>();
+    }
+
+    void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
+
+    std::shared_ptr<ISoundDose> soundDose;
+    std::shared_ptr<ISoundDose::IHalSoundDoseCallback> callback;
+};
+
+ndk::ScopedAStatus AudioCoreSoundDose::NoOpHalSoundDoseCallback::onMomentaryExposureWarning(
+        float in_currentDbA, const AudioDevice& in_audioDevice) {
+    // Do nothing
+    (void)in_currentDbA;
+    (void)in_audioDevice;
+    LOG(INFO) << "NoOpHalSoundDoseCallback::onMomentaryExposureWarning called";
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AudioCoreSoundDose::NoOpHalSoundDoseCallback::onNewMelValues(
+        const ISoundDose::IHalSoundDoseCallback::MelRecord& in_melRecord,
+        const AudioDevice& in_audioDevice) {
+    // Do nothing
+    (void)in_melRecord;
+    (void)in_audioDevice;
+    LOG(INFO) << "NoOpHalSoundDoseCallback::onNewMelValues called";
+
+    return ndk::ScopedAStatus::ok();
+}
+
+TEST_P(AudioCoreSoundDose, SameInstance) {
+    if (soundDose == nullptr) {
+        GTEST_SKIP() << "SoundDose is not supported";
+    }
+    std::shared_ptr<ISoundDose> soundDose2;
+    EXPECT_IS_OK(module->getSoundDose(&soundDose2));
+    ASSERT_NE(nullptr, soundDose2.get());
+    EXPECT_EQ(soundDose->asBinder(), soundDose2->asBinder())
+            << "getSoundDose must return the same interface instance across invocations";
+}
+
+TEST_P(AudioCoreSoundDose, GetSetOutputRs2) {
+    if (soundDose == nullptr) {
+        GTEST_SKIP() << "SoundDose is not supported";
+    }
+
+    bool isSupported = false;
+    EXPECT_NO_FATAL_FAILURE(TestAccessors<float>(soundDose.get(), &ISoundDose::getOutputRs2,
+                                                 &ISoundDose::setOutputRs2,
+                                                 /*validValues=*/{80.f, 90.f, 100.f},
+                                                 /*invalidValues=*/{79.f, 101.f}, &isSupported));
+    EXPECT_TRUE(isSupported) << "Getting/Setting RS2 must be supported";
+}
+
+TEST_P(AudioCoreSoundDose, CheckDefaultRs2Value) {
+    if (soundDose == nullptr) {
+        GTEST_SKIP() << "SoundDose is not supported";
+    }
+
+    float rs2Value;
+    ASSERT_IS_OK(soundDose->getOutputRs2(&rs2Value));
+    EXPECT_EQ(rs2Value, ISoundDose::DEFAULT_MAX_RS2);
+}
+
+TEST_P(AudioCoreSoundDose, RegisterSoundDoseCallbackTwiceThrowsException) {
+    if (soundDose == nullptr) {
+        GTEST_SKIP() << "SoundDose is not supported";
+    }
+
+    ASSERT_IS_OK(soundDose->registerSoundDoseCallback(callback));
+    EXPECT_STATUS(EX_ILLEGAL_STATE, soundDose->registerSoundDoseCallback(callback))
+            << "Registering sound dose callback twice should throw EX_ILLEGAL_STATE";
+}
+
+TEST_P(AudioCoreSoundDose, RegisterSoundDoseNullCallbackThrowsException) {
+    if (soundDose == nullptr) {
+        GTEST_SKIP() << "SoundDose is not supported";
+    }
+
+    EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, soundDose->registerSoundDoseCallback(nullptr))
+            << "Registering nullptr sound dose callback should throw EX_ILLEGAL_ARGUMENT";
+}
+
 INSTANTIATE_TEST_SUITE_P(AudioCoreModuleTest, AudioCoreModule,
                          testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
                          android::PrintInstanceNameToString);
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreModule);
+INSTANTIATE_TEST_SUITE_P(AudioCoreBluetoothTest, AudioCoreBluetooth,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+                         android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreBluetooth);
 INSTANTIATE_TEST_SUITE_P(AudioCoreTelephonyTest, AudioCoreTelephony,
                          testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
                          android::PrintInstanceNameToString);
@@ -2484,6 +3208,10 @@
                          testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
                          android::PrintInstanceNameToString);
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamOut);
+INSTANTIATE_TEST_SUITE_P(AudioCoreSoundDoseTest, AudioCoreSoundDose,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+                         android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreSoundDose);
 
 // This is the value used in test sequences for which the test needs to ensure
 // that the HAL stays in a transient state long enough to receive the next command.
diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
index 4f14bf0..8938618 100644
--- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -49,18 +49,30 @@
 using aidl::android::hardware::audio::effect::State;
 
 enum ParamName { PARAM_INSTANCE_NAME };
-using EffectTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>>;
+using EffectTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>>;
 
 class AudioEffectTest : public testing::TestWithParam<EffectTestParam>, public EffectHelper {
   public:
-    AudioEffectTest() { std::tie(mFactory, mIdentity) = std::get<PARAM_INSTANCE_NAME>(GetParam()); }
+    AudioEffectTest() {
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    }
 
     void SetUp() override {}
-    void TearDown() override {}
+
+    void TearDown() override {
+        // Do the cleanup for every test case
+        if (mEffect) {
+            ASSERT_NO_FATAL_FAILURE(commandIgnoreRet(mEffect, CommandId::STOP));
+            ASSERT_NO_FATAL_FAILURE(closeIgnoreRet(mEffect));
+            ASSERT_NO_FATAL_FAILURE(destroyIgnoreRet(mFactory, mEffect));
+            mEffect.reset();
+        }
+    }
 
     static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
     std::shared_ptr<IFactory> mFactory;
-    Descriptor::Identity mIdentity;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
 };
 
 TEST_P(AudioEffectTest, SetupAndTearDown) {
@@ -68,30 +80,27 @@
 }
 
 TEST_P(AudioEffectTest, CreateAndDestroy) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 TEST_P(AudioEffectTest, OpenAndClose) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 TEST_P(AudioEffectTest, CloseUnopenedEffect) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 TEST_P(AudioEffectTest, DoubleOpenAndClose) {
     std::shared_ptr<IEffect> effect1, effect2;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mDescriptor));
     ASSERT_NO_FATAL_FAILURE(open(effect1));
     ASSERT_NO_FATAL_FAILURE(open(effect2, 1 /* session */));
     ASSERT_NO_FATAL_FAILURE(close(effect1));
@@ -102,9 +111,9 @@
 
 TEST_P(AudioEffectTest, TripleOpenAndClose) {
     std::shared_ptr<IEffect> effect1, effect2, effect3;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect3, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect3, mDescriptor));
     ASSERT_NO_FATAL_FAILURE(open(effect1));
     ASSERT_NO_FATAL_FAILURE(open(effect2, 1 /* session */));
     ASSERT_NO_FATAL_FAILURE(open(effect3, 2 /* session */));
@@ -117,513 +126,505 @@
 }
 
 TEST_P(AudioEffectTest, GetDescritorBeforeOpen) {
-    std::shared_ptr<IEffect> effect;
     Descriptor desc;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, desc));
-    EXPECT_EQ(mIdentity.toString(), desc.common.id.toString());
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(getDescriptor(mEffect, desc));
+    EXPECT_EQ(mDescriptor.common, desc.common);
+    // Effect implementation Must fill in implementor and name
     EXPECT_NE("", desc.common.name);
     EXPECT_NE("", desc.common.implementor);
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 TEST_P(AudioEffectTest, GetDescritorAfterOpen) {
-    std::shared_ptr<IEffect> effect;
     Descriptor beforeOpen, afterOpen, afterClose;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, beforeOpen));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, afterOpen));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(getDescriptor(mEffect, beforeOpen));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(getDescriptor(mEffect, afterOpen));
     EXPECT_EQ(beforeOpen.toString(), afterOpen.toString()) << "\n"
                                                            << beforeOpen.toString() << "\n"
                                                            << afterOpen.toString();
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, afterClose));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(getDescriptor(mEffect, afterClose));
     EXPECT_EQ(beforeOpen.toString(), afterClose.toString()) << "\n"
                                                             << beforeOpen.toString() << "\n"
                                                             << afterClose.toString();
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 TEST_P(AudioEffectTest, DescriptorExistAndUnique) {
-    std::shared_ptr<IEffect> effect;
     Descriptor desc;
 
     auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor);
     std::set<Descriptor::Identity> idSet;
     for (const auto& it : descList) {
-        auto& id = it.second;
+        auto& id = it.second.common.id;
         EXPECT_EQ(0ul, idSet.count(id));
         idSet.insert(id);
     }
 
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, desc));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(getDescriptor(mEffect, desc));
     EXPECT_EQ(1ul, idSet.count(desc.common.id));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 /// State testing.
 // An effect instance is in INIT state by default after it was created.
 TEST_P(AudioEffectTest, InitStateAfterCreation) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::INIT));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // An effect instance transfer to IDLE state after IEffect.ASSERT_NO_FATAL_FAILURE(open().
 TEST_P(AudioEffectTest, IdleStateAfterOpen) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // An effect instance is in PROCESSING state after it receive an START command.
 TEST_P(AudioEffectTest, ProcessingStateAfterStart) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::INIT));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // An effect instance transfer to IDLE state after Command.Id.STOP in PROCESSING state.
 TEST_P(AudioEffectTest, IdleStateAfterStop) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // An effect instance transfer to IDLE state after Command.Id.RESET in PROCESSING state.
 TEST_P(AudioEffectTest, IdleStateAfterReset) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // An effect instance transfer to INIT after IEffect.ASSERT_NO_FATAL_FAILURE(close().
 TEST_P(AudioEffectTest, InitStateAfterClose) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::INIT));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // An effect instance shouldn't accept any command before open.
 TEST_P(AudioEffectTest, NoCommandAcceptedBeforeOpen) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START, EX_ILLEGAL_STATE));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP, EX_ILLEGAL_STATE));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET, EX_ILLEGAL_STATE));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START, EX_ILLEGAL_STATE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP, EX_ILLEGAL_STATE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET, EX_ILLEGAL_STATE));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // No-op when receive STOP command in IDLE state.
 TEST_P(AudioEffectTest, StopCommandInIdleStateNoOp) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // No-op when receive RESET command in IDLE state.
 TEST_P(AudioEffectTest, ResetCommandInIdleStateNoOp) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Repeat START and STOP command.
 TEST_P(AudioEffectTest, RepeatStartAndStop) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Repeat START and RESET command.
 TEST_P(AudioEffectTest, RepeatStartAndReset) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Try to close an effect instance at PROCESSING state.
 TEST_P(AudioEffectTest, CloseProcessingStateEffects) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
-    ASSERT_NO_FATAL_FAILURE(close(effect, EX_ILLEGAL_STATE));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect, EX_ILLEGAL_STATE));
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Expect EX_ILLEGAL_STATE if the effect instance is not in a proper state to be destroyed.
 TEST_P(AudioEffectTest, DestroyOpenEffects) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect, EX_ILLEGAL_STATE));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect, EX_ILLEGAL_STATE));
+
+    // cleanup
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Expect EX_ILLEGAL_STATE if the effect instance is not in a proper state to be destroyed.
 TEST_P(AudioEffectTest, DestroyProcessingEffects) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect, EX_ILLEGAL_STATE));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect, EX_ILLEGAL_STATE));
+
+    // cleanup
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 TEST_P(AudioEffectTest, NormalSequenceStates) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::INIT));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 /// Parameter testing.
 // Verify parameters pass in open can be successfully get.
 TEST_P(AudioEffectTest, VerifyCommonParametersAfterOpen) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
     Parameter::Common common = EffectHelper::createParamCommon();
     IEffect::OpenEffectReturn ret;
-    ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
 
     Parameter get = Parameter(), expect = Parameter();
     expect.set<Parameter::common>(common);
     Parameter::Id id;
     id.set<Parameter::Id::commonTag>(Parameter::common);
-    EXPECT_IS_OK(effect->getParameter(id, &get));
+    EXPECT_IS_OK(mEffect->getParameter(id, &get));
     EXPECT_EQ(expect, get) << expect.toString() << " vs " << get.toString();
 
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Verify parameters pass in set can be successfully get.
 TEST_P(AudioEffectTest, SetAndGetCommonParameter) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
 
     Parameter::Common common = EffectHelper::createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
     Parameter get = Parameter(), set = Parameter();
     set.set<Parameter::common>(common);
-    EXPECT_IS_OK(effect->setParameter(set));
+    EXPECT_IS_OK(mEffect->setParameter(set));
 
     Parameter::Id id;
     id.set<Parameter::Id::commonTag>(Parameter::common);
-    EXPECT_IS_OK(effect->getParameter(id, &get));
+    EXPECT_IS_OK(mEffect->getParameter(id, &get));
     EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
 
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Verify parameters set and get in PROCESSING state.
 TEST_P(AudioEffectTest, SetAndGetParameterInProcessing) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
     Parameter::Common common = EffectHelper::createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
     Parameter get = Parameter(), set = Parameter();
     set.set<Parameter::common>(common);
-    EXPECT_IS_OK(effect->setParameter(set));
+    EXPECT_IS_OK(mEffect->setParameter(set));
 
     Parameter::Id id;
     id.set<Parameter::Id::commonTag>(Parameter::common);
-    EXPECT_IS_OK(effect->getParameter(id, &get));
+    EXPECT_IS_OK(mEffect->getParameter(id, &get));
     EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Verify parameters set and get in IDLE state.
 TEST_P(AudioEffectTest, SetAndGetParameterInIdle) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
     Parameter::Common common = EffectHelper::createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
     Parameter get = Parameter(), set = Parameter();
     set.set<Parameter::common>(common);
-    EXPECT_IS_OK(effect->setParameter(set));
+    EXPECT_IS_OK(mEffect->setParameter(set));
 
     Parameter::Id id;
     id.set<Parameter::Id::commonTag>(Parameter::common);
-    EXPECT_IS_OK(effect->getParameter(id, &get));
+    EXPECT_IS_OK(mEffect->getParameter(id, &get));
     EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
 
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Verify Parameters kept after stop.
 TEST_P(AudioEffectTest, SetAndGetParameterAfterStop) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
     Parameter::Common common = EffectHelper::createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
     Parameter get = Parameter(), set = Parameter();
     set.set<Parameter::common>(common);
-    EXPECT_IS_OK(effect->setParameter(set));
+    EXPECT_IS_OK(mEffect->setParameter(set));
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
     Parameter::Id id;
     id.set<Parameter::Id::commonTag>(Parameter::common);
-    EXPECT_IS_OK(effect->getParameter(id, &get));
+    EXPECT_IS_OK(mEffect->getParameter(id, &get));
     EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
 
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Verify Parameters kept after reset.
 TEST_P(AudioEffectTest, SetAndGetParameterAfterReset) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
     Parameter::Common common = EffectHelper::createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
     Parameter get = Parameter(), set = Parameter();
     set.set<Parameter::common>(common);
-    EXPECT_IS_OK(effect->setParameter(set));
+    EXPECT_IS_OK(mEffect->setParameter(set));
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
     Parameter::Id id;
     id.set<Parameter::Id::commonTag>(Parameter::common);
-    EXPECT_IS_OK(effect->getParameter(id, &get));
+    EXPECT_IS_OK(mEffect->getParameter(id, &get));
     EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
 
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
-
 /// Data processing test
 // Send data to effects and expect it to be consumed by checking statusMQ.
 TEST_P(AudioEffectTest, ConsumeDataInProcessingState) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
     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(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
     auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    ASSERT_TRUE(statusMQ->isValid());
     auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    ASSERT_TRUE(inputMQ->isValid());
     auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+    ASSERT_TRUE(outputMQ->isValid());
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
     std::vector<float> buffer;
     EffectHelper::allocateInputData(common, inputMQ, buffer);
     EffectHelper::writeToFmq(inputMQ, buffer);
     EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Send data to effects and expect it to be consumed after effect restart.
 TEST_P(AudioEffectTest, ConsumeDataAfterRestart) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
     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(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
     auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    ASSERT_TRUE(statusMQ->isValid());
     auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    ASSERT_TRUE(inputMQ->isValid());
     auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+    ASSERT_TRUE(outputMQ->isValid());
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
     std::vector<float> buffer;
     EffectHelper::allocateInputData(common, inputMQ, buffer);
     EffectHelper::writeToFmq(inputMQ, buffer);
     EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Send data to IDLE effects and expect it to be consumed after effect start.
 TEST_P(AudioEffectTest, SendDataAtIdleAndConsumeDataInProcessing) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
     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(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
     auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    ASSERT_TRUE(statusMQ->isValid());
     auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    ASSERT_TRUE(inputMQ->isValid());
     auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+    ASSERT_TRUE(outputMQ->isValid());
 
     std::vector<float> buffer;
     EffectHelper::allocateInputData(common, inputMQ, buffer);
     EffectHelper::writeToFmq(inputMQ, buffer);
     EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
     EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Send data multiple times.
 TEST_P(AudioEffectTest, ProcessDataMultipleTimes) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
     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(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
     auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    ASSERT_TRUE(statusMQ->isValid());
     auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    ASSERT_TRUE(inputMQ->isValid());
     auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+    ASSERT_TRUE(outputMQ->isValid());
 
     std::vector<float> buffer;
     EffectHelper::allocateInputData(common, inputMQ, buffer);
     EffectHelper::writeToFmq(inputMQ, buffer);
     EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
     EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
     // expect no status and data after consume
@@ -634,77 +635,81 @@
     // expect no status and data after consume
     EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Send data to IDLE state effects and expect it not be consumed.
 TEST_P(AudioEffectTest, NotConsumeDataInIdleState) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
     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(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
     auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    ASSERT_TRUE(statusMQ->isValid());
     auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    ASSERT_TRUE(inputMQ->isValid());
     auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+    ASSERT_TRUE(outputMQ->isValid());
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
     std::vector<float> buffer;
     EffectHelper::allocateInputData(common, inputMQ, buffer);
     EffectHelper::writeToFmq(inputMQ, buffer);
     EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
     EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Send data to closed effects and expect it not be consumed.
 TEST_P(AudioEffectTest, NotConsumeDataByClosedEffect) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
     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(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
 
     auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    ASSERT_TRUE(statusMQ->isValid());
     auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    ASSERT_TRUE(inputMQ->isValid());
     auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+    ASSERT_TRUE(outputMQ->isValid());
 
     std::vector<float> buffer;
     EffectHelper::allocateInputData(common, inputMQ, buffer);
     EffectHelper::writeToFmq(inputMQ, buffer);
     EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
 
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Send data to multiple effects.
 TEST_P(AudioEffectTest, ConsumeDataMultipleEffects) {
     std::shared_ptr<IEffect> effect1, effect2;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mDescriptor));
 
     Parameter::Common common1 = EffectHelper::createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
@@ -721,8 +726,11 @@
     ASSERT_NO_FATAL_FAILURE(expectState(effect2, State::PROCESSING));
 
     auto statusMQ1 = std::make_unique<EffectHelper::StatusMQ>(ret1.statusMQ);
+    ASSERT_TRUE(statusMQ1->isValid());
     auto inputMQ1 = std::make_unique<EffectHelper::DataMQ>(ret1.inputDataMQ);
+    ASSERT_TRUE(inputMQ1->isValid());
     auto outputMQ1 = std::make_unique<EffectHelper::DataMQ>(ret1.outputDataMQ);
+    ASSERT_TRUE(outputMQ1->isValid());
 
     std::vector<float> buffer1, buffer2;
     EffectHelper::allocateInputData(common1, inputMQ1, buffer1);
@@ -730,8 +738,11 @@
     EffectHelper::readFromFmq(statusMQ1, 1, outputMQ1, buffer1.size(), buffer1);
 
     auto statusMQ2 = std::make_unique<EffectHelper::StatusMQ>(ret2.statusMQ);
+    ASSERT_TRUE(statusMQ2->isValid());
     auto inputMQ2 = std::make_unique<EffectHelper::DataMQ>(ret2.inputDataMQ);
+    ASSERT_TRUE(inputMQ2->isValid());
     auto outputMQ2 = std::make_unique<EffectHelper::DataMQ>(ret2.outputDataMQ);
+    ASSERT_TRUE(outputMQ2->isValid());
     EffectHelper::allocateInputData(common2, inputMQ2, buffer2);
     EffectHelper::writeToFmq(inputMQ2, buffer2);
     EffectHelper::readFromFmq(statusMQ2, 1, outputMQ2, buffer2.size(), buffer2);
@@ -752,9 +763,11 @@
         ::testing::Combine(testing::ValuesIn(
                 EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor))),
         [](const testing::TestParamInfo<AudioEffectTest::ParamType>& info) {
-            auto instance = std::get<PARAM_INSTANCE_NAME>(info.param);
-            std::string name = "TYPE_" + instance.second.type.toString() + "_UUID_" +
-                               instance.second.uuid.toString();
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_TYPE_" +
+                               descriptor.common.id.type.toString() + "_UUID_" +
+                               descriptor.common.id.uuid.toString();
             std::replace_if(
                     name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
             return name;
diff --git a/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp b/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
index 7adf63c..d49a865 100644
--- a/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
@@ -37,8 +37,7 @@
  * VtsAudioEffectTargetTest.
  */
 enum ParamName { PARAM_INSTANCE_NAME, PARAM_STRENGTH };
-using BassBoostParamTestParam =
-        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>, int>;
+using BassBoostParamTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>;
 
 /*
  * Testing parameter range, assuming the parameter supported by effect is in this range.
@@ -47,25 +46,16 @@
  * otherwise expect EX_ILLEGAL_ARGUMENT.
  */
 
-const std::vector<int> kStrengthValues = {
-        std::numeric_limits<int>::min(),
-        BassBoost::MIN_PER_MILLE_STRENGTH - 1,
-        BassBoost::MIN_PER_MILLE_STRENGTH,
-        (BassBoost::MIN_PER_MILLE_STRENGTH + BassBoost::MAX_PER_MILLE_STRENGTH) >> 1,
-        BassBoost::MAX_PER_MILLE_STRENGTH,
-        BassBoost::MAX_PER_MILLE_STRENGTH + 2,
-        std::numeric_limits<int>::max()};
-
 class BassBoostParamTest : public ::testing::TestWithParam<BassBoostParamTestParam>,
                            public EffectHelper {
   public:
     BassBoostParamTest() : mParamStrength(std::get<PARAM_STRENGTH>(GetParam())) {
-        std::tie(mFactory, mIdentity) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
     }
 
     void SetUp() override {
         ASSERT_NE(nullptr, mFactory);
-        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mIdentity));
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
         Parameter::Specific specific = getDefaultParamSpecific();
         Parameter::Common common = EffectHelper::createParamCommon(
@@ -82,7 +72,7 @@
     }
 
     Parameter::Specific getDefaultParamSpecific() {
-        BassBoost bb = BassBoost::make<BassBoost::strengthPm>(BassBoost::MIN_PER_MILLE_STRENGTH);
+        BassBoost bb = BassBoost::make<BassBoost::strengthPm>(0);
         Parameter::Specific specific =
                 Parameter::Specific::make<Parameter::Specific::bassBoost>(bb);
         return specific;
@@ -91,8 +81,8 @@
     static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
     std::shared_ptr<IFactory> mFactory;
     std::shared_ptr<IEffect> mEffect;
-    Descriptor::Identity mIdentity;
-    int mParamStrength = BassBoost::MIN_PER_MILLE_STRENGTH;
+    Descriptor mDescriptor;
+    int mParamStrength = 0;
 
     void SetAndGetBassBoostParameters() {
         for (auto& it : mTags) {
@@ -147,8 +137,29 @@
     }
 
     bool isStrengthInRange(const BassBoost::Capability& cap, int strength) const {
-        return cap.strengthSupported && strength >= BassBoost::MIN_PER_MILLE_STRENGTH &&
-               strength <= BassBoost::MAX_PER_MILLE_STRENGTH;
+        return cap.strengthSupported && strength >= 0 && strength <= cap.maxStrengthPm;
+    }
+
+    static std::vector<int> getStrengthTestValues(
+            std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kFactoryDescList) {
+        const auto max = std::max_element(
+                kFactoryDescList.begin(), kFactoryDescList.end(),
+                [](const std::pair<std::shared_ptr<IFactory>, Descriptor>& a,
+                   const std::pair<std::shared_ptr<IFactory>, Descriptor>& b) {
+                    return a.second.capability.get<Capability::bassBoost>().maxStrengthPm <
+                           b.second.capability.get<Capability::bassBoost>().maxStrengthPm;
+                });
+        if (max == kFactoryDescList.end()) {
+            return {0};
+        }
+        int maxStrength = max->second.capability.get<Capability::bassBoost>().maxStrengthPm;
+        return {std::numeric_limits<int>::min(),
+                -1,
+                0,
+                maxStrength >> 1,
+                maxStrength,
+                maxStrength + 1,
+                std::numeric_limits<int>::max()};
     }
 
   private:
@@ -163,13 +174,18 @@
 
 INSTANTIATE_TEST_SUITE_P(
         BassBoostTest, BassBoostParamTest,
-        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
-                                   IFactory::descriptor, kBassBoostTypeUUID)),
-                           testing::ValuesIn(kStrengthValues)),
+        ::testing::Combine(
+                testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+                                                                               kBassBoostTypeUUID)),
+                testing::ValuesIn(BassBoostParamTest::getStrengthTestValues(
+                        EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+                                                                     kBassBoostTypeUUID)))),
         [](const testing::TestParamInfo<BassBoostParamTest::ParamType>& info) {
-            auto instance = std::get<PARAM_INSTANCE_NAME>(info.param);
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
             std::string strength = std::to_string(std::get<PARAM_STRENGTH>(info.param));
-            std::string name = instance.second.uuid.toString() + "_strength_" + strength;
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_strength_" + strength;
             std::replace_if(
                     name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
             return name;
diff --git a/audio/aidl/vts/VtsHalDownmixTargetTest.cpp b/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
new file mode 100644
index 0000000..8612660
--- /dev/null
+++ b/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
@@ -0,0 +1,146 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "VtsHalDownmixTargetTest"
+
+#include <Utils.h>
+#include <aidl/Vintf.h>
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::Downmix;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kDownmixTypeUUID;
+using aidl::android::hardware::audio::effect::kEffectNullUuid;
+using aidl::android::hardware::audio::effect::Parameter;
+
+/**
+ * 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>;
+
+// Testing for enum values
+const std::vector<Downmix::Type> kTypeValues = {Downmix::Type::STRIP, Downmix::Type::FOLD};
+
+class DownmixParamTest : public ::testing::TestWithParam<DownmixParamTestParam>,
+                         public EffectHelper {
+  public:
+    DownmixParamTest() : mParamType(std::get<PARAM_TYPE>(GetParam())) {
+        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));
+    }
+
+    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);
+        }
+    }
+
+    void addTypeParam(Downmix::Type type) {
+        Downmix dm;
+        dm.set<Downmix::type>(type);
+        mTags.push_back({Downmix::type, dm});
+    }
+
+    Parameter::Specific getDefaultParamSpecific() {
+        Downmix dm = Downmix::make<Downmix::type>(Downmix::Type::STRIP);
+        Parameter::Specific specific = Parameter::Specific::make<Parameter::Specific::downmix>(dm);
+        return specific;
+    }
+
+  private:
+    std::vector<std::pair<Downmix::Tag, Downmix>> mTags;
+    void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(DownmixParamTest, SetAndGetType) {
+    EXPECT_NO_FATAL_FAILURE(addTypeParam(mParamType));
+    SetAndGetDownmixParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        DownmixTest, DownmixParamTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kDownmixTypeUUID)),
+                           testing::ValuesIn(kTypeValues)),
+        [](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 = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_type" + type;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DownmixParamTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
new file mode 100644
index 0000000..e99c4a4
--- /dev/null
+++ b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
@@ -0,0 +1,629 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "VtsHalEnvironmentalReverbTest"
+
+#include <Utils.h>
+#include <aidl/Vintf.h>
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::EnvironmentalReverb;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kEnvReverbTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ * Testing parameter range, assuming the parameter supported by effect is in this range.
+ * This range is verified with IEffect.getDescriptor() and range defined in the documentation, for
+ * any index supported value test expects EX_NONE from IEffect.setParameter(), otherwise expects
+ * EX_ILLEGAL_ARGUMENT.
+ */
+const std::vector<int> kRoomLevelValues = {
+        EnvironmentalReverb::MIN_ROOM_LEVEL_MB - 1, EnvironmentalReverb::MIN_ROOM_LEVEL_MB,
+        EnvironmentalReverb::MAX_ROOM_LEVEL_MB, EnvironmentalReverb::MAX_ROOM_LEVEL_MB + 1};
+const std::vector<int> kRoomHfLevelValues = {
+        EnvironmentalReverb::MIN_ROOM_HF_LEVEL_MB - 1, EnvironmentalReverb::MIN_ROOM_HF_LEVEL_MB,
+        EnvironmentalReverb::MAX_ROOM_HF_LEVEL_MB, EnvironmentalReverb::MAX_ROOM_HF_LEVEL_MB + 1};
+const std::vector<int> kDecayTimeValues = {
+        EnvironmentalReverb::MIN_DECAY_TIME_MS - 1, EnvironmentalReverb::MIN_DECAY_TIME_MS,
+        EnvironmentalReverb::MAX_DECAY_TIME_MS, EnvironmentalReverb::MAX_DECAY_TIME_MS + 1};
+const std::vector<int> kDecayHfRatioValues = {
+        EnvironmentalReverb::MIN_DECAY_HF_RATIO_PM - 1, EnvironmentalReverb::MIN_DECAY_HF_RATIO_PM,
+        EnvironmentalReverb::MAX_DECAY_HF_RATIO_PM, EnvironmentalReverb::MAX_DECAY_HF_RATIO_PM + 1};
+const std::vector<int> kLevelValues = {
+        EnvironmentalReverb::MIN_LEVEL_MB - 1, EnvironmentalReverb::MIN_LEVEL_MB,
+        EnvironmentalReverb::MAX_LEVEL_MB, EnvironmentalReverb::MAX_LEVEL_MB + 1};
+const std::vector<int> kDelayValues = {
+        EnvironmentalReverb::MIN_DELAY_MS - 1, EnvironmentalReverb::MIN_DELAY_MS,
+        EnvironmentalReverb::MAX_DELAY_MS, EnvironmentalReverb::MAX_DELAY_MS + 1};
+const std::vector<int> kDiffusionValues = {
+        EnvironmentalReverb::MIN_DIFFUSION_PM - 1, EnvironmentalReverb::MIN_DIFFUSION_PM,
+        EnvironmentalReverb::MAX_DIFFUSION_PM, EnvironmentalReverb::MAX_DIFFUSION_PM + 1};
+const std::vector<int> kDensityValues = {
+        EnvironmentalReverb::MIN_DENSITY_PM - 1, EnvironmentalReverb::MIN_DENSITY_PM,
+        EnvironmentalReverb::MAX_DENSITY_PM, EnvironmentalReverb::MAX_DENSITY_PM + 1};
+
+class EnvironmentalReverbHelper : public EffectHelper {
+  public:
+    EnvironmentalReverbHelper(std::pair<std::shared_ptr<IFactory>, Descriptor> pair) {
+        std::tie(mFactory, mDescriptor) = pair;
+    }
+
+    void SetUpReverb() {
+        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 TearDownReverb() {
+        ASSERT_NO_FATAL_FAILURE(close(mEffect));
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+    }
+
+    Parameter::Specific getDefaultParamSpecific() {
+        EnvironmentalReverb er = EnvironmentalReverb::make<EnvironmentalReverb::roomLevelMb>(
+                EnvironmentalReverb::MIN_ROOM_LEVEL_MB);
+        Parameter::Specific specific =
+                Parameter::Specific::make<Parameter::Specific::environmentalReverb>(er);
+        return specific;
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+    int mRoomLevel = EnvironmentalReverb::MIN_ROOM_LEVEL_MB;
+    int mRoomHfLevel = EnvironmentalReverb::MAX_ROOM_HF_LEVEL_MB;
+    int mDecayTime = 1000;
+    int mDecayHfRatio = 500;
+    int mLevel = EnvironmentalReverb::MIN_LEVEL_MB;
+    int mDelay = 40;
+    int mDiffusion = EnvironmentalReverb::MAX_DIFFUSION_PM;
+    int mDensity = EnvironmentalReverb::MAX_DENSITY_PM;
+    bool mBypass = false;
+
+    void SetAndGetReverbParameters() {
+        for (auto& it : mTags) {
+            auto& tag = it.first;
+            auto& er = it.second;
+
+            // validate parameter
+            Descriptor desc;
+            ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+            const bool valid = isTagInRange(it.first, it.second, desc);
+            const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+            // set
+            Parameter expectParam;
+            Parameter::Specific specific;
+            specific.set<Parameter::Specific::environmentalReverb>(er);
+            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;
+                EnvironmentalReverb::Id erId;
+                erId.set<EnvironmentalReverb::Id::commonTag>(tag);
+                id.set<Parameter::Id::environmentalReverbTag>(erId);
+                // if set success, then get should match
+                EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
+                EXPECT_EQ(expectParam, getParam);
+            }
+        }
+    }
+
+    void addRoomLevelParam() {
+        EnvironmentalReverb er;
+        er.set<EnvironmentalReverb::roomLevelMb>(mRoomLevel);
+        mTags.push_back({EnvironmentalReverb::roomLevelMb, er});
+    }
+
+    void addRoomHfLevelParam(int roomHfLevel) {
+        EnvironmentalReverb er;
+        er.set<EnvironmentalReverb::roomHfLevelMb>(roomHfLevel);
+        mTags.push_back({EnvironmentalReverb::roomHfLevelMb, er});
+    }
+
+    void addDecayTimeParam(int decayTime) {
+        EnvironmentalReverb er;
+        er.set<EnvironmentalReverb::decayTimeMs>(decayTime);
+        mTags.push_back({EnvironmentalReverb::decayTimeMs, er});
+    }
+
+    void addDecayHfRatioParam(int decayHfRatio) {
+        EnvironmentalReverb er;
+        er.set<EnvironmentalReverb::decayHfRatioPm>(decayHfRatio);
+        mTags.push_back({EnvironmentalReverb::decayHfRatioPm, er});
+    }
+
+    void addLevelParam(int level) {
+        EnvironmentalReverb er;
+        er.set<EnvironmentalReverb::levelMb>(level);
+        mTags.push_back({EnvironmentalReverb::levelMb, er});
+    }
+
+    void addDelayParam(int delay) {
+        EnvironmentalReverb er;
+        er.set<EnvironmentalReverb::delayMs>(delay);
+        mTags.push_back({EnvironmentalReverb::delayMs, er});
+    }
+
+    void addDiffusionParam(int diffusion) {
+        EnvironmentalReverb er;
+        er.set<EnvironmentalReverb::diffusionPm>(diffusion);
+        mTags.push_back({EnvironmentalReverb::diffusionPm, er});
+    }
+
+    void addDensityParam(int density) {
+        EnvironmentalReverb er;
+        er.set<EnvironmentalReverb::densityPm>(density);
+        mTags.push_back({EnvironmentalReverb::densityPm, er});
+    }
+
+    void addBypassParam(bool bypass) {
+        EnvironmentalReverb er;
+        er.set<EnvironmentalReverb::bypass>(bypass);
+        mTags.push_back({EnvironmentalReverb::bypass, er});
+    }
+
+    bool isTagInRange(const EnvironmentalReverb::Tag& tag, const EnvironmentalReverb er,
+                      const Descriptor& desc) const {
+        const EnvironmentalReverb::Capability& erCap =
+                desc.capability.get<Capability::environmentalReverb>();
+        switch (tag) {
+            case EnvironmentalReverb::roomLevelMb: {
+                int roomLevel = er.get<EnvironmentalReverb::roomLevelMb>();
+                return isRoomLevelInRange(roomLevel);
+            }
+            case EnvironmentalReverb::roomHfLevelMb: {
+                int roomHfLevel = er.get<EnvironmentalReverb::roomHfLevelMb>();
+                return isRoomHfLevelInRange(roomHfLevel);
+            }
+            case EnvironmentalReverb::decayTimeMs: {
+                int decayTime = er.get<EnvironmentalReverb::decayTimeMs>();
+                return isDecayTimeInRange(erCap, decayTime);
+            }
+            case EnvironmentalReverb::decayHfRatioPm: {
+                int decayHfRatio = er.get<EnvironmentalReverb::decayHfRatioPm>();
+                return isDecayHfRatioInRange(decayHfRatio);
+            }
+            case EnvironmentalReverb::levelMb: {
+                int level = er.get<EnvironmentalReverb::levelMb>();
+                return isLevelInRange(level);
+            }
+            case EnvironmentalReverb::delayMs: {
+                int delay = er.get<EnvironmentalReverb::delayMs>();
+                return isDelayInRange(delay);
+            }
+            case EnvironmentalReverb::diffusionPm: {
+                int diffusion = er.get<EnvironmentalReverb::diffusionPm>();
+                return isDiffusionInRange(diffusion);
+            }
+            case EnvironmentalReverb::densityPm: {
+                int density = er.get<EnvironmentalReverb::densityPm>();
+                return isDensityInRange(density);
+            }
+            case EnvironmentalReverb::bypass: {
+                return true;
+            }
+            default:
+                return false;
+        }
+        return false;
+    }
+
+    bool isRoomLevelInRange(int roomLevel) const {
+        return roomLevel >= EnvironmentalReverb::MIN_ROOM_LEVEL_MB &&
+               roomLevel <= EnvironmentalReverb::MAX_ROOM_LEVEL_MB;
+    }
+
+    bool isRoomHfLevelInRange(int roomHfLevel) const {
+        return roomHfLevel >= EnvironmentalReverb::MIN_ROOM_HF_LEVEL_MB &&
+               roomHfLevel <= EnvironmentalReverb::MAX_ROOM_HF_LEVEL_MB;
+    }
+
+    bool isDecayTimeInRange(const EnvironmentalReverb::Capability& cap, int decayTime) const {
+        return decayTime >= EnvironmentalReverb::MIN_DECAY_TIME_MS &&
+               decayTime <= EnvironmentalReverb::MAX_DECAY_TIME_MS &&
+               decayTime <= cap.maxDecayTimeMs;
+    }
+
+    bool isDecayHfRatioInRange(int decayHfRatio) const {
+        return decayHfRatio >= EnvironmentalReverb::MIN_DECAY_HF_RATIO_PM &&
+               decayHfRatio <= EnvironmentalReverb::MAX_DECAY_HF_RATIO_PM;
+    }
+
+    bool isLevelInRange(int level) const {
+        return level >= EnvironmentalReverb::MIN_LEVEL_MB &&
+               level <= EnvironmentalReverb::MAX_LEVEL_MB;
+    }
+
+    bool isDelayInRange(int delay) const {
+        return delay >= EnvironmentalReverb::MIN_DELAY_MS &&
+               delay <= EnvironmentalReverb::MAX_DELAY_MS;
+    }
+
+    bool isDiffusionInRange(int diffusion) const {
+        return diffusion >= EnvironmentalReverb::MIN_DIFFUSION_PM &&
+               diffusion <= EnvironmentalReverb::MAX_DIFFUSION_PM;
+    }
+
+    bool isDensityInRange(int density) const {
+        return density >= EnvironmentalReverb::MIN_DENSITY_PM &&
+               density <= EnvironmentalReverb::MAX_DENSITY_PM;
+    }
+
+  private:
+    std::vector<std::pair<EnvironmentalReverb::Tag, EnvironmentalReverb>> mTags;
+    void CleanUp() { mTags.clear(); }
+};
+
+class EnvironmentalReverbRoomLevelTest
+    : public ::testing::TestWithParam<
+              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+      public EnvironmentalReverbHelper {
+  public:
+    EnvironmentalReverbRoomLevelTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+        mRoomLevel = std::get<1>(GetParam());
+    }
+
+    void SetUp() override { SetUpReverb(); }
+
+    void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbRoomLevelTest, SetAndGetRoomLevel) {
+    EXPECT_NO_FATAL_FAILURE(addRoomLevelParam());
+    SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        EnvironmentalReverbTest, EnvironmentalReverbRoomLevelTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kEnvReverbTypeUUID)),
+                           testing::ValuesIn(kRoomLevelValues)),
+        [](const testing::TestParamInfo<EnvironmentalReverbRoomLevelTest::ParamType>& info) {
+            auto descriptor = std::get<0>(info.param).second;
+            std::string roomLevel = std::to_string(std::get<1>(info.param));
+
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_roomLevel" + roomLevel;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbRoomLevelTest);
+
+class EnvironmentalReverbRoomHfLevelTest
+    : public ::testing::TestWithParam<
+              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+      public EnvironmentalReverbHelper {
+  public:
+    EnvironmentalReverbRoomHfLevelTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+        mRoomHfLevel = std::get<1>(GetParam());
+    }
+
+    void SetUp() override { SetUpReverb(); }
+
+    void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbRoomHfLevelTest, SetAndGetRoomHfLevel) {
+    EXPECT_NO_FATAL_FAILURE(addRoomHfLevelParam(mRoomHfLevel));
+    SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        EnvironmentalReverbTest, EnvironmentalReverbRoomHfLevelTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kEnvReverbTypeUUID)),
+                           testing::ValuesIn(kRoomHfLevelValues)),
+        [](const testing::TestParamInfo<EnvironmentalReverbRoomHfLevelTest::ParamType>& info) {
+            auto descriptor = std::get<0>(info.param).second;
+            std::string roomHfLevel = std::to_string(std::get<1>(info.param));
+
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_roomHfLevel" + roomHfLevel;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbRoomHfLevelTest);
+
+class EnvironmentalReverbDecayTimeTest
+    : public ::testing::TestWithParam<
+              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+      public EnvironmentalReverbHelper {
+  public:
+    EnvironmentalReverbDecayTimeTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+        mDecayTime = std::get<1>(GetParam());
+    }
+
+    void SetUp() override { SetUpReverb(); }
+
+    void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbDecayTimeTest, SetAndGetDecayTime) {
+    EXPECT_NO_FATAL_FAILURE(addDecayTimeParam(mDecayTime));
+    SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        EnvironmentalReverbTest, EnvironmentalReverbDecayTimeTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kEnvReverbTypeUUID)),
+                           testing::ValuesIn(kDecayTimeValues)),
+        [](const testing::TestParamInfo<EnvironmentalReverbDecayTimeTest::ParamType>& info) {
+            auto descriptor = std::get<0>(info.param).second;
+            std::string decayTime = std::to_string(std::get<1>(info.param));
+
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_decayTime" + decayTime;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDecayTimeTest);
+
+class EnvironmentalReverbDecayHfRatioTest
+    : public ::testing::TestWithParam<
+              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+      public EnvironmentalReverbHelper {
+  public:
+    EnvironmentalReverbDecayHfRatioTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+        mDecayHfRatio = std::get<1>(GetParam());
+    }
+
+    void SetUp() override { SetUpReverb(); }
+
+    void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbDecayHfRatioTest, SetAndGetDecayHfRatio) {
+    EXPECT_NO_FATAL_FAILURE(addDecayHfRatioParam(mDecayHfRatio));
+    SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        EnvironmentalReverbTest, EnvironmentalReverbDecayHfRatioTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kEnvReverbTypeUUID)),
+                           testing::ValuesIn(kDecayHfRatioValues)),
+        [](const testing::TestParamInfo<EnvironmentalReverbDecayHfRatioTest::ParamType>& info) {
+            auto descriptor = std::get<0>(info.param).second;
+            std::string decayHfRatio = std::to_string(std::get<1>(info.param));
+
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_decayHfRatio" +
+                               decayHfRatio;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDecayHfRatioTest);
+
+class EnvironmentalReverbLevelTest
+    : public ::testing::TestWithParam<
+              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+      public EnvironmentalReverbHelper {
+  public:
+    EnvironmentalReverbLevelTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+        mLevel = std::get<1>(GetParam());
+    }
+
+    void SetUp() override { SetUpReverb(); }
+
+    void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbLevelTest, SetAndGetLevel) {
+    EXPECT_NO_FATAL_FAILURE(addLevelParam(mLevel));
+    SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        EnvironmentalReverbTest, EnvironmentalReverbLevelTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kEnvReverbTypeUUID)),
+                           testing::ValuesIn(kLevelValues)),
+        [](const testing::TestParamInfo<EnvironmentalReverbDecayHfRatioTest::ParamType>& info) {
+            auto descriptor = std::get<0>(info.param).second;
+            std::string level = std::to_string(std::get<1>(info.param));
+
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_level" + level;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbLevelTest);
+
+class EnvironmentalReverbDelayTest
+    : public ::testing::TestWithParam<
+              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+      public EnvironmentalReverbHelper {
+  public:
+    EnvironmentalReverbDelayTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+        mDelay = std::get<1>(GetParam());
+    }
+
+    void SetUp() override { SetUpReverb(); }
+
+    void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbDelayTest, SetAndGetDelay) {
+    EXPECT_NO_FATAL_FAILURE(addDelayParam(mDelay));
+    SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        EnvironmentalReverbTest, EnvironmentalReverbDelayTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kEnvReverbTypeUUID)),
+                           testing::ValuesIn(kDelayValues)),
+        [](const testing::TestParamInfo<EnvironmentalReverbDelayTest::ParamType>& info) {
+            auto descriptor = std::get<0>(info.param).second;
+            std::string delay = std::to_string(std::get<1>(info.param));
+
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_delay" + delay;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDelayTest);
+
+class EnvironmentalReverbDiffusionTest
+    : public ::testing::TestWithParam<
+              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+      public EnvironmentalReverbHelper {
+  public:
+    EnvironmentalReverbDiffusionTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+        mDiffusion = std::get<1>(GetParam());
+    }
+
+    void SetUp() override { SetUpReverb(); }
+
+    void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbDiffusionTest, SetAndGetDiffusion) {
+    EXPECT_NO_FATAL_FAILURE(addDiffusionParam(mDiffusion));
+    SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        EnvironmentalReverbTest, EnvironmentalReverbDiffusionTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kEnvReverbTypeUUID)),
+                           testing::ValuesIn(kDiffusionValues)),
+        [](const testing::TestParamInfo<EnvironmentalReverbDiffusionTest::ParamType>& info) {
+            auto descriptor = std::get<0>(info.param).second;
+            std::string diffusion = std::to_string(std::get<1>(info.param));
+
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_diffusion" + diffusion;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDiffusionTest);
+
+class EnvironmentalReverbDensityTest
+    : public ::testing::TestWithParam<
+              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+      public EnvironmentalReverbHelper {
+  public:
+    EnvironmentalReverbDensityTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+        mDensity = std::get<1>(GetParam());
+    }
+
+    void SetUp() override { SetUpReverb(); }
+
+    void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbDensityTest, SetAndGetDensity) {
+    EXPECT_NO_FATAL_FAILURE(addDensityParam(mDensity));
+    SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        EnvironmentalReverbTest, EnvironmentalReverbDensityTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kEnvReverbTypeUUID)),
+                           testing::ValuesIn(kDensityValues)),
+        [](const testing::TestParamInfo<EnvironmentalReverbDensityTest::ParamType>& info) {
+            auto descriptor = std::get<0>(info.param).second;
+            std::string density = std::to_string(std::get<1>(info.param));
+
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_density" + density;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDensityTest);
+
+class EnvironmentalReverbBypassTest
+    : public ::testing::TestWithParam<
+              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, bool>>,
+      public EnvironmentalReverbHelper {
+  public:
+    EnvironmentalReverbBypassTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+        mBypass = std::get<1>(GetParam());
+    }
+
+    void SetUp() override { SetUpReverb(); }
+
+    void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbBypassTest, SetAndGetBypass) {
+    EXPECT_NO_FATAL_FAILURE(addBypassParam(mBypass));
+    SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        EnvironmentalReverbTest, EnvironmentalReverbBypassTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kEnvReverbTypeUUID)),
+                           testing::Bool()),
+        [](const testing::TestParamInfo<EnvironmentalReverbBypassTest::ParamType>& info) {
+            auto descriptor = std::get<0>(info.param).second;
+            std::string bypass = std::to_string(std::get<1>(info.param));
+
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_bypass" + bypass;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbBypassTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
index 1b147a6..e11a936 100644
--- a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
@@ -57,8 +57,7 @@
  */
 
 enum ParamName { PARAM_INSTANCE_NAME, PARAM_BAND_LEVEL };
-using EqualizerParamTestParam =
-        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>, int>;
+using EqualizerParamTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>;
 
 /*
 Testing parameter range, assuming the parameter supported by effect is in this range.
@@ -71,12 +70,12 @@
                       public EffectHelper {
   public:
     EqualizerTest() : mBandLevel(std::get<PARAM_BAND_LEVEL>(GetParam())) {
-        std::tie(mFactory, mIdentity) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
     }
 
     void SetUp() override {
         ASSERT_NE(nullptr, mFactory);
-        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mIdentity));
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
         Parameter::Specific specific = getDefaultParamSpecific();
         Parameter::Common common = EffectHelper::createParamCommon(
@@ -115,7 +114,7 @@
     static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
     std::shared_ptr<IFactory> mFactory;
     std::shared_ptr<IEffect> mEffect;
-    Descriptor::Identity mIdentity;
+    Descriptor mDescriptor;
     std::pair<int, int> mPresetIndex;
     std::pair<int, int> mBandIndex;
     const int mBandLevel;
@@ -327,9 +326,11 @@
                                    IFactory::descriptor, kEqualizerTypeUUID)),
                            testing::ValuesIn(kBandLevels)),
         [](const testing::TestParamInfo<EqualizerTest::ParamType>& info) {
-            auto instance = std::get<PARAM_INSTANCE_NAME>(info.param);
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
             std::string bandLevel = std::to_string(std::get<PARAM_BAND_LEVEL>(info.param));
-            std::string name = instance.second.uuid.toString() + "_bandLevel_" + bandLevel;
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_bandLevel_" + bandLevel;
             std::replace_if(
                     name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
             return name;
diff --git a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
new file mode 100644
index 0000000..b8ea9c1
--- /dev/null
+++ b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
@@ -0,0 +1,440 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "VtsHalHapticGeneratorTargetTest"
+
+#include <Utils.h>
+#include <aidl/Vintf.h>
+#include <android/binder_enums.h>
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::HapticGenerator;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kHapticGeneratorTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+enum ParamName {
+    PARAM_INSTANCE_NAME,
+    PARAM_HAPTIC_SCALE_ID,
+    PARAM_HAPTIC_SCALE_VIBRATOR_SCALE,
+    PARAM_VIBRATION_INFORMATION_RESONANT_FREQUENCY,
+    PARAM_VIBRATION_INFORMATION_Q_FACTOR,
+    PARAM_VIBRATION_INFORMATION_MAX_AMPLITUDE,
+};
+using HapticGeneratorParamTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int,
+                   HapticGenerator::VibratorScale, float, float, float>;
+
+/*
+ * Testing parameter range, assuming the parameter supported by effect is in this range.
+ * Parameter should be within the valid range defined in the documentation,
+ * for any supported value test expects EX_NONE from IEffect.setParameter(),
+ * otherwise expect EX_ILLEGAL_ARGUMENT.
+ */
+
+// TODO : Update the test values once range/capability is updated by implementation
+const int MIN_ID = std::numeric_limits<int>::min();
+const int MAX_ID = std::numeric_limits<int>::max();
+const float MIN_FLOAT = std::numeric_limits<float>::min();
+const float MAX_FLOAT = std::numeric_limits<float>::max();
+
+const std::vector<int> kHapticScaleIdValues = {MIN_ID, 0, MAX_ID};
+const std::vector<HapticGenerator::VibratorScale> kVibratorScaleValues = {
+        ndk::enum_range<HapticGenerator::VibratorScale>().begin(),
+        ndk::enum_range<HapticGenerator::VibratorScale>().end()};
+
+const std::vector<float> kResonantFrequencyValues = {MIN_FLOAT, 100, MAX_FLOAT};
+const std::vector<float> kQFactorValues = {MIN_FLOAT, 100, MAX_FLOAT};
+const std::vector<float> kMaxAmplitude = {MIN_FLOAT, 100, MAX_FLOAT};
+
+class HapticGeneratorParamTest : public ::testing::TestWithParam<HapticGeneratorParamTestParam>,
+                                 public EffectHelper {
+  public:
+    HapticGeneratorParamTest()
+        : mParamHapticScaleId(std::get<PARAM_HAPTIC_SCALE_ID>(GetParam())),
+          mParamVibratorScale(std::get<PARAM_HAPTIC_SCALE_VIBRATOR_SCALE>(GetParam())),
+          mParamResonantFrequency(
+                  std::get<PARAM_VIBRATION_INFORMATION_RESONANT_FREQUENCY>(GetParam())),
+          mParamQFactor(std::get<PARAM_VIBRATION_INFORMATION_Q_FACTOR>(GetParam())),
+          mParamMaxAmplitude(std::get<PARAM_VIBRATION_INFORMATION_MAX_AMPLITUDE>(GetParam())) {
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    }
+    void SetUp() override {
+        ASSERT_NE(nullptr, mFactory);
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+        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, std::nullopt, &ret, EX_NONE));
+        ASSERT_NE(nullptr, mEffect);
+    }
+
+    void TearDown() override {
+        ASSERT_NO_FATAL_FAILURE(close(mEffect));
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+    int mParamHapticScaleId = 0;
+    HapticGenerator::VibratorScale mParamVibratorScale = HapticGenerator::VibratorScale::MUTE;
+    float mParamResonantFrequency = 0;
+    float mParamQFactor = 0;
+    float mParamMaxAmplitude = 0;
+
+    void SetAndGetHapticGeneratorParameters() {
+        for (auto& it : mTags) {
+            auto& tag = std::get<ParamTestEnum::PARAM_TEST_TAG>(it);
+            auto& setHg = std::get<ParamTestEnum::PARAM_TEST_TARGET>(it);
+
+            // set parameter
+            Parameter expectParam;
+            Parameter::Specific specific;
+            specific.set<Parameter::Specific::hapticGenerator>(setHg);
+            expectParam.set<Parameter::specific>(specific);
+            EXPECT_STATUS(EX_NONE, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+            // get parameter
+            Parameter getParam;
+            Parameter::Id id;
+            HapticGenerator::Id hgId;
+            hgId.set<HapticGenerator::Id::commonTag>(tag);
+            id.set<Parameter::Id::hapticGeneratorTag>(hgId);
+            EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+            EXPECT_EQ(expectParam, getParam) << expectParam.toString() << "\n"
+                                             << getParam.toString();
+        }
+    }
+
+    void addHapticScaleParam(int id, HapticGenerator::VibratorScale scale) {
+        HapticGenerator setHg;
+        std::vector<HapticGenerator::HapticScale> hapticScales = {{.id = id, .scale = scale}};
+        setHg.set<HapticGenerator::hapticScales>(hapticScales);
+        mTags.push_back({HapticGenerator::hapticScales, setHg});
+    }
+
+    void addVibratorInformationParam(float resonantFrequencyHz, float qFactor, float maxAmplitude) {
+        HapticGenerator hg;
+        HapticGenerator::VibratorInformation vibrationInfo = {
+                .resonantFrequencyHz = resonantFrequencyHz,
+                .qFactor = qFactor,
+                .maxAmplitude = maxAmplitude};
+        hg.set<HapticGenerator::vibratorInfo>(vibrationInfo);
+        mTags.push_back({HapticGenerator::vibratorInfo, hg});
+    }
+
+  private:
+    enum ParamTestEnum { PARAM_TEST_TAG, PARAM_TEST_TARGET };
+    std::vector<std::tuple<HapticGenerator::Tag, HapticGenerator>> mTags;
+
+    void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(HapticGeneratorParamTest, SetAndGetHapticScale) {
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(mParamHapticScaleId, mParamVibratorScale));
+    SetAndGetHapticGeneratorParameters();
+}
+
+TEST_P(HapticGeneratorParamTest, SetAndGetMultipleHapticScales) {
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(mParamHapticScaleId, mParamVibratorScale));
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(mParamHapticScaleId, mParamVibratorScale));
+    SetAndGetHapticGeneratorParameters();
+}
+
+TEST_P(HapticGeneratorParamTest, SetAndGetVibratorInformation) {
+    EXPECT_NO_FATAL_FAILURE(addVibratorInformationParam(mParamResonantFrequency, mParamQFactor,
+                                                        mParamMaxAmplitude));
+    SetAndGetHapticGeneratorParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        HapticGeneratorValidTest, HapticGeneratorParamTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kHapticGeneratorTypeUUID)),
+                           testing::ValuesIn(kHapticScaleIdValues),
+                           testing::ValuesIn(kVibratorScaleValues),
+                           testing::ValuesIn(kResonantFrequencyValues),
+                           testing::ValuesIn(kQFactorValues), testing::ValuesIn(kMaxAmplitude)),
+        [](const testing::TestParamInfo<HapticGeneratorParamTest::ParamType>& info) {
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string hapticScaleID = std::to_string(std::get<PARAM_HAPTIC_SCALE_ID>(info.param));
+            std::string hapticScaleVibScale = std::to_string(
+                    static_cast<int>(std::get<PARAM_HAPTIC_SCALE_VIBRATOR_SCALE>(info.param)));
+            std::string resonantFrequency = std::to_string(
+                    std::get<PARAM_VIBRATION_INFORMATION_RESONANT_FREQUENCY>(info.param));
+            std::string qFactor =
+                    std::to_string(std::get<PARAM_VIBRATION_INFORMATION_Q_FACTOR>(info.param));
+            std::string maxAmplitude =
+                    std::to_string(std::get<PARAM_VIBRATION_INFORMATION_MAX_AMPLITUDE>(info.param));
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_hapticScaleId" +
+                               hapticScaleID + "_hapticScaleVibScale" + hapticScaleVibScale +
+                               "_resonantFrequency" + resonantFrequency + "_qFactor" + qFactor +
+                               "_maxAmplitude" + maxAmplitude;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+INSTANTIATE_TEST_SUITE_P(
+        HapticGeneratorInvalidTest, HapticGeneratorParamTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kHapticGeneratorTypeUUID)),
+                           testing::Values(MIN_ID - 1),
+                           testing::Values(HapticGenerator::VibratorScale::NONE),
+                           testing::Values(MIN_FLOAT), testing::Values(MIN_FLOAT),
+                           testing::Values(MIN_FLOAT)),
+        [](const testing::TestParamInfo<HapticGeneratorParamTest::ParamType>& info) {
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string hapticScaleID = std::to_string(std::get<PARAM_HAPTIC_SCALE_ID>(info.param));
+            std::string hapticScaleVibScale = std::to_string(
+                    static_cast<int>(std::get<PARAM_HAPTIC_SCALE_VIBRATOR_SCALE>(info.param)));
+            std::string resonantFrequency = std::to_string(
+                    std::get<PARAM_VIBRATION_INFORMATION_RESONANT_FREQUENCY>(info.param));
+            std::string qFactor =
+                    std::to_string(std::get<PARAM_VIBRATION_INFORMATION_Q_FACTOR>(info.param));
+            std::string maxAmplitude =
+                    std::to_string(std::get<PARAM_VIBRATION_INFORMATION_MAX_AMPLITUDE>(info.param));
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_hapticScaleId" +
+                               hapticScaleID + "_hapticScaleVibScale" + hapticScaleVibScale +
+                               "_resonantFrequency" + resonantFrequency + "_qFactor" + qFactor +
+                               "_maxAmplitude" + maxAmplitude;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorParamTest);
+
+// Test HapticScale[] hapticScales parameter
+using HapticGeneratorScalesTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>>;
+class HapticGeneratorScalesTest : public ::testing::TestWithParam<HapticGeneratorScalesTestParam>,
+                                  public EffectHelper {
+  public:
+    HapticGeneratorScalesTest() {
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    }
+
+    void SetUp() override {
+        ASSERT_NE(nullptr, mFactory);
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+        Parameter::Common common = EffectHelper::createParamCommon(
+                0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+        IEffect::OpenEffectReturn ret;
+        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt, &ret, EX_NONE));
+        ASSERT_NE(nullptr, mEffect);
+    }
+
+    void TearDown() override {
+        ASSERT_NO_FATAL_FAILURE(close(mEffect));
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+        CleanUp();
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+
+    void addHapticScaleParam(std::vector<HapticGenerator::HapticScale> scales) {
+        mHapticScales.push_back(HapticGenerator::make<HapticGenerator::hapticScales>(scales));
+        for (const auto& scale : scales) {
+            expectMap.insert_or_assign(scale.id, scale.scale);
+        }
+    }
+
+    void SetHapticScaleParameters() {
+        // std::unordered_set<HapticGenerator::HapticScale> target;
+        for (auto& it : mHapticScales) {
+            Parameter::Specific specific =
+                    Parameter::Specific::make<Parameter::Specific::hapticGenerator>(it);
+            Parameter param = Parameter::make<Parameter::specific>(specific);
+            EXPECT_STATUS(EX_NONE, mEffect->setParameter(param)) << param.toString();
+        }
+    }
+
+    void checkHapticScaleParameter() {
+        // get parameter
+        Parameter targetParam;
+        HapticGenerator::Id hgId = HapticGenerator::Id::make<HapticGenerator::Id::commonTag>(
+                HapticGenerator::hapticScales);
+        Parameter::Id id = Parameter::Id::make<Parameter::Id::hapticGeneratorTag>(hgId);
+        EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &targetParam));
+        ASSERT_EQ(Parameter::specific, targetParam.getTag());
+        Parameter::Specific specific = targetParam.get<Parameter::specific>();
+        ASSERT_EQ(Parameter::Specific::hapticGenerator, specific.getTag());
+        HapticGenerator hg = specific.get<Parameter::Specific::hapticGenerator>();
+        ASSERT_EQ(HapticGenerator::hapticScales, hg.getTag());
+        std::vector<HapticGenerator::HapticScale> scales = hg.get<HapticGenerator::hapticScales>();
+        ASSERT_EQ(scales.size(), expectMap.size());
+        for (const auto& scale : scales) {
+            auto itor = expectMap.find(scale.id);
+            ASSERT_NE(expectMap.end(), itor);
+            ASSERT_EQ(scale.scale, itor->second);
+            expectMap.erase(scale.id);
+        }
+        ASSERT_EQ(0ul, expectMap.size());
+    }
+
+    const static HapticGenerator::HapticScale kHapticScaleWithMinId;
+    const static HapticGenerator::HapticScale kHapticScaleWithMinIdNew;
+    const static HapticGenerator::HapticScale kHapticScale;
+    const static HapticGenerator::HapticScale kHapticScaleNew;
+    const static HapticGenerator::HapticScale kHapticScaleWithMaxId;
+    const static HapticGenerator::HapticScale kHapticScaleWithMaxIdNew;
+
+    std::vector<HapticGenerator> mHapticScales;
+
+    void CleanUp() {
+        mHapticScales.clear();
+        expectMap.clear();
+    }
+
+  private:
+    std::map<int /* trackID */, HapticGenerator::VibratorScale> expectMap;
+};
+
+const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleWithMinId = {
+        .id = MIN_ID, .scale = HapticGenerator::VibratorScale::MUTE};
+const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleWithMinIdNew = {
+        .id = MIN_ID, .scale = HapticGenerator::VibratorScale::VERY_LOW};
+const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScale = {
+        .id = 1, .scale = HapticGenerator::VibratorScale::LOW};
+const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleNew = {
+        .id = 1, .scale = HapticGenerator::VibratorScale::NONE};
+const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleWithMaxId = {
+        .id = MAX_ID, .scale = HapticGenerator::VibratorScale::VERY_HIGH};
+const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleWithMaxIdNew = {
+        .id = MAX_ID, .scale = HapticGenerator::VibratorScale::MUTE};
+
+TEST_P(HapticGeneratorScalesTest, SetAndUpdateOne) {
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScale}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleNew}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMinId}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMinIdNew}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMaxId}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMaxIdNew}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+
+    EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
+}
+
+TEST_P(HapticGeneratorScalesTest, SetAndUpdateVector) {
+    EXPECT_NO_FATAL_FAILURE(
+            addHapticScaleParam({kHapticScale, kHapticScaleWithMaxId, kHapticScaleWithMinId}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(
+            {kHapticScaleNew, kHapticScaleWithMaxIdNew, kHapticScaleWithMinIdNew}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+
+    EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
+}
+
+TEST_P(HapticGeneratorScalesTest, SetAndUpdateMultipleVector) {
+    EXPECT_NO_FATAL_FAILURE(
+            addHapticScaleParam({kHapticScale, kHapticScaleWithMaxId, kHapticScaleWithMinId}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(
+            {kHapticScaleNew, kHapticScaleWithMaxIdNew, kHapticScaleWithMinIdNew}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+    EXPECT_NO_FATAL_FAILURE(
+            addHapticScaleParam({kHapticScale, kHapticScaleWithMaxId, kHapticScaleWithMinId}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+
+    EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
+}
+
+TEST_P(HapticGeneratorScalesTest, SetOneAndAddMoreVector) {
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScale}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMaxId, kHapticScaleWithMinId}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+
+    EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
+}
+
+TEST_P(HapticGeneratorScalesTest, SetMultipleAndAddOneVector) {
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMaxId, kHapticScaleWithMinId}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScale}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+
+    EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
+}
+
+TEST_P(HapticGeneratorScalesTest, SetMultipleVectorRepeat) {
+    EXPECT_NO_FATAL_FAILURE(
+            addHapticScaleParam({kHapticScaleWithMaxId, kHapticScale, kHapticScaleWithMinId}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+    EXPECT_NO_FATAL_FAILURE(
+            addHapticScaleParam({kHapticScaleWithMaxId, kHapticScale, kHapticScaleWithMinId}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+    EXPECT_NO_FATAL_FAILURE(
+            addHapticScaleParam({kHapticScaleWithMaxId, kHapticScale, kHapticScaleWithMinId}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+
+    EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        HapticGeneratorScalesTest, HapticGeneratorScalesTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                IFactory::descriptor, kHapticGeneratorTypeUUID))),
+        [](const testing::TestParamInfo<HapticGeneratorScalesTest::ParamType>& info) {
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString();
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorScalesTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
index 3fd2812..305c243 100644
--- a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
@@ -38,7 +38,7 @@
  */
 enum ParamName { PARAM_INSTANCE_NAME, PARAM_GAIN_MB };
 using LoudnessEnhancerParamTestParam =
-        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>, int>;
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>;
 
 // Every int 32 bit value is a valid gain, so testing the corner cases and one regular value.
 // TODO : Update the test values once range/capability is updated by implementation.
@@ -49,12 +49,12 @@
                                   public EffectHelper {
   public:
     LoudnessEnhancerParamTest() : mParamGainMb(std::get<PARAM_GAIN_MB>(GetParam())) {
-        std::tie(mFactory, mIdentity) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
     }
 
     void SetUp() override {
         ASSERT_NE(nullptr, mFactory);
-        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mIdentity));
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
         Parameter::Specific specific = getDefaultParamSpecific();
         Parameter::Common common = EffectHelper::createParamCommon(
@@ -79,7 +79,7 @@
     static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
     std::shared_ptr<IFactory> mFactory;
     std::shared_ptr<IEffect> mEffect;
-    Descriptor::Identity mIdentity;
+    Descriptor mDescriptor;
     int mParamGainMb = 0;
 
     void SetAndGetParameters() {
@@ -130,9 +130,11 @@
                                    IFactory::descriptor, kLoudnessEnhancerTypeUUID)),
                            testing::ValuesIn(kGainMbValues)),
         [](const testing::TestParamInfo<LoudnessEnhancerParamTest::ParamType>& info) {
-            auto instance = std::get<PARAM_INSTANCE_NAME>(info.param);
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
             std::string gainMb = std::to_string(std::get<PARAM_GAIN_MB>(info.param));
-            std::string name = instance.second.uuid.toString() + "_gainMb_" + gainMb;
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_gainMb_" + gainMb;
             std::replace_if(
                     name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
             return name;
diff --git a/audio/aidl/vts/VtsHalNSTargetTest.cpp b/audio/aidl/vts/VtsHalNSTargetTest.cpp
new file mode 100644
index 0000000..93ad86d
--- /dev/null
+++ b/audio/aidl/vts/VtsHalNSTargetTest.cpp
@@ -0,0 +1,155 @@
+/*
+ * 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.
+ */
+
+#include <Utils.h>
+#include <aidl/Vintf.h>
+#include <android/binder_enums.h>
+#include <unordered_set>
+
+#define LOG_TAG "VtsHalNSParamTest"
+
+#include <aidl/android/hardware/audio/effect/NoiseSuppression.h>
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kNoiseSuppressionTypeUUID;
+using aidl::android::hardware::audio::effect::NoiseSuppression;
+using aidl::android::hardware::audio::effect::Parameter;
+
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_LEVEL };
+using NSParamTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, NoiseSuppression::Level>;
+
+class NSParamTest : public ::testing::TestWithParam<NSParamTestParam>, public EffectHelper {
+  public:
+    NSParamTest() : mLevel(std::get<PARAM_LEVEL>(GetParam())) {
+        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() {
+        NoiseSuppression ns =
+                NoiseSuppression::make<NoiseSuppression::level>(NoiseSuppression::Level::MEDIUM);
+        Parameter::Specific specific =
+                Parameter::Specific::make<Parameter::Specific::noiseSuppression>(ns);
+        return specific;
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+    NoiseSuppression::Level mLevel;
+
+    void SetAndGetParameters() {
+        for (auto& it : mTags) {
+            auto& tag = it.first;
+            auto& ns = it.second;
+
+            // validate parameter
+            Descriptor desc;
+            ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+            const binder_exception_t expected = EX_NONE;
+
+            // set parameter
+            Parameter expectParam;
+            Parameter::Specific specific;
+            specific.set<Parameter::Specific::noiseSuppression>(ns);
+            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;
+                NoiseSuppression::Id specificId;
+                specificId.set<NoiseSuppression::Id::commonTag>(tag);
+                id.set<Parameter::Id::noiseSuppressionTag>(specificId);
+                EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+
+                EXPECT_EQ(expectParam, getParam) << "\nexpect:" << expectParam.toString()
+                                                 << "\ngetParam:" << getParam.toString();
+            }
+        }
+    }
+
+    void addLevelParam(NoiseSuppression::Level level) {
+        NoiseSuppression ns;
+        ns.set<NoiseSuppression::level>(level);
+        mTags.push_back({NoiseSuppression::level, ns});
+    }
+    static std::unordered_set<NoiseSuppression::Level> getLevelValues() {
+        return {ndk::enum_range<NoiseSuppression::Level>().begin(),
+                ndk::enum_range<NoiseSuppression::Level>().end()};
+    }
+
+  private:
+    std::vector<std::pair<NoiseSuppression::Tag, NoiseSuppression>> mTags;
+    void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(NSParamTest, SetAndGetLevel) {
+    EXPECT_NO_FATAL_FAILURE(addLevelParam(mLevel));
+    SetAndGetParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        NSParamTest, NSParamTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kNoiseSuppressionTypeUUID)),
+                           testing::ValuesIn(NSParamTest::getLevelValues())),
+        [](const testing::TestParamInfo<NSParamTest::ParamType>& info) {
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string level = aidl::android::hardware::audio::effect::toString(
+                    std::get<PARAM_LEVEL>(info.param));
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_level_" + level;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(NSParamTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp b/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp
new file mode 100644
index 0000000..19d5747
--- /dev/null
+++ b/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp
@@ -0,0 +1,178 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "VtsHalPresetReverbTargetTest"
+
+#include <Utils.h>
+#include <aidl/Vintf.h>
+#include <android/binder_enums.h>
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kEffectNullUuid;
+using aidl::android::hardware::audio::effect::kPresetReverbTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+using aidl::android::hardware::audio::effect::PresetReverb;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_PRESETS };
+using PresetReverbParamTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, PresetReverb::Presets>;
+
+// Testing for enum values
+const std::vector<PresetReverb::Presets> kPresetsValues{
+        ndk::enum_range<PresetReverb::Presets>().begin(),
+        ndk::enum_range<PresetReverb::Presets>().end()};
+
+class PresetReverbParamTest : public ::testing::TestWithParam<PresetReverbParamTestParam>,
+                              public EffectHelper {
+  public:
+    PresetReverbParamTest() : mParamPresets(std::get<PARAM_PRESETS>(GetParam())) {
+        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));
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+    PresetReverb::Presets mParamPresets = PresetReverb::Presets::NONE;
+
+    void SetAndGetPresetReverbParameters() {
+        for (auto& it : mTags) {
+            auto& tag = it.first;
+            auto& pr = it.second;
+
+            // validate parameter
+            Descriptor desc;
+            ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+            const bool valid = isTagInRange(it.first, 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::presetReverb>(pr);
+            expectParam.set<Parameter::specific>(specific);
+            // All values are valid, set parameter should succeed
+            EXPECT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+            // get parameter
+            Parameter getParam;
+            Parameter::Id id;
+            PresetReverb::Id prId;
+            prId.set<PresetReverb::Id::commonTag>(tag);
+            id.set<Parameter::Id::presetReverbTag>(prId);
+            EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
+
+            EXPECT_EQ(expectParam, getParam);
+        }
+    }
+
+    void addPresetsParam(PresetReverb::Presets preset) {
+        PresetReverb pr;
+        pr.set<PresetReverb::preset>(preset);
+        mTags.push_back({PresetReverb::preset, pr});
+    }
+
+    bool isTagInRange(const PresetReverb::Tag& tag, const PresetReverb& pr,
+                      const Descriptor& desc) const {
+        const PresetReverb::Capability& prCap = desc.capability.get<Capability::presetReverb>();
+        switch (tag) {
+            case PresetReverb::preset: {
+                PresetReverb::Presets preset = pr.get<PresetReverb::preset>();
+                return isPresetInRange(prCap, preset);
+            }
+            default:
+                return false;
+        }
+        return false;
+    }
+
+    bool isPresetInRange(const PresetReverb::Capability& cap, PresetReverb::Presets preset) const {
+        for (auto i : cap.supportedPresets) {
+            if (preset == i) return true;
+        }
+        return false;
+    }
+
+    Parameter::Specific getDefaultParamSpecific() {
+        PresetReverb pr = PresetReverb::make<PresetReverb::preset>(PresetReverb::Presets::NONE);
+        Parameter::Specific specific =
+                Parameter::Specific::make<Parameter::Specific::presetReverb>(pr);
+        return specific;
+    }
+
+  private:
+    std::vector<std::pair<PresetReverb::Tag, PresetReverb>> mTags;
+    void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(PresetReverbParamTest, SetAndGetPresets) {
+    EXPECT_NO_FATAL_FAILURE(addPresetsParam(mParamPresets));
+    SetAndGetPresetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        PresetReverbTest, PresetReverbParamTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kPresetReverbTypeUUID)),
+                           testing::ValuesIn(kPresetsValues)),
+        [](const testing::TestParamInfo<PresetReverbParamTest::ParamType>& info) {
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string preset =
+                    std::to_string(static_cast<int>(std::get<PARAM_PRESETS>(info.param)));
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_preset" + preset;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PresetReverbParamTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp b/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
new file mode 100644
index 0000000..090de17
--- /dev/null
+++ b/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
@@ -0,0 +1,198 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "VtsHalVirtualizerTest"
+
+#include <Utils.h>
+#include <aidl/Vintf.h>
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kVirtualizerTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+using aidl::android::hardware::audio::effect::Virtualizer;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_STRENGTH };
+using VirtualizerParamTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>;
+
+/*
+ * Testing parameter range, assuming the parameter supported by effect is in this range.
+ * Parameter should be within the valid range defined in the documentation,
+ * for any supported value test expects EX_NONE from IEffect.setParameter(),
+ * otherwise expect EX_ILLEGAL_ARGUMENT.
+ */
+
+class VirtualizerParamTest : public ::testing::TestWithParam<VirtualizerParamTestParam>,
+                             public EffectHelper {
+  public:
+    VirtualizerParamTest() : mParamStrength(std::get<PARAM_STRENGTH>(GetParam())) {
+        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() {
+        Virtualizer vr = Virtualizer::make<Virtualizer::strengthPm>(0);
+        Parameter::Specific specific =
+                Parameter::Specific::make<Parameter::Specific::virtualizer>(vr);
+        return specific;
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+    int mParamStrength = 0;
+
+    void SetAndGetVirtualizerParameters() {
+        for (auto& it : mTags) {
+            auto& tag = it.first;
+            auto& vr = it.second;
+
+            // validate parameter
+            Descriptor desc;
+            ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+            const bool valid = isTagInRange(it.first, 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::virtualizer>(vr);
+            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;
+                Virtualizer::Id vrId;
+                vrId.set<Virtualizer::Id::commonTag>(tag);
+                id.set<Parameter::Id::virtualizerTag>(vrId);
+                // if set success, then get should match
+                EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
+                EXPECT_EQ(expectParam, getParam);
+            }
+        }
+    }
+
+    void addStrengthParam(int strength) {
+        Virtualizer vr;
+        vr.set<Virtualizer::strengthPm>(strength);
+        mTags.push_back({Virtualizer::strengthPm, vr});
+    }
+
+    bool isTagInRange(const Virtualizer::Tag& tag, const Virtualizer& vr,
+                      const Descriptor& desc) const {
+        const Virtualizer::Capability& vrCap = desc.capability.get<Capability::virtualizer>();
+        switch (tag) {
+            case Virtualizer::strengthPm: {
+                int strength = vr.get<Virtualizer::strengthPm>();
+                return isStrengthInRange(vrCap, strength);
+            }
+            default:
+                return false;
+        }
+        return false;
+    }
+
+    bool isStrengthInRange(const Virtualizer::Capability& cap, int strength) const {
+        return cap.strengthSupported && strength >= 0 && strength <= cap.maxStrengthPm;
+    }
+
+    static std::vector<int> getStrengthTestValues(
+            std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kFactoryDescList) {
+        const auto max = std::max_element(
+                kFactoryDescList.begin(), kFactoryDescList.end(),
+                [](const std::pair<std::shared_ptr<IFactory>, Descriptor>& a,
+                   const std::pair<std::shared_ptr<IFactory>, Descriptor>& b) {
+                    return a.second.capability.get<Capability::virtualizer>().maxStrengthPm <
+                           b.second.capability.get<Capability::virtualizer>().maxStrengthPm;
+                });
+        if (max == kFactoryDescList.end()) {
+            return {0};
+        }
+        int maxStrength = max->second.capability.get<Capability::virtualizer>().maxStrengthPm;
+        return {std::numeric_limits<int>::min(),
+                -1,
+                0,
+                maxStrength >> 1,
+                maxStrength,
+                maxStrength + 1,
+                std::numeric_limits<int>::max()};
+    }
+
+  private:
+    std::vector<std::pair<Virtualizer::Tag, Virtualizer>> mTags;
+    void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(VirtualizerParamTest, SetAndGetStrength) {
+    EXPECT_NO_FATAL_FAILURE(addStrengthParam(mParamStrength));
+    SetAndGetVirtualizerParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        VirtualizerTest, VirtualizerParamTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kVirtualizerTypeUUID)),
+                           testing::ValuesIn(VirtualizerParamTest::getStrengthTestValues(
+                                   EffectFactoryHelper::getAllEffectDescriptors(
+                                           IFactory::descriptor, kVirtualizerTypeUUID)))),
+        [](const testing::TestParamInfo<VirtualizerParamTest::ParamType>& info) {
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string strength = std::to_string(std::get<PARAM_STRENGTH>(info.param));
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_strength" + strength;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VirtualizerParamTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
new file mode 100644
index 0000000..242be3f
--- /dev/null
+++ b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
@@ -0,0 +1,366 @@
+/*
+ * 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.
+ */
+
+#include <aidl/Vintf.h>
+
+#define LOG_TAG "VtsHalVisualizerTest"
+
+#include <Utils.h>
+#include <android/binder_enums.h>
+#include <unordered_set>
+
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kVisualizerTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+using aidl::android::hardware::audio::effect::Visualizer;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+enum ParamName {
+    PARAM_INSTANCE_NAME,
+    PARAM_CAPTURE_SIZE,
+    PARAM_SCALING_MODE,
+    PARAM_MEASUREMENT_MODE,
+    PARAM_LATENCY,
+};
+using VisualizerParamTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int, Visualizer::ScalingMode,
+                   Visualizer::MeasurementMode, int>;
+
+class VisualizerParamTest : public ::testing::TestWithParam<VisualizerParamTestParam>,
+                            public EffectHelper {
+  public:
+    VisualizerParamTest()
+        : mCaptureSize(std::get<PARAM_CAPTURE_SIZE>(GetParam())),
+          mScalingMode(std::get<PARAM_SCALING_MODE>(GetParam())),
+          mMeasurementMode(std::get<PARAM_MEASUREMENT_MODE>(GetParam())),
+          mLatency(std::get<PARAM_LATENCY>(GetParam())) {
+        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() {
+        Visualizer vs = Visualizer::make<Visualizer::captureSamples>(
+                mDescriptor.capability.get<Capability::visualizer>().captureSampleRange.max);
+        Parameter::Specific specific =
+                Parameter::Specific::make<Parameter::Specific::visualizer>(vs);
+        return specific;
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+    int mCaptureSize;
+    Visualizer::ScalingMode mScalingMode = Visualizer::ScalingMode::NORMALIZED;
+    Visualizer::MeasurementMode mMeasurementMode = Visualizer::MeasurementMode::NONE;
+    int mLatency = 0;
+
+    void SetAndGetCommonParameters() {
+        for (auto& it : mCommonTags) {
+            auto& tag = it.first;
+            auto& vs = it.second;
+
+            // validate parameter
+            Descriptor desc;
+            ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+            const bool valid = isTagInRange(tag, vs, desc);
+            const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+            // set parameter
+            Parameter expectParam;
+            Parameter::Specific specific;
+            specific.set<Parameter::Specific::visualizer>(vs);
+            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;
+                Visualizer::Id vsId;
+                vsId.set<Visualizer::Id::commonTag>(tag);
+                id.set<Parameter::Id::visualizerTag>(vsId);
+                EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+
+                EXPECT_EQ(expectParam, getParam) << "\nexpect:" << expectParam.toString()
+                                                 << "\ngetParam:" << getParam.toString();
+            }
+        }
+    }
+
+    void SetAndGetSetOnlyParameters() {
+        for (auto& it : mSetOnlyParamTags) {
+            auto& tag = it.first;
+            auto& vs = it.second;
+
+            // validate parameter
+            Descriptor desc;
+            ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+            const bool valid = isSetOnlyParamTagInRange(vs, desc);
+            const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+            // set parameter
+            Parameter expectParam;
+            Parameter::Specific specific;
+            specific.set<Parameter::Specific::visualizer>(vs);
+            expectParam.set<Parameter::specific>(specific);
+            ASSERT_STATUS(expected, mEffect->setParameter(expectParam));
+
+            //  parameter defined in this setOnlyParameter union must be settable via
+            //  setParameter(), but must not be gettable
+            Parameter getParam;
+            Parameter::Id id;
+            Visualizer::Id vsId;
+            vsId.set<Visualizer::Id::setOnlyParamTag>(tag);
+            id.set<Parameter::Id::visualizerTag>(vsId);
+            EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, mEffect->getParameter(id, &getParam));
+        }
+    }
+
+    void GetandSetGetOnlyParameters() {
+        for (auto& tag : mGetOnlyParamTags) {
+            // get parameter
+            Parameter getParam;
+            Parameter::Id id;
+            Visualizer::Id vsId;
+            vsId.set<Visualizer::Id::getOnlyParamTag>(tag);
+            id.set<Parameter::Id::visualizerTag>(vsId);
+            ASSERT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+
+            //  parameter defined in this getOnlyParameter union must be gettable via
+            //  getParameter(), but must not be settable
+            // set parameter
+            ASSERT_STATUS(EX_ILLEGAL_ARGUMENT, mEffect->setParameter(getParam));
+        }
+    }
+
+    void addCaptureSizeParam(int captureSize) {
+        Visualizer vs;
+        vs.set<Visualizer::captureSamples>(captureSize);
+        mCommonTags.push_back({Visualizer::captureSamples, vs});
+    }
+
+    void addScalingModeParam(Visualizer::ScalingMode scalingMode) {
+        Visualizer vs;
+        vs.set<Visualizer::scalingMode>(scalingMode);
+        mCommonTags.push_back({Visualizer::scalingMode, vs});
+    }
+
+    void addMeasurementModeParam(Visualizer::MeasurementMode measurementMode) {
+        Visualizer vs;
+        vs.set<Visualizer::measurementMode>(measurementMode);
+        mCommonTags.push_back({Visualizer::measurementMode, vs});
+    }
+
+    void addLatencyParam(int latency) {
+        Visualizer vs;
+        Visualizer::SetOnlyParameters setOnlyParam;
+        setOnlyParam.set<Visualizer::SetOnlyParameters::latencyMs>(latency);
+        vs.set<Visualizer::setOnlyParameters>(setOnlyParam);
+        mSetOnlyParamTags.push_back({Visualizer::SetOnlyParameters::latencyMs, vs});
+    }
+
+    void addMeasurementTag() {
+        mGetOnlyParamTags.push_back(Visualizer::GetOnlyParameters::measurement);
+    }
+
+    void addCaptureBytesTag() {
+        mGetOnlyParamTags.push_back(Visualizer::GetOnlyParameters::captureSampleBuffer);
+    }
+
+    bool isTagInRange(const Visualizer::Tag& tag, const Visualizer& vs,
+                      const Descriptor& desc) const {
+        const Visualizer::Capability& vsCap = desc.capability.get<Capability::visualizer>();
+        switch (tag) {
+            case Visualizer::captureSamples: {
+                int captureSize = vs.get<Visualizer::captureSamples>();
+                return captureSize >= vsCap.captureSampleRange.min &&
+                       captureSize <= vsCap.captureSampleRange.max;
+            }
+            case Visualizer::scalingMode:
+            case Visualizer::measurementMode:
+                return true;
+            case Visualizer::setOnlyParameters: {
+                auto setOnly = vs.get<Visualizer::setOnlyParameters>();
+                if (setOnly.getTag() != Visualizer::SetOnlyParameters::latencyMs) {
+                    return false;
+                }
+                auto latencyMs = setOnly.get<Visualizer::SetOnlyParameters::latencyMs>();
+                return latencyMs >= 0 && latencyMs <= vsCap.maxLatencyMs;
+            }
+            default:
+                return false;
+        }
+    }
+
+    bool isSetOnlyParamTagInRange(const Visualizer& vs, const Descriptor& desc) const {
+        const Visualizer::Capability& vsCap = desc.capability.get<Capability::visualizer>();
+        if (vs.getTag() != Visualizer::setOnlyParameters) return false;
+        Visualizer::SetOnlyParameters setOnlyParam = vs.get<Visualizer::setOnlyParameters>();
+        if (setOnlyParam.getTag() != Visualizer::SetOnlyParameters::latencyMs) return false;
+        int latency = setOnlyParam.get<Visualizer::SetOnlyParameters::latencyMs>();
+        return isLatencyInRange(vsCap, latency);
+    }
+
+    bool isLatencyInRange(const Visualizer::Capability& cap, int latency) const {
+        return (latency >= 0 && latency <= cap.maxLatencyMs);
+    }
+
+    static std::unordered_set<int> getCaptureSizeValues() {
+        auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+                                                                     kVisualizerTypeUUID);
+        int minCaptureSize = std::numeric_limits<int>::max();
+        int maxCaptureSize = std::numeric_limits<int>::min();
+        for (const auto& it : descList) {
+            maxCaptureSize = std::max(
+                    it.second.capability.get<Capability::visualizer>().captureSampleRange.max,
+                    maxCaptureSize);
+            minCaptureSize = std::min(
+                    it.second.capability.get<Capability ::visualizer>().captureSampleRange.min,
+                    minCaptureSize);
+        }
+        return {std::numeric_limits<int>::min(),        minCaptureSize - 1, minCaptureSize,
+                (minCaptureSize + maxCaptureSize) >> 1, maxCaptureSize,     maxCaptureSize + 1,
+                std::numeric_limits<int>::max()};
+    }
+
+    static std::unordered_set<int> getLatencyValues() {
+        auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+                                                                     kVisualizerTypeUUID);
+        const auto max = std::max_element(
+                descList.begin(), descList.end(),
+                [](const std::pair<std::shared_ptr<IFactory>, Descriptor>& a,
+                   const std::pair<std::shared_ptr<IFactory>, Descriptor>& b) {
+                    return a.second.capability.get<Capability::visualizer>().maxLatencyMs <
+                           b.second.capability.get<Capability::visualizer>().maxLatencyMs;
+                });
+        if (max == descList.end()) {
+            return {0};
+        }
+        int maxDelay = max->second.capability.get<Capability::visualizer>().maxLatencyMs;
+        return {-1, 0, maxDelay >> 1, maxDelay - 1, maxDelay, maxDelay + 1};
+    }
+    static std::unordered_set<Visualizer::MeasurementMode> getMeasurementModeValues() {
+        return {ndk::enum_range<Visualizer::MeasurementMode>().begin(),
+                ndk::enum_range<Visualizer::MeasurementMode>().end()};
+    }
+    static std::unordered_set<Visualizer::ScalingMode> getScalingModeValues() {
+        return {ndk::enum_range<Visualizer::ScalingMode>().begin(),
+                ndk::enum_range<Visualizer::ScalingMode>().end()};
+    }
+
+  private:
+    std::vector<std::pair<Visualizer::Tag, Visualizer>> mCommonTags;
+    std::vector<std::pair<Visualizer::SetOnlyParameters::Tag, Visualizer>> mSetOnlyParamTags;
+    std::vector<Visualizer::GetOnlyParameters::Tag> mGetOnlyParamTags;
+    void CleanUp() {
+        mCommonTags.clear();
+        mSetOnlyParamTags.clear();
+        mGetOnlyParamTags.clear();
+    }
+};
+
+TEST_P(VisualizerParamTest, SetAndGetCaptureSize) {
+    EXPECT_NO_FATAL_FAILURE(addCaptureSizeParam(mCaptureSize));
+    SetAndGetCommonParameters();
+}
+
+TEST_P(VisualizerParamTest, SetAndGetScalingMode) {
+    EXPECT_NO_FATAL_FAILURE(addScalingModeParam(mScalingMode));
+    SetAndGetCommonParameters();
+}
+
+TEST_P(VisualizerParamTest, SetAndGetMeasurementMode) {
+    EXPECT_NO_FATAL_FAILURE(addMeasurementModeParam(mMeasurementMode));
+    SetAndGetCommonParameters();
+}
+
+TEST_P(VisualizerParamTest, SetAndGetLatency) {
+    EXPECT_NO_FATAL_FAILURE(addLatencyParam(mLatency));
+    SetAndGetSetOnlyParameters();
+}
+
+TEST_P(VisualizerParamTest, GetAndSetMeasurement) {
+    EXPECT_NO_FATAL_FAILURE(addMeasurementTag());
+    GetandSetGetOnlyParameters();
+}
+
+TEST_P(VisualizerParamTest, GetAndSetCaptureBytes) {
+    EXPECT_NO_FATAL_FAILURE(addCaptureBytesTag());
+    GetandSetGetOnlyParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        VisualizerParamTest, VisualizerParamTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kVisualizerTypeUUID)),
+                           testing::ValuesIn(VisualizerParamTest::getCaptureSizeValues()),
+                           testing::ValuesIn(VisualizerParamTest::getScalingModeValues()),
+                           testing::ValuesIn(VisualizerParamTest::getMeasurementModeValues()),
+                           testing::ValuesIn(VisualizerParamTest::getLatencyValues())),
+        [](const testing::TestParamInfo<VisualizerParamTest::ParamType>& info) {
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string captureSize = std::to_string(std::get<PARAM_CAPTURE_SIZE>(info.param));
+            std::string scalingMode = aidl::android::hardware::audio::effect::toString(
+                    std::get<PARAM_SCALING_MODE>(info.param));
+            std::string measurementMode = aidl::android::hardware::audio::effect::toString(
+                    std::get<PARAM_MEASUREMENT_MODE>(info.param));
+            std::string latency = std::to_string(std::get<PARAM_LATENCY>(info.param));
+
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_captureSize" + captureSize +
+                               "_scalingMode" + scalingMode + "_measurementMode" + measurementMode +
+                               "_latency" + latency;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VisualizerParamTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/audio/aidl/vts/VtsHalVolumeTargetTest.cpp b/audio/aidl/vts/VtsHalVolumeTargetTest.cpp
new file mode 100644
index 0000000..34625e7
--- /dev/null
+++ b/audio/aidl/vts/VtsHalVolumeTargetTest.cpp
@@ -0,0 +1,206 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "VtsHalVolumeTest"
+
+#include <Utils.h>
+#include <aidl/Vintf.h>
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kVolumeTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+using aidl::android::hardware::audio::effect::Volume;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_LEVEL, PARAM_MUTE };
+using VolumeParamTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int, bool>;
+
+class VolumeParamTest : public ::testing::TestWithParam<VolumeParamTestParam>, public EffectHelper {
+  public:
+    VolumeParamTest()
+        : mParamLevel(std::get<PARAM_LEVEL>(GetParam())),
+          mParamMute(std::get<PARAM_MUTE>(GetParam())) {
+        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() {
+        Volume vol = Volume::make<Volume::levelDb>(-9600);
+        Parameter::Specific specific = Parameter::Specific::make<Parameter::Specific::volume>(vol);
+        return specific;
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+    int mParamLevel = 0;
+    bool mParamMute = false;
+
+    void SetAndGetParameters() {
+        for (auto& it : mTags) {
+            auto& tag = it.first;
+            auto& vol = it.second;
+
+            // validate parameter
+            Descriptor desc;
+            ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+            // only set and get parameter if capability is valid
+            ASSERT_TRUE(isCapabilityValid(desc));
+            const bool valid = isTagInRange(it.first, 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::volume>(vol);
+            expectParam.set<Parameter::specific>(specific);
+            EXPECT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+            // only get if parameter is in range and set success
+            if (expected == EX_NONE) {
+                Parameter getParam;
+                Parameter::Id id;
+                Volume::Id volId;
+                volId.set<Volume::Id::commonTag>(tag);
+                id.set<Parameter::Id::volumeTag>(volId);
+                EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+
+                EXPECT_EQ(expectParam, getParam) << "\nexpect:" << expectParam.toString()
+                                                 << "\ngetParam:" << getParam.toString();
+            }
+        }
+    }
+
+    void addLevelParam(int level) {
+        Volume vol;
+        vol.set<Volume::levelDb>(level);
+        mTags.push_back({Volume::levelDb, vol});
+    }
+
+    void addMuteParam(bool mute) {
+        Volume vol;
+        vol.set<Volume::mute>(mute);
+        mTags.push_back({Volume::mute, vol});
+    }
+
+    bool isCapabilityValid(const Descriptor& desc) {
+        const Volume::Capability& volCap = desc.capability.get<Capability::volume>();
+        return (volCap.minLevelDb <= volCap.maxLevelDb);
+    }
+
+    bool isTagInRange(const Volume::Tag& tag, const Volume& vol, const Descriptor& desc) const {
+        const Volume::Capability& volCap = desc.capability.get<Capability::volume>();
+        switch (tag) {
+            case Volume::levelDb: {
+                int level = vol.get<Volume::levelDb>();
+                return isLevelInRange(volCap, level);
+            }
+            case Volume::mute:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    static std::vector<int> getLevelTestValues(
+            std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kFactoryDescList) {
+        int minLevelDb = std::numeric_limits<int>::max();
+        int maxLevelDb = std::numeric_limits<int>::min();
+        for (const auto& it : kFactoryDescList) {
+            maxLevelDb =
+                    std::max(it.second.capability.get<Capability::volume>().maxLevelDb, maxLevelDb);
+            minLevelDb = std::min(it.second.capability.get<Capability ::volume>().minLevelDb,
+                                  minLevelDb);
+        }
+        return {minLevelDb - 1, minLevelDb, -100, maxLevelDb, maxLevelDb + 1};
+    }
+
+    bool isLevelInRange(const Volume::Capability& volCap, int level) const {
+        return level >= volCap.minLevelDb && level <= volCap.maxLevelDb;
+    }
+
+  private:
+    std::vector<std::pair<Volume::Tag, Volume>> mTags;
+    void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(VolumeParamTest, SetAndGetLevel) {
+    EXPECT_NO_FATAL_FAILURE(addLevelParam(mParamLevel));
+    SetAndGetParameters();
+}
+
+TEST_P(VolumeParamTest, SetAndGetMute) {
+    EXPECT_NO_FATAL_FAILURE(addMuteParam(mParamMute));
+    SetAndGetParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        VolumeTest, VolumeParamTest,
+        ::testing::Combine(
+                testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+                                                                               kVolumeTypeUUID)),
+                testing::ValuesIn(VolumeParamTest::getLevelTestValues(
+                        EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+                                                                     kVolumeTypeUUID))),
+                testing::Bool() /* mute */),
+        [](const testing::TestParamInfo<VolumeParamTest::ParamType>& info) {
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string level = std::to_string(std::get<PARAM_LEVEL>(info.param));
+            std::string mute = std::to_string(std::get<PARAM_MUTE>(info.param));
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_level" + level + "_mute" +
+                               mute;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VolumeParamTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/audio/common/7.0/enums/OWNERS b/audio/common/7.0/enums/OWNERS
deleted file mode 100644
index 24071af..0000000
--- a/audio/common/7.0/enums/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/common/7.0/example/OWNERS b/audio/common/7.0/example/OWNERS
deleted file mode 100644
index 24071af..0000000
--- a/audio/common/7.0/example/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/common/7.1/enums/OWNERS b/audio/common/7.1/enums/OWNERS
deleted file mode 100644
index 24071af..0000000
--- a/audio/common/7.1/enums/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/common/all-versions/OWNERS b/audio/common/all-versions/OWNERS
deleted file mode 100644
index 24071af..0000000
--- a/audio/common/all-versions/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/common/all-versions/default/OWNERS b/audio/common/all-versions/default/OWNERS
deleted file mode 100644
index 24071af..0000000
--- a/audio/common/all-versions/default/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/common/all-versions/default/service/Android.bp b/audio/common/all-versions/default/service/Android.bp
index 9890be2..2fcfb23 100644
--- a/audio/common/all-versions/default/service/Android.bp
+++ b/audio/common/all-versions/default/service/Android.bp
@@ -38,9 +38,15 @@
     name: "android.hardware.audio.service",
 
     init_rc: ["android.hardware.audio.service.rc"],
+    vintf_fragments: ["android.hardware.audio.sounddose-aidl.xml"],
     relative_install_path: "hw",
     vendor: true,
 
+    defaults: [
+        "android_hardware_audio_config_defaults",
+        "latest_android_hardware_audio_sounddose_ndk_shared",
+    ],
+
     srcs: ["service.cpp"],
 
     cflags: [
@@ -50,6 +56,7 @@
     ],
 
     shared_libs: [
+        "//hardware/interfaces/audio/aidl/sounddose/default:libsounddoseserviceexampleimpl",
         "libcutils",
         "libbinder",
         "libbinder_ndk",
@@ -58,10 +65,6 @@
         "libutils",
         "libhardware",
     ],
-
-    defaults: [
-        "android_hardware_audio_config_defaults",
-    ],
 }
 
 // Legacy service name, use android.hardware.audio.service instead
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 45fef9a..0de4eea 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
@@ -3,7 +3,9 @@
     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
-    capabilities BLOCK_SUSPEND
+    capabilities BLOCK_SUSPEND SYS_NICE
+    # setting RLIMIT_RTPRIO allows binder RT priority inheritance
+    rlimit rtprio 10 10
     ioprio rt 4
     task_profiles ProcessCapacityHigh HighPerformance
     onrestart restart audioserver
diff --git a/audio/common/all-versions/default/service/android.hardware.audio.sounddose-aidl.xml b/audio/common/all-versions/default/service/android.hardware.audio.sounddose-aidl.xml
new file mode 100644
index 0000000..a297bfb
--- /dev/null
+++ b/audio/common/all-versions/default/service/android.hardware.audio.sounddose-aidl.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+  <hal format="aidl">
+    <name>android.hardware.audio.sounddose</name>
+    <version>1</version>
+    <fqname>ISoundDoseFactory/default</fqname>
+  </hal>
+</manifest>
diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp
index fbf6165..e79ad75 100644
--- a/audio/common/all-versions/default/service/service.cpp
+++ b/audio/common/all-versions/default/service/service.cpp
@@ -20,6 +20,10 @@
 #include <string>
 #include <vector>
 
+#include <SoundDoseFactory.h>
+#include <android-base/logging.h>
+#include <android/binder_ibinder_platform.h>
+#include <android/binder_manager.h>
 #include <android/binder_process.h>
 #include <binder/ProcessState.h>
 #include <cutils/properties.h>
@@ -33,6 +37,8 @@
 
 using InterfacesList = std::vector<std::string>;
 
+using aidl::android::hardware::audio::sounddose::SoundDoseFactory;
+
 /** Try to register the provided factories in the provided order.
  *  If any registers successfully, do not register any other and return true.
  *  If all fail, return false.
@@ -164,5 +170,13 @@
         }
     }
 
+    // Register ISoundDoseFactory interface as a workaround for using the audio AIDL HAL
+    auto soundDoseDefault = ndk::SharedRefBase::make<SoundDoseFactory>();
+    const std::string soundDoseDefaultName =
+            std::string() + SoundDoseFactory::descriptor + "/default";
+    binder_status_t status = AServiceManager_addService(soundDoseDefault->asBinder().get(),
+                                                        soundDoseDefaultName.c_str());
+    CHECK_EQ(STATUS_OK, status);
+
     joinRpcThreadpool();
 }
diff --git a/audio/core/all-versions/OWNERS b/audio/core/all-versions/OWNERS
deleted file mode 100644
index f9a2d6b..0000000
--- a/audio/core/all-versions/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 48436
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp
index b954fcd..d03118a 100644
--- a/audio/core/all-versions/default/Device.cpp
+++ b/audio/core/all-versions/default/Device.cpp
@@ -30,6 +30,7 @@
 #include <algorithm>
 
 #include <android/log.h>
+#include <hidl/HidlTransportSupport.h>
 #include <mediautils/MemoryLeakTrackUtil.h>
 #include <memunreachable/memunreachable.h>
 
@@ -183,6 +184,7 @@
     if (status == OK) {
         streamOut = new StreamOut(this, halStream);
         ++mOpenedStreamsCount;
+        android::hardware::setMinSchedulerPolicy(streamOut, SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
     }
     status_t convertStatus =
             HidlUtils::audioConfigFromHal(halConfig, false /*isInput*/, suggestedConfig);
@@ -220,6 +222,7 @@
     if (status == OK) {
         streamIn = new StreamIn(this, halStream);
         ++mOpenedStreamsCount;
+        android::hardware::setMinSchedulerPolicy(streamIn, SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
     }
     status_t convertStatus =
             HidlUtils::audioConfigFromHal(halConfig, true /*isInput*/, suggestedConfig);
diff --git a/audio/core/all-versions/default/DevicesFactory.cpp b/audio/core/all-versions/default/DevicesFactory.cpp
index f44daf0..011f9ac 100644
--- a/audio/core/all-versions/default/DevicesFactory.cpp
+++ b/audio/core/all-versions/default/DevicesFactory.cpp
@@ -23,6 +23,8 @@
 #include <string.h>
 
 #include <android/log.h>
+#include <hidl/HidlTransportSupport.h>
+#include <system/thread_defs.h>
 
 namespace android {
 namespace hardware {
@@ -103,6 +105,7 @@
     int halStatus = loadAudioInterface(moduleName, &halDevice);
     if (halStatus == OK) {
         result = new DeviceShim(halDevice);
+        android::hardware::setMinSchedulerPolicy(result, SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
         retval = Result::OK;
     } else if (halStatus == -EINVAL) {
         retval = Result::NOT_INITIALIZED;
diff --git a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
index 55d4e1d..f6440f2 100644
--- a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
@@ -687,7 +687,12 @@
         InputStreamTest::TearDown();
     }
 
-    bool canQueryCapturePosition() const { return !xsd::isTelephonyDevice(address.deviceType); }
+    bool canQueryCapturePosition() const {
+        // See b/263305254 and b/259636577. Must use the device initially passed in
+        // as a parameter, not 'address' which gets adjusted during test setup for
+        // the telephony case.
+        return !xsd::isTelephonyDevice(getAttachedDeviceAddress().deviceType);
+    }
 
     void createPatchIfNeeded() {
         if (areAudioPatchesSupported()) {
diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp
index f51a8d0..9d93bb0 100644
--- a/audio/core/all-versions/vts/functional/Android.bp
+++ b/audio/core/all-versions/vts/functional/Android.bp
@@ -30,6 +30,7 @@
         "android.hardware.audio.common.test.utility",
         "audioclient-types-aidl-cpp",
         "libaudioclient_aidl_conversion",
+        "libaudio_aidl_conversion_common_cpp",
         "libstagefright_foundation",
     ],
     shared_libs: [
diff --git a/audio/core/all-versions/vts/functional/OWNERS b/audio/core/all-versions/vts/functional/OWNERS
deleted file mode 100644
index 448d9fe..0000000
--- a/audio/core/all-versions/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 48436
-mnaganov@google.com
diff --git a/audio/effect/all-versions/OWNERS b/audio/effect/all-versions/OWNERS
deleted file mode 100644
index f9a2d6b..0000000
--- a/audio/effect/all-versions/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 48436
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/effect/all-versions/default/Effect.cpp b/audio/effect/all-versions/default/Effect.cpp
index b57dc63..87e1ab7 100644
--- a/audio/effect/all-versions/default/Effect.cpp
+++ b/audio/effect/all-versions/default/Effect.cpp
@@ -25,8 +25,11 @@
 #define ATRACE_TAG ATRACE_TAG_AUDIO
 #include <HidlUtils.h>
 #include <android/log.h>
+#include <cutils/properties.h>
 #include <media/EffectsFactoryApi.h>
 #include <mediautils/ScopedStatistics.h>
+#include <sys/syscall.h>
+#include <system/audio_effects/effect_spatializer.h>
 #include <util/EffectUtils.h>
 #include <utils/Trace.h>
 
@@ -47,6 +50,160 @@
 
 namespace {
 
+/**
+ * Some basic scheduling tools.
+ */
+namespace scheduler {
+
+int getCpu() {
+    return sched_getcpu();
+}
+
+uint64_t getAffinity(pid_t tid) {
+    cpu_set_t set;
+    CPU_ZERO_S(sizeof(set), &set);
+
+    if (sched_getaffinity(tid, sizeof(set), &set)) {
+        ALOGW("%s: for tid:%d returning 0, failed %s", __func__, tid, strerror(errno));
+        return 0;
+    }
+    const int count = CPU_COUNT_S(sizeof(set), &set);
+    uint64_t mask = 0;
+    for (int i = 0; i < CPU_SETSIZE; ++i) {
+        if (CPU_ISSET_S(i, sizeof(set), &set)) {
+            mask |= 1 << i;
+        }
+    }
+    ALOGV("%s: for tid:%d returning cpu count %d mask %llu", __func__, tid, count,
+          (unsigned long long)mask);
+    return mask;
+}
+
+status_t setAffinity(pid_t tid, uint64_t mask) {
+    cpu_set_t set;
+    CPU_ZERO_S(sizeof(set), &set);
+
+    for (uint64_t m = mask; m != 0;) {
+        uint64_t tz = __builtin_ctz(m);
+        CPU_SET_S(tz, sizeof(set), &set);
+        m &= ~(1 << tz);
+    }
+    if (sched_setaffinity(tid, sizeof(set), &set)) {
+        ALOGW("%s: for tid:%d setting cpu mask %llu failed %s", __func__, tid,
+              (unsigned long long)mask, strerror(errno));
+        return -errno;
+    }
+    ALOGV("%s: for tid:%d setting cpu mask %llu", __func__, tid, (unsigned long long)mask);
+    return OK;
+}
+
+__unused status_t setPriority(pid_t tid, int policy, int priority) {
+    struct sched_param param {
+        .sched_priority = priority,
+    };
+    if (sched_setscheduler(tid, policy, &param) != 0) {
+        ALOGW("%s: Cannot set FIFO priority for tid %d to policy %d priority %d  %s", __func__, tid,
+              policy, priority, strerror(errno));
+        return -errno;
+    }
+    ALOGV("%s: Successfully set priority for tid %d to policy %d priority %d", __func__, tid,
+          policy, priority);
+    return NO_ERROR;
+}
+
+status_t setUtilMin(pid_t tid, uint32_t utilMin) {
+    // Currently, there is no wrapper in bionic: b/183240349.
+    struct {
+        uint32_t size;
+        uint32_t sched_policy;
+        uint64_t sched_flags;
+        int32_t sched_nice;
+        uint32_t sched_priority;
+        uint64_t sched_runtime;
+        uint64_t sched_deadline;
+        uint64_t sched_period;
+        uint32_t sched_util_min;
+        uint32_t sched_util_max;
+    } attr{
+            .size = sizeof(attr),
+            .sched_flags = SCHED_FLAG_KEEP_ALL | SCHED_FLAG_UTIL_CLAMP_MIN,
+            .sched_util_min = utilMin,
+    };
+
+    if (syscall(__NR_sched_setattr, tid, &attr, 0 /* flags */)) {
+        ALOGW("%s: Cannot set sched_util_min for pid %d to %u  %s", __func__, tid, utilMin,
+              strerror(errno));
+        return -errno;
+    }
+    ALOGV("%s: Successfully set sched_util_min for pid %d to %u", __func__, tid, utilMin);
+    return NO_ERROR;
+}
+
+/*
+   Attempts to raise the priority and usage of tid for spatialization.
+   Returns OK if everything works.
+*/
+status_t updateSpatializerPriority(pid_t tid) {
+    status_t status = OK;
+
+    const int cpu = getCpu();
+    ALOGV("%s: current CPU:%d", __func__, cpu);
+
+    const auto currentAffinity = getAffinity(tid);
+    ALOGV("%s: current Affinity:%llx", __func__, (unsigned long long)currentAffinity);
+
+    // Set the desired CPU core affinity.
+    // Typically this would be done to move the Spatializer effect off of the little cores.
+    // The mid cores and large cores typically have more FP/NEON units
+    // and will advantageously reduce power and prevent glitches due CPU limitations.
+    //
+    // Since this is SOC dependent, we do not set the core affinity here but
+    // prefer to set the util_clamp_min below.
+    //
+    constexpr uint64_t kDefaultAffinity = 0;
+    const int32_t desiredAffinity =
+            property_get_int32("audio.spatializer.effect.affinity", kDefaultAffinity);
+    if (desiredAffinity != 0 && (desiredAffinity & ~currentAffinity) == 0) {
+        const status_t localStatus = setAffinity(tid, desiredAffinity);
+        status = status ? status : localStatus;
+    }
+
+    // Set the util_clamp_min.
+    // This is beneficial to reduce glitches when starting up, or due to scheduler
+    // thread statistics reset (e.g. core migration), which cause the CPU frequency to drop
+    // to minimum.
+    //
+    // Experimentation has found that moving to a mid core over a little core reduces
+    // power if the mid core (e.g. A76/78) has more (e.g. 2x) FP/NEON units
+    // than the little core (e.g. A55).
+    // A possible value is 300.
+    //
+    constexpr uint32_t kUtilMin = 0;
+    const int32_t utilMin = property_get_int32("audio.spatializer.effect.util_clamp_min", kUtilMin);
+    if (utilMin > 0 && utilMin <= 1024) {
+        const status_t localStatus = setUtilMin(tid, utilMin);
+        status = status ? status : localStatus;
+    }
+
+#if 0
+    // Provided for local vendor testing but not enabled as audioserver does this for us.
+    //
+    // Set priority if specified.
+    constexpr int32_t kRTPriorityMin = 1;
+    constexpr int32_t kRTPriorityMax = 3;
+    const int32_t priorityBoost =
+            property_get_int32("audio.spatializer.priority", kRTPriorityMin);
+    if (priorityBoost >= kRTPriorityMin && priorityBoost <= kRTPriorityMax) {
+        const status_t localStatus = scheduler::setPriority(threadId, SCHED_FIFO, priorityBoost);
+        status = status ? status : localStatus;
+    }
+#endif
+
+    return status;
+}
+
+}  // namespace scheduler
+
 #define SCOPED_STATS()                                                       \
     ::android::mediautils::ScopedStatistics scopedStatistics {               \
         std::string("EffectHal::").append(__func__), mEffectHal->mStatistics \
@@ -83,6 +240,16 @@
 };
 
 bool ProcessThread::threadLoop() {
+    // For a spatializer effect, we perform scheduler adjustments to reduce glitches and power.
+    {
+        effect_descriptor_t halDescriptor{};
+        if ((*mEffect)->get_descriptor(mEffect, &halDescriptor) == NO_ERROR &&
+            memcmp(&halDescriptor.type, FX_IID_SPATIALIZER, sizeof(effect_uuid_t)) == 0) {
+            const status_t status = scheduler::updateSpatializerPriority(gettid());
+            ALOGW_IF(status != OK, "Failed to update Spatializer priority");
+        }
+    }
+
     // This implementation doesn't return control back to the Thread until it decides to stop,
     // as the Thread uses mutexes, and this can lead to priority inversion.
     while (!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
@@ -700,8 +867,21 @@
 
     void* dataPtr = halDataSize > 0 ? &halData[0] : NULL;
     void* resultPtr = halResultSize > 0 ? &halResult[0] : NULL;
-    status_t status =
-        (*mHandle)->command(mHandle, commandId, halDataSize, dataPtr, &halResultSize, resultPtr);
+    status_t status = BAD_VALUE;
+    switch (commandId) {
+        case 'gtid':  // retrieve the tid, used for spatializer priority boost
+            if (halDataSize == 0 && resultMaxSize == sizeof(int32_t)) {
+                auto ptid = (int32_t*)resultPtr;
+                ptid[0] = mProcessThread ? mProcessThread->getTid() : -1;
+                status = OK;
+                break;  // we have handled 'gtid' here.
+            }
+            [[fallthrough]];  // allow 'gtid' overload (checked halDataSize and resultMaxSize).
+        default:
+            status = (*mHandle)->command(mHandle, commandId, halDataSize, dataPtr, &halResultSize,
+                                         resultPtr);
+            break;
+    }
     hidl_vec<uint8_t> result;
     if (status == OK && resultPtr != NULL) {
         result.setToExternal(&halResult[0], halResultSize);
diff --git a/audio/effect/all-versions/default/EffectsFactory.cpp b/audio/effect/all-versions/default/EffectsFactory.cpp
index e93ad89..9bf309c 100644
--- a/audio/effect/all-versions/default/EffectsFactory.cpp
+++ b/audio/effect/all-versions/default/EffectsFactory.cpp
@@ -32,6 +32,7 @@
 
 #include <UuidUtils.h>
 #include <android/log.h>
+#include <hidl/HidlTransportSupport.h>
 #include <media/EffectsFactoryApi.h>
 #include <system/audio_effects/effect_aec.h>
 #include <system/audio_effects/effect_agc.h>
@@ -44,6 +45,7 @@
 #include <system/audio_effects/effect_presetreverb.h>
 #include <system/audio_effects/effect_virtualizer.h>
 #include <system/audio_effects/effect_visualizer.h>
+#include <system/thread_defs.h>
 #include <util/EffectUtils.h>
 
 namespace android {
@@ -189,6 +191,7 @@
         status = (*handle)->get_descriptor(handle, &halDescriptor);
         if (status == OK) {
             effect = dispatchEffectInstanceCreation(halDescriptor, handle);
+            android::hardware::setMinSchedulerPolicy(effect, SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
             effectId = EffectMap::getInstance().add(handle);
         } else {
             ALOGE("Error querying effect descriptor for %s: %s",
diff --git a/audio/effect/all-versions/vts/functional/OWNERS b/audio/effect/all-versions/vts/functional/OWNERS
deleted file mode 100644
index 448d9fe..0000000
--- a/audio/effect/all-versions/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 48436
-mnaganov@google.com
diff --git a/audio/policy/1.0/vts/OWNERS b/audio/policy/1.0/vts/OWNERS
deleted file mode 100644
index 24071af..0000000
--- a/audio/policy/1.0/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/policy/1.0/vts/functional/OWNERS b/audio/policy/1.0/vts/functional/OWNERS
deleted file mode 100644
index 448d9fe..0000000
--- a/audio/policy/1.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 48436
-mnaganov@google.com
diff --git a/automotive/vehicle/aidl/Android.bp b/automotive/vehicle/aidl/Android.bp
index 9aeb4d2..88d1c74 100644
--- a/automotive/vehicle/aidl/Android.bp
+++ b/automotive/vehicle/aidl/Android.bp
@@ -27,6 +27,7 @@
     srcs: [
         "android/hardware/automotive/vehicle/**/*.aidl",
     ],
+    frozen: true,
     stability: "vintf",
     backend: {
         cpp: {
diff --git a/biometrics/common/aidl/Android.bp b/biometrics/common/aidl/Android.bp
index 167e0c7..0f795f8 100644
--- a/biometrics/common/aidl/Android.bp
+++ b/biometrics/common/aidl/Android.bp
@@ -13,6 +13,7 @@
     srcs: [
         "android/hardware/biometrics/common/*.aidl",
     ],
+    frozen: true,
     stability: "vintf",
     backend: {
         java: {
diff --git a/biometrics/face/aidl/Android.bp b/biometrics/face/aidl/Android.bp
index 0bec0c5..78f113d 100644
--- a/biometrics/face/aidl/Android.bp
+++ b/biometrics/face/aidl/Android.bp
@@ -14,7 +14,7 @@
         "android/hardware/biometrics/face/**/*.aidl",
     ],
     imports: [
-        "android.hardware.biometrics.common",
+        "android.hardware.biometrics.common-V2",
         "android.hardware.common-V2",
         "android.hardware.keymaster-V3",
     ],
diff --git a/biometrics/fingerprint/aidl/Android.bp b/biometrics/fingerprint/aidl/Android.bp
index 0bd6422..620e270 100644
--- a/biometrics/fingerprint/aidl/Android.bp
+++ b/biometrics/fingerprint/aidl/Android.bp
@@ -14,7 +14,7 @@
         "android/hardware/biometrics/fingerprint/**/*.aidl",
     ],
     imports: [
-        "android.hardware.biometrics.common",
+        "android.hardware.biometrics.common-V2",
         "android.hardware.keymaster-V3",
     ],
     stability: "vintf",
diff --git a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml
index ea7adc9..6010c60 100644
--- a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml
+++ b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml
@@ -24,8 +24,10 @@
 
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <option name="run-command" value="settings put global ble_scan_always_enabled 0" />
-        <option name="run-command" value="su u$(am get-current-user)_system svc bluetooth disable" />
-        <option name="teardown-command" value="su u$(am get-current-user)_system svc bluetooth enable" />
+        <option name="run-command" value="cmd bluetooth_manager disable" />
+        <option name="run-command" value="cmd bluetooth_manager wait-for-state:STATE_OFF" />
+        <option name="teardown-command" value="cmd bluetooth_manager enable" />
+        <option name="teardown-command" value="cmd bluetooth_manager wait-for-state:STATE_ON" />
         <option name="teardown-command" value="settings put global ble_scan_always_enabled 1" />
     </target_preparer>
 
diff --git a/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml b/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml
index 98b62ef..0234dc8 100644
--- a/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml
+++ b/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml
@@ -22,8 +22,10 @@
 
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <option name="run-command" value="settings put global ble_scan_always_enabled 0" />
-        <option name="run-command" value="su u$(am get-current-user)_system svc bluetooth disable" />
-        <option name="teardown-command" value="su u$(am get-current-user)_system svc bluetooth enable" />
+        <option name="run-command" value="cmd bluetooth_manager disable" />
+        <option name="run-command" value="cmd bluetooth_manager wait-for-state:STATE_OFF" />
+        <option name="teardown-command" value="cmd bluetooth_manager enable" />
+        <option name="teardown-command" value="cmd bluetooth_manager wait-for-state:STATE_ON" />
         <option name="teardown-command" value="settings put global ble_scan_always_enabled 1" />
     </target_preparer>
 
diff --git a/bluetooth/audio/aidl/Android.bp b/bluetooth/audio/aidl/Android.bp
index 4aea83f..618141f 100644
--- a/bluetooth/audio/aidl/Android.bp
+++ b/bluetooth/audio/aidl/Android.bp
@@ -29,7 +29,7 @@
     imports: [
         "android.hardware.common-V2",
         "android.hardware.common.fmq-V1",
-        "android.hardware.audio.common",
+        "android.hardware.audio.common-V1",
     ],
     backend: {
         cpp: {
diff --git a/camera/common/aidl/Android.bp b/camera/common/aidl/Android.bp
index d21ae58..fa74392 100644
--- a/camera/common/aidl/Android.bp
+++ b/camera/common/aidl/Android.bp
@@ -11,6 +11,7 @@
     name: "android.hardware.camera.common",
     vendor_available: true,
     srcs: ["android/hardware/camera/common/*.aidl"],
+    frozen: true,
     stability: "vintf",
     backend: {
         cpp: {
diff --git a/camera/device/aidl/Android.bp b/camera/device/aidl/Android.bp
index 6115d53..461e89d 100644
--- a/camera/device/aidl/Android.bp
+++ b/camera/device/aidl/Android.bp
@@ -11,13 +11,14 @@
     name: "android.hardware.camera.device",
     vendor_available: true,
     srcs: ["android/hardware/camera/device/*.aidl"],
+    frozen: true,
     stability: "vintf",
     imports: [
         "android.hardware.common-V2",
         "android.hardware.common.fmq-V1",
-        "android.hardware.camera.common",
-        "android.hardware.camera.metadata",
-        "android.hardware.graphics.common",
+        "android.hardware.camera.common-V1",
+        "android.hardware.camera.metadata-V1",
+        "android.hardware.graphics.common-V4",
     ],
     backend: {
         cpp: {
diff --git a/camera/metadata/aidl/Android.bp b/camera/metadata/aidl/Android.bp
index 301a943..8c13ce5 100644
--- a/camera/metadata/aidl/Android.bp
+++ b/camera/metadata/aidl/Android.bp
@@ -11,6 +11,7 @@
     name: "android.hardware.camera.metadata",
     vendor_available: true,
     srcs: ["android/hardware/camera/metadata/*.aidl"],
+    frozen: true,
     stability: "vintf",
     backend: {
         cpp: {
diff --git a/camera/provider/aidl/Android.bp b/camera/provider/aidl/Android.bp
index 87a94b2..e2c2bea 100644
--- a/camera/provider/aidl/Android.bp
+++ b/camera/provider/aidl/Android.bp
@@ -14,8 +14,8 @@
         "android/hardware/camera/provider/*.aidl",
     ],
     imports: [
-        "android.hardware.camera.device",
-        "android.hardware.camera.common",
+        "android.hardware.camera.device-V1",
+        "android.hardware.camera.common-V1",
     ],
     stability: "vintf",
     backend: {
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/AidlCasPluginDescriptor.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/AidlCasPluginDescriptor.aidl
index 7b8099f..89d8625 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/AidlCasPluginDescriptor.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/AidlCasPluginDescriptor.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @VintfStability
 parcelable AidlCasPluginDescriptor {
   int caSystemId;
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/DestinationBuffer.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/DestinationBuffer.aidl
index dd355af..b69cc33 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/DestinationBuffer.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/DestinationBuffer.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @VintfStability
 union DestinationBuffer {
   android.hardware.cas.SharedBuffer nonsecureMemory;
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICas.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICas.aidl
index e169beb..28c9eb0 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICas.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICas.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @VintfStability
 interface ICas {
   void closeSession(in byte[] sessionId);
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICasListener.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICasListener.aidl
index ebc13ce..db75062 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICasListener.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICasListener.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @VintfStability
 interface ICasListener {
   void onEvent(in int event, in int arg, in byte[] data);
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IDescrambler.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IDescrambler.aidl
index 9bf7903..411891b 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IDescrambler.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IDescrambler.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @VintfStability
 interface IDescrambler {
   int descramble(in android.hardware.cas.ScramblingControl scramblingControl, in android.hardware.cas.SubSample[] subSamples, in android.hardware.cas.SharedBuffer srcBuffer, in long srcOffset, in android.hardware.cas.DestinationBuffer dstBuffer, in long dstOffset);
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IMediaCasService.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IMediaCasService.aidl
index f5c8018..1f945a7 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IMediaCasService.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IMediaCasService.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @VintfStability
 interface IMediaCasService {
   android.hardware.cas.IDescrambler createDescrambler(in int CA_system_id);
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingControl.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingControl.aidl
index d71d4be..c8834ac 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingControl.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingControl.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @Backing(type="int") @VintfStability
 enum ScramblingControl {
   UNSCRAMBLED = 0,
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingMode.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingMode.aidl
index e3923c7..a0b08c9 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingMode.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingMode.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @Backing(type="int") @VintfStability
 enum ScramblingMode {
   RESERVED = 0,
@@ -44,9 +45,9 @@
   DVB_IDSA = 7,
   MULTI2 = 8,
   AES128 = 9,
-  AES_CBC = 10,
-  AES_ECB = 11,
-  AES_SCTE52 = 12,
-  TDES_ECB = 13,
-  TDES_SCTE52 = 14,
+  AES_ECB = 10,
+  AES_SCTE52 = 11,
+  TDES_ECB = 12,
+  TDES_SCTE52 = 13,
+  AES_CBC = 14,
 }
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SessionIntent.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SessionIntent.aidl
index af95f80..ade3001 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SessionIntent.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SessionIntent.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @Backing(type="int") @VintfStability
 enum SessionIntent {
   LIVE = 0,
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SharedBuffer.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SharedBuffer.aidl
index a18aa57..9200b1d 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SharedBuffer.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SharedBuffer.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @VintfStability
 parcelable SharedBuffer {
   android.hardware.common.Ashmem heapBase;
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/Status.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/Status.aidl
index 3d3a8a0..343c810 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/Status.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/Status.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @VintfStability
 parcelable Status {
   const int OK = 0;
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/StatusEvent.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/StatusEvent.aidl
index 178cabc..165c0d4 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/StatusEvent.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/StatusEvent.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @Backing(type="byte") @VintfStability
 enum StatusEvent {
   PLUGIN_PHYSICAL_MODULE_CHANGED = 0,
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SubSample.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SubSample.aidl
index d9ee3b4..5bd1a1e 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SubSample.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SubSample.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @VintfStability
 parcelable SubSample {
   int numBytesOfClearData;
diff --git a/cas/aidl/android/hardware/cas/AidlCasPluginDescriptor.aidl b/cas/aidl/android/hardware/cas/AidlCasPluginDescriptor.aidl
index 55b328a..1dc7ac6 100644
--- a/cas/aidl/android/hardware/cas/AidlCasPluginDescriptor.aidl
+++ b/cas/aidl/android/hardware/cas/AidlCasPluginDescriptor.aidl
@@ -18,6 +18,7 @@
 
 /**
  * Describes a CAS plugin with its system ID and name.
+ * @hide
  */
 @VintfStability
 parcelable AidlCasPluginDescriptor {
diff --git a/cas/aidl/android/hardware/cas/DestinationBuffer.aidl b/cas/aidl/android/hardware/cas/DestinationBuffer.aidl
index 068f29d..74336c2 100644
--- a/cas/aidl/android/hardware/cas/DestinationBuffer.aidl
+++ b/cas/aidl/android/hardware/cas/DestinationBuffer.aidl
@@ -19,6 +19,9 @@
 import android.hardware.cas.SharedBuffer;
 import android.hardware.common.NativeHandle;
 
+/**
+ * @hide
+ */
 @VintfStability
 union DestinationBuffer {
     /**
diff --git a/cas/aidl/android/hardware/cas/ICas.aidl b/cas/aidl/android/hardware/cas/ICas.aidl
index 4c938c7..e6494ae 100644
--- a/cas/aidl/android/hardware/cas/ICas.aidl
+++ b/cas/aidl/android/hardware/cas/ICas.aidl
@@ -23,6 +23,7 @@
  * ICas is the API to control the CAS. It is used to manage sessions, provision/refresh the cas
  * system, and process the EMM/ECM messages. It also allows bi-directional, scheme-specific
  * communications between the client and the cas system.
+ * @hide
  */
 @VintfStability
 interface ICas {
diff --git a/cas/aidl/android/hardware/cas/ICasListener.aidl b/cas/aidl/android/hardware/cas/ICasListener.aidl
index 32d843f..21cd257 100644
--- a/cas/aidl/android/hardware/cas/ICasListener.aidl
+++ b/cas/aidl/android/hardware/cas/ICasListener.aidl
@@ -18,6 +18,9 @@
 
 import android.hardware.cas.StatusEvent;
 
+/**
+ * @hide
+ */
 @VintfStability
 interface ICasListener {
     /**
diff --git a/cas/aidl/android/hardware/cas/IDescrambler.aidl b/cas/aidl/android/hardware/cas/IDescrambler.aidl
index 33fbe75..0ac995c 100644
--- a/cas/aidl/android/hardware/cas/IDescrambler.aidl
+++ b/cas/aidl/android/hardware/cas/IDescrambler.aidl
@@ -23,6 +23,7 @@
 
 /**
  * IDescrambler is the API to control the descrambling operations.
+ * @hide
  */
 @VintfStability
 interface IDescrambler {
diff --git a/cas/aidl/android/hardware/cas/IMediaCasService.aidl b/cas/aidl/android/hardware/cas/IMediaCasService.aidl
index 8bc31f6..641c4a9 100644
--- a/cas/aidl/android/hardware/cas/IMediaCasService.aidl
+++ b/cas/aidl/android/hardware/cas/IMediaCasService.aidl
@@ -26,6 +26,7 @@
  * cas HAL to create cas and descrambler plugin instances. A cas plugin instance
  * opens cas sessions which are used to obtain keys for a descrambler session,
  * which can in turn be used to descramble protected video content.
+ * @hide
  */
 @VintfStability
 interface IMediaCasService {
diff --git a/cas/aidl/android/hardware/cas/ScramblingControl.aidl b/cas/aidl/android/hardware/cas/ScramblingControl.aidl
index b36787c..ba0e439 100644
--- a/cas/aidl/android/hardware/cas/ScramblingControl.aidl
+++ b/cas/aidl/android/hardware/cas/ScramblingControl.aidl
@@ -18,6 +18,7 @@
 
 /**
  * Enumerates the keys used to scramble the content.
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
diff --git a/cas/aidl/android/hardware/cas/ScramblingMode.aidl b/cas/aidl/android/hardware/cas/ScramblingMode.aidl
index 9d73eba..dfca8dc 100644
--- a/cas/aidl/android/hardware/cas/ScramblingMode.aidl
+++ b/cas/aidl/android/hardware/cas/ScramblingMode.aidl
@@ -18,6 +18,7 @@
 
 /**
  * The Scrambling Mode.
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
@@ -70,11 +71,6 @@
     AES128,
 
     /**
-     * Advanced Encryption System (AES) Cipher Block Chaining (CBC) mode.
-     */
-    AES_CBC,
-
-    /**
      * Advanced Encryption System (AES) Electronic Code Book (ECB) mode.
      */
     AES_ECB,
@@ -95,4 +91,9 @@
      * Engineers (SCTE) 52 mode.
      */
     TDES_SCTE52,
+
+    /**
+     * Advanced Encryption System (AES) Cipher Block Chaining (CBC) mode.
+     */
+    AES_CBC,
 }
diff --git a/cas/aidl/android/hardware/cas/SessionIntent.aidl b/cas/aidl/android/hardware/cas/SessionIntent.aidl
index 844deab..d7da137 100644
--- a/cas/aidl/android/hardware/cas/SessionIntent.aidl
+++ b/cas/aidl/android/hardware/cas/SessionIntent.aidl
@@ -18,6 +18,7 @@
 
 /**
  * The intented usage for the session.
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
diff --git a/cas/aidl/android/hardware/cas/SharedBuffer.aidl b/cas/aidl/android/hardware/cas/SharedBuffer.aidl
index 8a94ff7..0c89cfe 100644
--- a/cas/aidl/android/hardware/cas/SharedBuffer.aidl
+++ b/cas/aidl/android/hardware/cas/SharedBuffer.aidl
@@ -22,6 +22,7 @@
  * SharedBuffer describes a shared buffer which is defined by a heapBase, an
  * offset and a size. The offset is relative to the shared memory base for the
  * memory region identified by heapBase.
+ * @hide
  */
 @VintfStability
 parcelable SharedBuffer {
diff --git a/cas/aidl/android/hardware/cas/Status.aidl b/cas/aidl/android/hardware/cas/Status.aidl
index b2be34b..e7ae8ff 100644
--- a/cas/aidl/android/hardware/cas/Status.aidl
+++ b/cas/aidl/android/hardware/cas/Status.aidl
@@ -16,6 +16,9 @@
 
 package android.hardware.cas;
 
+/**
+ * @hide
+ */
 @VintfStability
 parcelable Status {
     /**
diff --git a/cas/aidl/android/hardware/cas/StatusEvent.aidl b/cas/aidl/android/hardware/cas/StatusEvent.aidl
index 0f62634..1fe732e 100644
--- a/cas/aidl/android/hardware/cas/StatusEvent.aidl
+++ b/cas/aidl/android/hardware/cas/StatusEvent.aidl
@@ -18,6 +18,7 @@
 
 /**
  * The Event Type for status change.
+ * @hide
  */
 @VintfStability
 @Backing(type="byte")
diff --git a/cas/aidl/android/hardware/cas/SubSample.aidl b/cas/aidl/android/hardware/cas/SubSample.aidl
index c1353cb..8e1ff77 100644
--- a/cas/aidl/android/hardware/cas/SubSample.aidl
+++ b/cas/aidl/android/hardware/cas/SubSample.aidl
@@ -19,6 +19,7 @@
 /**
  * A subsample consists of some number of bytes of clear (unscrambled)
  * data followed by a number of bytes of scrambled data.
+ * @hide
  */
 @VintfStability
 parcelable SubSample {
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 99d4bb7..71afee3 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -53,6 +53,14 @@
         </interface>
     </hal>
     <hal format="aidl" optional="true">
+        <name>android.hardware.audio.sounddose</name>
+        <version>1</version>
+        <interface>
+            <name>ISoundDoseFactory</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
          <name>android.hardware.authsecret</name>
          <version>1</version>
          <interface>
@@ -582,6 +590,16 @@
         </interface>
     </hal>
     <hal format="aidl" optional="true">
+        <name>android.hardware.radio.sap</name>
+        <version>1</version>
+        <interface>
+            <name>ISap</name>
+            <instance>slot1</instance>
+            <instance>slot2</instance>
+            <instance>slot3</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
         <name>android.hardware.radio.voice</name>
         <version>1</version>
         <interface>
@@ -705,6 +723,13 @@
         </interface>
     </hal>
     <hal format="aidl" optional="true">
+        <name>android.hardware.tv.earc</name>
+        <interface>
+            <name>IEArc</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
         <name>android.hardware.tv.hdmi</name>
         <interface>
             <name>IHdmi</name>
@@ -821,4 +846,12 @@
             <instance>default</instance>
         </interface>
     </hal>
+    <hal format="native">
+        <name>mapper</name>
+        <version>1.0</version>
+        <interface>
+            <name>I</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+    </hal>
 </compatibility-matrix>
diff --git a/compatibility_matrices/exclude/fcm_exclude.cpp b/compatibility_matrices/exclude/fcm_exclude.cpp
index cf1e138..3c0c5f1 100644
--- a/compatibility_matrices/exclude/fcm_exclude.cpp
+++ b/compatibility_matrices/exclude/fcm_exclude.cpp
@@ -52,6 +52,7 @@
             "android.hardware.radio.config@1.2",
             // AIDL
             "android.hardware.audio.common",
+            "android.hardware.audio.core.sounddose",
             "android.hardware.biometrics.common",
             "android.hardware.camera.metadata",
             "android.hardware.camera.device",
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PixelFormat.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PixelFormat.aidl
index 59d6468..68857e8 100644
--- a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PixelFormat.aidl
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PixelFormat.aidl
@@ -65,4 +65,7 @@
   YCBCR_P010 = 54,
   HSV_888 = 55,
   R_8 = 56,
+  R_16_UINT = 57,
+  RG_1616_UINT = 58,
+  RGBA_10101010 = 59,
 }
diff --git a/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl b/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
index ccf437b..2985212 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
@@ -506,4 +506,30 @@
      * The component values are unsigned normalized to the range [0, 1].
      */
     R_8 = 0x38,
+
+    /**
+     * 16-bit format with a single 16-bit component
+     *
+     * The component values are unsigned integers, whose interpretation is
+     * defined by the dataspace.
+     */
+    R_16_UINT = 0x39,
+
+    /**
+     * 32-bit format that has 16-bit R and G components, in that order,
+     * from the lowest memory address to the highest memory address.
+     *
+     * The component values are unsigned integers, whose interpretation is
+     * defined by the dataspace.
+     */
+    RG_1616_UINT = 0x3a,
+
+    /**
+     * 40-bit format that has 10-bit R, G, B, and A components, in that order,
+     * from the lowest memory address to the highest memory address.
+     *
+     * The component values are unsigned normalized to the range [0, 1], whose
+     * interpretation is defined by the dataspace.
+     */
+    RGBA_10101010 = 0x3b,
 }
diff --git a/identity/support/Android.bp b/identity/support/Android.bp
index 4e3d1f7..3096fe5 100644
--- a/identity/support/Android.bp
+++ b/identity/support/Android.bp
@@ -65,57 +65,3 @@
     ],
     test_suites: ["general-tests"],
 }
-
-// --
-
-cc_library {
-    name: "libcppbor",
-    vendor_available: true,
-    host_supported: true,
-    srcs: [
-        "src/cppbor.cpp",
-        "src/cppbor_parse.cpp",
-    ],
-    export_include_dirs: [
-        "include/cppbor",
-    ],
-    shared_libs: [
-        "libbase",
-    ],
-}
-
-cc_test {
-    name: "cppbor_test",
-    tidy_timeout_srcs: [
-        "tests/cppbor_test.cpp",
-    ],
-    srcs: [
-        "tests/cppbor_test.cpp",
-    ],
-    shared_libs: [
-        "libcppbor_external",
-        "libbase",
-    ],
-    static_libs: [
-        "libgmock",
-    ],
-    test_suites: ["general-tests"],
-}
-
-cc_test_host {
-    name: "cppbor_host_test",
-    tidy_timeout_srcs: [
-        "tests/cppbor_test.cpp",
-    ],
-    srcs: [
-        "tests/cppbor_test.cpp",
-    ],
-    shared_libs: [
-        "libcppbor_external",
-        "libbase",
-    ],
-    static_libs: [
-        "libgmock",
-    ],
-    test_suites: ["general-tests"],
-}
diff --git a/identity/support/include/cppbor/README.md b/identity/support/include/cppbor/README.md
deleted file mode 100644
index 723bfcf..0000000
--- a/identity/support/include/cppbor/README.md
+++ /dev/null
@@ -1,216 +0,0 @@
-CppBor: A Modern C++ CBOR Parser and Generator
-==============================================
-
-CppBor provides a natural and easy-to-use syntax for constructing and
-parsing CBOR messages.  It does not (yet) support all features of
-CBOR, nor (yet) support validation against CDDL schemata, though both
-are planned.  CBOR features that aren't supported include:
-
-* Indefinite length values
-* Semantic tagging
-* Floating point
-
-CppBor requires C++-17.
-
-## CBOR representation
-
-CppBor represents CBOR data items as instances of the `Item` class or,
-more precisely, as instances of subclasses of `Item`, since `Item` is a
-pure interface.  The subclasses of `Item` correspond almost one-to-one
-with CBOR major types, and are named to match the CDDL names to which
-they correspond.  They are:
-
-* `Uint` corresponds to major type 0, and can hold unsigned integers
-  up through (2^64 - 1).
-* `Nint` corresponds to major type 1.  It can only hold values from -1
-  to -(2^63 - 1), since it's internal representation is an int64_t.
-  This can be fixed, but it seems unlikely that applications will need
-  the omitted range from -(2^63) to (2^64 - 1), since it's
-  inconvenient to represent them in many programming languages.
-* `Int` is an abstract base of `Uint` and `Nint` that facilitates
-  working with all signed integers representable with int64_t.
-* `Bstr` corresponds to major type 2, a byte string.
-* `Tstr` corresponds to major type 3, a text string.
-* `Array` corresponds to major type 4, an Array.  It holds a
-  variable-length array of `Item`s.
-* `Map` corresponds to major type 5, a Map.  It holds a
-  variable-length array of pairs of `Item`s.
-* `Simple` corresponds to major type 7.  It's an abstract class since
-  items require more specific type.
-* `Bool` is the only currently-implemented subclass of `Simple`.
-
-Note that major type 6, semantic tag, is not yet implemented.
-
-In practice, users of CppBor will rarely use most of these classes
-when generating CBOR encodings.  This is because CppBor provides
-straightforward conversions from the obvious normal C++ types.
-Specifically, the following conversions are provided in appropriate
-contexts:
-
-* Signed and unsigned integers convert to `Uint` or `Nint`, as
-  appropriate.
-* `std::string`, `std::string_view`, `const char*` and
-  `std::pair<char iterator, char iterator>` convert to `Tstr`.
-* `std::vector<uint8_t>`, `std::pair<uint8_t iterator, uint8_t
-  iterator>` and `std::pair<uint8_t*, size_t>` convert to `Bstr`.
-* `bool` converts to `Bool`.
-
-## CBOR generation
-
-### Complete tree generation
-
-The set of `encode` methods in `Item` provide the interface for
-producing encoded CBOR.  The basic process for "complete tree"
-generation (as opposed to "incremental" generation, which is discussed
-below) is to construct an `Item` which models the data to be encoded,
-and then call one of the `encode` methods, whichever is convenient for
-the encoding destination.  A trivial example:
-
-```
-cppbor::Uint val(0);
-std::vector<uint8_t> encoding = val.encode();
-```
-
-    It's relatively rare that single values are encoded as above.  More often, the
-    "root" data item will be an `Array` or `Map` which contains a more complex structure.For example
-    :
-
-``` using cppbor::Map;
-using cppbor::Array;
-
-std::vector<uint8_t> vec =  // ...
-    Map val("key1", Array(Map("key_a", 99 "key_b", vec), "foo"), "key2", true);
-std::vector<uint8_t> encoding = val.encode();
-```
-
-This creates a map with two entries, with `Tstr` keys "Outer1" and
-"Outer2", respectively.  The "Outer1" entry has as its value an
-`Array` containing a `Map` and a `Tstr`.  The "Outer2" entry has a
-`Bool` value.
-
-This example demonstrates how automatic conversion of C++ types to
-CppBor `Item` subclass instances is done.  Where the caller provides a
-C++ or C string, a `Tstr` entry is added.  Where the caller provides
-an integer literal or variable, a `Uint` or `Nint` is added, depending
-on whether the value is positive or negative.
-
-As an alternative, a more fluent-style API is provided for building up
-structures.  For example:
-
-```
-using cppbor::Map;
-using cppbor::Array;
-
-std::vector<uint8_t> vec =  // ...
-    Map val();
-val.add("key1", Array().add(Map().add("key_a", 99).add("key_b", vec)).add("foo")).add("key2", true);
-std::vector<uint8_t> encoding = val.encode();
-```
-
-    An advantage of this interface over the constructor -
-    based creation approach above is that it need not be done all at once
-        .The `add` methods return a reference to the object added to to allow calls to be chained,
-    but chaining is not necessary; calls can be made
-sequentially, as the data to add is available.
-
-#### `encode` methods
-
-There are several variations of `Item::encode`, all of which
-accomplish the same task but output the encoded data in different
-ways, and with somewhat different performance characteristics.  The
-provided options are:
-
-* `bool encode(uint8\_t** pos, const uint8\_t* end)` encodes into the
-  buffer referenced by the range [`*pos`, end).  `*pos` is moved.  If
-  the encoding runs out of buffer space before finishing, the method
-  returns false.  This is the most efficient way to encode, into an
-  already-allocated buffer.
-* `void encode(EncodeCallback encodeCallback)` calls `encodeCallback`
-  for each encoded byte.  It's the responsibility of the implementor
-  of the callback to behave safely in the event that the output buffer
-  (if applicable) is exhausted.  This is less efficient than the prior
-  method because it imposes an additional function call for each byte.
-* `template </*...*/> void encode(OutputIterator i)`
-  encodes into the provided iterator.  SFINAE ensures that the
-  template doesn't match for non-iterators.  The implementation
-  actually uses the callback-based method, plus has whatever overhead
-  the iterator adds.
-* `std::vector<uint8_t> encode()` creates a new std::vector, reserves
-  sufficient capacity to hold the encoding, and inserts the encoded
-  bytes with a std::pushback_iterator and the previous method.
-* `std::string toString()` does the same as the previous method, but
-  returns a string instead of a vector.
-
-### Incremental generation
-
-Incremental generation requires deeper understanding of CBOR, because
-the library can't do as much to ensure that the output is valid.  The
-basic tool for intcremental generation is the `encodeHeader`
-function.  There are two variations, one which writes into a buffer,
-and one which uses a callback.  Both simply write out the bytes of a
-header.  To construct the same map as in the above examples,
-incrementally, one might write:
-
-```
-using namespace cppbor;  // For example brevity
-
-std::vector encoding;
-auto iter = std::back_inserter(result);
-encodeHeader(MAP, 2 /* # of map entries */, iter);
-std::string s = "key1";
-encodeHeader(TSTR, s.size(), iter);
-std::copy(s.begin(), s.end(), iter);
-encodeHeader(ARRAY, 2 /* # of array entries */, iter);
-Map().add("key_a", 99).add("key_b", vec).encode(iter)
-s = "foo";
-encodeHeader(TSTR, foo.size(), iter);
-std::copy(s.begin(), s.end(), iter);
-s = "key2";
-encodeHeader(TSTR, foo.size(), iter);
-std::copy(s.begin(), s.end(), iter);
-encodeHeader(SIMPLE, TRUE, iter);
-```
-
-As the above example demonstrates, the styles can be mixed -- Note the
-creation and encoding of the inner Map using the fluent style.
-
-## Parsing
-
-CppBor also supports parsing of encoded CBOR data, with the same
-feature set as encoding.  There are two basic approaches to parsing,
-"full" and "stream"
-
-### Full parsing
-
-Full parsing means completely parsing a (possibly-compound) data
-item from a byte buffer.  The `parse` functions that do not take a
-`ParseClient` pointer do this.  They return a `ParseResult` which is a
-tuple of three values:
-
-* std::unique_ptr<Item> that points to the parsed item, or is nullptr
-  if there was a parse error.
-* const uint8_t* that points to the byte after the end of the decoded
-  item, or to the first unparseable byte in the event of an error.
-* std::string that is empty on success or contains an error message if
-  a parse error occurred.
-
-Assuming a successful parse, you can then use `Item::type()` to
-discover the type of the parsed item (e.g. MAP), and then use the
-appropriate `Item::as*()` method (e.g. `Item::asMap()`) to get a
-pointer to an interface which allows you to retrieve specific values.
-
-### Stream parsing
-
-Stream parsing is more complex, but more flexible.  To use
-StreamParsing, you must create your own subclass of `ParseClient` and
-call one of the `parse` functions that accepts it.  See the
-`ParseClient` methods docstrings for details.
-
-One unusual feature of stream parsing is that the `ParseClient`
-callback methods not only provide the parsed Item, but also pointers
-to the portion of the buffer that encode that Item.  This is useful
-if, for example, you want to find an element inside of a structure,
-and then copy the encoding of that sub-structure, without bothering to
-parse the rest.
-
-The full parser is implemented with the stream parser.
diff --git a/identity/support/include/cppbor/cppbor.h b/identity/support/include/cppbor/cppbor.h
deleted file mode 100644
index af5d82e..0000000
--- a/identity/support/include/cppbor/cppbor.h
+++ /dev/null
@@ -1,827 +0,0 @@
-/*
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <functional>
-#include <iterator>
-#include <memory>
-#include <numeric>
-#include <string>
-#include <vector>
-
-namespace cppbor {
-
-enum MajorType : uint8_t {
-    UINT = 0 << 5,
-    NINT = 1 << 5,
-    BSTR = 2 << 5,
-    TSTR = 3 << 5,
-    ARRAY = 4 << 5,
-    MAP = 5 << 5,
-    SEMANTIC = 6 << 5,
-    SIMPLE = 7 << 5,
-};
-
-enum SimpleType {
-    BOOLEAN,
-    NULL_T,  // Only two supported, as yet.
-};
-
-enum SpecialAddlInfoValues : uint8_t {
-    FALSE = 20,
-    TRUE = 21,
-    NULL_V = 22,
-    ONE_BYTE_LENGTH = 24,
-    TWO_BYTE_LENGTH = 25,
-    FOUR_BYTE_LENGTH = 26,
-    EIGHT_BYTE_LENGTH = 27,
-};
-
-class Item;
-class Uint;
-class Nint;
-class Int;
-class Tstr;
-class Bstr;
-class Simple;
-class Bool;
-class Array;
-class Map;
-class Null;
-class Semantic;
-
-/**
- * Returns the size of a CBOR header that contains the additional info value addlInfo.
- */
-size_t headerSize(uint64_t addlInfo);
-
-/**
- * Encodes a CBOR header with the specified type and additional info into the range [pos, end).
- * Returns a pointer to one past the last byte written, or nullptr if there isn't sufficient space
- * to write the header.
- */
-uint8_t* encodeHeader(MajorType type, uint64_t addlInfo, uint8_t* pos, const uint8_t* end);
-
-using EncodeCallback = std::function<void(uint8_t)>;
-
-/**
- * Encodes a CBOR header with the specified type and additional info, passing each byte in turn to
- * encodeCallback.
- */
-void encodeHeader(MajorType type, uint64_t addlInfo, EncodeCallback encodeCallback);
-
-/**
- * Encodes a CBOR header with the specified type and additional info, writing each byte to the
- * provided OutputIterator.
- */
-template <typename OutputIterator,
-          typename = std::enable_if_t<std::is_base_of_v<
-                  std::output_iterator_tag,
-                  typename std::iterator_traits<OutputIterator>::iterator_category>>>
-void encodeHeader(MajorType type, uint64_t addlInfo, OutputIterator iter) {
-    return encodeHeader(type, addlInfo, [&](uint8_t v) { *iter++ = v; });
-}
-
-/**
- * Item represents a CBOR-encodeable data item.  Item is an abstract interface with a set of virtual
- * methods that allow encoding of the item or conversion to the appropriate derived type.
- */
-class Item {
-  public:
-    virtual ~Item() {}
-
-    /**
-     * Returns the CBOR type of the item.
-     */
-    virtual MajorType type() const = 0;
-
-    // These methods safely downcast an Item to the appropriate subclass.
-    virtual const Int* asInt() const { return nullptr; }
-    virtual const Uint* asUint() const { return nullptr; }
-    virtual const Nint* asNint() const { return nullptr; }
-    virtual const Tstr* asTstr() const { return nullptr; }
-    virtual const Bstr* asBstr() const { return nullptr; }
-    virtual const Simple* asSimple() const { return nullptr; }
-    virtual const Map* asMap() const { return nullptr; }
-    virtual const Array* asArray() const { return nullptr; }
-    virtual const Semantic* asSemantic() const { return nullptr; }
-
-    /**
-     * Returns true if this is a "compound" item, i.e. one that contains one or more other items.
-     */
-    virtual bool isCompound() const { return false; }
-
-    bool operator==(const Item& other) const&;
-    bool operator!=(const Item& other) const& { return !(*this == other); }
-
-    /**
-     * Returns the number of bytes required to encode this Item into CBOR.  Note that if this is a
-     * complex Item, calling this method will require walking the whole tree.
-     */
-    virtual size_t encodedSize() const = 0;
-
-    /**
-     * Encodes the Item into buffer referenced by range [*pos, end).  Returns a pointer to one past
-     * the last position written.  Returns nullptr if there isn't enough space to encode.
-     */
-    virtual uint8_t* encode(uint8_t* pos, const uint8_t* end) const = 0;
-
-    /**
-     * Encodes the Item by passing each encoded byte to encodeCallback.
-     */
-    virtual void encode(EncodeCallback encodeCallback) const = 0;
-
-    /**
-     * Clones the Item
-     */
-    virtual std::unique_ptr<Item> clone() const = 0;
-
-    /**
-     * Encodes the Item into the provided OutputIterator.
-     */
-    template <typename OutputIterator,
-              typename = typename std::iterator_traits<OutputIterator>::iterator_category>
-    void encode(OutputIterator i) const {
-        return encode([&](uint8_t v) { *i++ = v; });
-    }
-
-    /**
-     * Encodes the Item into a new std::vector<uint8_t>.
-     */
-    std::vector<uint8_t> encode() const {
-        std::vector<uint8_t> retval;
-        retval.reserve(encodedSize());
-        encode(std::back_inserter(retval));
-        return retval;
-    }
-
-    /**
-     * Encodes the Item into a new std::string.
-     */
-    std::string toString() const {
-        std::string retval;
-        retval.reserve(encodedSize());
-        encode([&](uint8_t v) { retval.push_back(v); });
-        return retval;
-    }
-
-    /**
-     * Encodes only the header of the Item.
-     */
-    inline uint8_t* encodeHeader(uint64_t addlInfo, uint8_t* pos, const uint8_t* end) const {
-        return ::cppbor::encodeHeader(type(), addlInfo, pos, end);
-    }
-
-    /**
-     * Encodes only the header of the Item.
-     */
-    inline void encodeHeader(uint64_t addlInfo, EncodeCallback encodeCallback) const {
-        ::cppbor::encodeHeader(type(), addlInfo, encodeCallback);
-    }
-};
-
-/**
- * Int is an abstraction that allows Uint and Nint objects to be manipulated without caring about
- * the sign.
- */
-class Int : public Item {
-  public:
-    bool operator==(const Int& other) const& { return value() == other.value(); }
-
-    virtual int64_t value() const = 0;
-
-    const Int* asInt() const override { return this; }
-};
-
-/**
- * Uint is a concrete Item that implements CBOR major type 0.
- */
-class Uint : public Int {
-  public:
-    static constexpr MajorType kMajorType = UINT;
-
-    explicit Uint(uint64_t v) : mValue(v) {}
-
-    bool operator==(const Uint& other) const& { return mValue == other.mValue; }
-
-    MajorType type() const override { return kMajorType; }
-    const Uint* asUint() const override { return this; }
-
-    size_t encodedSize() const override { return headerSize(mValue); }
-
-    int64_t value() const override { return mValue; }
-    uint64_t unsignedValue() const { return mValue; }
-
-    using Item::encode;
-    uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
-        return encodeHeader(mValue, pos, end);
-    }
-    void encode(EncodeCallback encodeCallback) const override {
-        encodeHeader(mValue, encodeCallback);
-    }
-
-    virtual std::unique_ptr<Item> clone() const override { return std::make_unique<Uint>(mValue); }
-
-  private:
-    uint64_t mValue;
-};
-
-/**
- * Nint is a concrete Item that implements CBOR major type 1.
-
- * Note that it is incapable of expressing the full range of major type 1 values, becaue it can only
- * express values that fall into the range [std::numeric_limits<int64_t>::min(), -1].  It cannot
- * express values in the range [std::numeric_limits<int64_t>::min() - 1,
- * -std::numeric_limits<uint64_t>::max()].
- */
-class Nint : public Int {
-  public:
-    static constexpr MajorType kMajorType = NINT;
-
-    explicit Nint(int64_t v);
-
-    bool operator==(const Nint& other) const& { return mValue == other.mValue; }
-
-    MajorType type() const override { return kMajorType; }
-    const Nint* asNint() const override { return this; }
-    size_t encodedSize() const override { return headerSize(addlInfo()); }
-
-    int64_t value() const override { return mValue; }
-
-    using Item::encode;
-    uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
-        return encodeHeader(addlInfo(), pos, end);
-    }
-    void encode(EncodeCallback encodeCallback) const override {
-        encodeHeader(addlInfo(), encodeCallback);
-    }
-
-    virtual std::unique_ptr<Item> clone() const override { return std::make_unique<Nint>(mValue); }
-
-  private:
-    uint64_t addlInfo() const { return -1LL - mValue; }
-
-    int64_t mValue;
-};
-
-/**
- * Bstr is a concrete Item that implements major type 2.
- */
-class Bstr : public Item {
-  public:
-    static constexpr MajorType kMajorType = BSTR;
-
-    // Construct from a vector
-    explicit Bstr(std::vector<uint8_t> v) : mValue(std::move(v)) {}
-
-    // Construct from a string
-    explicit Bstr(const std::string& v)
-        : mValue(reinterpret_cast<const uint8_t*>(v.data()),
-                 reinterpret_cast<const uint8_t*>(v.data()) + v.size()) {}
-
-    // Construct from a pointer/size pair
-    explicit Bstr(const std::pair<const uint8_t*, size_t>& buf)
-        : mValue(buf.first, buf.first + buf.second) {}
-
-    // Construct from a pair of iterators
-    template <typename I1, typename I2,
-              typename = typename std::iterator_traits<I1>::iterator_category,
-              typename = typename std::iterator_traits<I2>::iterator_category>
-    explicit Bstr(const std::pair<I1, I2>& pair) : mValue(pair.first, pair.second) {}
-
-    // Construct from an iterator range.
-    template <typename I1, typename I2,
-              typename = typename std::iterator_traits<I1>::iterator_category,
-              typename = typename std::iterator_traits<I2>::iterator_category>
-    Bstr(I1 begin, I2 end) : mValue(begin, end) {}
-
-    bool operator==(const Bstr& other) const& { return mValue == other.mValue; }
-
-    MajorType type() const override { return kMajorType; }
-    const Bstr* asBstr() const override { return this; }
-    size_t encodedSize() const override { return headerSize(mValue.size()) + mValue.size(); }
-    using Item::encode;
-    uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
-    void encode(EncodeCallback encodeCallback) const override {
-        encodeHeader(mValue.size(), encodeCallback);
-        encodeValue(encodeCallback);
-    }
-
-    const std::vector<uint8_t>& value() const { return mValue; }
-
-    virtual std::unique_ptr<Item> clone() const override { return std::make_unique<Bstr>(mValue); }
-
-  private:
-    void encodeValue(EncodeCallback encodeCallback) const;
-
-    std::vector<uint8_t> mValue;
-};
-
-/**
- * Bstr is a concrete Item that implements major type 3.
- */
-class Tstr : public Item {
-  public:
-    static constexpr MajorType kMajorType = TSTR;
-
-    // Construct from a string
-    explicit Tstr(std::string v) : mValue(std::move(v)) {}
-
-    // Construct from a string_view
-    explicit Tstr(const std::string_view& v) : mValue(v) {}
-
-    // Construct from a C string
-    explicit Tstr(const char* v) : mValue(std::string(v)) {}
-
-    // Construct from a pair of iterators
-    template <typename I1, typename I2,
-              typename = typename std::iterator_traits<I1>::iterator_category,
-              typename = typename std::iterator_traits<I2>::iterator_category>
-    explicit Tstr(const std::pair<I1, I2>& pair) : mValue(pair.first, pair.second) {}
-
-    // Construct from an iterator range
-    template <typename I1, typename I2,
-              typename = typename std::iterator_traits<I1>::iterator_category,
-              typename = typename std::iterator_traits<I2>::iterator_category>
-    Tstr(I1 begin, I2 end) : mValue(begin, end) {}
-
-    bool operator==(const Tstr& other) const& { return mValue == other.mValue; }
-
-    MajorType type() const override { return kMajorType; }
-    const Tstr* asTstr() const override { return this; }
-    size_t encodedSize() const override { return headerSize(mValue.size()) + mValue.size(); }
-    using Item::encode;
-    uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
-    void encode(EncodeCallback encodeCallback) const override {
-        encodeHeader(mValue.size(), encodeCallback);
-        encodeValue(encodeCallback);
-    }
-
-    const std::string& value() const { return mValue; }
-
-    virtual std::unique_ptr<Item> clone() const override { return std::make_unique<Tstr>(mValue); }
-
-  private:
-    void encodeValue(EncodeCallback encodeCallback) const;
-
-    std::string mValue;
-};
-
-/**
- * CompoundItem is an abstract Item that provides common functionality for Items that contain other
- * items, i.e. Arrays (CBOR type 4) and Maps (CBOR type 5).
- */
-class CompoundItem : public Item {
-  public:
-    bool operator==(const CompoundItem& other) const&;
-
-    virtual size_t size() const { return mEntries.size(); }
-
-    bool isCompound() const override { return true; }
-
-    size_t encodedSize() const override {
-        return std::accumulate(mEntries.begin(), mEntries.end(), headerSize(size()),
-                               [](size_t sum, auto& entry) { return sum + entry->encodedSize(); });
-    }
-
-    using Item::encode;  // Make base versions visible.
-    uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
-    void encode(EncodeCallback encodeCallback) const override;
-
-    virtual uint64_t addlInfo() const = 0;
-
-  protected:
-    std::vector<std::unique_ptr<Item>> mEntries;
-};
-
-/*
- * Array is a concrete Item that implements CBOR major type 4.
- *
- * Note that Arrays are not copyable.  This is because copying them is expensive and making them
- * move-only ensures that they're never copied accidentally.  If you actually want to copy an Array,
- * use the clone() method.
- */
-class Array : public CompoundItem {
-  public:
-    static constexpr MajorType kMajorType = ARRAY;
-
-    Array() = default;
-    Array(const Array& other) = delete;
-    Array(Array&&) = default;
-    Array& operator=(const Array&) = delete;
-    Array& operator=(Array&&) = default;
-
-    /**
-     * Construct an Array from a variable number of arguments of different types.  See
-     * details::makeItem below for details on what types may be provided.  In general, this accepts
-     * all of the types you'd expect and doest the things you'd expect (integral values are addes as
-     * Uint or Nint, std::string and char* are added as Tstr, bools are added as Bool, etc.).
-     */
-    template <typename... Args, typename Enable>
-    Array(Args&&... args);
-
-    /**
-     * Append a single element to the Array, of any compatible type.
-     */
-    template <typename T>
-    Array& add(T&& v) &;
-    template <typename T>
-    Array&& add(T&& v) &&;
-
-    const std::unique_ptr<Item>& operator[](size_t index) const { return mEntries[index]; }
-    std::unique_ptr<Item>& operator[](size_t index) { return mEntries[index]; }
-
-    MajorType type() const override { return kMajorType; }
-    const Array* asArray() const override { return this; }
-
-    virtual std::unique_ptr<Item> clone() const override;
-
-    uint64_t addlInfo() const override { return size(); }
-};
-
-/*
- * Map is a concrete Item that implements CBOR major type 5.
- *
- * Note that Maps are not copyable.  This is because copying them is expensive and making them
- * move-only ensures that they're never copied accidentally.  If you actually want to copy a
- * Map, use the clone() method.
- */
-class Map : public CompoundItem {
-  public:
-    static constexpr MajorType kMajorType = MAP;
-
-    Map() = default;
-    Map(const Map& other) = delete;
-    Map(Map&&) = default;
-    Map& operator=(const Map& other) = delete;
-    Map& operator=(Map&&) = default;
-
-    /**
-     * Construct a Map from a variable number of arguments of different types.  An even number of
-     * arguments must be provided (this is verified statically). See details::makeItem below for
-     * details on what types may be provided.  In general, this accepts all of the types you'd
-     * expect and doest the things you'd expect (integral values are addes as Uint or Nint,
-     * std::string and char* are added as Tstr, bools are added as Bool, etc.).
-     */
-    template <typename... Args, typename Enable>
-    Map(Args&&... args);
-
-    /**
-     * Append a key/value pair to the Map, of any compatible types.
-     */
-    template <typename Key, typename Value>
-    Map& add(Key&& key, Value&& value) &;
-    template <typename Key, typename Value>
-    Map&& add(Key&& key, Value&& value) &&;
-
-    size_t size() const override {
-        assertInvariant();
-        return mEntries.size() / 2;
-    }
-
-    template <typename Key, typename Enable>
-    std::pair<std::unique_ptr<Item>&, bool> get(Key key);
-
-    std::pair<const std::unique_ptr<Item>&, const std::unique_ptr<Item>&> operator[](
-            size_t index) const {
-        assertInvariant();
-        return {mEntries[index * 2], mEntries[index * 2 + 1]};
-    }
-
-    std::pair<std::unique_ptr<Item>&, std::unique_ptr<Item>&> operator[](size_t index) {
-        assertInvariant();
-        return {mEntries[index * 2], mEntries[index * 2 + 1]};
-    }
-
-    MajorType type() const override { return kMajorType; }
-    const Map* asMap() const override { return this; }
-
-    virtual std::unique_ptr<Item> clone() const override;
-
-    uint64_t addlInfo() const override { return size(); }
-
-  private:
-    void assertInvariant() const;
-};
-
-class Semantic : public CompoundItem {
-  public:
-    static constexpr MajorType kMajorType = SEMANTIC;
-
-    template <typename T>
-    explicit Semantic(uint64_t value, T&& child);
-
-    Semantic(const Semantic& other) = delete;
-    Semantic(Semantic&&) = default;
-    Semantic& operator=(const Semantic& other) = delete;
-    Semantic& operator=(Semantic&&) = default;
-
-    size_t size() const override {
-        assertInvariant();
-        return 1;
-    }
-
-    size_t encodedSize() const override {
-        return std::accumulate(mEntries.begin(), mEntries.end(), headerSize(mValue),
-                               [](size_t sum, auto& entry) { return sum + entry->encodedSize(); });
-    }
-
-    MajorType type() const override { return kMajorType; }
-    const Semantic* asSemantic() const override { return this; }
-
-    const std::unique_ptr<Item>& child() const {
-        assertInvariant();
-        return mEntries[0];
-    }
-
-    std::unique_ptr<Item>& child() {
-        assertInvariant();
-        return mEntries[0];
-    }
-
-    uint64_t value() const { return mValue; }
-
-    uint64_t addlInfo() const override { return value(); }
-
-    virtual std::unique_ptr<Item> clone() const override {
-        assertInvariant();
-        return std::make_unique<Semantic>(mValue, mEntries[0]->clone());
-    }
-
-  protected:
-    Semantic() = default;
-    Semantic(uint64_t value) : mValue(value) {}
-    uint64_t mValue;
-
-  private:
-    void assertInvariant() const;
-};
-
-/**
- * Simple is abstract Item that implements CBOR major type 7.  It is intended to be subclassed to
- * create concrete Simple types.  At present only Bool is provided.
- */
-class Simple : public Item {
-  public:
-    static constexpr MajorType kMajorType = SIMPLE;
-
-    bool operator==(const Simple& other) const&;
-
-    virtual SimpleType simpleType() const = 0;
-    MajorType type() const override { return kMajorType; }
-
-    const Simple* asSimple() const override { return this; }
-
-    virtual const Bool* asBool() const { return nullptr; };
-    virtual const Null* asNull() const { return nullptr; };
-};
-
-/**
- * Bool is a concrete type that implements CBOR major type 7, with additional item values for TRUE
- * and FALSE.
- */
-class Bool : public Simple {
-  public:
-    static constexpr SimpleType kSimpleType = BOOLEAN;
-
-    explicit Bool(bool v) : mValue(v) {}
-
-    bool operator==(const Bool& other) const& { return mValue == other.mValue; }
-
-    SimpleType simpleType() const override { return kSimpleType; }
-    const Bool* asBool() const override { return this; }
-
-    size_t encodedSize() const override { return 1; }
-
-    using Item::encode;
-    uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
-        return encodeHeader(mValue ? TRUE : FALSE, pos, end);
-    }
-    void encode(EncodeCallback encodeCallback) const override {
-        encodeHeader(mValue ? TRUE : FALSE, encodeCallback);
-    }
-
-    bool value() const { return mValue; }
-
-    virtual std::unique_ptr<Item> clone() const override { return std::make_unique<Bool>(mValue); }
-
-  private:
-    bool mValue;
-};
-
-/**
- * Null is a concrete type that implements CBOR major type 7, with additional item value for NULL
- */
-class Null : public Simple {
-  public:
-    static constexpr SimpleType kSimpleType = NULL_T;
-
-    explicit Null() {}
-
-    SimpleType simpleType() const override { return kSimpleType; }
-    const Null* asNull() const override { return this; }
-
-    size_t encodedSize() const override { return 1; }
-
-    using Item::encode;
-    uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
-        return encodeHeader(NULL_V, pos, end);
-    }
-    void encode(EncodeCallback encodeCallback) const override {
-        encodeHeader(NULL_V, encodeCallback);
-    }
-
-    virtual std::unique_ptr<Item> clone() const override { return std::make_unique<Null>(); }
-};
-
-template <typename T>
-std::unique_ptr<T> downcastItem(std::unique_ptr<Item>&& v) {
-    static_assert(std::is_base_of_v<Item, T> && !std::is_abstract_v<T>,
-                  "returned type is not an Item or is an abstract class");
-    if (v && T::kMajorType == v->type()) {
-        if constexpr (std::is_base_of_v<Simple, T>) {
-            if (T::kSimpleType != v->asSimple()->simpleType()) {
-                return nullptr;
-            }
-        }
-        return std::unique_ptr<T>(static_cast<T*>(v.release()));
-    } else {
-        return nullptr;
-    }
-}
-
-/**
- * Details. Mostly you shouldn't have to look below, except perhaps at the docstring for makeItem.
- */
-namespace details {
-
-template <typename T, typename V, typename Enable = void>
-struct is_iterator_pair_over : public std::false_type {};
-
-template <typename I1, typename I2, typename V>
-struct is_iterator_pair_over<
-        std::pair<I1, I2>, V,
-        typename std::enable_if_t<std::is_same_v<V, typename std::iterator_traits<I1>::value_type>>>
-    : public std::true_type {};
-
-template <typename T, typename V, typename Enable = void>
-struct is_unique_ptr_of_subclass_of_v : public std::false_type {};
-
-template <typename T, typename P>
-struct is_unique_ptr_of_subclass_of_v<T, std::unique_ptr<P>,
-                                      typename std::enable_if_t<std::is_base_of_v<T, P>>>
-    : public std::true_type {};
-
-/* check if type is one of std::string (1), std::string_view (2), null-terminated char* (3) or pair
- *     of iterators (4)*/
-template <typename T, typename Enable = void>
-struct is_text_type_v : public std::false_type {};
-
-template <typename T>
-struct is_text_type_v<
-        T, typename std::enable_if_t<
-                   /* case 1 */  //
-                   std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, std::string>
-                   /* case 2 */  //
-                   || std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, std::string_view>
-                   /* case 3 */                                                 //
-                   || std::is_same_v<std::remove_cv_t<std::decay_t<T>>, char*>  //
-                   || std::is_same_v<std::remove_cv_t<std::decay_t<T>>, const char*>
-                   /* case 4 */
-                   || details::is_iterator_pair_over<T, char>::value>> : public std::true_type {};
-
-/**
- * Construct a unique_ptr<Item> from many argument types. Accepts:
- *
- * (a) booleans;
- * (b) integers, all sizes and signs;
- * (c) text strings, as defined by is_text_type_v above;
- * (d) byte strings, as std::vector<uint8_t>(d1), pair of iterators (d2) or pair<uint8_t*, size_T>
- *     (d3); and
- * (e) Item subclass instances, including Array and Map.  Items may be provided by naked pointer
- *     (e1), unique_ptr (e2), reference (e3) or value (e3).  If provided by reference or value, will
- *     be moved if possible.  If provided by pointer, ownership is taken.
- * (f) null pointer;
- */
-template <typename T>
-std::unique_ptr<Item> makeItem(T v) {
-    Item* p = nullptr;
-    if constexpr (/* case a */ std::is_same_v<T, bool>) {
-        p = new Bool(v);
-    } else if constexpr (/* case b */ std::is_integral_v<T>) {  // b
-        if (v < 0) {
-            p = new Nint(v);
-        } else {
-            p = new Uint(static_cast<uint64_t>(v));
-        }
-    } else if constexpr (/* case c */  //
-                         details::is_text_type_v<T>::value) {
-        p = new Tstr(v);
-    } else if constexpr (/* case d1 */  //
-                         std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>,
-                                        std::vector<uint8_t>>
-                         /* case d2 */  //
-                         || details::is_iterator_pair_over<T, uint8_t>::value
-                         /* case d3 */  //
-                         || std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>,
-                                           std::pair<uint8_t*, size_t>>) {
-        p = new Bstr(v);
-    } else if constexpr (/* case e1 */  //
-                         std::is_pointer_v<T> &&
-                         std::is_base_of_v<Item, std::remove_pointer_t<T>>) {
-        p = v;
-    } else if constexpr (/* case e2 */  //
-                         details::is_unique_ptr_of_subclass_of_v<Item, T>::value) {
-        p = v.release();
-    } else if constexpr (/* case e3 */  //
-                         std::is_base_of_v<Item, T>) {
-        p = new T(std::move(v));
-    } else if constexpr (/* case f */ std::is_null_pointer_v<T>) {
-        p = new Null();
-    } else {
-        // It's odd that this can't be static_assert(false), since it shouldn't be evaluated if one
-        // of the above ifs matches.  But static_assert(false) always triggers.
-        static_assert(std::is_same_v<T, bool>, "makeItem called with unsupported type");
-    }
-    return std::unique_ptr<Item>(p);
-}
-
-}  // namespace details
-
-template <typename... Args,
-          /* Prevent use as copy ctor */ typename = std::enable_if_t<
-                  (sizeof...(Args)) != 1 ||
-                  !(std::is_same_v<Array, std::remove_cv_t<std::remove_reference_t<Args>>> || ...)>>
-Array::Array(Args&&... args) {
-    mEntries.reserve(sizeof...(args));
-    (mEntries.push_back(details::makeItem(std::forward<Args>(args))), ...);
-}
-
-template <typename T>
-Array& Array::add(T&& v) & {
-    mEntries.push_back(details::makeItem(std::forward<T>(v)));
-    return *this;
-}
-
-template <typename T>
-Array&& Array::add(T&& v) && {
-    mEntries.push_back(details::makeItem(std::forward<T>(v)));
-    return std::move(*this);
-}
-
-template <typename... Args,
-          /* Prevent use as copy ctor */ typename = std::enable_if_t<(sizeof...(Args)) != 1>>
-Map::Map(Args&&... args) {
-    static_assert((sizeof...(Args)) % 2 == 0, "Map must have an even number of entries");
-    mEntries.reserve(sizeof...(args));
-    (mEntries.push_back(details::makeItem(std::forward<Args>(args))), ...);
-}
-
-template <typename Key, typename Value>
-Map& Map::add(Key&& key, Value&& value) & {
-    mEntries.push_back(details::makeItem(std::forward<Key>(key)));
-    mEntries.push_back(details::makeItem(std::forward<Value>(value)));
-    return *this;
-}
-
-template <typename Key, typename Value>
-Map&& Map::add(Key&& key, Value&& value) && {
-    this->add(std::forward<Key>(key), std::forward<Value>(value));
-    return std::move(*this);
-}
-
-template <typename Key, typename = std::enable_if_t<std::is_integral_v<Key> ||
-                                                    details::is_text_type_v<Key>::value>>
-std::pair<std::unique_ptr<Item>&, bool> Map::get(Key key) {
-    assertInvariant();
-    auto keyItem = details::makeItem(key);
-    for (size_t i = 0; i < mEntries.size(); i += 2) {
-        if (*keyItem == *mEntries[i]) {
-            return {mEntries[i + 1], true};
-        }
-    }
-    return {keyItem, false};
-}
-
-template <typename T>
-Semantic::Semantic(uint64_t value, T&& child) : mValue(value) {
-    mEntries.reserve(1);
-    mEntries.push_back(details::makeItem(std::forward<T>(child)));
-}
-
-}  // namespace cppbor
diff --git a/identity/support/include/cppbor/cppbor_parse.h b/identity/support/include/cppbor/cppbor_parse.h
deleted file mode 100644
index 66cd5a3..0000000
--- a/identity/support/include/cppbor/cppbor_parse.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "cppbor.h"
-
-namespace cppbor {
-
-using ParseResult = std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */,
-                               std::string /* errMsg */>;
-
-/**
- * Parse the first CBOR data item (possibly compound) from the range [begin, end).
- *
- * Returns a tuple of Item pointer, buffer pointer and error message.  If parsing is successful, the
- * Item pointer is non-null, the buffer pointer points to the first byte after the
- * successfully-parsed item and the error message string is empty.  If parsing fails, the Item
- * pointer is null, the buffer pointer points to the first byte that was unparseable (the first byte
- * of a data item header that is malformed in some way, e.g. an invalid value, or a length that is
- * too large for the remining buffer, etc.) and the string contains an error message describing the
- * problem encountered.
- */
-ParseResult parse(const uint8_t* begin, const uint8_t* end);
-
-/**
- * Parse the first CBOR data item (possibly compound) from the byte vector.
- *
- * Returns a tuple of Item pointer, buffer pointer and error message.  If parsing is successful, the
- * Item pointer is non-null, the buffer pointer points to the first byte after the
- * successfully-parsed item and the error message string is empty.  If parsing fails, the Item
- * pointer is null, the buffer pointer points to the first byte that was unparseable (the first byte
- * of a data item header that is malformed in some way, e.g. an invalid value, or a length that is
- * too large for the remining buffer, etc.) and the string contains an error message describing the
- * problem encountered.
- */
-inline ParseResult parse(const std::vector<uint8_t>& encoding) {
-    return parse(encoding.data(), encoding.data() + encoding.size());
-}
-
-/**
- * Parse the first CBOR data item (possibly compound) from the range [begin, begin + size).
- *
- * Returns a tuple of Item pointer, buffer pointer and error message.  If parsing is successful, the
- * Item pointer is non-null, the buffer pointer points to the first byte after the
- * successfully-parsed item and the error message string is empty.  If parsing fails, the Item
- * pointer is null, the buffer pointer points to the first byte that was unparseable (the first byte
- * of a data item header that is malformed in some way, e.g. an invalid value, or a length that is
- * too large for the remining buffer, etc.) and the string contains an error message describing the
- * problem encountered.
- */
-inline ParseResult parse(const uint8_t* begin, size_t size) {
-    return parse(begin, begin + size);
-}
-
-class ParseClient;
-
-/**
- * Parse the CBOR data in the range [begin, end) in streaming fashion, calling methods on the
- * provided ParseClient when elements are found.
- */
-void parse(const uint8_t* begin, const uint8_t* end, ParseClient* parseClient);
-
-/**
- * Parse the CBOR data in the vector in streaming fashion, calling methods on the
- * provided ParseClient when elements are found.
- */
-inline void parse(const std::vector<uint8_t>& encoding, ParseClient* parseClient) {
-    return parse(encoding.data(), encoding.data() + encoding.size(), parseClient);
-}
-
-/**
- * A pure interface that callers of the streaming parse functions must implement.
- */
-class ParseClient {
-  public:
-    virtual ~ParseClient() {}
-
-    /**
-     * Called when an item is found.  The Item pointer points to the found item; use type() and
-     * the appropriate as*() method to examine the value.  hdrBegin points to the first byte of the
-     * header, valueBegin points to the first byte of the value and end points one past the end of
-     * the item.  In the case of header-only items, such as integers, and compound items (ARRAY,
-     * MAP or SEMANTIC) whose end has not yet been found, valueBegin and end are equal and point to
-     * the byte past the header.
-     *
-     * Note that for compound types (ARRAY, MAP, and SEMANTIC), the Item will have no content.  For
-     * Map and Array items, the size() method will return a correct value, but the index operators
-     * are unsafe, and the object cannot be safely compared with another Array/Map.
-     *
-     * The method returns a ParseClient*.  In most cases "return this;" will be the right answer,
-     * but a different ParseClient may be returned, which the parser will begin using. If the method
-     * returns nullptr, parsing will be aborted immediately.
-     */
-    virtual ParseClient* item(std::unique_ptr<Item>& item, const uint8_t* hdrBegin,
-                              const uint8_t* valueBegin, const uint8_t* end) = 0;
-
-    /**
-     * Called when the end of a compound item (MAP or ARRAY) is found.  The item argument will be
-     * the same one passed to the item() call -- and may be empty if item() moved its value out.
-     * hdrBegin, valueBegin and end point to the beginning of the item header, the beginning of the
-     * first contained value, and one past the end of the last contained value, respectively.
-     *
-     * Note that the Item will have no content.
-     *
-     * As with item(), itemEnd() can change the ParseClient by returning a different one, or end the
-     * parsing by returning nullptr;
-     */
-    virtual ParseClient* itemEnd(std::unique_ptr<Item>& item, const uint8_t* hdrBegin,
-                                 const uint8_t* valueBegin, const uint8_t* end) = 0;
-
-    /**
-     * Called when parsing encounters an error.  position is set to the first unparsed byte (one
-     * past the last successfully-parsed byte) and errorMessage contains an message explaining what
-     * sort of error occurred.
-     */
-    virtual void error(const uint8_t* position, const std::string& errorMessage) = 0;
-};
-
-}  // namespace cppbor
diff --git a/identity/support/src/cppbor.cpp b/identity/support/src/cppbor.cpp
deleted file mode 100644
index d289985..0000000
--- a/identity/support/src/cppbor.cpp
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "cppbor.h"
-#include "cppbor_parse.h"
-
-#define LOG_TAG "CppBor"
-#include <android-base/logging.h>
-
-namespace cppbor {
-
-namespace {
-
-template <typename T, typename Iterator, typename = std::enable_if<std::is_unsigned<T>::value>>
-Iterator writeBigEndian(T value, Iterator pos) {
-    for (unsigned i = 0; i < sizeof(value); ++i) {
-        *pos++ = static_cast<uint8_t>(value >> (8 * (sizeof(value) - 1)));
-        value = static_cast<T>(value << 8);
-    }
-    return pos;
-}
-
-template <typename T, typename = std::enable_if<std::is_unsigned<T>::value>>
-void writeBigEndian(T value, std::function<void(uint8_t)>& cb) {
-    for (unsigned i = 0; i < sizeof(value); ++i) {
-        cb(static_cast<uint8_t>(value >> (8 * (sizeof(value) - 1))));
-        value = static_cast<T>(value << 8);
-    }
-}
-
-}  // namespace
-
-size_t headerSize(uint64_t addlInfo) {
-    if (addlInfo < ONE_BYTE_LENGTH) return 1;
-    if (addlInfo <= std::numeric_limits<uint8_t>::max()) return 2;
-    if (addlInfo <= std::numeric_limits<uint16_t>::max()) return 3;
-    if (addlInfo <= std::numeric_limits<uint32_t>::max()) return 5;
-    return 9;
-}
-
-uint8_t* encodeHeader(MajorType type, uint64_t addlInfo, uint8_t* pos, const uint8_t* end) {
-    size_t sz = headerSize(addlInfo);
-    if (end - pos < static_cast<ssize_t>(sz)) return nullptr;
-    switch (sz) {
-        case 1:
-            *pos++ = type | static_cast<uint8_t>(addlInfo);
-            return pos;
-        case 2:
-            *pos++ = type | ONE_BYTE_LENGTH;
-            *pos++ = static_cast<uint8_t>(addlInfo);
-            return pos;
-        case 3:
-            *pos++ = type | TWO_BYTE_LENGTH;
-            return writeBigEndian(static_cast<uint16_t>(addlInfo), pos);
-        case 5:
-            *pos++ = type | FOUR_BYTE_LENGTH;
-            return writeBigEndian(static_cast<uint32_t>(addlInfo), pos);
-        case 9:
-            *pos++ = type | EIGHT_BYTE_LENGTH;
-            return writeBigEndian(addlInfo, pos);
-        default:
-            CHECK(false);  // Impossible to get here.
-            return nullptr;
-    }
-}
-
-void encodeHeader(MajorType type, uint64_t addlInfo, EncodeCallback encodeCallback) {
-    size_t sz = headerSize(addlInfo);
-    switch (sz) {
-        case 1:
-            encodeCallback(type | static_cast<uint8_t>(addlInfo));
-            break;
-        case 2:
-            encodeCallback(type | ONE_BYTE_LENGTH);
-            encodeCallback(static_cast<uint8_t>(addlInfo));
-            break;
-        case 3:
-            encodeCallback(type | TWO_BYTE_LENGTH);
-            writeBigEndian(static_cast<uint16_t>(addlInfo), encodeCallback);
-            break;
-        case 5:
-            encodeCallback(type | FOUR_BYTE_LENGTH);
-            writeBigEndian(static_cast<uint32_t>(addlInfo), encodeCallback);
-            break;
-        case 9:
-            encodeCallback(type | EIGHT_BYTE_LENGTH);
-            writeBigEndian(addlInfo, encodeCallback);
-            break;
-        default:
-            CHECK(false);  // Impossible to get here.
-    }
-}
-
-bool Item::operator==(const Item& other) const& {
-    if (type() != other.type()) return false;
-    switch (type()) {
-        case UINT:
-            return *asUint() == *(other.asUint());
-        case NINT:
-            return *asNint() == *(other.asNint());
-        case BSTR:
-            return *asBstr() == *(other.asBstr());
-        case TSTR:
-            return *asTstr() == *(other.asTstr());
-        case ARRAY:
-            return *asArray() == *(other.asArray());
-        case MAP:
-            return *asMap() == *(other.asMap());
-        case SIMPLE:
-            return *asSimple() == *(other.asSimple());
-        case SEMANTIC:
-            return *asSemantic() == *(other.asSemantic());
-        default:
-            CHECK(false);  // Impossible to get here.
-            return false;
-    }
-}
-
-Nint::Nint(int64_t v) : mValue(v) {
-    CHECK(v < 0) << "Only negative values allowed";
-}
-
-bool Simple::operator==(const Simple& other) const& {
-    if (simpleType() != other.simpleType()) return false;
-
-    switch (simpleType()) {
-        case BOOLEAN:
-            return *asBool() == *(other.asBool());
-        case NULL_T:
-            return true;
-        default:
-            CHECK(false);  // Impossible to get here.
-            return false;
-    }
-}
-
-uint8_t* Bstr::encode(uint8_t* pos, const uint8_t* end) const {
-    pos = encodeHeader(mValue.size(), pos, end);
-    if (!pos || end - pos < static_cast<ptrdiff_t>(mValue.size())) return nullptr;
-    return std::copy(mValue.begin(), mValue.end(), pos);
-}
-
-void Bstr::encodeValue(EncodeCallback encodeCallback) const {
-    for (auto c : mValue) {
-        encodeCallback(c);
-    }
-}
-
-uint8_t* Tstr::encode(uint8_t* pos, const uint8_t* end) const {
-    pos = encodeHeader(mValue.size(), pos, end);
-    if (!pos || end - pos < static_cast<ptrdiff_t>(mValue.size())) return nullptr;
-    return std::copy(mValue.begin(), mValue.end(), pos);
-}
-
-void Tstr::encodeValue(EncodeCallback encodeCallback) const {
-    for (auto c : mValue) {
-        encodeCallback(static_cast<uint8_t>(c));
-    }
-}
-
-bool CompoundItem::operator==(const CompoundItem& other) const& {
-    return type() == other.type()             //
-           && addlInfo() == other.addlInfo()  //
-           // Can't use vector::operator== because the contents are pointers.  std::equal lets us
-           // provide a predicate that does the dereferencing.
-           && std::equal(mEntries.begin(), mEntries.end(), other.mEntries.begin(),
-                         [](auto& a, auto& b) -> bool { return *a == *b; });
-}
-
-uint8_t* CompoundItem::encode(uint8_t* pos, const uint8_t* end) const {
-    pos = encodeHeader(addlInfo(), pos, end);
-    if (!pos) return nullptr;
-    for (auto& entry : mEntries) {
-        pos = entry->encode(pos, end);
-        if (!pos) return nullptr;
-    }
-    return pos;
-}
-
-void CompoundItem::encode(EncodeCallback encodeCallback) const {
-    encodeHeader(addlInfo(), encodeCallback);
-    for (auto& entry : mEntries) {
-        entry->encode(encodeCallback);
-    }
-}
-
-void Map::assertInvariant() const {
-    CHECK(mEntries.size() % 2 == 0);
-}
-
-std::unique_ptr<Item> Map::clone() const {
-    assertInvariant();
-    auto res = std::make_unique<Map>();
-    for (size_t i = 0; i < mEntries.size(); i += 2) {
-        res->add(mEntries[i]->clone(), mEntries[i + 1]->clone());
-    }
-    return res;
-}
-
-std::unique_ptr<Item> Array::clone() const {
-    auto res = std::make_unique<Array>();
-    for (size_t i = 0; i < mEntries.size(); i++) {
-        res->add(mEntries[i]->clone());
-    }
-    return res;
-}
-
-void Semantic::assertInvariant() const {
-    CHECK(mEntries.size() == 1);
-}
-
-}  // namespace cppbor
diff --git a/identity/support/src/cppbor_parse.cpp b/identity/support/src/cppbor_parse.cpp
deleted file mode 100644
index c9ebb8a..0000000
--- a/identity/support/src/cppbor_parse.cpp
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "cppbor_parse.h"
-
-#include <sstream>
-#include <stack>
-
-#define LOG_TAG "CppBor"
-#include <android-base/logging.h>
-
-namespace cppbor {
-
-namespace {
-
-std::string insufficientLengthString(size_t bytesNeeded, size_t bytesAvail,
-                                     const std::string& type) {
-    std::stringstream errStream;
-    errStream << "Need " << bytesNeeded << " byte(s) for " << type << ", have " << bytesAvail
-              << ".";
-    return errStream.str();
-}
-
-template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
-std::tuple<bool, uint64_t, const uint8_t*> parseLength(const uint8_t* pos, const uint8_t* end,
-                                                       ParseClient* parseClient) {
-    if (pos + sizeof(T) > end) {
-        parseClient->error(pos - 1, insufficientLengthString(sizeof(T), end - pos, "length field"));
-        return {false, 0, pos};
-    }
-
-    const uint8_t* intEnd = pos + sizeof(T);
-    T result = 0;
-    do {
-        result = static_cast<T>((result << 8) | *pos++);
-    } while (pos < intEnd);
-    return {true, result, pos};
-}
-
-std::tuple<const uint8_t*, ParseClient*> parseRecursively(const uint8_t* begin, const uint8_t* end,
-                                                          ParseClient* parseClient);
-
-std::tuple<const uint8_t*, ParseClient*> handleUint(uint64_t value, const uint8_t* hdrBegin,
-                                                    const uint8_t* hdrEnd,
-                                                    ParseClient* parseClient) {
-    std::unique_ptr<Item> item = std::make_unique<Uint>(value);
-    return {hdrEnd,
-            parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
-}
-
-std::tuple<const uint8_t*, ParseClient*> handleNint(uint64_t value, const uint8_t* hdrBegin,
-                                                    const uint8_t* hdrEnd,
-                                                    ParseClient* parseClient) {
-    if (value > std::numeric_limits<int64_t>::max()) {
-        parseClient->error(hdrBegin, "NINT values that don't fit in int64_t are not supported.");
-        return {hdrBegin, nullptr /* end parsing */};
-    }
-    std::unique_ptr<Item> item = std::make_unique<Nint>(-1 - static_cast<uint64_t>(value));
-    return {hdrEnd,
-            parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
-}
-
-std::tuple<const uint8_t*, ParseClient*> handleBool(uint64_t value, const uint8_t* hdrBegin,
-                                                    const uint8_t* hdrEnd,
-                                                    ParseClient* parseClient) {
-    std::unique_ptr<Item> item = std::make_unique<Bool>(value == TRUE);
-    return {hdrEnd,
-            parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
-}
-
-std::tuple<const uint8_t*, ParseClient*> handleNull(const uint8_t* hdrBegin, const uint8_t* hdrEnd,
-                                                    ParseClient* parseClient) {
-    std::unique_ptr<Item> item = std::make_unique<Null>();
-    return {hdrEnd,
-            parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
-}
-
-template <typename T>
-std::tuple<const uint8_t*, ParseClient*> handleString(uint64_t length, const uint8_t* hdrBegin,
-                                                      const uint8_t* valueBegin, const uint8_t* end,
-                                                      const std::string& errLabel,
-                                                      ParseClient* parseClient) {
-    if (end - valueBegin < static_cast<ssize_t>(length)) {
-        parseClient->error(hdrBegin, insufficientLengthString(length, end - valueBegin, errLabel));
-        return {hdrBegin, nullptr /* end parsing */};
-    }
-
-    std::unique_ptr<Item> item = std::make_unique<T>(valueBegin, valueBegin + length);
-    return {valueBegin + length,
-            parseClient->item(item, hdrBegin, valueBegin, valueBegin + length)};
-}
-
-class IncompleteItem {
-  public:
-    virtual ~IncompleteItem() {}
-    virtual void add(std::unique_ptr<Item> item) = 0;
-};
-
-class IncompleteArray : public Array, public IncompleteItem {
-  public:
-    IncompleteArray(size_t size) : mSize(size) {}
-
-    // We return the "complete" size, rather than the actual size.
-    size_t size() const override { return mSize; }
-
-    void add(std::unique_ptr<Item> item) override {
-        mEntries.reserve(mSize);
-        mEntries.push_back(std::move(item));
-    }
-
-  private:
-    size_t mSize;
-};
-
-class IncompleteMap : public Map, public IncompleteItem {
-  public:
-    IncompleteMap(size_t size) : mSize(size) {}
-
-    // We return the "complete" size, rather than the actual size.
-    size_t size() const override { return mSize; }
-
-    void add(std::unique_ptr<Item> item) override {
-        mEntries.reserve(mSize * 2);
-        mEntries.push_back(std::move(item));
-    }
-
-  private:
-    size_t mSize;
-};
-
-class IncompleteSemantic : public Semantic, public IncompleteItem {
-  public:
-    IncompleteSemantic(uint64_t value) : Semantic(value) {}
-
-    // We return the "complete" size, rather than the actual size.
-    size_t size() const override { return 1; }
-
-    void add(std::unique_ptr<Item> item) override {
-        mEntries.reserve(1);
-        mEntries.push_back(std::move(item));
-    }
-};
-
-std::tuple<const uint8_t*, ParseClient*> handleEntries(size_t entryCount, const uint8_t* hdrBegin,
-                                                       const uint8_t* pos, const uint8_t* end,
-                                                       const std::string& typeName,
-                                                       ParseClient* parseClient) {
-    while (entryCount > 0) {
-        --entryCount;
-        if (pos == end) {
-            parseClient->error(hdrBegin, "Not enough entries for " + typeName + ".");
-            return {hdrBegin, nullptr /* end parsing */};
-        }
-        std::tie(pos, parseClient) = parseRecursively(pos, end, parseClient);
-        if (!parseClient) return {hdrBegin, nullptr};
-    }
-    return {pos, parseClient};
-}
-
-std::tuple<const uint8_t*, ParseClient*> handleCompound(
-        std::unique_ptr<Item> item, uint64_t entryCount, const uint8_t* hdrBegin,
-        const uint8_t* valueBegin, const uint8_t* end, const std::string& typeName,
-        ParseClient* parseClient) {
-    parseClient =
-            parseClient->item(item, hdrBegin, valueBegin, valueBegin /* don't know the end yet */);
-    if (!parseClient) return {hdrBegin, nullptr};
-
-    const uint8_t* pos;
-    std::tie(pos, parseClient) =
-            handleEntries(entryCount, hdrBegin, valueBegin, end, typeName, parseClient);
-    if (!parseClient) return {hdrBegin, nullptr};
-
-    return {pos, parseClient->itemEnd(item, hdrBegin, valueBegin, pos)};
-}
-
-std::tuple<const uint8_t*, ParseClient*> parseRecursively(const uint8_t* begin, const uint8_t* end,
-                                                          ParseClient* parseClient) {
-    const uint8_t* pos = begin;
-
-    MajorType type = static_cast<MajorType>(*pos & 0xE0);
-    uint8_t tagInt = *pos & 0x1F;
-    ++pos;
-
-    bool success = true;
-    uint64_t addlData;
-    if (tagInt < ONE_BYTE_LENGTH || tagInt > EIGHT_BYTE_LENGTH) {
-        addlData = tagInt;
-    } else {
-        switch (tagInt) {
-            case ONE_BYTE_LENGTH:
-                std::tie(success, addlData, pos) = parseLength<uint8_t>(pos, end, parseClient);
-                break;
-
-            case TWO_BYTE_LENGTH:
-                std::tie(success, addlData, pos) = parseLength<uint16_t>(pos, end, parseClient);
-                break;
-
-            case FOUR_BYTE_LENGTH:
-                std::tie(success, addlData, pos) = parseLength<uint32_t>(pos, end, parseClient);
-                break;
-
-            case EIGHT_BYTE_LENGTH:
-                std::tie(success, addlData, pos) = parseLength<uint64_t>(pos, end, parseClient);
-                break;
-
-            default:
-                CHECK(false);  //  It's impossible to get here
-                break;
-        }
-    }
-
-    if (!success) return {begin, nullptr};
-
-    switch (type) {
-        case UINT:
-            return handleUint(addlData, begin, pos, parseClient);
-
-        case NINT:
-            return handleNint(addlData, begin, pos, parseClient);
-
-        case BSTR:
-            return handleString<Bstr>(addlData, begin, pos, end, "byte string", parseClient);
-
-        case TSTR:
-            return handleString<Tstr>(addlData, begin, pos, end, "text string", parseClient);
-
-        case ARRAY:
-            return handleCompound(std::make_unique<IncompleteArray>(addlData), addlData, begin, pos,
-                                  end, "array", parseClient);
-
-        case MAP:
-            return handleCompound(std::make_unique<IncompleteMap>(addlData), addlData * 2, begin,
-                                  pos, end, "map", parseClient);
-
-        case SEMANTIC:
-            return handleCompound(std::make_unique<IncompleteSemantic>(addlData), 1, begin, pos,
-                                  end, "semantic", parseClient);
-
-        case SIMPLE:
-            switch (addlData) {
-                case TRUE:
-                case FALSE:
-                    return handleBool(addlData, begin, pos, parseClient);
-                case NULL_V:
-                    return handleNull(begin, pos, parseClient);
-            }
-    }
-    CHECK(false);  // Impossible to get here.
-    return {};
-}
-
-class FullParseClient : public ParseClient {
-  public:
-    virtual ParseClient* item(std::unique_ptr<Item>& item, const uint8_t*, const uint8_t*,
-                              const uint8_t* end) override {
-        if (mParentStack.empty() && !item->isCompound()) {
-            // This is the first and only item.
-            mTheItem = std::move(item);
-            mPosition = end;
-            return nullptr;  //  We're done.
-        }
-
-        if (item->isCompound()) {
-            // Starting a new compound data item, i.e. a new parent.  Save it on the parent stack.
-            // It's safe to save a raw pointer because the unique_ptr is guaranteed to stay in
-            // existence until the corresponding itemEnd() call.
-            assert(dynamic_cast<CompoundItem*>(item.get()));
-            mParentStack.push(static_cast<CompoundItem*>(item.get()));
-            return this;
-        } else {
-            appendToLastParent(std::move(item));
-            return this;
-        }
-    }
-
-    virtual ParseClient* itemEnd(std::unique_ptr<Item>& item, const uint8_t*, const uint8_t*,
-                                 const uint8_t* end) override {
-        CHECK(item->isCompound() && item.get() == mParentStack.top());
-        mParentStack.pop();
-
-        if (mParentStack.empty()) {
-            mTheItem = std::move(item);
-            mPosition = end;
-            return nullptr;  // We're done
-        } else {
-            appendToLastParent(std::move(item));
-            return this;
-        }
-    }
-
-    virtual void error(const uint8_t* position, const std::string& errorMessage) override {
-        mPosition = position;
-        mErrorMessage = errorMessage;
-    }
-
-    std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */,
-               std::string /* errMsg */>
-    parseResult() {
-        std::unique_ptr<Item> p = std::move(mTheItem);
-        return {std::move(p), mPosition, std::move(mErrorMessage)};
-    }
-
-  private:
-    void appendToLastParent(std::unique_ptr<Item> item) {
-        auto parent = mParentStack.top();
-        assert(dynamic_cast<IncompleteItem*>(parent));
-        if (parent->type() == ARRAY) {
-            static_cast<IncompleteArray*>(parent)->add(std::move(item));
-        } else if (parent->type() == MAP) {
-            static_cast<IncompleteMap*>(parent)->add(std::move(item));
-        } else if (parent->type() == SEMANTIC) {
-            static_cast<IncompleteSemantic*>(parent)->add(std::move(item));
-        } else {
-            CHECK(false);  // Impossible to get here.
-        }
-    }
-
-    std::unique_ptr<Item> mTheItem;
-    std::stack<CompoundItem*> mParentStack;
-    const uint8_t* mPosition = nullptr;
-    std::string mErrorMessage;
-};
-
-}  // anonymous namespace
-
-void parse(const uint8_t* begin, const uint8_t* end, ParseClient* parseClient) {
-    parseRecursively(begin, end, parseClient);
-}
-
-std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */,
-           std::string /* errMsg */>
-parse(const uint8_t* begin, const uint8_t* end) {
-    FullParseClient parseClient;
-    parse(begin, end, &parseClient);
-    return parseClient.parseResult();
-}
-
-}  // namespace cppbor
diff --git a/identity/support/tests/cppbor_test.cpp b/identity/support/tests/cppbor_test.cpp
deleted file mode 100644
index 3eb5598..0000000
--- a/identity/support/tests/cppbor_test.cpp
+++ /dev/null
@@ -1,1013 +0,0 @@
-/*
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <iomanip>
-#include <sstream>
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include "cppbor.h"
-#include "cppbor_parse.h"
-
-using namespace cppbor;
-using namespace std;
-
-using ::testing::_;
-using ::testing::AllOf;
-using ::testing::ByRef;
-using ::testing::InSequence;
-using ::testing::IsNull;
-using ::testing::NotNull;
-using ::testing::Return;
-using ::testing::Truly;
-using ::testing::Unused;
-
-string hexDump(const string& str) {
-    stringstream s;
-    for (auto c : str) {
-        s << setfill('0') << setw(2) << hex << (static_cast<unsigned>(c) & 0xff);
-    }
-    return s.str();
-}
-
-TEST(SimpleValueTest, UnsignedValueSizes) {
-    // Check that unsigned integers encode to correct lengths, and that encodedSize() is correct.
-    vector<pair<uint64_t /* value */, size_t /* expected encoded size */>> testCases{
-            {0, 1},
-            {1, 1},
-            {23, 1},
-            {24, 2},
-            {255, 2},
-            {256, 3},
-            {65535, 3},
-            {65536, 5},
-            {4294967295, 5},
-            {4294967296, 9},
-            {std::numeric_limits<uint64_t>::max(), 9},
-    };
-    for (auto& testCase : testCases) {
-        Uint val(testCase.first);
-        EXPECT_EQ(testCase.second, val.encodedSize()) << "Wrong size for value " << testCase.first;
-        EXPECT_EQ(val.encodedSize(), val.toString().size())
-                << "encodedSize and encoding disagree for value " << testCase.first;
-    }
-}
-
-TEST(SimpleValueTest, UnsignedValueEncodings) {
-    EXPECT_EQ("\x00"s, Uint(0u).toString());
-    EXPECT_EQ("\x01"s, Uint(1u).toString());
-    EXPECT_EQ("\x0a"s, Uint(10u).toString());
-    EXPECT_EQ("\x17"s, Uint(23u).toString());
-    EXPECT_EQ("\x18\x18"s, Uint(24u).toString());
-    EXPECT_EQ("\x18\x19"s, Uint(25u).toString());
-    EXPECT_EQ("\x18\x64"s, Uint(100u).toString());
-    EXPECT_EQ("\x19\x03\xe8"s, Uint(1000u).toString());
-    EXPECT_EQ("\x1a\x00\x0f\x42\x40"s, Uint(1000000u).toString());
-    EXPECT_EQ("\x1b\x00\x00\x00\xe8\xd4\xa5\x10\x00"s, Uint(1000000000000u).toString());
-    EXPECT_EQ("\x1B\x7f\xff\xff\xff\xff\xff\xff\xff"s,
-              Uint(std::numeric_limits<int64_t>::max()).toString());
-}
-
-TEST(SimpleValueTest, NegativeValueEncodings) {
-    EXPECT_EQ("\x20"s, Nint(-1).toString());
-    EXPECT_EQ("\x28"s, Nint(-9).toString());
-    EXPECT_EQ("\x29"s, Nint(-10).toString());
-    EXPECT_EQ("\x36"s, Nint(-23).toString());
-    EXPECT_EQ("\x37"s, Nint(-24).toString());
-    EXPECT_EQ("\x38\x18"s, Nint(-25).toString());
-    EXPECT_EQ("\x38\x62"s, Nint(-99).toString());
-    EXPECT_EQ("\x38\x63"s, Nint(-100).toString());
-    EXPECT_EQ("\x39\x03\xe6"s, Nint(-999).toString());
-    EXPECT_EQ("\x39\x03\xe7"s, Nint(-1000).toString());
-    EXPECT_EQ("\x3a\x00\x0f\x42\x3F"s, Nint(-1000000).toString());
-    EXPECT_EQ("\x3b\x00\x00\x00\xe8\xd4\xa5\x0f\xff"s, Nint(-1000000000000).toString());
-    EXPECT_EQ("\x3B\x7f\xff\xff\xff\xff\xff\xff\xff"s,
-              Nint(std::numeric_limits<int64_t>::min()).toString());
-}
-
-TEST(SimpleValueDeathTest, NegativeValueEncodings) {
-    EXPECT_DEATH(Nint(0), "");
-    EXPECT_DEATH(Nint(1), "");
-}
-
-TEST(SimpleValueTest, BooleanEncodings) {
-    EXPECT_EQ("\xf4"s, Bool(false).toString());
-    EXPECT_EQ("\xf5"s, Bool(true).toString());
-}
-
-TEST(SimpleValueTest, ByteStringEncodings) {
-    EXPECT_EQ("\x40", Bstr("").toString());
-    EXPECT_EQ("\x41\x61", Bstr("a").toString());
-    EXPECT_EQ("\x41\x41", Bstr("A").toString());
-    EXPECT_EQ("\x44\x49\x45\x54\x46", Bstr("IETF").toString());
-    EXPECT_EQ("\x42\x22\x5c", Bstr("\"\\").toString());
-    EXPECT_EQ("\x42\xc3\xbc", Bstr("\xc3\xbc").toString());
-    EXPECT_EQ("\x43\xe6\xb0\xb4", Bstr("\xe6\xb0\xb4").toString());
-    EXPECT_EQ("\x44\xf0\x90\x85\x91", Bstr("\xf0\x90\x85\x91").toString());
-    EXPECT_EQ("\x44\x01\x02\x03\x04", Bstr("\x01\x02\x03\x04").toString());
-    EXPECT_EQ("\x44\x40\x40\x40\x40", Bstr("@@@@").toString());
-}
-
-TEST(SimpleValueTest, TextStringEncodings) {
-    EXPECT_EQ("\x60"s, Tstr("").toString());
-    EXPECT_EQ("\x61\x61"s, Tstr("a").toString());
-    EXPECT_EQ("\x61\x41"s, Tstr("A").toString());
-    EXPECT_EQ("\x64\x49\x45\x54\x46"s, Tstr("IETF").toString());
-    EXPECT_EQ("\x62\x22\x5c"s, Tstr("\"\\").toString());
-    EXPECT_EQ("\x62\xc3\xbc"s, Tstr("\xc3\xbc").toString());
-    EXPECT_EQ("\x63\xe6\xb0\xb4"s, Tstr("\xe6\xb0\xb4").toString());
-    EXPECT_EQ("\x64\xf0\x90\x85\x91"s, Tstr("\xf0\x90\x85\x91").toString());
-    EXPECT_EQ("\x64\x01\x02\x03\x04"s, Tstr("\x01\x02\x03\x04").toString());
-}
-
-TEST(IsIteratorPairOverTest, All) {
-    EXPECT_TRUE((
-            details::is_iterator_pair_over<pair<string::iterator, string::iterator>, char>::value));
-    EXPECT_TRUE((details::is_iterator_pair_over<pair<string::const_iterator, string::iterator>,
-                                                char>::value));
-    EXPECT_TRUE((details::is_iterator_pair_over<pair<string::iterator, string::const_iterator>,
-                                                char>::value));
-    EXPECT_TRUE((details::is_iterator_pair_over<pair<char*, char*>, char>::value));
-    EXPECT_TRUE((details::is_iterator_pair_over<pair<const char*, char*>, char>::value));
-    EXPECT_TRUE((details::is_iterator_pair_over<pair<char*, const char*>, char>::value));
-    EXPECT_FALSE((details::is_iterator_pair_over<pair<string::iterator, string::iterator>,
-                                                 uint8_t>::value));
-    EXPECT_FALSE((details::is_iterator_pair_over<pair<char*, char*>, uint8_t>::value));
-    EXPECT_TRUE((details::is_iterator_pair_over<
-                 pair<vector<uint8_t>::iterator, vector<uint8_t>::iterator>, uint8_t>::value));
-    EXPECT_TRUE((details::is_iterator_pair_over<
-                 pair<vector<uint8_t>::const_iterator, vector<uint8_t>::iterator>,
-                 uint8_t>::value));
-    EXPECT_TRUE((details::is_iterator_pair_over<
-                 pair<vector<uint8_t>::iterator, vector<uint8_t>::const_iterator>,
-                 uint8_t>::value));
-    EXPECT_TRUE((details::is_iterator_pair_over<pair<uint8_t*, uint8_t*>, uint8_t>::value));
-    EXPECT_TRUE((details::is_iterator_pair_over<pair<const uint8_t*, uint8_t*>, uint8_t>::value));
-    EXPECT_TRUE((details::is_iterator_pair_over<pair<uint8_t*, const uint8_t*>, uint8_t>::value));
-    EXPECT_FALSE((details::is_iterator_pair_over<
-                  pair<vector<uint8_t>::iterator, vector<uint8_t>::iterator>, char>::value));
-    EXPECT_FALSE((details::is_iterator_pair_over<pair<uint8_t*, const uint8_t*>, char>::value));
-}
-
-TEST(MakeEntryTest, Boolean) {
-    EXPECT_EQ("\xf4"s, details::makeItem(false)->toString());
-}
-
-TEST(MakeEntryTest, Integers) {
-    EXPECT_EQ("\x00"s, details::makeItem(static_cast<uint8_t>(0))->toString());
-    EXPECT_EQ("\x00"s, details::makeItem(static_cast<uint16_t>(0))->toString());
-    EXPECT_EQ("\x00"s, details::makeItem(static_cast<uint32_t>(0))->toString());
-    EXPECT_EQ("\x00"s, details::makeItem(static_cast<uint64_t>(0))->toString());
-    EXPECT_EQ("\x00"s, details::makeItem(static_cast<int8_t>(0))->toString());
-    EXPECT_EQ("\x00"s, details::makeItem(static_cast<int16_t>(0))->toString());
-    EXPECT_EQ("\x00"s, details::makeItem(static_cast<int32_t>(0))->toString());
-    EXPECT_EQ("\x00"s, details::makeItem(static_cast<int64_t>(0))->toString());
-    EXPECT_EQ("\x20"s, details::makeItem(static_cast<int8_t>(-1))->toString());
-    EXPECT_EQ("\x20"s, details::makeItem(static_cast<int16_t>(-1))->toString());
-    EXPECT_EQ("\x20"s, details::makeItem(static_cast<int32_t>(-1))->toString());
-    EXPECT_EQ("\x20"s, details::makeItem(static_cast<int64_t>(-1))->toString());
-
-    EXPECT_EQ("\x1b\xff\xff\xff\xff\xff\xff\xff\xff"s,
-              details::makeItem(static_cast<uint64_t>(std::numeric_limits<uint64_t>::max()))
-                      ->toString());
-}
-
-TEST(MakeEntryTest, StdStrings) {
-    string s1("hello");
-    const string s2("hello");
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(s1)->toString());  // copy of string
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s,
-              details::makeItem(s2)->toString());  // copy of const string
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s,
-              details::makeItem(std::move(s1))->toString());  // move string
-    EXPECT_EQ(0U, s1.size());                                 // Prove string was moved, not copied.
-}
-
-TEST(MakeEntryTest, StdStringViews) {
-    string_view s1("hello");
-    const string_view s2("hello");
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(s1)->toString());
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(s2)->toString());
-}
-
-TEST(MakeEntryTest, CStrings) {
-    char s1[] = "hello";
-    const char s2[] = "hello";
-    const char* s3 = "hello";
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(s1)->toString());
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(s2)->toString());
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(s3)->toString());
-}
-
-TEST(MakeEntryTest, StringIteratorPairs) {
-    // Use iterators from string to prove that "real" iterators work
-    string s1 = "hello"s;
-    pair<string::iterator, string::iterator> p1 = make_pair(s1.begin(), s1.end());
-
-    const pair<string::iterator, string::iterator> p2 = p1;
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(p1)->toString());
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(p2)->toString());
-
-    // Use char*s  as iterators
-    const char* s2 = "hello";
-    pair p3 = make_pair(s2, s2 + 5);
-    const pair p4 = p3;
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(p3)->toString());
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(p4)->toString());
-}
-
-TEST(MakeEntryTest, ByteStrings) {
-    vector<uint8_t> v1 = {0x00, 0x01, 0x02};
-    const vector<uint8_t> v2 = {0x00, 0x01, 0x02};
-    EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(v1)->toString());  // copy of vector
-    EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(v2)->toString());  // copy of const vector
-    EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(std::move(v1))->toString());  // move vector
-    EXPECT_EQ(0U, v1.size());  // Prove vector was moved, not copied.
-}
-
-TEST(MakeEntryTest, ByteStringIteratorPairs) {
-    using vec = vector<uint8_t>;
-    using iter = vec::iterator;
-    vec v1 = {0x00, 0x01, 0x02};
-    pair<iter, iter> p1 = make_pair(v1.begin(), v1.end());
-    const pair<iter, iter> p2 = make_pair(v1.begin(), v1.end());
-    EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(p1)->toString());
-    EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(p2)->toString());
-
-    // Use uint8_t*s as iterators
-    uint8_t v2[] = {0x00, 0x01, 0x02};
-    uint8_t* v3 = v2;
-    pair<uint8_t*, uint8_t*> p3 = make_pair(v2, v2 + 3);
-    const pair<uint8_t*, uint8_t*> p4 = make_pair(v2, v2 + 3);
-    pair<uint8_t*, uint8_t*> p5 = make_pair(v3, v3 + 3);
-    const pair<uint8_t*, uint8_t*> p6 = make_pair(v3, v3 + 3);
-    EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(p3)->toString());
-    EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(p4)->toString());
-    EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(p5)->toString());
-    EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(p6)->toString());
-}
-
-TEST(MakeEntryTest, ByteStringBuffers) {
-    uint8_t v1[] = {0x00, 0x01, 0x02};
-    EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(make_pair(v1, 3))->toString());
-}
-
-TEST(MakeEntryTest, ItemPointer) {
-    Uint* p1 = new Uint(0);
-    EXPECT_EQ("\x00"s, details::makeItem(p1)->toString());
-    EXPECT_EQ("\x60"s, details::makeItem(new Tstr(string()))->toString());
-}
-
-TEST(MakeEntryTest, ItemReference) {
-    Tstr str("hello"s);
-    Tstr& strRef = str;
-    const Tstr& strConstRef = str;
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(str)->toString());
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(strRef)->toString());
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(strConstRef)->toString());
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(std::move(str))->toString());
-    EXPECT_EQ("\x60"s, details::makeItem(str)->toString());  // Prove that it moved
-
-    EXPECT_EQ("\x00"s, details::makeItem(Uint(0))->toString());
-
-    EXPECT_EQ("\x43\x00\x01\x02"s,
-              details::makeItem(Bstr(vector<uint8_t>{0x00, 0x01, 0x02}))->toString());
-
-    EXPECT_EQ("\x80"s, details::makeItem(Array())->toString());
-    EXPECT_EQ("\xa0"s, details::makeItem(Map())->toString());
-}
-
-TEST(CompoundValueTest, ArrayOfInts) {
-    EXPECT_EQ("\x80"s, Array().toString());
-    Array(Uint(0)).toString();
-
-    EXPECT_EQ("\x81\x00"s, Array(Uint(0U)).toString());
-    EXPECT_EQ("\x82\x00\x01"s, Array(Uint(0), Uint(1)).toString());
-    EXPECT_EQ("\x83\x00\x01\x38\x62"s, Array(Uint(0), Uint(1), Nint(-99)).toString());
-
-    EXPECT_EQ("\x81\x00"s, Array(0).toString());
-    EXPECT_EQ("\x82\x00\x01"s, Array(0, 1).toString());
-    EXPECT_EQ("\x83\x00\x01\x38\x62"s, Array(0, 1, -99).toString());
-}
-
-TEST(CompoundValueTest, MapOfInts) {
-    EXPECT_EQ("\xA0"s, Map().toString());
-    EXPECT_EQ("\xA1\x00\x01"s, Map(Uint(0), Uint(1)).toString());
-    // Maps with an odd number of arguments will fail to compile.  Uncomment the next lines to test.
-    // EXPECT_EQ("\xA1\x00"s, Map(Int(0)).toString());
-    // EXPECT_EQ("\xA1\x00\x01\x02"s, Map(Int(0), Int(1), Int(2)).toString());
-}
-
-TEST(CompoundValueTest, MixedArray) {
-    vector<uint8_t> vec = {3, 2, 1};
-    EXPECT_EQ("\x84\x01\x20\x43\x03\x02\x01\x65\x68\x65\x6C\x6C\x6F"s,
-              Array(Uint(1), Nint(-1), Bstr(vec), Tstr("hello")).toString());
-
-    EXPECT_EQ("\x84\x01\x20\x43\x03\x02\x01\x65\x68\x65\x6C\x6C\x6F"s,
-              Array(1, -1, vec, "hello").toString());
-}
-
-TEST(CompoundValueTest, MixedMap) {
-    vector<uint8_t> vec = {3, 2, 1};
-    EXPECT_EQ("\xA2\x01\x20\x43\x03\x02\x01\x65\x68\x65\x6C\x6C\x6F"s,
-              Map(Uint(1), Nint(-1), Bstr(vec), Tstr("hello")).toString());
-
-    EXPECT_EQ("\xA2\x01\x20\x43\x03\x02\x01\x65\x68\x65\x6C\x6C\x6F"s,
-              Map(1, -1, vec, "hello").toString());
-}
-
-TEST(CompoundValueTest, NestedStructures) {
-    vector<uint8_t> vec = {3, 2, 1};
-
-    string expectedEncoding =
-            "\xA2\x66\x4F\x75\x74\x65\x72\x31\x82\xA2\x66\x49\x6E\x6E\x65\x72\x31\x18\x63\x66\x49"
-            "\x6E"
-            "\x6E\x65\x72\x32\x43\x03\x02\x01\x63\x66\x6F\x6F\x66\x4F\x75\x74\x65\x72\x32\x0A"s;
-
-    // Do it with explicitly-created Items
-    EXPECT_EQ(expectedEncoding,
-              Map(Tstr("Outer1"),
-                  Array(  //
-                          Map(Tstr("Inner1"), Uint(99), Tstr("Inner2"), Bstr(vec)), Tstr("foo")),
-                  Tstr("Outer2"),  //
-                  Uint(10))
-                      .toString());
-    EXPECT_EQ(3U, vec.size());
-
-    // Now just use convertible types
-    EXPECT_EQ(expectedEncoding, Map("Outer1",
-                                    Array(Map("Inner1", 99,  //
-                                              "Inner2", vec),
-                                          "foo"),
-                                    "Outer2", 10)
-                                        .toString());
-    EXPECT_EQ(3U, vec.size());
-
-    // Finally, do it with the .add() method.  This is slightly less efficient, but has the
-    // advantage you can build a structure up incrementally, or somewhat fluently if you like.
-    // First, fluently.
-    EXPECT_EQ(expectedEncoding, Map().add("Outer1", Array().add(Map()  //
-                                                                        .add("Inner1", 99)
-                                                                        .add("Inner2", vec))
-                                                            .add("foo"))
-                                        .add("Outer2", 10)
-                                        .toString());
-    EXPECT_EQ(3U, vec.size());
-
-    // Next, more incrementally
-    Array arr;
-    arr.add(Map()  //
-                    .add("Inner1", 99)
-                    .add("Inner2", vec))
-            .add("foo");
-    EXPECT_EQ(3U, vec.size());
-
-    Map m;
-    m.add("Outer1", std::move(arr));  // Moving is necessary; Map and Array cannot be copied.
-    m.add("Outer2", 10);
-    auto s = m.toString();
-    EXPECT_EQ(expectedEncoding, s);
-}
-
-TEST(EncodingMethodsTest, AllVariants) {
-    Map map;
-    map.add("key1", Array().add(Map()  //
-                                        .add("key_a", 9999999)
-                                        .add("key_b", std::vector<uint8_t>{0x01, 0x02, 0x03})
-                                        .add("key_c", std::numeric_limits<uint64_t>::max())
-                                        .add("key_d", std::numeric_limits<int16_t>::min()))
-                            .add("foo"))
-            .add("key2", true);
-
-    std::vector<uint8_t> buf;
-    buf.resize(map.encodedSize());
-
-    EXPECT_EQ(buf.data() + buf.size(), map.encode(buf.data(), buf.data() + buf.size()));
-
-    EXPECT_EQ(buf, map.encode());
-
-    std::vector<uint8_t> buf2;
-    map.encode(std::back_inserter(buf2));
-    EXPECT_EQ(buf, buf2);
-
-    auto iter = buf.begin();
-    map.encode([&](uint8_t c) { EXPECT_EQ(c, *iter++); });
-}
-
-TEST(EncodingMethodsTest, UintWithTooShortBuf) {
-    Uint val(100000);
-    vector<uint8_t> buf(val.encodedSize() - 1);
-    EXPECT_EQ(nullptr, val.encode(buf.data(), buf.data() + buf.size()));
-}
-
-TEST(EncodingMethodsTest, TstrWithTooShortBuf) {
-    Tstr val("01234567890123456789012345"s);
-    vector<uint8_t> buf(1);
-    EXPECT_EQ(nullptr, val.encode(buf.data(), buf.data() + buf.size()));
-
-    buf.resize(val.encodedSize() - 1);
-    EXPECT_EQ(nullptr, val.encode(buf.data(), buf.data() + buf.size()));
-}
-
-TEST(EncodingMethodsTest, BstrWithTooShortBuf) {
-    Bstr val("01234567890123456789012345"s);
-    vector<uint8_t> buf(1);
-    EXPECT_EQ(nullptr, val.encode(buf.data(), buf.data() + buf.size()));
-
-    buf.resize(val.encodedSize() - 1);
-    EXPECT_EQ(nullptr, val.encode(buf.data(), buf.data() + buf.size()));
-}
-
-TEST(EncodingMethodsTest, ArrayWithTooShortBuf) {
-    Array val("a", 5, -100);
-
-    std::vector<uint8_t> buf(val.encodedSize() - 1);
-    EXPECT_EQ(nullptr, val.encode(buf.data(), buf.data() + buf.size()));
-}
-
-TEST(EncodingMethodsTest, MapWithTooShortBuf) {
-    Map map;
-    map.add("key1", Array().add(Map()  //
-                                        .add("key_a", 99)
-                                        .add("key_b", std::vector<uint8_t>{0x01, 0x02, 0x03}))
-                            .add("foo"))
-            .add("key2", true);
-
-    std::vector<uint8_t> buf(map.encodedSize() - 1);
-    EXPECT_EQ(nullptr, map.encode(buf.data(), buf.data() + buf.size()));
-}
-
-TEST(EqualityTest, Uint) {
-    Uint val(99);
-    EXPECT_EQ(val, Uint(99));
-
-    EXPECT_NE(val, Uint(98));
-    EXPECT_NE(val, Nint(-1));
-    EXPECT_NE(val, Tstr("99"));
-    EXPECT_NE(val, Bstr("99"));
-    EXPECT_NE(val, Bool(false));
-    EXPECT_NE(val, Array(99, 1));
-    EXPECT_NE(val, Map(99, 1));
-}
-
-TEST(EqualityTest, Nint) {
-    Nint val(-1);
-    EXPECT_EQ(val, Nint(-1));
-
-    EXPECT_NE(val, Uint(99));
-    EXPECT_NE(val, Nint(-4));
-    EXPECT_NE(val, Tstr("99"));
-    EXPECT_NE(val, Bstr("99"));
-    EXPECT_NE(val, Bool(false));
-    EXPECT_NE(val, Array(99));
-    EXPECT_NE(val, Map(99, 1));
-}
-
-TEST(EqualityTest, Tstr) {
-    Tstr val("99");
-    EXPECT_EQ(val, Tstr("99"));
-
-    EXPECT_NE(val, Uint(99));
-    EXPECT_NE(val, Nint(-1));
-    EXPECT_NE(val, Nint(-4));
-    EXPECT_NE(val, Tstr("98"));
-    EXPECT_NE(val, Bstr("99"));
-    EXPECT_NE(val, Bool(false));
-    EXPECT_NE(val, Array(99, 1));
-    EXPECT_NE(val, Map(99, 1));
-}
-
-TEST(EqualityTest, Bstr) {
-    Bstr val("99");
-    EXPECT_EQ(val, Bstr("99"));
-
-    EXPECT_NE(val, Uint(99));
-    EXPECT_NE(val, Nint(-1));
-    EXPECT_NE(val, Nint(-4));
-    EXPECT_NE(val, Tstr("99"));
-    EXPECT_NE(val, Bstr("98"));
-    EXPECT_NE(val, Bool(false));
-    EXPECT_NE(val, Array(99, 1));
-    EXPECT_NE(val, Map(99, 1));
-}
-
-TEST(EqualityTest, Bool) {
-    Bool val(false);
-    EXPECT_EQ(val, Bool(false));
-
-    EXPECT_NE(val, Uint(99));
-    EXPECT_NE(val, Nint(-1));
-    EXPECT_NE(val, Nint(-4));
-    EXPECT_NE(val, Tstr("99"));
-    EXPECT_NE(val, Bstr("98"));
-    EXPECT_NE(val, Bool(true));
-    EXPECT_NE(val, Array(99, 1));
-    EXPECT_NE(val, Map(99, 1));
-}
-
-TEST(EqualityTest, Array) {
-    Array val(99, 1);
-    EXPECT_EQ(val, Array(99, 1));
-
-    EXPECT_NE(val, Uint(99));
-    EXPECT_NE(val, Nint(-1));
-    EXPECT_NE(val, Nint(-4));
-    EXPECT_NE(val, Tstr("99"));
-    EXPECT_NE(val, Bstr("98"));
-    EXPECT_NE(val, Bool(true));
-    EXPECT_NE(val, Array(99, 2));
-    EXPECT_NE(val, Array(98, 1));
-    EXPECT_NE(val, Array(99, 1, 2));
-    EXPECT_NE(val, Map(99, 1));
-}
-
-TEST(EqualityTest, Map) {
-    Map val(99, 1);
-    EXPECT_EQ(val, Map(99, 1));
-
-    EXPECT_NE(val, Uint(99));
-    EXPECT_NE(val, Nint(-1));
-    EXPECT_NE(val, Nint(-4));
-    EXPECT_NE(val, Tstr("99"));
-    EXPECT_NE(val, Bstr("98"));
-    EXPECT_NE(val, Bool(true));
-    EXPECT_NE(val, Array(99, 1));
-    EXPECT_NE(val, Map(99, 2));
-    EXPECT_NE(val, Map(99, 1, 99, 2));
-}
-
-TEST(ConvertTest, Uint) {
-    unique_ptr<Item> item = details::makeItem(10);
-
-    EXPECT_EQ(UINT, item->type());
-    EXPECT_NE(nullptr, item->asInt());
-    EXPECT_NE(nullptr, item->asUint());
-    EXPECT_EQ(nullptr, item->asNint());
-    EXPECT_EQ(nullptr, item->asTstr());
-    EXPECT_EQ(nullptr, item->asBstr());
-    EXPECT_EQ(nullptr, item->asSimple());
-    EXPECT_EQ(nullptr, item->asMap());
-    EXPECT_EQ(nullptr, item->asArray());
-
-    EXPECT_EQ(10, item->asInt()->value());
-    EXPECT_EQ(10, item->asUint()->value());
-}
-
-TEST(ConvertTest, Nint) {
-    unique_ptr<Item> item = details::makeItem(-10);
-
-    EXPECT_EQ(NINT, item->type());
-    EXPECT_NE(nullptr, item->asInt());
-    EXPECT_EQ(nullptr, item->asUint());
-    EXPECT_NE(nullptr, item->asNint());
-    EXPECT_EQ(nullptr, item->asTstr());
-    EXPECT_EQ(nullptr, item->asBstr());
-    EXPECT_EQ(nullptr, item->asSimple());
-    EXPECT_EQ(nullptr, item->asMap());
-    EXPECT_EQ(nullptr, item->asArray());
-
-    EXPECT_EQ(-10, item->asInt()->value());
-    EXPECT_EQ(-10, item->asNint()->value());
-}
-
-TEST(ConvertTest, Tstr) {
-    unique_ptr<Item> item = details::makeItem("hello");
-
-    EXPECT_EQ(TSTR, item->type());
-    EXPECT_EQ(nullptr, item->asInt());
-    EXPECT_EQ(nullptr, item->asUint());
-    EXPECT_EQ(nullptr, item->asNint());
-    EXPECT_NE(nullptr, item->asTstr());
-    EXPECT_EQ(nullptr, item->asBstr());
-    EXPECT_EQ(nullptr, item->asSimple());
-    EXPECT_EQ(nullptr, item->asMap());
-    EXPECT_EQ(nullptr, item->asArray());
-
-    EXPECT_EQ("hello"s, item->asTstr()->value());
-}
-
-TEST(ConvertTest, Bstr) {
-    vector<uint8_t> vec{0x23, 0x24, 0x22};
-    unique_ptr<Item> item = details::makeItem(vec);
-
-    EXPECT_EQ(BSTR, item->type());
-    EXPECT_EQ(nullptr, item->asInt());
-    EXPECT_EQ(nullptr, item->asUint());
-    EXPECT_EQ(nullptr, item->asNint());
-    EXPECT_EQ(nullptr, item->asTstr());
-    EXPECT_NE(nullptr, item->asBstr());
-    EXPECT_EQ(nullptr, item->asSimple());
-    EXPECT_EQ(nullptr, item->asMap());
-    EXPECT_EQ(nullptr, item->asArray());
-
-    EXPECT_EQ(vec, item->asBstr()->value());
-}
-
-TEST(ConvertTest, Bool) {
-    unique_ptr<Item> item = details::makeItem(false);
-
-    EXPECT_EQ(SIMPLE, item->type());
-    EXPECT_EQ(nullptr, item->asInt());
-    EXPECT_EQ(nullptr, item->asUint());
-    EXPECT_EQ(nullptr, item->asNint());
-    EXPECT_EQ(nullptr, item->asTstr());
-    EXPECT_EQ(nullptr, item->asBstr());
-    EXPECT_NE(nullptr, item->asSimple());
-    EXPECT_EQ(nullptr, item->asMap());
-    EXPECT_EQ(nullptr, item->asArray());
-
-    EXPECT_EQ(BOOLEAN, item->asSimple()->simpleType());
-    EXPECT_NE(nullptr, item->asSimple()->asBool());
-
-    EXPECT_FALSE(item->asSimple()->asBool()->value());
-}
-
-TEST(ConvertTest, Map) {
-    unique_ptr<Item> item(new Map);
-
-    EXPECT_EQ(MAP, item->type());
-    EXPECT_EQ(nullptr, item->asInt());
-    EXPECT_EQ(nullptr, item->asUint());
-    EXPECT_EQ(nullptr, item->asNint());
-    EXPECT_EQ(nullptr, item->asTstr());
-    EXPECT_EQ(nullptr, item->asBstr());
-    EXPECT_EQ(nullptr, item->asSimple());
-    EXPECT_NE(nullptr, item->asMap());
-    EXPECT_EQ(nullptr, item->asArray());
-
-    EXPECT_EQ(0U, item->asMap()->size());
-}
-
-TEST(ConvertTest, Array) {
-    unique_ptr<Item> item(new Array);
-
-    EXPECT_EQ(ARRAY, item->type());
-    EXPECT_EQ(nullptr, item->asInt());
-    EXPECT_EQ(nullptr, item->asUint());
-    EXPECT_EQ(nullptr, item->asNint());
-    EXPECT_EQ(nullptr, item->asTstr());
-    EXPECT_EQ(nullptr, item->asBstr());
-    EXPECT_EQ(nullptr, item->asSimple());
-    EXPECT_EQ(nullptr, item->asMap());
-    EXPECT_NE(nullptr, item->asArray());
-
-    EXPECT_EQ(0U, item->asArray()->size());
-}
-
-class MockParseClient : public ParseClient {
-  public:
-    MOCK_METHOD4(item, ParseClient*(std::unique_ptr<Item>& item, const uint8_t* hdrBegin,
-                                    const uint8_t* valueBegin, const uint8_t* end));
-    MOCK_METHOD4(itemEnd, ParseClient*(std::unique_ptr<Item>& item, const uint8_t* hdrBegin,
-                                       const uint8_t* valueBegin, const uint8_t* end));
-    MOCK_METHOD2(error, void(const uint8_t* position, const std::string& errorMessage));
-};
-
-MATCHER_P(IsType, value, std::string("Type ") + (negation ? "doesn't match" : "matches")) {
-    return arg->type() == value;
-}
-
-MATCHER_P(MatchesItem, value, "") {
-    return arg && *arg == value;
-}
-
-MATCHER_P(IsArrayOfSize, value, "") {
-    return arg->type() == ARRAY && arg->asArray()->size() == value;
-}
-
-MATCHER_P(IsMapOfSize, value, "") {
-    return arg->type() == MAP && arg->asMap()->size() == value;
-}
-
-TEST(StreamParseTest, Uint) {
-    MockParseClient mpc;
-
-    Uint val(100);
-    auto encoded = val.encode();
-    uint8_t* encBegin = encoded.data();
-    uint8_t* encEnd = encoded.data() + encoded.size();
-
-    EXPECT_CALL(mpc, item(MatchesItem(val), encBegin, encEnd, encEnd)).WillOnce(Return(&mpc));
-    EXPECT_CALL(mpc, itemEnd(_, _, _, _)).Times(0);
-    EXPECT_CALL(mpc, error(_, _)).Times(0);
-
-    parse(encoded.data(), encoded.data() + encoded.size(), &mpc);
-}
-
-TEST(StreamParseTest, Nint) {
-    MockParseClient mpc;
-
-    Nint val(-10);
-    auto encoded = val.encode();
-    uint8_t* encBegin = encoded.data();
-    uint8_t* encEnd = encoded.data() + encoded.size();
-
-    EXPECT_CALL(mpc, item(MatchesItem(val), encBegin, encEnd, encEnd)).WillOnce(Return(&mpc));
-
-    EXPECT_CALL(mpc, itemEnd(_, _, _, _)).Times(0);
-    EXPECT_CALL(mpc, error(_, _)).Times(0);
-
-    parse(encoded.data(), encoded.data() + encoded.size(), &mpc);
-}
-
-TEST(StreamParseTest, Bool) {
-    MockParseClient mpc;
-
-    Bool val(true);
-    auto encoded = val.encode();
-    uint8_t* encBegin = encoded.data();
-    uint8_t* encEnd = encoded.data() + encoded.size();
-
-    EXPECT_CALL(mpc, item(MatchesItem(val), encBegin, encEnd, encEnd)).WillOnce(Return(&mpc));
-    EXPECT_CALL(mpc, itemEnd(_, _, _, _)).Times(0);
-    EXPECT_CALL(mpc, error(_, _)).Times(0);
-
-    parse(encoded.data(), encoded.data() + encoded.size(), &mpc);
-}
-
-TEST(StreamParseTest, Tstr) {
-    MockParseClient mpc;
-
-    Tstr val("Hello");
-    auto encoded = val.encode();
-    uint8_t* encBegin = encoded.data();
-    uint8_t* encEnd = encoded.data() + encoded.size();
-
-    EXPECT_CALL(mpc, item(MatchesItem(val), encBegin, encBegin + 1, encEnd)).WillOnce(Return(&mpc));
-    EXPECT_CALL(mpc, itemEnd(_, _, _, _)).Times(0);
-    EXPECT_CALL(mpc, error(_, _)).Times(0);
-
-    parse(encoded.data(), encoded.data() + encoded.size(), &mpc);
-}
-
-TEST(StreamParseTest, Bstr) {
-    MockParseClient mpc;
-
-    Bstr val("Hello");
-    auto encoded = val.encode();
-    uint8_t* encBegin = encoded.data();
-    uint8_t* encEnd = encoded.data() + encoded.size();
-
-    EXPECT_CALL(mpc, item(MatchesItem(val), encBegin, encBegin + 1, encEnd)).WillOnce(Return(&mpc));
-    EXPECT_CALL(mpc, itemEnd(_, _, _, _)).Times(0);
-    EXPECT_CALL(mpc, error(_, _)).Times(0);
-
-    parse(encoded.data(), encoded.data() + encoded.size(), &mpc);
-}
-
-TEST(StreamParseTest, Array) {
-    MockParseClient mpc;
-
-    Array val("Hello", 4, Array(-9, "Goodbye"), std::numeric_limits<uint64_t>::max());
-    ASSERT_NE(val[2]->asArray(), nullptr);
-    const Array& interior = *(val[2]->asArray());
-    auto encoded = val.encode();
-    uint8_t* encBegin = encoded.data();
-    uint8_t* encEnd = encoded.data() + encoded.size();
-
-    {
-        InSequence s;
-        const uint8_t* pos = encBegin;
-        EXPECT_CALL(mpc, item(IsArrayOfSize(val.size()), pos, pos + 1, pos + 1))
-                .WillOnce(Return(&mpc));
-        ++pos;
-        EXPECT_CALL(mpc, item(MatchesItem(ByRef(*val[0])), pos, pos + 1, pos + 6))
-                .WillOnce(Return(&mpc));
-        pos += 6;
-        EXPECT_CALL(mpc, item(MatchesItem(ByRef(*val[1])), pos, pos + 1, pos + 1))
-                .WillOnce(Return(&mpc));
-        ++pos;
-        const uint8_t* innerArrayBegin = pos;
-        EXPECT_CALL(mpc, item(IsArrayOfSize(interior.size()), pos, pos + 1, pos + 1))
-                .WillOnce(Return(&mpc));
-        ++pos;
-        EXPECT_CALL(mpc, item(MatchesItem(ByRef(*interior[0])), pos, pos + 1, pos + 1))
-                .WillOnce(Return(&mpc));
-        ++pos;
-        EXPECT_CALL(mpc, item(MatchesItem(ByRef(*interior[1])), pos, pos + 1, pos + 8))
-                .WillOnce(Return(&mpc));
-        pos += 8;
-        EXPECT_CALL(mpc, itemEnd(IsArrayOfSize(interior.size()), innerArrayBegin,
-                                 innerArrayBegin + 1, pos))
-                .WillOnce(Return(&mpc));
-        EXPECT_CALL(mpc, item(MatchesItem(ByRef(*val[3])), pos, pos + 9, pos + 9))
-                .WillOnce(Return(&mpc));
-        EXPECT_CALL(mpc, itemEnd(IsArrayOfSize(val.size()), encBegin, encBegin + 1, encEnd))
-                .WillOnce(Return(&mpc));
-    }
-
-    EXPECT_CALL(mpc, error(_, _))  //
-            .Times(0);
-
-    parse(encoded.data(), encoded.data() + encoded.size(), &mpc);
-}
-
-TEST(StreamParseTest, Map) {
-    MockParseClient mpc;
-
-    Map val("Hello", 4, Array(-9, "Goodbye"), std::numeric_limits<uint64_t>::max());
-    ASSERT_NE(val[1].first->asArray(), nullptr);
-    const Array& interior = *(val[1].first->asArray());
-    auto encoded = val.encode();
-    uint8_t* encBegin = encoded.data();
-    uint8_t* encEnd = encoded.data() + encoded.size();
-
-    {
-        InSequence s;
-        const uint8_t* pos = encBegin;
-        EXPECT_CALL(mpc, item(_, pos, pos + 1, pos + 1)).WillOnce(Return(&mpc));
-        ++pos;
-        EXPECT_CALL(mpc, item(MatchesItem(ByRef(*val[0].first)), pos, pos + 1, pos + 6))
-                .WillOnce(Return(&mpc));
-        pos += 6;
-        EXPECT_CALL(mpc, item(MatchesItem(ByRef(*val[0].second)), pos, pos + 1, pos + 1))
-                .WillOnce(Return(&mpc));
-        ++pos;
-        const uint8_t* innerArrayBegin = pos;
-        EXPECT_CALL(mpc, item(IsArrayOfSize(interior.size()), pos, pos + 1, pos + 1))
-                .WillOnce(Return(&mpc));
-        ++pos;
-        EXPECT_CALL(mpc, item(MatchesItem(ByRef(*interior[0])), pos, pos + 1, pos + 1))
-                .WillOnce(Return(&mpc));
-        ++pos;
-        EXPECT_CALL(mpc, item(MatchesItem(ByRef(*interior[1])), pos, pos + 1, pos + 8))
-                .WillOnce(Return(&mpc));
-        pos += 8;
-        EXPECT_CALL(mpc, itemEnd(IsArrayOfSize(interior.size()), innerArrayBegin,
-                                 innerArrayBegin + 1, pos))
-                .WillOnce(Return(&mpc));
-        EXPECT_CALL(mpc, item(MatchesItem(ByRef(*val[1].second)), pos, pos + 9, pos + 9))
-                .WillOnce(Return(&mpc));
-        EXPECT_CALL(mpc, itemEnd(IsMapOfSize(val.size()), encBegin, encBegin + 1, encEnd))
-                .WillOnce(Return(&mpc));
-    }
-
-    EXPECT_CALL(mpc, error(_, _))  //
-            .Times(0);
-
-    parse(encoded.data(), encoded.data() + encoded.size(), &mpc);
-}
-
-TEST(StreamParseTest, Semantic) {
-    MockParseClient mpc;
-
-    vector<uint8_t> encoded;
-    auto iter = back_inserter(encoded);
-    encodeHeader(SEMANTIC, 0, iter);
-    Uint(999).encode(iter);
-
-    EXPECT_CALL(mpc, item(_, _, _, _)).Times(0);
-    EXPECT_CALL(mpc, itemEnd(_, _, _, _)).Times(0);
-    EXPECT_CALL(mpc, error(encoded.data(), "Semantic tags not supported"));
-
-    parse(encoded.data(), encoded.data() + encoded.size(), &mpc);
-}
-
-TEST(FullParserTest, Uint) {
-    Uint val(10);
-
-    auto [item, pos, message] = parse(val.encode());
-    EXPECT_THAT(item, MatchesItem(val));
-}
-
-TEST(FullParserTest, Nint) {
-    Nint val(-10);
-
-    auto [item, pos, message] = parse(val.encode());
-    EXPECT_THAT(item, MatchesItem(val));
-
-    vector<uint8_t> minNint = {0x3B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
-
-    std::tie(item, pos, message) = parse(minNint);
-    EXPECT_THAT(item, NotNull());
-    EXPECT_EQ(item->asNint()->value(), std::numeric_limits<int64_t>::min());
-}
-
-TEST(FullParserTest, NintOutOfRange) {
-    vector<uint8_t> outOfRangeNint = {0x3B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
-
-    auto [item, pos, message] = parse(outOfRangeNint);
-    EXPECT_THAT(item, IsNull());
-    EXPECT_EQ(pos, outOfRangeNint.data());
-    EXPECT_EQ(message, "NINT values that don't fit in int64_t are not supported.");
-}
-
-TEST(FullParserTest, Tstr) {
-    Tstr val("Hello");
-
-    auto [item, pos, message] = parse(val.encode());
-    EXPECT_THAT(item, MatchesItem(val));
-}
-
-TEST(FullParserTest, Bstr) {
-    Bstr val("\x00\x01\0x02"s);
-
-    auto [item, pos, message] = parse(val.encode());
-    EXPECT_THAT(item, MatchesItem(val));
-}
-
-TEST(FullParserTest, Array) {
-    Array val("hello", -4, 3);
-
-    auto encoded = val.encode();
-    auto [item, pos, message] = parse(encoded);
-    EXPECT_THAT(item, MatchesItem(ByRef(val)));
-    EXPECT_EQ(pos, encoded.data() + encoded.size());
-    EXPECT_EQ("", message);
-
-    // We've already checked it all, but walk it just for fun.
-    ASSERT_NE(nullptr, item->asArray());
-    const Array& arr = *(item->asArray());
-    ASSERT_EQ(arr[0]->type(), TSTR);
-    EXPECT_EQ(arr[0]->asTstr()->value(), "hello");
-}
-
-TEST(FullParserTest, Map) {
-    Map val("hello", -4, 3, Bstr("hi"));
-
-    auto [item, pos, message] = parse(val.encode());
-    EXPECT_THAT(item, MatchesItem(ByRef(val)));
-}
-
-TEST(FullParserTest, Complex) {
-    vector<uint8_t> vec = {0x01, 0x02, 0x08, 0x03};
-    Map val("Outer1",
-            Array(Map("Inner1", 99,  //
-                      "Inner2", vec),
-                  "foo"),
-            "Outer2", 10);
-
-    std::unique_ptr<Item> item;
-    const uint8_t* pos;
-    std::string message;
-    std::tie(item, pos, message) = parse(val.encode());
-    EXPECT_THAT(item, MatchesItem(ByRef(val)));
-}
-
-TEST(FullParserTest, IncompleteUint) {
-    Uint val(1000);
-
-    auto encoding = val.encode();
-    auto [item, pos, message] = parse(encoding.data(), encoding.size() - 1);
-    EXPECT_EQ(nullptr, item.get());
-    EXPECT_EQ(encoding.data(), pos);
-    EXPECT_EQ("Need 2 byte(s) for length field, have 1.", message);
-}
-
-TEST(FullParserTest, IncompleteString) {
-    Tstr val("hello");
-
-    auto encoding = val.encode();
-    auto [item, pos, message] = parse(encoding.data(), encoding.size() - 2);
-    EXPECT_EQ(nullptr, item.get());
-    EXPECT_EQ(encoding.data(), pos);
-    EXPECT_EQ("Need 5 byte(s) for text string, have 3.", message);
-}
-
-TEST(FullParserTest, ArrayWithInsufficientEntries) {
-    Array val(1, 2, 3, 4);
-
-    auto encoding = val.encode();
-    auto [item, pos, message] = parse(encoding.data(), encoding.size() - 1);
-    EXPECT_EQ(nullptr, item.get());
-    EXPECT_EQ(encoding.data(), pos);
-    EXPECT_EQ("Not enough entries for array.", message);
-}
-
-TEST(FullParserTest, ArrayWithTruncatedEntry) {
-    Array val(1, 2, 3, 400000);
-
-    auto encoding = val.encode();
-    auto [item, pos, message] = parse(encoding.data(), encoding.size() - 1);
-    EXPECT_EQ(nullptr, item.get());
-    EXPECT_EQ(encoding.data() + encoding.size() - 5, pos);
-    EXPECT_EQ("Need 4 byte(s) for length field, have 3.", message);
-}
-
-TEST(FullParserTest, MapWithTruncatedEntry) {
-    Map val(1, 2, 300000, 4);
-
-    auto encoding = val.encode();
-    auto [item, pos, message] = parse(encoding.data(), encoding.size() - 2);
-    EXPECT_EQ(nullptr, item.get());
-    EXPECT_EQ(encoding.data() + 3, pos);
-    EXPECT_EQ("Need 4 byte(s) for length field, have 3.", message);
-}
-int main(int argc, char** argv) {
-    ::testing::InitGoogleTest(&argc, argv);
-    return RUN_ALL_TESTS();
-}
diff --git a/input/common/aidl/Android.bp b/input/common/aidl/Android.bp
index 95a14b2..5aa820c 100644
--- a/input/common/aidl/Android.bp
+++ b/input/common/aidl/Android.bp
@@ -12,6 +12,7 @@
     host_supported: true,
     vendor_available: true,
     srcs: ["android/hardware/input/common/*.aidl"],
+    frozen: true,
     stability: "vintf",
     backend: {
         cpp: {
diff --git a/input/processor/aidl/Android.bp b/input/processor/aidl/Android.bp
index 773bb49..f1a73d2 100644
--- a/input/processor/aidl/Android.bp
+++ b/input/processor/aidl/Android.bp
@@ -13,7 +13,7 @@
     vendor_available: true,
     srcs: ["android/hardware/input/processor/*.aidl"],
     imports: [
-        "android.hardware.input.common",
+        "android.hardware.input.common-V1",
     ],
     stability: "vintf",
     backend: {
diff --git a/media/bufferpool/aidl/Android.bp b/media/bufferpool/aidl/Android.bp
index 3b2ea3c..68ac489 100644
--- a/media/bufferpool/aidl/Android.bp
+++ b/media/bufferpool/aidl/Android.bp
@@ -12,6 +12,15 @@
 // 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.media.bufferpool2",
     vendor_available: true,
diff --git a/media/c2/aidl/Android.bp b/media/c2/aidl/Android.bp
index 10867c0..3393ede 100644
--- a/media/c2/aidl/Android.bp
+++ b/media/c2/aidl/Android.bp
@@ -1,5 +1,14 @@
 // This is the expected build file, but it may not be right in all cases
 
+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.media.c2",
     vendor_available: true,
diff --git a/radio/aidl/Android.bp b/radio/aidl/Android.bp
index 98eafc1..08bcc28 100644
--- a/radio/aidl/Android.bp
+++ b/radio/aidl/Android.bp
@@ -12,6 +12,7 @@
     vendor_available: true,
     host_supported: true,
     srcs: ["android/hardware/radio/*.aidl"],
+    frozen: true,
     stability: "vintf",
     backend: {
         cpp: {
@@ -35,8 +36,9 @@
     vendor_available: true,
     host_supported: true,
     srcs: ["android/hardware/radio/config/*.aidl"],
+    frozen: true,
     stability: "vintf",
-    imports: ["android.hardware.radio"],
+    imports: ["android.hardware.radio-V1"],
     backend: {
         cpp: {
             enabled: false,
@@ -60,7 +62,7 @@
     host_supported: true,
     srcs: ["android/hardware/radio/data/*.aidl"],
     stability: "vintf",
-    imports: ["android.hardware.radio"],
+    imports: ["android.hardware.radio-V1"],
     backend: {
         cpp: {
             enabled: false,
@@ -84,7 +86,7 @@
     host_supported: true,
     srcs: ["android/hardware/radio/messaging/*.aidl"],
     stability: "vintf",
-    imports: ["android.hardware.radio"],
+    imports: ["android.hardware.radio-V1"],
     backend: {
         cpp: {
             enabled: false,
@@ -108,7 +110,7 @@
     host_supported: true,
     srcs: ["android/hardware/radio/modem/*.aidl"],
     stability: "vintf",
-    imports: ["android.hardware.radio"],
+    imports: ["android.hardware.radio-V1"],
     backend: {
         cpp: {
             enabled: false,
@@ -132,7 +134,7 @@
     host_supported: true,
     srcs: ["android/hardware/radio/network/*.aidl"],
     stability: "vintf",
-    imports: ["android.hardware.radio"],
+    imports: ["android.hardware.radio-V1"],
     backend: {
         cpp: {
             enabled: false,
@@ -151,14 +153,36 @@
 }
 
 aidl_interface {
+    name: "android.hardware.radio.sap",
+    vendor_available: true,
+    host_supported: true,
+    srcs: ["android/hardware/radio/sap/*.aidl"],
+    stability: "vintf",
+    backend: {
+        cpp: {
+            enabled: true,
+        },
+        java: {
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.btservices",
+            ],
+            sdk_version: "module_current",
+            min_sdk_version: "Tiramisu",
+        },
+    },
+
+}
+
+aidl_interface {
     name: "android.hardware.radio.sim",
     vendor_available: true,
     host_supported: true,
     srcs: ["android/hardware/radio/sim/*.aidl"],
     stability: "vintf",
     imports: [
-        "android.hardware.radio",
-        "android.hardware.radio.config",
+        "android.hardware.radio-V1",
+        "android.hardware.radio.config-V1",
     ],
     backend: {
         cpp: {
@@ -186,7 +210,7 @@
     host_supported: true,
     srcs: ["android/hardware/radio/voice/*.aidl"],
     stability: "vintf",
-    imports: ["android.hardware.radio"],
+    imports: ["android.hardware.radio-V1"],
     backend: {
         cpp: {
             enabled: false,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/ISap.aidl b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/ISap.aidl
new file mode 100644
index 0000000..37391e9
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/ISap.aidl
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.radio.sap;
+@VintfStability
+interface ISap {
+  oneway void apduReq(in int serial, in android.hardware.radio.sap.SapApduType type, in byte[] command);
+  oneway void connectReq(in int serial, in int maxMsgSizeBytes);
+  oneway void disconnectReq(in int serial);
+  oneway void powerReq(in int serial, in boolean powerOn);
+  oneway void resetSimReq(in int serial);
+  oneway void setCallback(in android.hardware.radio.sap.ISapCallback sapCallback);
+  oneway void setTransferProtocolReq(in int serial, in android.hardware.radio.sap.SapTransferProtocol transferProtocol);
+  oneway void transferAtrReq(in int serial);
+  oneway void transferCardReaderStatusReq(in int serial);
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/ISapCallback.aidl b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/ISapCallback.aidl
new file mode 100644
index 0000000..d507709
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/ISapCallback.aidl
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.radio.sap;
+@VintfStability
+interface ISapCallback {
+  oneway void apduResponse(in int serial, in android.hardware.radio.sap.SapResultCode resultCode, in byte[] apduRsp);
+  oneway void connectResponse(in int serial, in android.hardware.radio.sap.SapConnectRsp sapConnectRsp, in int maxMsgSizeBytes);
+  oneway void disconnectIndication(in int serial, in android.hardware.radio.sap.SapDisconnectType disconnectType);
+  oneway void disconnectResponse(in int serial);
+  oneway void errorResponse(in int serial);
+  oneway void powerResponse(in int serial, in android.hardware.radio.sap.SapResultCode resultCode);
+  oneway void resetSimResponse(in int serial, in android.hardware.radio.sap.SapResultCode resultCode);
+  oneway void statusIndication(in int serial, in android.hardware.radio.sap.SapStatus status);
+  oneway void transferAtrResponse(in int serial, in android.hardware.radio.sap.SapResultCode resultCode, in byte[] atr);
+  oneway void transferCardReaderStatusResponse(in int serial, in android.hardware.radio.sap.SapResultCode resultCode, in int cardReaderStatus);
+  oneway void transferProtocolResponse(in int serial, in android.hardware.radio.sap.SapResultCode resultCode);
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapApduType.aidl b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapApduType.aidl
new file mode 100644
index 0000000..e0e2a03
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapApduType.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.radio.sap;
+@Backing(type="int") @VintfStability
+enum SapApduType {
+  APDU = 0,
+  APDU7816 = 1,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapConnectRsp.aidl b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapConnectRsp.aidl
new file mode 100644
index 0000000..aceac37
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapConnectRsp.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.radio.sap;
+@Backing(type="int") @VintfStability
+enum SapConnectRsp {
+  SUCCESS = 0,
+  CONNECT_FAILURE = 1,
+  MSG_SIZE_TOO_LARGE = 2,
+  MSG_SIZE_TOO_SMALL = 3,
+  CONNECT_OK_CALL_ONGOING = 4,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapDisconnectType.aidl b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapDisconnectType.aidl
new file mode 100644
index 0000000..0447f9b
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapDisconnectType.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.radio.sap;
+@Backing(type="int") @VintfStability
+enum SapDisconnectType {
+  GRACEFUL = 0,
+  IMMEDIATE = 1,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapResultCode.aidl b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapResultCode.aidl
new file mode 100644
index 0000000..1db226b
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapResultCode.aidl
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.radio.sap;
+@Backing(type="int") @VintfStability
+enum SapResultCode {
+  SUCCESS = 0,
+  GENERIC_FAILURE = 1,
+  CARD_NOT_ACCESSSIBLE = 2,
+  CARD_ALREADY_POWERED_OFF = 3,
+  CARD_REMOVED = 4,
+  CARD_ALREADY_POWERED_ON = 5,
+  DATA_NOT_AVAILABLE = 6,
+  NOT_SUPPORTED = 7,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapStatus.aidl b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapStatus.aidl
new file mode 100644
index 0000000..32f71c2
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapStatus.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.radio.sap;
+@Backing(type="int") @VintfStability
+enum SapStatus {
+  UNKNOWN_ERROR = 0,
+  CARD_RESET = 1,
+  CARD_NOT_ACCESSIBLE = 2,
+  CARD_REMOVED = 3,
+  CARD_INSERTED = 4,
+  RECOVERED = 5,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapTransferProtocol.aidl b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapTransferProtocol.aidl
new file mode 100644
index 0000000..e3ffdb0
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapTransferProtocol.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.radio.sap;
+@Backing(type="int") @VintfStability
+enum SapTransferProtocol {
+  T0 = 0,
+  T1 = 1,
+}
diff --git a/radio/aidl/android/hardware/radio/sap/ISap.aidl b/radio/aidl/android/hardware/radio/sap/ISap.aidl
new file mode 100644
index 0000000..552e602
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sap/ISap.aidl
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+package android.hardware.radio.sap;
+
+import android.hardware.radio.sap.ISapCallback;
+import android.hardware.radio.sap.SapApduType;
+import android.hardware.radio.sap.SapTransferProtocol;
+
+@VintfStability
+oneway interface ISap {
+    /**
+     * TRANSFER_APDU_REQ from SAP 1.1 spec 5.1.6
+     *
+     * @param serial Id to match req-resp. Resp must include same serial.
+     * @param type APDU command type
+     * @param command CommandAPDU/CommandAPDU7816 parameter depending on type
+     */
+    void apduReq(in int serial, in SapApduType type, in byte[] command);
+
+    /**
+     * CONNECT_REQ from SAP 1.1 spec 5.1.1
+     *
+     * @param serial Id to match req-resp. Resp must include same serial.
+     * @param maxMsgSizeBytes MaxMsgSize to be used for SIM Access Profile connection
+     */
+    void connectReq(in int serial, in int maxMsgSizeBytes);
+
+    /**
+     * DISCONNECT_REQ from SAP 1.1 spec 5.1.3
+     *
+     * @param serial Id to match req-resp. Resp must include same serial.
+     */
+    void disconnectReq(in int serial);
+
+    /**
+     * POWER_SIM_OFF_REQ and POWER_SIM_ON_REQ from SAP 1.1 spec 5.1.10 + 5.1.12
+     *
+     * @param serial Id to match req-resp. Resp must include same serial.
+     * @param powerOn true for on, false for off
+     */
+    void powerReq(in int serial, in boolean powerOn);
+
+    /**
+     * RESET_SIM_REQ from SAP 1.1 spec 5.1.14
+     *
+     * @param serial Id to match req-resp. Resp must include same serial.
+     */
+    void resetSimReq(in int serial);
+
+    /**
+     * Set callback that has response and unsolicited indication functions
+     *
+     * @param sapCallback Object containing response and unosolicited indication callbacks
+     */
+    void setCallback(in ISapCallback sapCallback);
+
+    /**
+     * SET_TRANSPORT_PROTOCOL_REQ from SAP 1.1 spec 5.1.20
+     *
+     * @param serial Id to match req-resp. Resp must include same serial.
+     * @param transferProtocol Transport Protocol
+     */
+    void setTransferProtocolReq(in int serial, in SapTransferProtocol transferProtocol);
+
+    /**
+     * TRANSFER_ATR_REQ from SAP 1.1 spec 5.1.8
+     *
+     * @param serial Id to match req-resp. Resp must include same serial.
+     */
+    void transferAtrReq(in int serial);
+
+    /**
+     * TRANSFER_CARD_READER_STATUS_REQ from SAP 1.1 spec 5.1.17
+     *
+     * @param serial Id to match req-resp. Resp must include same serial.
+     */
+    void transferCardReaderStatusReq(in int serial);
+}
diff --git a/radio/aidl/android/hardware/radio/sap/ISapCallback.aidl b/radio/aidl/android/hardware/radio/sap/ISapCallback.aidl
new file mode 100644
index 0000000..34111eb
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sap/ISapCallback.aidl
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+package android.hardware.radio.sap;
+
+import android.hardware.radio.sap.SapConnectRsp;
+import android.hardware.radio.sap.SapDisconnectType;
+import android.hardware.radio.sap.SapResultCode;
+import android.hardware.radio.sap.SapStatus;
+
+@VintfStability
+oneway interface ISapCallback {
+    /**
+     * TRANSFER_APDU_RESP from SAP 1.1 spec 5.1.7
+     *
+     * @param serial Id to match req-resp. Value must match the one in req.
+     * @param resultCode ResultCode to indicate if command was processed correctly
+     *        Possible values:
+     *        SapResultCode:SUCCESS,
+     *        SapResultCode:GENERIC_FAILURE,
+     *        SapResultCode:CARD_NOT_ACCESSSIBLE,
+     *        SapResultCode:CARD_ALREADY_POWERED_OFF,
+     *        SapResultCode:CARD_REMOVED
+     * @param apduRsp APDU Response. Valid only if command was processed correctly and no error
+     *        occurred.
+     */
+    void apduResponse(in int serial, in SapResultCode resultCode, in byte[] apduRsp);
+
+    /**
+     * CONNECT_RESP from SAP 1.1 spec 5.1.2
+     *
+     * @param serial Id to match req-resp. Value must match the one in req.
+     * @param sapConnectRsp Connection Status
+     * @param maxMsgSizeBytes MaxMsgSize supported by server if request cannot be fulfilled.
+     *        Valid only if connectResponse is SapConnectResponse:MSG_SIZE_TOO_LARGE.
+     */
+    void connectResponse(in int serial, in SapConnectRsp sapConnectRsp, in int maxMsgSizeBytes);
+
+    /**
+     * DISCONNECT_IND from SAP 1.1 spec 5.1.5
+     *
+     * @param serial Id to match req-resp. Value must match the one in req.
+     * @param disconnectType Disconnect Type to indicate if shutdown is graceful or immediate
+     */
+    void disconnectIndication(in int serial, in SapDisconnectType disconnectType);
+
+    /**
+     * DISCONNECT_RESP from SAP 1.1 spec 5.1.4
+     *
+     * @param serial Id to match req-resp. Value must match the one in req.
+     */
+    void disconnectResponse(in int serial);
+
+    /**
+     * ERROR_RESP from SAP 1.1 spec 5.1.19
+     *
+     * @param serial Id to match req-resp. Value must match the one in req.
+     */
+    void errorResponse(in int serial);
+
+    /**
+     * POWER_SIM_OFF_RESP and POWER_SIM_ON_RESP from SAP 1.1 spec 5.1.11 + 5.1.13
+     *
+     * @param serial Id to match req-resp. Value must match the one in req.
+     * @param resultCode ResultCode to indicate if command was processed correctly
+     *        Possible values:
+     *        SapResultCode:SUCCESS,
+     *        SapResultCode:GENERIC_FAILURE,
+     *        SapResultCode:CARD_NOT_ACCESSSIBLE, (possible only for power on req)
+     *        SapResultCode:CARD_ALREADY_POWERED_OFF, (possible only for power off req)
+     *        SapResultCode:CARD_REMOVED,
+     *        SapResultCode:CARD_ALREADY_POWERED_ON (possible only for power on req)
+     */
+    void powerResponse(in int serial, in SapResultCode resultCode);
+
+    /**
+     * RESET_SIM_RESP from SAP 1.1 spec 5.1.15
+     *
+     * @param serial Id to match req-resp. Value must match the one in req.
+     * @param resultCode ResultCode to indicate if command was processed correctly
+     *        Possible values:
+     *        SapResultCode:SUCCESS,
+     *        SapResultCode:GENERIC_FAILURE,
+     *        SapResultCode:CARD_NOT_ACCESSSIBLE,
+     *        SapResultCode:CARD_ALREADY_POWERED_OFF,
+     *        SapResultCode:CARD_REMOVED
+     */
+    void resetSimResponse(in int serial, in SapResultCode resultCode);
+
+    /**
+     * STATUS_IND from SAP 1.1 spec 5.1.16
+     *
+     * @param serial Id to match req-resp. Value must match the one in req.
+     * @param status Parameter to indicate reason for the status change.
+     */
+    void statusIndication(in int serial, in SapStatus status);
+
+    /**
+     * TRANSFER_ATR_RESP from SAP 1.1 spec 5.1.9
+     *
+     * @param serial Id to match req-resp. Value must match the one in req.
+     * @param resultCode ResultCode to indicate if command was processed correctly
+     *        Possible values:
+     *        SapResultCode:SUCCESS,
+     *        SapResultCode:GENERIC_FAILURE,
+     *        SapResultCode:CARD_ALREADY_POWERED_OFF,
+     *        SapResultCode:CARD_REMOVED,
+     *        SapResultCode:DATA_NOT_AVAILABLE
+     * @param atr Answer to Reset from the subscription module. Included only if no error occurred,
+     *        otherwise empty.
+     */
+    void transferAtrResponse(in int serial, in SapResultCode resultCode, in byte[] atr);
+
+    /**
+     * TRANSFER_CARD_READER_STATUS_REQ from SAP 1.1 spec 5.1.18
+     *
+     * @param serial Id to match req-resp. Value must match the one in req.
+     * @param resultCode ResultCode to indicate if command was processed correctly
+     *        Possible values:
+     *        SapResultCode:SUCCESS,
+     *        SapResultCode:GENERIC_FAILURE
+     *        SapResultCode:DATA_NOT_AVAILABLE
+     * @param cardReaderStatus Card Reader Status coded as described in 3GPP TS 11.14 Section 12.33
+     *        and TS 31.111 Section 8.33
+     */
+    void transferCardReaderStatusResponse(
+            in int serial, in SapResultCode resultCode, in int cardReaderStatus);
+
+    /**
+     * SET_TRANSPORT_PROTOCOL_RESP from SAP 1.1 spec 5.1.21
+     *
+     * @param serial Id to match req-resp. Value must match the one in req.
+     * @param resultCode ResultCode to indicate if command was processed correctly
+     *        Possible values:
+     *        SapResultCode:SUCCESS
+     *        SapResultCode:NOT_SUPPORTED
+     */
+    void transferProtocolResponse(in int serial, in SapResultCode resultCode);
+}
diff --git a/radio/aidl/android/hardware/radio/sap/SapApduType.aidl b/radio/aidl/android/hardware/radio/sap/SapApduType.aidl
new file mode 100644
index 0000000..ab8ffb9
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sap/SapApduType.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+package android.hardware.radio.sap;
+
+@VintfStability
+@Backing(type="int")
+enum SapApduType {
+    APDU,
+    APDU7816,
+}
diff --git a/radio/aidl/android/hardware/radio/sap/SapConnectRsp.aidl b/radio/aidl/android/hardware/radio/sap/SapConnectRsp.aidl
new file mode 100644
index 0000000..0e1d528
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sap/SapConnectRsp.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+package android.hardware.radio.sap;
+
+@VintfStability
+@Backing(type="int")
+enum SapConnectRsp {
+    SUCCESS,
+    CONNECT_FAILURE,
+    MSG_SIZE_TOO_LARGE,
+    MSG_SIZE_TOO_SMALL,
+    CONNECT_OK_CALL_ONGOING,
+}
diff --git a/radio/aidl/android/hardware/radio/sap/SapDisconnectType.aidl b/radio/aidl/android/hardware/radio/sap/SapDisconnectType.aidl
new file mode 100644
index 0000000..16d7cc6
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sap/SapDisconnectType.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+package android.hardware.radio.sap;
+
+@VintfStability
+@Backing(type="int")
+enum SapDisconnectType {
+    GRACEFUL,
+    IMMEDIATE,
+}
diff --git a/radio/aidl/android/hardware/radio/sap/SapResultCode.aidl b/radio/aidl/android/hardware/radio/sap/SapResultCode.aidl
new file mode 100644
index 0000000..4728ebe
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sap/SapResultCode.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+package android.hardware.radio.sap;
+
+@VintfStability
+@Backing(type="int")
+enum SapResultCode {
+    SUCCESS,
+    GENERIC_FAILURE,
+    CARD_NOT_ACCESSSIBLE,
+    CARD_ALREADY_POWERED_OFF,
+    CARD_REMOVED,
+    CARD_ALREADY_POWERED_ON,
+    DATA_NOT_AVAILABLE,
+    NOT_SUPPORTED,
+}
diff --git a/radio/aidl/android/hardware/radio/sap/SapStatus.aidl b/radio/aidl/android/hardware/radio/sap/SapStatus.aidl
new file mode 100644
index 0000000..309352d
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sap/SapStatus.aidl
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+package android.hardware.radio.sap;
+
+@VintfStability
+@Backing(type="int")
+enum SapStatus {
+    UNKNOWN_ERROR,
+    CARD_RESET,
+    CARD_NOT_ACCESSIBLE,
+    CARD_REMOVED,
+    CARD_INSERTED,
+    RECOVERED,
+}
diff --git a/radio/aidl/android/hardware/radio/sap/SapTransferProtocol.aidl b/radio/aidl/android/hardware/radio/sap/SapTransferProtocol.aidl
new file mode 100644
index 0000000..823c5f2
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sap/SapTransferProtocol.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+package android.hardware.radio.sap;
+
+@VintfStability
+@Backing(type="int")
+enum SapTransferProtocol {
+    T0,
+    T1,
+}
diff --git a/radio/aidl/compat/libradiocompat/Android.bp b/radio/aidl/compat/libradiocompat/Android.bp
index 487d91b..aa20fc3 100644
--- a/radio/aidl/compat/libradiocompat/Android.bp
+++ b/radio/aidl/compat/libradiocompat/Android.bp
@@ -40,6 +40,7 @@
         "android.hardware.radio.messaging-V1-ndk",
         "android.hardware.radio.modem-V1-ndk",
         "android.hardware.radio.network-V1-ndk",
+        "android.hardware.radio.sap-V1-ndk",
         "android.hardware.radio.sim-V1-ndk",
         "android.hardware.radio.voice-V1-ndk",
         "android.hardware.radio@1.0",
@@ -82,6 +83,9 @@
         "network/RadioResponse-network.cpp",
         "network/structs.cpp",
         "network/utils.cpp",
+        "sap/Sap.cpp",
+        "sap/SapCallback.cpp",
+        "sap/structs.cpp",
         "sim/RadioIndication-sim.cpp",
         "sim/RadioResponse-sim.cpp",
         "sim/RadioSim.cpp",
diff --git a/radio/aidl/compat/libradiocompat/commonStructs.cpp b/radio/aidl/compat/libradiocompat/commonStructs.cpp
index 6e4c873..d65ed1a 100644
--- a/radio/aidl/compat/libradiocompat/commonStructs.cpp
+++ b/radio/aidl/compat/libradiocompat/commonStructs.cpp
@@ -48,6 +48,10 @@
     return v;
 }
 
+uint8_t toHidl(int8_t v) {
+    return v;
+}
+
 aidl::RadioIndicationType toAidl(V1_0::RadioIndicationType type) {
     return aidl::RadioIndicationType(type);
 }
diff --git a/radio/aidl/compat/libradiocompat/commonStructs.h b/radio/aidl/compat/libradiocompat/commonStructs.h
index a4a4869..f43a599 100644
--- a/radio/aidl/compat/libradiocompat/commonStructs.h
+++ b/radio/aidl/compat/libradiocompat/commonStructs.h
@@ -28,6 +28,7 @@
 uint8_t toAidl(int8_t v);
 int8_t toAidl(uint8_t v);
 int32_t toAidl(uint32_t v);
+uint8_t toHidl(int8_t v);
 
 aidl::android::hardware::radio::RadioIndicationType toAidl(V1_0::RadioIndicationType type);
 aidl::android::hardware::radio::RadioResponseType toAidl(V1_0::RadioResponseType type);
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/Sap.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/Sap.h
new file mode 100644
index 0000000..a293d11
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/Sap.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include "RadioCompatBase.h"
+#include "SapCallback.h"
+
+#include <aidl/android/hardware/radio/sap/BnSap.h>
+#include <android/hardware/radio/1.0/ISap.h>
+#include <android/hardware/radio/1.0/ISapCallback.h>
+
+namespace android::hardware::radio::compat {
+
+/**
+ * HAL translator from HIDL ISap to AIDL ISap
+ *
+ * This class wraps existing HIDL implementation (either a binder stub or real
+ * class implementing the HAL) and implements AIDL HAL. It's up to the caller to
+ * fetch source implementation and publish resulting HAL instance.
+ */
+class Sap : public aidl::android::hardware::radio::sap::BnSap {
+    const sp<radio::V1_0::ISap> mHal;
+
+    const sp<SapCallback> mSapCallback;
+
+    ::ndk::ScopedAStatus apduReq(int32_t serial,
+                                 aidl::android::hardware::radio::sap::SapApduType type,
+                                 const std::vector<uint8_t>& command) override;
+    ::ndk::ScopedAStatus connectReq(int32_t serial, int32_t maxMsgSize) override;
+    ::ndk::ScopedAStatus disconnectReq(int32_t serial) override;
+    ::ndk::ScopedAStatus powerReq(int32_t serial, bool state) override;
+    ::ndk::ScopedAStatus resetSimReq(int32_t serial) override;
+    ::ndk::ScopedAStatus setCallback(
+            const std::shared_ptr<::aidl::android::hardware::radio::sap::ISapCallback>& sapCallback)
+            override;
+    ::ndk::ScopedAStatus setTransferProtocolReq(
+            int32_t serial,
+            aidl::android::hardware::radio::sap::SapTransferProtocol transferProtocol) override;
+    ::ndk::ScopedAStatus transferAtrReq(int32_t serial) override;
+    ::ndk::ScopedAStatus transferCardReaderStatusReq(int32_t serial) override;
+
+  public:
+    /**
+     * Constructs AIDL ISap instance wrapping existing HIDL ISap instance.
+     *
+     * \param hidlHal existing HIDL ISap HAL instance
+     */
+    Sap(sp<V1_0::ISap> hidlHal);
+};
+
+}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/SapCallback.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/SapCallback.h
new file mode 100644
index 0000000..7e72106
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/SapCallback.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include "GuaranteedCallback.h"
+
+#include <aidl/android/hardware/radio/sap/ISapCallback.h>
+#include <android/hardware/radio/1.0/ISapCallback.h>
+
+namespace android::hardware::radio::compat {
+
+class SapCallback : public V1_0::ISapCallback {
+    GuaranteedCallback<aidl::android::hardware::radio::sap::ISapCallback,
+                       aidl::android::hardware::radio::sap::ISapCallbackDefault>
+            mCallback;
+
+    Return<void> apduResponse(int32_t serial, V1_0::SapResultCode resultCode,
+                              const ::android::hardware::hidl_vec<uint8_t>& apduRsp) override;
+    Return<void> connectResponse(int32_t serial, V1_0::SapConnectRsp sapConnectRsp,
+                                 int32_t maxMsgSize) override;
+    Return<void> disconnectIndication(int32_t serial,
+                                      V1_0::SapDisconnectType disconnectType) override;
+    Return<void> disconnectResponse(int32_t serial) override;
+    Return<void> errorResponse(int32_t serial) override;
+    Return<void> powerResponse(int32_t serial, V1_0::SapResultCode resultCode) override;
+    Return<void> resetSimResponse(int32_t serial, V1_0::SapResultCode resultCode) override;
+    Return<void> statusIndication(int32_t serial, V1_0::SapStatus status) override;
+    Return<void> transferAtrResponse(int32_t serial, V1_0::SapResultCode resultCode,
+                                     const ::android::hardware::hidl_vec<uint8_t>& atr) override;
+    Return<void> transferCardReaderStatusResponse(int32_t serial, V1_0::SapResultCode resultCode,
+                                                  int32_t cardReaderStatus) override;
+    Return<void> transferProtocolResponse(int32_t serial, V1_0::SapResultCode resultCode) override;
+
+  public:
+    void setResponseFunction(
+            const std::shared_ptr<aidl::android::hardware::radio::sap::ISapCallback>& callback);
+
+    std::shared_ptr<aidl::android::hardware::radio::sap::ISapCallback> respond();
+};
+
+}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/sap/Sap.cpp b/radio/aidl/compat/libradiocompat/sap/Sap.cpp
new file mode 100644
index 0000000..1a77169
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/sap/Sap.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+#include <libradiocompat/Sap.h>
+
+#include "commonStructs.h"
+#include "debug.h"
+#include "structs.h"
+
+#include "collections.h"
+
+#define RADIO_MODULE "Sap"
+
+namespace android::hardware::radio::compat {
+
+using ::ndk::ScopedAStatus;
+namespace aidl = ::aidl::android::hardware::radio::sap;
+constexpr auto ok = &ScopedAStatus::ok;
+
+Sap::Sap(sp<V1_0::ISap> hidlHal) : mHal(hidlHal), mSapCallback(sp<SapCallback>::make()) {}
+
+ScopedAStatus Sap::apduReq(int32_t serial, aidl::SapApduType type,
+                           const std::vector<uint8_t>& command) {
+    LOG_CALL << serial;
+    mHal->apduReq(serial, toHidl(type), toHidl(command));
+    return ok();
+}
+
+ScopedAStatus Sap::connectReq(int32_t serial, int32_t maxMsgSize) {
+    LOG_CALL << serial;
+    mHal->connectReq(serial, maxMsgSize);
+    return ok();
+}
+
+ScopedAStatus Sap::disconnectReq(int32_t serial) {
+    LOG_CALL << serial;
+    mHal->disconnectReq(serial);
+    return ok();
+}
+
+ScopedAStatus Sap::powerReq(int32_t serial, bool state) {
+    LOG_CALL << serial;
+    mHal->powerReq(serial, state);
+    return ok();
+}
+
+ScopedAStatus Sap::resetSimReq(int32_t serial) {
+    LOG_CALL << serial;
+    mHal->resetSimReq(serial);
+    return ok();
+}
+
+ScopedAStatus Sap::setCallback(
+        const std::shared_ptr<::aidl::android::hardware::radio::sap::ISapCallback>& sapCallback) {
+    LOG_CALL << sapCallback;
+
+    CHECK(sapCallback);
+
+    mSapCallback->setResponseFunction(sapCallback);
+    mHal->setCallback(mSapCallback).assertOk();
+    return ok();
+}
+ScopedAStatus Sap::setTransferProtocolReq(int32_t serial,
+                                          aidl::SapTransferProtocol transferProtocol) {
+    LOG_CALL << serial;
+    mHal->setTransferProtocolReq(serial, toHidl(transferProtocol));
+    return ok();
+}
+
+ScopedAStatus Sap::transferAtrReq(int32_t serial) {
+    LOG_CALL << serial;
+    mHal->transferAtrReq(serial);
+    return ok();
+}
+ScopedAStatus Sap::transferCardReaderStatusReq(int32_t serial) {
+    LOG_CALL << serial;
+    mHal->transferCardReaderStatusReq(serial);
+    return ok();
+}
+
+}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/sap/SapCallback.cpp b/radio/aidl/compat/libradiocompat/sap/SapCallback.cpp
new file mode 100644
index 0000000..a40dff8
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/sap/SapCallback.cpp
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+#include <libradiocompat/SapCallback.h>
+
+#include "commonStructs.h"
+#include "debug.h"
+#include "structs.h"
+
+#include "collections.h"
+
+#define RADIO_MODULE "SapCallback"
+
+namespace android::hardware::radio::compat {
+
+namespace aidl = ::aidl::android::hardware::radio::sap;
+
+void SapCallback::setResponseFunction(const std::shared_ptr<aidl::ISapCallback>& callback) {
+    mCallback = callback;
+}
+
+std::shared_ptr<aidl::ISapCallback> SapCallback::respond() {
+    return mCallback.get();
+}
+
+Return<void> SapCallback::apduResponse(int32_t serial, V1_0::SapResultCode resultCode,
+                                       const hidl_vec<uint8_t>& apduRsp) {
+    LOG_CALL << serial;
+    respond()->apduResponse(serial, toAidl(resultCode), apduRsp);
+    return {};
+}
+
+Return<void> SapCallback::connectResponse(int32_t serial, V1_0::SapConnectRsp sapConnectRsp,
+                                          int32_t maxMsgSize) {
+    LOG_CALL << serial;
+    respond()->connectResponse(serial, toAidl(sapConnectRsp), maxMsgSize);
+    return {};
+}
+
+Return<void> SapCallback::disconnectIndication(int32_t serial,
+                                               V1_0::SapDisconnectType disconnectType) {
+    LOG_CALL << serial;
+    respond()->disconnectIndication(serial, toAidl(disconnectType));
+    return {};
+}
+
+Return<void> SapCallback::disconnectResponse(int32_t serial) {
+    LOG_CALL << serial;
+    respond()->disconnectResponse(serial);
+    return {};
+}
+
+Return<void> SapCallback::errorResponse(int32_t serial) {
+    LOG_CALL << serial;
+    respond()->errorResponse(serial);
+    return {};
+}
+
+Return<void> SapCallback::powerResponse(int32_t serial, V1_0::SapResultCode resultCode) {
+    LOG_CALL << serial;
+    respond()->powerResponse(serial, toAidl(resultCode));
+    return {};
+}
+
+Return<void> SapCallback::resetSimResponse(int32_t serial, V1_0::SapResultCode resultCode) {
+    LOG_CALL << serial;
+    respond()->resetSimResponse(serial, toAidl(resultCode));
+    return {};
+}
+
+Return<void> SapCallback::statusIndication(int32_t serial, V1_0::SapStatus status) {
+    LOG_CALL << serial;
+    respond()->statusIndication(serial, toAidl(status));
+    return {};
+}
+
+Return<void> SapCallback::transferAtrResponse(int32_t serial, V1_0::SapResultCode resultCode,
+                                              const hidl_vec<uint8_t>& atr) {
+    LOG_CALL << serial;
+    respond()->transferAtrResponse(serial, toAidl(resultCode), atr);
+    return {};
+}
+
+Return<void> SapCallback::transferCardReaderStatusResponse(int32_t serial,
+                                                           V1_0::SapResultCode resultCode,
+                                                           int32_t cardReaderStatus) {
+    LOG_CALL << serial;
+    respond()->transferCardReaderStatusResponse(serial, toAidl(resultCode), cardReaderStatus);
+    return {};
+}
+
+Return<void> SapCallback::transferProtocolResponse(int32_t serial, V1_0::SapResultCode resultCode) {
+    LOG_CALL << serial;
+    respond()->transferProtocolResponse(serial, toAidl(resultCode));
+    return {};
+}
+
+}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/sap/structs.cpp b/radio/aidl/compat/libradiocompat/sap/structs.cpp
new file mode 100644
index 0000000..522056b
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/sap/structs.cpp
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+#include "structs.h"
+
+namespace android::hardware::radio::compat {
+
+namespace aidl = ::aidl::android::hardware::radio::sap;
+
+V1_0::SapApduType toHidl(const aidl::SapApduType sapApduType) {
+    return V1_0::SapApduType(sapApduType);
+}
+
+V1_0::SapTransferProtocol toHidl(const aidl::SapTransferProtocol sapTransferProtocol) {
+    return V1_0::SapTransferProtocol(sapTransferProtocol);
+}
+
+aidl::SapResultCode toAidl(const V1_0::SapResultCode sapResultCode) {
+    return aidl::SapResultCode(sapResultCode);
+}
+
+aidl::SapConnectRsp toAidl(const V1_0::SapConnectRsp sapConnectRsp) {
+    return aidl::SapConnectRsp(sapConnectRsp);
+}
+
+aidl::SapDisconnectType toAidl(const V1_0::SapDisconnectType sapDisconnectType) {
+    return aidl::SapDisconnectType(sapDisconnectType);
+}
+
+aidl::SapStatus toAidl(const V1_0::SapStatus sapStatus) {
+    return aidl::SapStatus(sapStatus);
+}
+
+}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/sap/structs.h b/radio/aidl/compat/libradiocompat/sap/structs.h
new file mode 100644
index 0000000..d88120d
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/sap/structs.h
@@ -0,0 +1,33 @@
+/*
+ * 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, eithe r express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <aidl/android/hardware/radio/sap/ISap.h>
+#include <android/hardware/radio/1.0/types.h>
+
+namespace android::hardware::radio::compat {
+
+V1_0::SapApduType toHidl(aidl::android::hardware::radio::sap::SapApduType sapAdpuType);
+V1_0::SapTransferProtocol toHidl(
+        aidl::android::hardware::radio::sap::SapTransferProtocol sapTransferProtocol);
+
+aidl::android::hardware::radio::sap::SapResultCode toAidl(V1_0::SapResultCode sapResultCode);
+aidl::android::hardware::radio::sap::SapConnectRsp toAidl(V1_0::SapConnectRsp sapConnectRsp);
+aidl::android::hardware::radio::sap::SapDisconnectType toAidl(
+        V1_0::SapDisconnectType sapDisconnectType);
+aidl::android::hardware::radio::sap::SapStatus toAidl(V1_0::SapStatus sapStatus);
+
+}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/service/Android.bp b/radio/aidl/compat/service/Android.bp
index 52eb71f..933e3e1 100644
--- a/radio/aidl/compat/service/Android.bp
+++ b/radio/aidl/compat/service/Android.bp
@@ -43,6 +43,7 @@
         "android.hardware.radio.messaging-V1-ndk",
         "android.hardware.radio.modem-V1-ndk",
         "android.hardware.radio.network-V1-ndk",
+        "android.hardware.radio.sap-V1-ndk",
         "android.hardware.radio.sim-V1-ndk",
         "android.hardware.radio.voice-V1-ndk",
         "android.hardware.radio@1.0",
diff --git a/radio/aidl/vts/Android.bp b/radio/aidl/vts/Android.bp
index 021ee89..97964b4 100644
--- a/radio/aidl/vts/Android.bp
+++ b/radio/aidl/vts/Android.bp
@@ -50,6 +50,8 @@
         "radio_network_indication.cpp",
         "radio_network_response.cpp",
         "radio_network_test.cpp",
+        "radio_sap_callback.cpp",
+        "radio_sap_test.cpp",
         "radio_sim_indication.cpp",
         "radio_sim_response.cpp",
         "radio_sim_test.cpp",
@@ -69,6 +71,7 @@
         "android.hardware.radio.messaging-V1-ndk",
         "android.hardware.radio.modem-V1-ndk",
         "android.hardware.radio.network-V1-ndk",
+        "android.hardware.radio.sap-V1-ndk",
         "android.hardware.radio.sim-V1-ndk",
         "android.hardware.radio.voice-V1-ndk",
     ],
diff --git a/radio/aidl/vts/VtsHalRadioTargetTest.cpp b/radio/aidl/vts/VtsHalRadioTargetTest.cpp
index 1ebc6af..03d3c5a 100644
--- a/radio/aidl/vts/VtsHalRadioTargetTest.cpp
+++ b/radio/aidl/vts/VtsHalRadioTargetTest.cpp
@@ -21,6 +21,7 @@
 #include "radio_messaging_utils.h"
 #include "radio_modem_utils.h"
 #include "radio_network_utils.h"
+#include "radio_sap_utils.h"
 #include "radio_sim_utils.h"
 #include "radio_voice_utils.h"
 
@@ -54,6 +55,11 @@
         testing::ValuesIn(android::getAidlHalInstanceNames(IRadioNetwork::descriptor)),
         android::PrintInstanceNameToString);
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(RadioSapTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, SapTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(ISap::descriptor)),
+                         android::PrintInstanceNameToString);
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(RadioSimTest);
 INSTANTIATE_TEST_SUITE_P(PerInstance, RadioSimTest,
                          testing::ValuesIn(android::getAidlHalInstanceNames(IRadioSim::descriptor)),
diff --git a/radio/aidl/vts/radio_sap_callback.cpp b/radio/aidl/vts/radio_sap_callback.cpp
new file mode 100644
index 0000000..3b21ede
--- /dev/null
+++ b/radio/aidl/vts/radio_sap_callback.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+#include "radio_sap_utils.h"
+
+#include <android-base/logging.h>
+
+SapCallback::SapCallback(SapTest& parent) : parent_sap(parent) {}
+
+::ndk::ScopedAStatus SapCallback::apduResponse(int32_t serialNumber, SapResultCode resultCode,
+                                               const std::vector<uint8_t>& /*apduRsp*/) {
+    sapResponseSerial = serialNumber;
+    sapResultCode = resultCode;
+    parent_sap.notify(serialNumber);
+    return ndk::ScopedAStatus::ok();
+}
+::ndk::ScopedAStatus SapCallback::connectResponse(int32_t serialNumber,
+                                                  SapConnectRsp /*sapConnectRsp*/,
+                                                  int32_t /*maxMsgSize*/) {
+    sapResponseSerial = serialNumber;
+    parent_sap.notify(serialNumber);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::disconnectIndication(int32_t /*serialNumber*/,
+                                                       SapDisconnectType /*sapDisconnectType*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::disconnectResponse(int32_t serialNumber) {
+    sapResponseSerial = serialNumber;
+    parent_sap.notify(serialNumber);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::errorResponse(int32_t /*serialNumber*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::powerResponse(int32_t serialNumber, SapResultCode resultCode) {
+    sapResponseSerial = serialNumber;
+    sapResultCode = resultCode;
+    parent_sap.notify(serialNumber);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::resetSimResponse(int32_t serialNumber, SapResultCode resultCode) {
+    sapResponseSerial = serialNumber;
+    sapResultCode = resultCode;
+    parent_sap.notify(serialNumber);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::statusIndication(int32_t /*serialNumber*/,
+                                                   SapStatus /*sapStatus*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::transferAtrResponse(int32_t serialNumber,
+                                                      SapResultCode resultCode,
+                                                      const std::vector<uint8_t>& /*atr*/) {
+    sapResponseSerial = serialNumber;
+    sapResultCode = resultCode;
+    parent_sap.notify(serialNumber);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::transferCardReaderStatusResponse(int32_t serialNumber,
+                                                                   SapResultCode resultCode,
+                                                                   int32_t /*cardReaderStatus*/) {
+    sapResponseSerial = serialNumber;
+    sapResultCode = resultCode;
+    parent_sap.notify(serialNumber);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::transferProtocolResponse(int32_t serialNumber,
+                                                           SapResultCode resultCode) {
+    sapResponseSerial = serialNumber;
+    sapResultCode = resultCode;
+    parent_sap.notify(serialNumber);
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_sap_test.cpp b/radio/aidl/vts/radio_sap_test.cpp
new file mode 100644
index 0000000..c94379c
--- /dev/null
+++ b/radio/aidl/vts/radio_sap_test.cpp
@@ -0,0 +1,233 @@
+/*
+ * 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.
+ */
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+
+#include "radio_sap_utils.h"
+
+#define ASSERT_OK(ret) ASSERT_TRUE((ret).isOk())
+#define TIMEOUT_PERIOD 40
+
+void SapTest::SetUp() {
+    std::string serviceName = GetParam();
+    if (!isServiceValidForDeviceConfiguration(serviceName)) {
+        LOG(DEBUG) << "Skipped the test due to device configuration.";
+        GTEST_SKIP();
+    }
+    sap = ISap::fromBinder(ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str())));
+    ASSERT_NE(sap.get(), nullptr);
+
+    sapCb = ndk::SharedRefBase::make<SapCallback>(*this);
+    ASSERT_NE(sapCb.get(), nullptr);
+
+    count = 0;
+
+    ndk::ScopedAStatus res = sap->setCallback(sapCb);
+    ASSERT_OK(res) << res;
+}
+
+void SapTest::TearDown() {}
+
+::testing::AssertionResult SapTest::CheckAnyOfErrors(SapResultCode err,
+                                                     std::vector<SapResultCode> errors) {
+    for (size_t i = 0; i < errors.size(); i++) {
+        if (err == errors[i]) {
+            return testing::AssertionSuccess();
+        }
+    }
+    return testing::AssertionFailure() << "SapError:" + toString(err) + " is returned";
+}
+
+void SapTest::notify(int receivedSerial) {
+    std::unique_lock<std::mutex> lock(mtx);
+    count++;
+    if (serial == receivedSerial) {
+        cv.notify_one();
+    }
+}
+
+std::cv_status SapTest::wait() {
+    std::unique_lock<std::mutex> lock(mtx);
+
+    std::cv_status status = std::cv_status::no_timeout;
+    auto now = std::chrono::system_clock::now();
+    while (count == 0) {
+        status = cv.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+        if (status == std::cv_status::timeout) {
+            return status;
+        }
+    }
+    count--;
+    return status;
+}
+
+/*
+ * Test ISap.connectReq() for the response returned.
+ */
+TEST_P(SapTest, connectReq) {
+    LOG(DEBUG) << "connectReq";
+    serial = GetRandomSerialNumber();
+    int32_t maxMsgSize = 100;
+
+    ndk::ScopedAStatus res = sap->connectReq(serial, maxMsgSize);
+    ASSERT_OK(res) << res;
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(sapCb->sapResponseSerial, serial);
+
+    // Modem side need time for connect to finish. Adding a waiting time to prevent
+    // disconnect being requested right after connect request.
+    sleep(1);
+}
+
+/*
+ * Test ISap.disconnectReq() for the response returned
+ */
+TEST_P(SapTest, disconnectReq) {
+    LOG(DEBUG) << "disconnectReq";
+    serial = GetRandomSerialNumber();
+
+    ndk::ScopedAStatus res = sap->disconnectReq(serial);
+    ASSERT_OK(res) << res;
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(sapCb->sapResponseSerial, serial);
+    LOG(DEBUG) << "disconnectReq finished";
+}
+
+/*
+ * Test ISap.apduReq() for the response returned.
+ */
+TEST_P(SapTest, apduReq) {
+    LOG(DEBUG) << "apduReq";
+    serial = GetRandomSerialNumber();
+    SapApduType sapApduType = SapApduType::APDU;
+    std::vector<uint8_t> command = {};
+
+    ndk::ScopedAStatus res = sap->apduReq(serial, sapApduType, command);
+    ASSERT_OK(res) << res;
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(sapCb->sapResponseSerial, serial);
+
+    ASSERT_TRUE(CheckAnyOfErrors(
+            sapCb->sapResultCode,
+            {SapResultCode::GENERIC_FAILURE, SapResultCode::CARD_ALREADY_POWERED_OFF,
+             SapResultCode::CARD_NOT_ACCESSSIBLE, SapResultCode::CARD_REMOVED,
+             SapResultCode::SUCCESS}));
+    LOG(DEBUG) << "apduReq finished";
+}
+
+/*
+ * Test ISap.transferAtrReq() for the response returned.
+ */
+TEST_P(SapTest, transferAtrReq) {
+    LOG(DEBUG) << "transferAtrReq";
+    serial = GetRandomSerialNumber();
+
+    ndk::ScopedAStatus res = sap->transferAtrReq(serial);
+    ASSERT_OK(res) << res;
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(sapCb->sapResponseSerial, serial);
+
+    ASSERT_TRUE(CheckAnyOfErrors(sapCb->sapResultCode,
+                                 {SapResultCode::GENERIC_FAILURE, SapResultCode::DATA_NOT_AVAILABLE,
+                                  SapResultCode::CARD_ALREADY_POWERED_OFF,
+                                  SapResultCode::CARD_REMOVED, SapResultCode::SUCCESS}));
+    LOG(DEBUG) << "transferAtrReq finished";
+}
+
+/*
+ * Test ISap.powerReq() for the response returned.
+ */
+TEST_P(SapTest, powerReq) {
+    LOG(DEBUG) << "powerReq";
+    serial = GetRandomSerialNumber();
+    bool state = true;
+
+    ndk::ScopedAStatus res = sap->powerReq(serial, state);
+    ASSERT_OK(res) << res;
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(sapCb->sapResponseSerial, serial);
+
+    ASSERT_TRUE(
+            CheckAnyOfErrors(sapCb->sapResultCode,
+                             {SapResultCode::GENERIC_FAILURE, SapResultCode::CARD_NOT_ACCESSSIBLE,
+                              SapResultCode::CARD_ALREADY_POWERED_OFF, SapResultCode::CARD_REMOVED,
+                              SapResultCode::CARD_ALREADY_POWERED_ON, SapResultCode::SUCCESS}));
+    LOG(DEBUG) << "powerReq finished";
+}
+
+/*
+ * Test ISap.resetSimReq() for the response returned.
+ */
+TEST_P(SapTest, resetSimReq) {
+    LOG(DEBUG) << "resetSimReq";
+    serial = GetRandomSerialNumber();
+
+    ndk::ScopedAStatus res = sap->resetSimReq(serial);
+    ASSERT_OK(res) << res;
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(sapCb->sapResponseSerial, serial);
+
+    ASSERT_TRUE(
+            CheckAnyOfErrors(sapCb->sapResultCode,
+                             {SapResultCode::GENERIC_FAILURE, SapResultCode::CARD_NOT_ACCESSSIBLE,
+                              SapResultCode::CARD_ALREADY_POWERED_OFF, SapResultCode::CARD_REMOVED,
+                              SapResultCode::SUCCESS}));
+    LOG(DEBUG) << "resetSimReq finished";
+}
+
+/*
+ * Test ISap.transferCardReaderStatusReq() for the response returned.
+ */
+TEST_P(SapTest, transferCardReaderStatusReq) {
+    LOG(DEBUG) << "transferCardReaderStatusReq";
+    serial = GetRandomSerialNumber();
+
+    ndk::ScopedAStatus res = sap->transferCardReaderStatusReq(serial);
+    ASSERT_OK(res) << res;
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(sapCb->sapResponseSerial, serial);
+
+    ASSERT_TRUE(CheckAnyOfErrors(sapCb->sapResultCode,
+                                 {SapResultCode::GENERIC_FAILURE, SapResultCode::DATA_NOT_AVAILABLE,
+                                  SapResultCode::SUCCESS}));
+    LOG(DEBUG) << "transferCardReaderStatusReq finished";
+}
+
+/*
+ * Test ISap.setTransferProtocolReq() for the response returned.
+ */
+TEST_P(SapTest, setTransferProtocolReq) {
+    LOG(DEBUG) << "setTransferProtocolReq";
+    serial = GetRandomSerialNumber();
+    SapTransferProtocol sapTransferProtocol = SapTransferProtocol::T0;
+
+    ndk::ScopedAStatus res = sap->setTransferProtocolReq(serial, sapTransferProtocol);
+    ASSERT_OK(res) << res;
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(sapCb->sapResponseSerial, serial);
+
+    ASSERT_TRUE(CheckAnyOfErrors(sapCb->sapResultCode,
+                                 {SapResultCode::NOT_SUPPORTED, SapResultCode::SUCCESS}));
+    LOG(DEBUG) << "setTransferProtocolReq finished";
+}
diff --git a/radio/aidl/vts/radio_sap_utils.h b/radio/aidl/vts/radio_sap_utils.h
new file mode 100644
index 0000000..bf17006
--- /dev/null
+++ b/radio/aidl/vts/radio_sap_utils.h
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <aidl/Gtest.h>
+#include <aidl/android/hardware/radio/sap/BnSapCallback.h>
+#include <aidl/android/hardware/radio/sap/ISap.h>
+
+#include "radio_aidl_hal_utils.h"
+
+using namespace aidl::android::hardware::radio::sap;
+
+class SapTest;
+
+/* Callback class for radio sap response */
+class SapCallback : public BnSapCallback {
+  protected:
+    SapTest& parent_sap;
+
+  public:
+    SapCallback(SapTest& parent_config);
+    virtual ~SapCallback() = default;
+
+    int32_t sapResponseSerial;
+    SapResultCode sapResultCode;
+
+    virtual ::ndk::ScopedAStatus apduResponse(int32_t serial, SapResultCode resultCode,
+                                              const std::vector<uint8_t>& adpuRsp) override;
+
+    virtual ::ndk::ScopedAStatus connectResponse(int32_t serial, SapConnectRsp sapConnectRsp,
+                                                 int32_t maxMsgSize) override;
+
+    virtual ::ndk::ScopedAStatus disconnectIndication(int32_t serial,
+                                                      SapDisconnectType sapDisconnectType) override;
+
+    virtual ::ndk::ScopedAStatus disconnectResponse(int32_t serial) override;
+
+    virtual ::ndk::ScopedAStatus errorResponse(int32_t serial) override;
+
+    virtual ::ndk::ScopedAStatus powerResponse(int32_t serial, SapResultCode resultCode) override;
+
+    virtual ::ndk::ScopedAStatus resetSimResponse(int32_t serial,
+                                                  SapResultCode resultCode) override;
+
+    virtual ::ndk::ScopedAStatus statusIndication(int32_t serial, SapStatus sapStatus) override;
+
+    virtual ::ndk::ScopedAStatus transferAtrResponse(int32_t serial, SapResultCode resultCode,
+                                                     const std::vector<uint8_t>& atr) override;
+
+    virtual ::ndk::ScopedAStatus transferCardReaderStatusResponse(
+            int32_t serial, SapResultCode resultCode, int32_t cardReaderStatus) override;
+
+    virtual ::ndk::ScopedAStatus transferProtocolResponse(int32_t serial,
+                                                          SapResultCode resultCode) override;
+};
+
+// The main test class for  AIDL SAP.
+class SapTest : public ::testing::TestWithParam<std::string> {
+  private:
+    std::mutex mtx;
+    std::condition_variable cv;
+    int count;
+
+  public:
+    virtual void SetUp() override;
+
+    virtual void TearDown() override;
+
+    ::testing::AssertionResult CheckAnyOfErrors(SapResultCode err,
+                                                std::vector<SapResultCode> errors);
+
+    /* Used as a mechanism to inform the test about data/event callback */
+    void notify(int receivedSerial);
+
+    /* Test code calls this function to wait for response */
+    std::cv_status wait();
+
+    /* Sap service */
+    std::shared_ptr<ISap> sap;
+
+    /* Sap Callback object */
+    std::shared_ptr<SapCallback> sapCb;
+
+    /* Serial for sap request */
+    int32_t serial;
+};
diff --git a/secure_element/aidl/default/main.cpp b/secure_element/aidl/default/main.cpp
index 16b8236..9b5a8fc 100644
--- a/secure_element/aidl/default/main.cpp
+++ b/secure_element/aidl/default/main.cpp
@@ -15,141 +15,673 @@
  */
 
 #include <aidl/android/hardware/secure_element/BnSecureElement.h>
-
 #include <android-base/hex.h>
 #include <android-base/logging.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
 
+#include <algorithm>
+
 using aidl::android::hardware::secure_element::BnSecureElement;
 using aidl::android::hardware::secure_element::ISecureElementCallback;
 using aidl::android::hardware::secure_element::LogicalChannelResponse;
 using android::base::HexString;
 using ndk::ScopedAStatus;
 
-static const std::vector<uint8_t> kAndroidTestAid = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41,
-                                                     0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64,
-                                                     0x43, 0x54, 0x53, 0x31};
-static const std::vector<uint8_t> kLongAndroidTestAid = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41,
-                                                         0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64,
-                                                         0x43, 0x54, 0x53, 0x32};
+static const std::vector<uint8_t> kIssuerSecurityDomainSelectResponse = {0x00, 0x00, 0x90, 0x00};
 
-class MySecureElement : public BnSecureElement {
+namespace se {
+// Application identifier.
+using Aid = std::vector<uint8_t>;
+
+// ISO7816 APDU status codes.
+enum Status : uint16_t {
+    SW_WRONG_DATA = 0x6A80,
+    SW_LOGICAL_CHANNEL_NOT_SUPPORTED = 0x6881,
+    SW_CONDITIONS_NOT_SATISFIED = 0x6985,
+    SW_INCORRECT_P1P2 = 0x6A86,
+    SW_BYTES_REMAINING_00 = 0x6100,
+    SW_WRONG_LENGTH = 0x6700,
+    SW_CORRECT_LENGTH_00 = 0x6C00,
+    SW_INS_NOT_SUPPORTED = 0x6D00,
+    SW_NO_ERROR = 0x9000,
+};
+
+// Type for raw APDUs.
+using RawApdu = std::vector<uint8_t>;
+
+// Wrap a command APDU (Application Processing Data Unit) to provide
+// accessors for header fields.
+struct Apdu {
   public:
-    ScopedAStatus closeChannel(int8_t channelNumber) override {
-        LOG(INFO) << __func__ << " channel number: " << channelNumber;
-        return ScopedAStatus::ok();
+    // Construct a command Apdu.
+    Apdu(std::vector<uint8_t> packet) : bytes_(std::move(packet)) {
+        CHECK(bytes_.size() >= kHeaderSize) << "command APDU created with invalid length";
+        size_t payload_len = bytes_.size() - kHeaderSize;
+
+        // TODO(b/123254068) - add support for extended command APDUs.
+        // Pre compute Lc and Le.
+
+        // Case 1: CLA | INS | P1 | P2
+        if (payload_len == 0) {
+            lc_ = 0;
+            le_ = 0;
+            return;
+        }
+
+        // Case 2: CLA | INS | P1 | P2 | Le
+        // Le has a value of 1 to 255.
+        if (payload_len == 1) {
+            le_ = bytes_[kHeaderSize];
+            le_ = le_ == 0 ? 256 : le_;
+            lc_ = 0;
+            return;
+        }
+
+        // Case 3: CLA | INS | P1 | P2 | Lc | Data
+        // Lc is less than 256 bytes
+        // of data, and Le is zero.
+        lc_ = bytes_[kHeaderSize];
+        if (payload_len <= (1 + lc_)) {
+            le_ = 0;
+        }
+
+        // Case 4: CLA | INS | P1 | P2 | Lc | Data | Le
+        // The legacy Case 4. Lc and Le
+        // are less than 256 bytes of data.
+        else {
+            le_ = bytes_[bytes_.size() - 1];
+            le_ = le_ == 0 ? 256 : le_;
+        }
     }
-    ScopedAStatus getAtr(std::vector<uint8_t>* _aidl_return) override {
-        LOG(INFO) << __func__;
-        _aidl_return->clear();
-        return ScopedAStatus::ok();
+
+    // Construct a response Apdu with data.
+    static RawApdu CreateResponse(std::vector<uint8_t> data, Status status) {
+        // Append status word.
+        data.push_back(status >> 8);
+        data.push_back(status);
+        return data;
     }
+
+    // Construct a response Apdu with no data.
+    static RawApdu CreateResponse(Status status) {
+        // Append status word.
+        return std::vector<uint8_t>{static_cast<uint8_t>(status >> 8),
+                                    static_cast<uint8_t>(status)};
+    }
+
+    // Return if command APDU is extended.
+    // The ISO/IEC 7816-4:2013 specification defines an extended APDU as any APDU
+    // whose payload data, response data or expected data length exceeds the 256
+    // byte limit.
+    bool IsExtended() const { return (bytes_.size() - kHeaderSize) > 256; }
+
+    // Return if command APDU has payload bytes.
+    bool HasPayload() const { return bytes_.size() > kHeaderSize; }
+
+    uint8_t get_cla() const { return bytes_[0]; }
+    uint8_t get_ins() const { return bytes_[1]; }
+    uint8_t get_p1() const { return bytes_[2]; }
+    uint8_t get_p2() const { return bytes_[3]; }
+
+    // Return the channel number encoded in the CLA field.
+    uint8_t get_channel_number() const {
+        // Type 4 commands — Encode legacy ISO/IEC 7816-4 logical channel
+        // information. Type 16 commands — Defined by the ISO/IEC 7816-4:2013
+        // specification to
+        //   encode information for additional 16 logical channels in the card.
+        uint8_t cla = get_cla();
+        return (cla & 0x40) == 0 ? cla & 0x3 : 4 + (cla & 0xf);
+    }
+
+    // Return the length of the command data field.
+    uint16_t get_lc() const { return lc_; }
+
+    // Return the expected length of the response data field.
+    // Le should be have the same format as Lc.
+    uint16_t get_le() const { return le_; }
+
+    // Get the pointer to the APDU raw data.
+    std::vector<uint8_t> const& get_data() const { return bytes_; }
+
+  private:
+    // Size of command header, including CLA, INS, P1, P2 fields.
+    const size_t kHeaderSize = 4;
+
+    // Command or response buffer.
+    std::vector<uint8_t> bytes_{};
+
+    // Lengths of command data field and expected response data field.
+    uint16_t lc_{0};
+    uint16_t le_{0};
+};
+
+// Type of SE applets.
+class Applet {
+  public:
+    virtual ~Applet() {}
+
+    // Called to inform this applet that it has been selected.
+    virtual RawApdu Select(Aid const& aid, uint8_t p2) = 0;
+
+    // Called by the Java Card runtime environment to process an
+    // incoming APDU command. SELECT commands are processed by \ref select
+    // instead.
+    virtual RawApdu Process(Apdu const& apdu) = 0;
+};
+};  // namespace se
+
+// Implement the Google-eSE-test.cap test applet for passing OMAPI CTS tests
+// on Cuttlefish. The reference can be found here:
+// cts/tests/tests/secure_element/sample_applet/src/com/android/cts/omapi/test/CtsAndroidOmapiTestApplet.java
+class CtsAndroidOmapiTestApplet : public se::Applet {
+  public:
+    CtsAndroidOmapiTestApplet() {}
+    virtual ~CtsAndroidOmapiTestApplet() {}
+
+    se::RawApdu Select(se::Aid const& aid, uint8_t /*p2*/) override {
+        if (aid[aid.size() - 1] == 0x31) {
+            // AID: A000000476416E64726F696443545331
+            return se::Apdu::CreateResponse(se::Status::SW_NO_ERROR);
+        } else {
+            // AID: A000000476416E64726F696443545332
+            return se::Apdu::CreateResponse(GenerateBerTLVBytes(SELECT_RESPONSE_DATA_LENGTH),
+                                            se::Status::SW_NO_ERROR);
+        }
+    }
+
+    se::RawApdu ReadNextResponseChunk(uint16_t max_output_len) {
+        uint16_t output_len = static_cast<uint16_t>(response_.size() - response_offset_);
+        output_len = std::min<uint16_t>(max_output_len, output_len);
+        std::vector<uint8_t> output{
+                &response_[response_offset_],
+                &response_[response_offset_ + output_len],
+        };
+        response_offset_ += output_len;
+        uint16_t remaining_len = response_.size() - response_offset_;
+        se::Status status = se::Status::SW_NO_ERROR;
+        if (remaining_len > 0) {
+            if (remaining_len > 256) {
+                remaining_len = 0x00;
+            }
+            status = se::Status(se::Status::SW_BYTES_REMAINING_00 | remaining_len);
+        } else {
+            response_.clear();
+            response_offset_ = 0;
+        }
+        return se::Apdu::CreateResponse(output, status);
+    }
+
+    se::RawApdu Process(se::Apdu const& apdu) override {
+        uint16_t lc;
+        uint16_t le = apdu.get_le();
+        uint8_t p1 = apdu.get_p1();
+        uint8_t p2 = apdu.get_p2();
+
+        switch (apdu.get_ins()) {
+            case NO_DATA_INS_1:
+            case NO_DATA_INS_2:
+                LOG(INFO) << __func__ << ": NO_DATA_INS_1|2";
+                return se::Apdu::CreateResponse(se::Status::SW_NO_ERROR);
+
+            case DATA_INS_1:
+            case DATA_INS_2:
+                // Return 256 bytes of data.
+                LOG(INFO) << __func__ << ": DATA_INS_1|2";
+                return se::Apdu::CreateResponse(GeneratesBytes(256), se::Status::SW_NO_ERROR);
+
+            case GET_RESPONSE_INS:
+                // ISO GET_RESPONSE command.
+                LOG(INFO) << __func__ << ": GET_RESPONSE_INS";
+                if (response_.empty()) {
+                    return se::Apdu::CreateResponse(se::Status::SW_CONDITIONS_NOT_SATISFIED);
+                }
+                return ReadNextResponseChunk(apdu.get_le());
+
+            case SW_62xx_APDU_INS:
+                LOG(INFO) << __func__ << ": SW_62xx_APDU_INS";
+                if (p1 < 1 || p1 > 16) {
+                    return se::Apdu::CreateResponse(se::Status::SW_INCORRECT_P1P2);
+                }
+                if (p2 == SW_62xx_DATA_APDU_P2) {
+                    return se::Apdu::CreateResponse(GeneratesBytes(3),
+                                                    se::Status(SW_62xx_resp[p1 - 1]));
+                }
+                if (p2 == SW_62xx_VALIDATE_DATA_P2) {
+                    std::vector<uint8_t> output{SW_62xx_VALIDATE_DATA_RESP.begin(),
+                                                SW_62xx_VALIDATE_DATA_RESP.end()};
+                    output[2] = p1;
+                    return se::Apdu::CreateResponse(std::move(output),
+                                                    se::Status(SW_62xx_resp[p1 - 1]));
+                }
+                return se::Apdu::CreateResponse(se::Status(SW_62xx_resp[p1 - 1]));
+
+            case SEGMENTED_RESP_INS_1:
+            case SEGMENTED_RESP_INS_2:
+                LOG(INFO) << __func__ << ": SEGMENTED_RESP_INS_1|2";
+                response_ = GeneratesBytes((static_cast<uint16_t>(p1) << 8) | p2);
+                response_offset_ = 0;
+                return ReadNextResponseChunk(std::min<uint16_t>(apdu.get_le(), 256));
+
+            case SEGMENTED_RESP_INS_3:
+            case SEGMENTED_RESP_INS_4:
+                LOG(INFO) << __func__ << ": SEGMENTED_RESP_INS_3|4";
+                response_ = GeneratesBytes((static_cast<uint16_t>(p1) << 8) | p2);
+                response_offset_ = 0;
+                return ReadNextResponseChunk(apdu.get_le());
+
+            case SEGMENTED_RESP_INS_5:
+                LOG(INFO) << __func__ << ": SEGMENTED_RESP_INS_5";
+                if (le == 0xff) {
+                    return se::Apdu::CreateResponse(
+                            se::Status(se::Status::SW_CORRECT_LENGTH_00 | 0xff));
+                }
+                response_ = GeneratesBytes((static_cast<uint16_t>(p1) << 8) | p2);
+                response_offset_ = 0;
+                return ReadNextResponseChunk(apdu.get_le());
+
+            case CHECK_SELECT_P2_APDU:
+                LOG(INFO) << __func__ << ": CHECK_SELECT_P2_APDU";
+                return se::Apdu::CreateResponse(std::vector<uint8_t>{apdu.get_p2()},
+                                                se::Status::SW_NO_ERROR);
+
+            default:
+                // Case is not known.
+                LOG(INFO) << __func__ << ": UNKNOWN_INS";
+                return se::Apdu::CreateResponse(se::Status::SW_INS_NOT_SUPPORTED);
+        }
+    }
+
+  private:
+    std::vector<uint8_t> response_{};
+    uint16_t response_offset_{0};
+
+    static const uint8_t NO_DATA_INS_1 = 0x06;
+    static const uint8_t NO_DATA_INS_2 = 0x0A;
+    static const uint8_t DATA_INS_1 = 0x08;
+    static const uint8_t DATA_INS_2 = 0x0C;
+    static const uint8_t SW_62xx_APDU_INS = 0xF3;
+    static const uint8_t SW_62xx_DATA_APDU_P2 = 0x08;
+    static const uint8_t SW_62xx_VALIDATE_DATA_P2 = 0x0C;
+
+    static constexpr std::array<uint8_t, 7> SW_62xx_VALIDATE_DATA_RESP = {0x01, 0xF3, 0x00, 0x0C,
+                                                                          0x01, 0xAA, 0x00};
+    static constexpr uint16_t SW_62xx_resp[] = {
+            0x6200, 0x6281, 0x6282, 0x6283, 0x6285, 0x62F1, 0x62F2, 0x63F1,
+            0x63F2, 0x63C2, 0x6202, 0x6280, 0x6284, 0x6286, 0x6300, 0x6381,
+    };
+
+    static const uint8_t SEGMENTED_RESP_INS_1 = 0xC2;
+    static const uint8_t SEGMENTED_RESP_INS_2 = 0xC4;
+    static const uint8_t SEGMENTED_RESP_INS_3 = 0xC6;
+    static const uint8_t SEGMENTED_RESP_INS_4 = 0xC8;
+    static const uint8_t SEGMENTED_RESP_INS_5 = 0xCF;
+    static const uint8_t CHECK_SELECT_P2_APDU = 0xF4;
+    static const uint8_t GET_RESPONSE_INS = 0xC0;
+    static const uint8_t BER_TLV_TYPE = 0x1F;
+    static const uint16_t SELECT_RESPONSE_DATA_LENGTH = 252;
+
+    static const uint16_t LENGTH_256 = 0x0100;
+    static constexpr std::array<uint8_t, 256> resp_bytes256{
+            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
+            0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
+            0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
+            0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+            0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
+            0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53,
+            0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61,
+            0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+            0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D,
+            0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B,
+            0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+            0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
+            0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5,
+            0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3,
+            0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1,
+            0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
+            0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED,
+            0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB,
+            0xFC, 0xFD, 0xFE, 0xFF};
+
+    // Generate a response buffer of the selected length containing valid
+    // BER TLV bytes.
+    static std::vector<uint8_t> GenerateBerTLVBytes(uint16_t le) {
+        // Support length from 0x00 - 0x7FFF.
+        uint16_t le_len = 1;
+        if (le < (uint16_t)0x80) {
+            le_len = 1;
+        } else if (le < (uint16_t)0x100) {
+            le_len = 2;
+        } else {
+            le_len = 3;
+        }
+
+        uint16_t total_len = (uint16_t)(le + 2 + le_len);
+        std::vector<uint8_t> output(total_len);
+        uint16_t i = 0;
+
+        output[i++] = BER_TLV_TYPE;
+        output[i++] = 0x00;  // second byte of Type
+        if (le < 0x80) {
+            output[i++] = le;
+        } else if (le < 0x100) {
+            output[i++] = 0x81;
+            output[i++] = le;
+        } else {
+            output[i++] = 0x82;
+            output[i++] = (le >> 8);
+            output[i++] = (le & 0xFF);
+        }
+        while (i < total_len) {
+            output[i++] = ((i - 2 - le_len) & 0xFF);
+        }
+
+        // Set the last byte to 0xFF for CTS validation.
+        output[total_len - 1] = 0xFF;
+        return output;
+    }
+
+    // Generate a response buffer of the selected length using the
+    // array resp_bytes256 as input.
+    static std::vector<uint8_t> GeneratesBytes(uint16_t total_len) {
+        std::vector<uint8_t> output(total_len);
+        uint16_t i = 0;
+
+        while (i < total_len) {
+            if ((total_len - i) >= resp_bytes256.size()) {
+                std::memcpy(&output[i], resp_bytes256.data(), resp_bytes256.size());
+                i += resp_bytes256.size();
+            } else {
+                output[i] = i & 0xFF;
+                i += 1;
+            }
+        }
+
+        // Set the last byte to 0xFF for CTS validation.
+        output[total_len - 1] = 0xFF;
+        return output;
+    }
+};
+
+class EmulatedSecureElement : public BnSecureElement {
+  public:
+    EmulatedSecureElement() {
+        std::shared_ptr<CtsAndroidOmapiTestApplet> test_applet =
+                std::make_shared<CtsAndroidOmapiTestApplet>();
+
+        applets_.push_back(std::pair{se::Aid{0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64, 0x72,
+                                             0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x31},
+                                     test_applet});
+
+        applets_.push_back(std::pair{se::Aid{0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64, 0x72,
+                                             0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x32},
+                                     test_applet});
+    }
+
     ScopedAStatus init(const std::shared_ptr<ISecureElementCallback>& clientCallback) override {
         LOG(INFO) << __func__ << " callback: " << clientCallback.get();
         if (!clientCallback) {
             return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
         }
-        mCb = clientCallback;
-        mCb->onStateChange(true, "");
+        client_callback_ = clientCallback;
+        client_callback_->onStateChange(true, "init");
         return ScopedAStatus::ok();
     }
-    ScopedAStatus isCardPresent(bool* _aidl_return) override {
+
+    ScopedAStatus getAtr(std::vector<uint8_t>* aidl_return) override {
         LOG(INFO) << __func__;
-        *_aidl_return = true;
+        *aidl_return = atr_;
         return ScopedAStatus::ok();
     }
+
+    ScopedAStatus reset() override {
+        LOG(INFO) << __func__;
+        CHECK(client_callback_ != nullptr) << " init not invoked";
+        client_callback_->onStateChange(false, "reset");
+        client_callback_->onStateChange(true, "reset");
+        // All channels are closed after reset.
+        for (auto channel : channels_) {
+            channel = Channel();
+        }
+        return ScopedAStatus::ok();
+    }
+
+    ScopedAStatus isCardPresent(bool* aidl_return) override {
+        LOG(INFO) << __func__;
+        *aidl_return = true;
+        return ScopedAStatus::ok();
+    }
+
     ScopedAStatus openBasicChannel(const std::vector<uint8_t>& aid, int8_t p2,
-                                   std::vector<uint8_t>* _aidl_return) override {
+                                   std::vector<uint8_t>* aidl_return) override {
         LOG(INFO) << __func__ << " aid: " << HexString(aid.data(), aid.size()) << " (" << aid.size()
                   << ") p2 " << p2;
 
-        // TODO(b/123254068) - this is not an implementation of the OMAPI protocol or APDU.
-        // The functionality here is enough to exercise the framework, but actual
-        // calls to the secure element will fail. This implementation does not model
-        // channel isolation or any other aspects important to implementing secure element.
-        *_aidl_return = {0x90, 0x00, 0x00};  // DO NOT COPY
+        std::vector<uint8_t> select_response;
+        std::shared_ptr<se::Applet> applet = nullptr;
+
+        // The basic channel can only be opened once, and stays opened
+        // and locked until the channel is closed.
+        if (channels_[0].opened) {
+            LOG(INFO) << __func__ << " basic channel already opened";
+            return ScopedAStatus::fromServiceSpecificError(CHANNEL_NOT_AVAILABLE);
+        }
+
+        // If the AID is defined (the AID is not Null and the length of the
+        // AID is not 0) and the channel is not locked then the corresponding
+        // applet shall be selected.
+        if (aid.size() > 0) {
+            applet = SelectApplet(aid);
+            if (applet == nullptr) {
+                // No applet registered with matching AID.
+                LOG(INFO) << __func__ << " basic channel AID not found";
+                return ScopedAStatus::fromServiceSpecificError(NO_SUCH_ELEMENT_ERROR);
+            }
+            select_response = applet->Select(aid, p2);
+        }
+
+        // If the AID is a 0 length AID and the channel is not locked, the
+        // method will select the Issuer Security Domain of the SE by sending a
+        // SELECT command with a 0 length AID as defined in
+        // [GP Card specification].
+        if (aid.size() == 0) {
+            select_response = kIssuerSecurityDomainSelectResponse;
+        }
+
+        LOG(INFO) << __func__ << " sending response: "
+                  << HexString(select_response.data(), select_response.size());
+
+        // TODO(b/123254068) - this is not an implementation of the OMAPI protocol
+        // or APDU. The functionality here is enough to exercise the framework,
+        // but actual calls to the secure element will fail. This implementation
+        // does not model channel isolation or any other aspects important to
+        // implementing secure element.
+        channels_[0] = Channel(aid, p2, applet);
+        *aidl_return = select_response;
         return ScopedAStatus::ok();
     }
+
     ScopedAStatus openLogicalChannel(
             const std::vector<uint8_t>& aid, int8_t p2,
-            ::aidl::android::hardware::secure_element::LogicalChannelResponse* _aidl_return)
+            ::aidl::android::hardware::secure_element::LogicalChannelResponse* aidl_return)
             override {
         LOG(INFO) << __func__ << " aid: " << HexString(aid.data(), aid.size()) << " (" << aid.size()
                   << ") p2 " << p2;
 
-        if (aid != kAndroidTestAid && aid != kLongAndroidTestAid) {
-            return ScopedAStatus::fromServiceSpecificError(NO_SUCH_ELEMENT_ERROR);
+        size_t channel_number = 1;
+        std::vector<uint8_t> select_response;
+        std::shared_ptr<se::Applet> applet = nullptr;
+
+        // Look for an available channel number.
+        for (; channel_number < channels_.size(); channel_number++) {
+            if (channels_[channel_number].opened == false) {
+                break;
+            }
         }
 
-        *_aidl_return = LogicalChannelResponse{.channelNumber = 1, .selectResponse = {}};
+        // All channels are currently allocated.
+        if (channel_number >= channels_.size()) {
+            LOG(INFO) << __func__ << " all logical channels already opened";
+            return ScopedAStatus::fromServiceSpecificError(CHANNEL_NOT_AVAILABLE);
+        }
 
-        // TODO(b/123254068) - this is not an implementation of the OMAPI protocol or APDU.
-        // The functionality here is enough to exercise the framework, but actual
-        // calls to the secure element will fail. This implementation does not model
-        // channel isolation or any other aspects important to implementing secure element.
-        if (aid == kAndroidTestAid) {                                 // DO NOT COPY
-            size_t size = 2050;                                       // DO NOT COPY
-            _aidl_return->selectResponse.resize(size);                // DO NOT COPY
-            _aidl_return->selectResponse[size - 1] = 0x00;            // DO NOT COPY
-            _aidl_return->selectResponse[size - 2] = 0x90;            // DO NOT COPY
-        } else {                                                      // DO NOT COPY
-            _aidl_return->selectResponse = {0x00, 0x00, 0x90, 0x00};  // DO NOT COPY
-        }                                                             // DO NOT COPY
+        // If the AID is defined (the AID is not Null and the length of the
+        // AID is not 0) then the corresponding applet shall be selected.
+        if (aid.size() > 0) {
+            applet = SelectApplet(aid);
+            if (applet == nullptr) {
+                // No applet registered with matching AID.
+                LOG(INFO) << __func__ << " logical channel AID not found";
+                return ScopedAStatus::fromServiceSpecificError(NO_SUCH_ELEMENT_ERROR);
+            }
+            select_response = applet->Select(aid, p2);
+        }
+
+        // If the length of the AID is 0, the method will select the
+        // Issuer Security Domain of the SE by sending a SELECT command
+        // with 0 length AID as defined in [GPCS].
+        if (aid.size() == 0) {
+            select_response = kIssuerSecurityDomainSelectResponse;
+        }
 
         LOG(INFO) << __func__ << " sending response: "
-                  << HexString(_aidl_return->selectResponse.data(),
-                               _aidl_return->selectResponse.size());
+                  << HexString(select_response.data(), select_response.size());
 
+        // TODO(b/123254068) - this is not an implementation of the OMAPI protocol
+        // or APDU. The functionality here is enough to exercise the framework,
+        // but actual calls to the secure element will fail. This implementation
+        // does not model channel isolation or any other aspects important to
+        // implementing secure element.
+        channels_[channel_number] = Channel(aid, p2, applet);
+        *aidl_return = LogicalChannelResponse{
+                .channelNumber = static_cast<int8_t>(channel_number),
+                .selectResponse = select_response,
+        };
         return ScopedAStatus::ok();
     }
-    ScopedAStatus reset() override {
-        LOG(INFO) << __func__;
-        mCb->onStateChange(false, "reset");
-        mCb->onStateChange(true, "reset");
+
+    ScopedAStatus closeChannel(int8_t channel_number) override {
+        LOG(INFO) << __func__ << " channel number: " << static_cast<int>(channel_number);
+        // The selected basic or logical channel is not opened.
+        if (channel_number >= channels_.size() || !channels_[channel_number].opened) {
+            return ScopedAStatus::ok();
+        }
+
+        // TODO(b/123254068) - this is not an implementation of the OMAPI protocol
+        // or APDU. The functionality here is enough to exercise the framework,
+        // but actual calls to the secure element will fail. This implementation
+        // does not model channel isolation or any other aspects important to
+        // implementing secure element.
+        channels_[channel_number].opened = false;
         return ScopedAStatus::ok();
     }
+
     ScopedAStatus transmit(const std::vector<uint8_t>& data,
-                           std::vector<uint8_t>* _aidl_return) override {
+                           std::vector<uint8_t>* aidl_return) override {
         LOG(INFO) << __func__ << " data: " << HexString(data.data(), data.size()) << " ("
                   << data.size() << ")";
 
-        // TODO(b/123254068) - this is not an implementation of the OMAPI protocol or APDU.
-        // The functionality here is enough to exercise the framework, but actual
-        // calls to the secure element will fail. This implementation does not model
-        // channel isolation or any other aspects important to implementing secure element.
+        se::Apdu apdu(data);
+        uint8_t channel_number = apdu.get_channel_number();
+        std::vector<uint8_t> response_apdu;
 
-        std::string hex = HexString(data.data(), data.size());                    // DO NOT COPY
-        if (hex == "01a4040210a000000476416e64726f696443545331") {                // DO NOT COPY
-            *_aidl_return = {0x00, 0x6A, 0x00};                                   // DO NOT COPY
-        } else if (data == std::vector<uint8_t>{0x00, 0xF4, 0x00, 0x00, 0x00}) {  // DO NOT COPY
-            // CHECK_SELECT_P2_APDU w/ channel 1 // DO NOT COPY
-            *_aidl_return = {0x00, 0x90, 0x00};                                   // DO NOT COPY
-        } else if (data == std::vector<uint8_t>{0x01, 0xF4, 0x00, 0x00, 0x00}) {  // DO NOT COPY
-            // CHECK_SELECT_P2_APDU w/ channel 1 // DO NOT COPY
-            *_aidl_return = {0x00, 0x90, 0x00};             // DO NOT COPY
-        } else if (data.size() == 5 || data.size() == 8) {  // DO NOT COPY
-            // SEGMENTED_RESP_APDU - happens to use length 5 and 8 // DO NOT COPY
-            size_t size = (data[2] << 8 | data[3]) + 2;       // DO NOT COPY
-            _aidl_return->resize(size);                       // DO NOT COPY
-            (*_aidl_return)[size - 1] = 0x00;                 // DO NOT COPY
-            (*_aidl_return)[size - 2] = 0x90;                 // DO NOT COPY
-            if (size >= 3) (*_aidl_return)[size - 3] = 0xFF;  // DO NOT COPY
-        } else {                                              // DO NOT COPY
-            *_aidl_return = {0x90, 0x00, 0x00};               // DO NOT COPY
-        }                                                     // DO NOT COPY
+        switch (apdu.get_ins()) {
+            // TODO(b/123254068) - Implement support channel management APDUs.
+            case MANAGE_CHANNEL_INS:
+                // P1 = '00' to open
+                // P1 = '80' to close
+                LOG(INFO) << __func__ << " MANAGE_CHANNEL apdu";
+                response_apdu =
+                        se::Apdu::CreateResponse(se::Status::SW_LOGICAL_CHANNEL_NOT_SUPPORTED);
+                break;
 
+            // TODO(b/123254068) - Implement support channel management APDUs.
+            case SELECT_INS:
+                LOG(INFO) << __func__ << " SELECT apdu";
+                response_apdu =
+                        se::Apdu::CreateResponse(se::Status::SW_LOGICAL_CHANNEL_NOT_SUPPORTED);
+                break;
+
+            default:
+                CHECK(channel_number < channels_.size()) << " invalid channel number";
+                if (!channels_[channel_number].opened) {
+                    LOG(INFO) << __func__ << " the channel " << static_cast<int>(channel_number)
+                              << " is not opened";
+                    response_apdu =
+                            se::Apdu::CreateResponse(se::Status::SW_LOGICAL_CHANNEL_NOT_SUPPORTED);
+                    break;
+                }
+                // Send the APDU to the applet for processing.
+                // Applet implementation is optional, default to sending
+                // SW_INS_NOT_SUPPORTED.
+                if (channels_[channel_number].applet == nullptr) {
+                    response_apdu = se::Apdu::CreateResponse(se::Status::SW_INS_NOT_SUPPORTED);
+                } else {
+                    response_apdu = channels_[channel_number].applet->Process(apdu);
+                }
+                break;
+        }
+
+        aidl_return->assign(response_apdu.begin(), response_apdu.end());
+        LOG(INFO) << __func__
+                  << " response: " << HexString(aidl_return->data(), aidl_return->size()) << " ("
+                  << aidl_return->size() << ")";
         return ScopedAStatus::ok();
     }
 
   private:
-    std::shared_ptr<ISecureElementCallback> mCb;
+    struct Channel {
+      public:
+        Channel() = default;
+        Channel(Channel const&) = default;
+        Channel(se::Aid const& aid, uint8_t p2, std::shared_ptr<se::Applet> applet)
+            : opened(true), aid(aid), p2(p2), applet(std::move(applet)) {}
+        Channel& operator=(Channel const&) = default;
+
+        bool opened{false};
+        se::Aid aid{};
+        uint8_t p2{0};
+        std::shared_ptr<se::Applet> applet{nullptr};
+    };
+
+    // OMAPI abstraction.
+
+    // Channel 0 is the basic channel, channels 1-19 are the logical channels.
+    std::array<Channel, 20> channels_{};
+    std::shared_ptr<ISecureElementCallback> client_callback_;
+
+    // Secure element abstraction.
+
+    static const uint8_t MANAGE_CHANNEL_INS = 0x70;
+    static const uint8_t SELECT_INS = 0xa4;
+
+    // Secure element ATR (Answer-To-Reset).
+    // The format is specified by ISO/IEC 1816-4 2020 and lists
+    // the capabilities of the card.
+    //
+    // TODO(b/123254068): encode the default SE properties in the ATR:
+    // support for extended Lc / Le fields, maximum number of logical channels.
+    // The CTS tests are *not* checking this value.
+    std::vector<uint8_t> const atr_{};
+
+    // Applet registration.
+    std::vector<std::pair<se::Aid, std::shared_ptr<se::Applet>>> applets_{};
+
+    // Return the first applet that matches the selected aid.
+    std::shared_ptr<se::Applet> SelectApplet(se::Aid const& aid) {
+        for (auto& [applet_aid, applet] : applets_) {
+            if (applet_aid == aid) {
+                return applet;
+            }
+        }
+        return nullptr;
+    }
 };
 
 int main() {
     ABinderProcess_setThreadPoolMaxThreadCount(0);
 
-    auto se = ndk::SharedRefBase::make<MySecureElement>();
+    auto se = ndk::SharedRefBase::make<EmulatedSecureElement>();
     const std::string name = std::string() + BnSecureElement::descriptor + "/eSE1";
     binder_status_t status = AServiceManager_addService(se->asBinder().get(), name.c_str());
     CHECK_EQ(status, STATUS_OK);
diff --git a/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp
index e7f5a0f..88badc7 100644
--- a/security/keymint/aidl/vts/functional/Android.bp
+++ b/security/keymint/aidl/vts/functional/Android.bp
@@ -57,6 +57,7 @@
     srcs: [
         "AttestKeyTest.cpp",
         "DeviceUniqueAttestationTest.cpp",
+        "KeyBlobUpgradeTest.cpp",
         "KeyMintTest.cpp",
         "SecureElementProvisioningTest.cpp",
     ],
diff --git a/security/keymint/aidl/vts/functional/KeyBlobUpgradeTest.cpp b/security/keymint/aidl/vts/functional/KeyBlobUpgradeTest.cpp
new file mode 100644
index 0000000..c952012
--- /dev/null
+++ b/security/keymint/aidl/vts/functional/KeyBlobUpgradeTest.cpp
@@ -0,0 +1,609 @@
+/*
+ * 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.
+ */
+
+// The tests in this file are intended to be run manually, to allow testing of whether
+// keyblob upgrade works correctly.  The manual procedure is roughly:
+//
+// 1) Run the "*Before*" subset of these tests with the `--keyblob_dir <dir>` command-line argument
+//    so that keyblobs are saved to a directory on the device:
+//
+//      VtsAidlKeyMintTargetTest --gtest_filter="*KeyBlobUpgradeTest*Before*" \
+//                               --keyblob_dir /data/local/tmp/keymint-blobs
+//
+//    All tests should pass, and the `UpgradeKeyBlobs` test should indicate that no keyblob
+//    upgrades were needed.
+//
+// 2) Copy the generated keyblobs off the device into a safe place.
+//
+//      adb pull /data/local/tmp/keymint-blobs
+//
+// 3) Upgrade the device to a new version.
+//
+// 4) Push the saved keyblobs back onto the upgraded device.
+//
+//      adb push keymint-blobs /data/local/tmp/keymint-blobs
+//
+// 5) Run the "*After*" subset of these tests with the `--keyblob_dir <dir>` command-line argument
+//    pointing to the directory with the keyblobs:
+//
+//      VtsAidlKeyMintTargetTest --gtest_filter="*KeyBlobUpgradeTest*After*" \
+//                               --keyblob_dir /data/local/tmp/keymint-blobs
+//
+//    (Note that this skips the `CreateKeyBlobs` test, which would otherwise replace the saved
+//    keyblobs with freshly generated ones.).
+//
+//    All tests should pass, and the `UpgradeKeyBlobs` test should have output that matches whether
+//    upgrade was expected or not.
+
+#define LOG_TAG "keymint_1_test"
+#include <cutils/log.h>
+
+#include <algorithm>
+#include <fstream>
+#include <iostream>
+
+#include <unistd.h>
+
+#include <openssl/curve25519.h>
+#include <openssl/ec.h>
+#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/x509v3.h>
+
+#include "KeyMintAidlTestBase.h"
+
+using aidl::android::hardware::security::keymint::KeyCharacteristics;
+
+namespace aidl::android::hardware::security::keymint::test {
+
+namespace {
+
+std::vector<std::string> keyblob_names_tee = {
+        "aes-key",        "aes-key-rr",      "des-key",           "hmac-key",
+        "rsa-key",        "p256-key",        "ed25519-key",       "x25519-key",
+        "rsa-attest-key", "p256-attest-key", "ed25519-attest-key"};
+
+std::vector<std::string> keyblob_names_sb = {"aes-key",        "aes-key-rr",     "des-key",
+                                             "hmac-key",       "rsa-key",        "p256-key",
+                                             "rsa-attest-key", "p256-attest-key"};
+
+const std::vector<std::string>& keyblob_names(SecurityLevel sec_level) {
+    if (sec_level == SecurityLevel::STRONGBOX) {
+        return keyblob_names_sb;
+    } else {
+        return keyblob_names_tee;
+    }
+}
+
+bool requires_rr(const std::string& name) {
+    return name.find("-rr") != std::string::npos;
+}
+
+bool is_asymmetric(const std::string& name) {
+    return (name.find("rsa") != std::string::npos || name.find("25519") != std::string::npos ||
+            name.find("p256") != std::string::npos);
+}
+
+std::string keyblob_subdir(const std::string& keyblob_dir, const std::string& full_name,
+                           bool create) {
+    if (keyblob_dir.empty()) {
+        return "";
+    }
+
+    // Use a subdirectory for the specific instance, so two different KeyMint instances won't
+    // clash with each other.
+    size_t found = full_name.find_last_of('/');
+    std::string subdir = keyblob_dir + "/" + full_name.substr(found + 1);
+
+    if (create) {
+        mkdir(keyblob_dir.c_str(), 0777);
+        mkdir(subdir.c_str(), 0777);
+    }
+    return subdir;
+}
+
+void save_keyblob(const std::string& subdir, const std::string& name,
+                  const vector<uint8_t>& keyblob,
+                  const std::vector<KeyCharacteristics>& key_characteristics) {
+    // Write the keyblob out to a file.
+    std::string blobname(subdir + "/" + name + ".keyblob");
+    std::ofstream blobfile(blobname, std::ios::out | std::ios::trunc | std::ios::binary);
+    blobfile.write(reinterpret_cast<const char*>(keyblob.data()), keyblob.size());
+    blobfile.close();
+
+    // Dump the characteristics too.
+    std::string charsname(subdir + "/" + name + ".chars");
+    std::ofstream charsfile(charsname, std::ios::out | std::ios::trunc);
+    charsfile << "{\n";
+    for (const auto& characteristic : key_characteristics) {
+        charsfile << "  " << characteristic.toString() << "\n";
+    }
+    charsfile << "}\n";
+    charsfile.close();
+
+    // Also write out a hexdump of the keyblob for convenience.
+    std::string hexname(subdir + "/" + name + ".hex");
+    std::ofstream hexfile(hexname, std::ios::out | std::ios::trunc);
+    hexfile << bin2hex(keyblob) << "\n";
+    hexfile.close();
+}
+
+void save_keyblob_and_cert(const std::string& subdir, const std::string& name,
+                           const vector<uint8_t>& keyblob,
+                           const std::vector<KeyCharacteristics>& key_characteristics,
+                           const std::vector<Certificate>& cert_chain) {
+    save_keyblob(subdir, name, keyblob, key_characteristics);
+
+    if (is_asymmetric(name)) {
+        // Dump the leaf certificate as DER.
+        if (cert_chain.empty()) {
+            FAIL() << "No cert available for " << name;
+        } else {
+            const vector<uint8_t>& certdata = cert_chain[0].encodedCertificate;
+            std::string certname(subdir + "/" + name + ".cert");
+            std::ofstream certfile(certname, std::ios::out | std::ios::trunc | std::ios::binary);
+            certfile.write(reinterpret_cast<const char*>(certdata.data()), certdata.size());
+            certfile.close();
+        }
+    }
+}
+
+void delete_keyblob(const std::string& subdir, const std::string& name) {
+    std::string blobname(subdir + "/" + name + ".keyblob");
+    unlink(blobname.c_str());
+    std::string charsname(subdir + "/" + name + ".chars");
+    unlink(charsname.c_str());
+    std::string hexname(subdir + "/" + name + ".hex");
+    unlink(hexname.c_str());
+    std::string certname(subdir + "/" + name + ".cert");
+    unlink(certname.c_str());
+}
+
+std::vector<uint8_t> load_file(const std::string& subdir, const std::string& name,
+                               const std::string& suffix) {
+    std::string blobname(subdir + "/" + name + suffix);
+    std::ifstream blobfile(blobname, std::ios::in | std::ios::binary);
+
+    std::vector<uint8_t> data((std::istreambuf_iterator<char>(blobfile)),
+                              std::istreambuf_iterator<char>());
+    return data;
+}
+
+std::vector<uint8_t> load_keyblob(const std::string& subdir, const std::string& name) {
+    return load_file(subdir, name, ".keyblob");
+}
+
+std::vector<uint8_t> load_cert(const std::string& subdir, const std::string& name) {
+    return load_file(subdir, name, ".cert");
+}
+
+}  // namespace
+
+class KeyBlobUpgradeTest : public KeyMintAidlTestBase {
+  protected:
+    void UpgradeKeyBlobs(bool expectUpgrade) {
+        std::string subdir = keyblob_subdir(keyblob_dir, GetParam(), /* create? */ false);
+        if (subdir.empty()) {
+            GTEST_SKIP() << "No keyblob directory provided";
+        }
+
+        for (std::string name : keyblob_names(SecLevel())) {
+            for (bool with_hidden : {false, true}) {
+                std::string app_id;
+                std::string app_data;
+                auto builder = AuthorizationSetBuilder();
+                if (with_hidden) {
+                    // Build a variant keyblob that requires app_id/app_data
+                    app_id = "appid";
+                    app_data = "appdata";
+                    builder.Authorization(TAG_APPLICATION_ID, "appid")
+                            .Authorization(TAG_APPLICATION_DATA, "appdata");
+                    name += "-hidden";
+                }
+                SCOPED_TRACE(testing::Message() << name);
+
+                // Load the old format keyblob.
+                std::vector<uint8_t> keyblob = load_keyblob(subdir, name);
+                if (keyblob.empty()) {
+                    if (requires_rr(name)) {
+                        std::cerr << "Skipping missing keyblob file '" << name
+                                  << "', assuming rollback resistance unavailable\n";
+                    } else {
+                        FAIL() << "Missing keyblob file '" << name << "'";
+                    }
+                    continue;
+                }
+
+                // An upgrade will either produce a new keyblob or no data (if upgrade isn't
+                // needed).
+                std::vector<uint8_t> upgraded_keyblob;
+                Status result =
+                        keymint_->upgradeKey(keyblob, builder.vector_data(), &upgraded_keyblob);
+                ASSERT_EQ(ErrorCode::OK, GetReturnErrorCode(result));
+
+                if (upgraded_keyblob.empty()) {
+                    std::cerr << "Keyblob '" << name << "' did not require upgrade\n";
+                    EXPECT_TRUE(!expectUpgrade) << "Keyblob '" << name << "' unexpectedly upgraded";
+                } else {
+                    // Ensure the old format keyblob is deleted (so any secure deletion data is
+                    // cleaned up).
+                    EXPECT_EQ(ErrorCode::OK, DeleteKey(&keyblob));
+
+                    std::vector<uint8_t> app_id_v(app_id.begin(), app_id.end());
+                    std::vector<uint8_t> app_data_v(app_data.begin(), app_data.end());
+                    std::vector<KeyCharacteristics> key_characteristics;
+                    result = keymint_->getKeyCharacteristics(upgraded_keyblob, app_id_v, app_data_v,
+                                                             &key_characteristics);
+                    ASSERT_EQ(ErrorCode::OK, GetReturnErrorCode(result))
+                            << "Failed getKeyCharacteristics() after upgrade";
+
+                    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";
+                }
+            }
+        }
+    }
+};
+
+// To save off keyblobs before upgrade, use:
+//
+//    VtsAidlKeyMintTargetTest --gtest_filter="*KeyBlobUpgradeTest.CreateKeyBlobs*" \
+//                             --keyblob_dir /data/local/tmp/keymint-blobs
+//
+// Then copy the contents of the /data/local/tmp/keymint-blobs/ directory somewhere safe:
+//
+//    adb pull /data/local/tmp/keymint-blobs/
+TEST_P(KeyBlobUpgradeTest, CreateKeyBlobsBefore) {
+    std::string subdir = keyblob_subdir(keyblob_dir, GetParam(), /* create? */ true);
+
+    std::map<const std::string, AuthorizationSetBuilder> keys_info = {
+            {"aes-key", AuthorizationSetBuilder()
+                                .AesEncryptionKey(256)
+                                .BlockMode(BlockMode::ECB)
+                                .Padding(PaddingMode::PKCS7)
+                                .Authorization(TAG_NO_AUTH_REQUIRED)},
+            {"aes-key-rr", AuthorizationSetBuilder()
+                                   .AesEncryptionKey(256)
+                                   .BlockMode(BlockMode::ECB)
+                                   .Padding(PaddingMode::PKCS7)
+                                   .Authorization(TAG_ROLLBACK_RESISTANCE)
+                                   .Authorization(TAG_NO_AUTH_REQUIRED)},
+            {"des-key", AuthorizationSetBuilder()
+                                .TripleDesEncryptionKey(168)
+                                .BlockMode(BlockMode::ECB)
+                                .Padding(PaddingMode::PKCS7)
+                                .Authorization(TAG_NO_AUTH_REQUIRED)},
+            {"hmac-key", AuthorizationSetBuilder()
+                                 .HmacKey(128)
+                                 .Digest(Digest::SHA1)
+                                 .Authorization(TAG_MIN_MAC_LENGTH, 128)
+                                 .Authorization(TAG_NO_AUTH_REQUIRED)},
+            {"rsa-key", AuthorizationSetBuilder()
+                                .RsaEncryptionKey(2048, 65537)
+                                .Authorization(TAG_PURPOSE, KeyPurpose::SIGN)
+                                .Digest(Digest::NONE)
+                                .Digest(Digest::SHA1)
+                                .Padding(PaddingMode::NONE)
+                                .Authorization(TAG_NO_AUTH_REQUIRED)
+                                .SetDefaultValidity()},
+            {
+                    "p256-key",
+                    AuthorizationSetBuilder()
+                            .EcdsaSigningKey(EcCurve::P_256)
+                            .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
+                            .Digest(Digest::NONE)
+                            .Digest(Digest::SHA1)
+                            .Authorization(TAG_NO_AUTH_REQUIRED)
+                            .SetDefaultValidity(),
+            },
+            {
+                    "ed25519-key",
+                    AuthorizationSetBuilder()
+                            .EcdsaSigningKey(EcCurve::CURVE_25519)
+                            .Digest(Digest::NONE)
+                            .Authorization(TAG_NO_AUTH_REQUIRED)
+                            .SetDefaultValidity(),
+            },
+            {"x25519-key", AuthorizationSetBuilder()
+                                   .Authorization(TAG_EC_CURVE, EcCurve::CURVE_25519)
+                                   .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
+                                   .Authorization(TAG_ALGORITHM, Algorithm::EC)
+                                   .Authorization(TAG_NO_AUTH_REQUIRED)
+                                   .SetDefaultValidity()},
+            {"rsa-attest-key", AuthorizationSetBuilder()
+                                       .RsaKey(2048, 65537)
+                                       .AttestKey()
+                                       .Authorization(TAG_NO_AUTH_REQUIRED)
+                                       .SetDefaultValidity()},
+            {
+                    "p256-attest-key",
+                    AuthorizationSetBuilder()
+                            .EcdsaKey(EcCurve::P_256)
+                            .AttestKey()
+                            .Authorization(TAG_NO_AUTH_REQUIRED)
+                            .SetDefaultValidity(),
+            },
+            {
+                    "ed25519-attest-key",
+                    AuthorizationSetBuilder()
+                            .EcdsaKey(EcCurve::CURVE_25519)
+                            .AttestKey()
+                            .Authorization(TAG_NO_AUTH_REQUIRED)
+                            .SetDefaultValidity(),
+            }};
+
+    for (std::string name : keyblob_names(SecLevel())) {
+        auto entry = keys_info.find(name);
+        ASSERT_NE(entry, keys_info.end()) << "no builder for " << name;
+        auto builder = entry->second;
+        for (bool with_hidden : {false, true}) {
+            if (with_hidden) {
+                // Build a variant keyblob that requires app_id/app_data
+                builder.Authorization(TAG_APPLICATION_ID, "appid")
+                        .Authorization(TAG_APPLICATION_DATA, "appdata");
+                name += "-hidden";
+            }
+            SCOPED_TRACE(testing::Message() << name);
+
+            vector<uint8_t> keyblob;
+            vector<KeyCharacteristics> key_characteristics;
+            vector<Certificate> cert_chain;
+            auto result =
+                    GenerateKey(builder, std::nullopt, &keyblob, &key_characteristics, &cert_chain);
+
+            if (requires_rr(name) && result == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE) {
+                // Rollback resistance support is optional.
+                std::cerr << "Skipping '" << name << "' key as rollback resistance unavailable\n";
+                continue;
+            }
+            ASSERT_EQ(ErrorCode::OK, result) << " failed for " << name;
+
+            if (!subdir.empty()) {
+                save_keyblob_and_cert(subdir, name, keyblob, key_characteristics, cert_chain);
+            }
+        }
+    }
+
+    if (!subdir.empty()) {
+        std::cerr << "Save generated keyblobs with:\n\n    adb pull " << keyblob_dir << "\n\n";
+    }
+}
+
+TEST_P(KeyBlobUpgradeTest, UpgradeKeyBlobsBefore) {
+    // Check that attempting to upgrade valid keyblobs does nothing.
+    UpgradeKeyBlobs(/* expectUpgrade= */ false);
+}
+
+// To run this test:
+//
+// - save off some keyblobs before upgrade as per the CreateKeyBlobs test above.
+// - upgrade the device to a version that should trigger keyblob upgrade (e.g. different patchlevel)
+// - put the saved keyblobs back onto the upgraded device:
+//
+//     adb push keymint-blobs /data/local/tmp/keymint-blobs
+//
+// - run the test with:
+//
+//     VtsAidlKeyMintTargetTest --gtest_filter="*KeyBlobUpgradeTest.UpgradeKeyBlobsAfter*" \
+//                              --keyblob_dir /data/local/tmp/keymint-blobs
+//
+// - this replaces the keyblob contents in that directory; if needed, save the upgraded keyblobs
+//   with:
+//      adb pull /data/local/tmp/keymint-blobs/
+TEST_P(KeyBlobUpgradeTest, UpgradeKeyBlobsAfter) {
+    UpgradeKeyBlobs(/* expectUpgrade= */ true);
+}
+
+// To run this test:
+//
+// - save off some keyblobs before upgrade as per the CreateKeyBlobs test above
+// - if needed, upgrade the saved keyblobs as per the UpgradeKeyBlobs test above
+// - run the test with:
+//
+//     VtsAidlKeyMintTargetTest --gtest_filter="*KeyBlobUpgradeTest.UseKeyBlobs*" \
+//                              --keyblob_dir /data/local/tmp/keymint-blobs
+TEST_P(KeyBlobUpgradeTest, UseKeyBlobsBeforeOrAfter) {
+    std::string subdir = keyblob_subdir(keyblob_dir, GetParam(), /* create? */ false);
+    if (subdir.empty()) {
+        GTEST_SKIP() << "No keyblob directory provided with (e.g.) --keyblob_dir "
+                        "/data/local/tmp/keymint-blobs";
+    }
+
+    for (std::string name : keyblob_names(SecLevel())) {
+        for (bool with_hidden : {false, true}) {
+            auto builder = AuthorizationSetBuilder();
+            if (with_hidden) {
+                // Build a variant keyblob that requires app_id/app_data
+                builder.Authorization(TAG_APPLICATION_ID, "appid")
+                        .Authorization(TAG_APPLICATION_DATA, "appdata");
+                name += "-hidden";
+            }
+            SCOPED_TRACE(testing::Message() << name);
+            std::vector<uint8_t> keyblob = load_keyblob(subdir, name);
+            if (keyblob.empty()) {
+                if (requires_rr(name)) {
+                    std::cerr << "Skipping missing keyblob file '" << name
+                              << "', assuming rollback resistance unavailable\n";
+                } else {
+                    FAIL() << "Missing keyblob file '" << name << "'";
+                }
+                continue;
+            }
+
+            std::vector<uint8_t> cert;
+            if (is_asymmetric(name)) {
+                cert = load_cert(subdir, name);
+            }
+
+            // Perform an algorithm-specific operation with the keyblob.
+            string message = "Hello World!";
+            AuthorizationSet out_params;
+            if (name.find("aes-key") != std::string::npos) {
+                builder.BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+                string ciphertext = EncryptMessage(keyblob, message, builder, &out_params);
+                string plaintext = DecryptMessage(keyblob, ciphertext, builder);
+                EXPECT_EQ(message, plaintext);
+            } else if (name.find("des-key") != std::string::npos) {
+                builder.BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+                string ciphertext = EncryptMessage(keyblob, message, builder, &out_params);
+                string plaintext = DecryptMessage(keyblob, ciphertext, builder);
+                EXPECT_EQ(message, plaintext);
+            } else if (name.find("hmac-key") != std::string::npos) {
+                builder.Digest(Digest::SHA1);
+                auto sign_builder = builder;
+                sign_builder.Authorization(TAG_MAC_LENGTH, 128);
+                string tag = SignMessage(keyblob, message, sign_builder);
+                VerifyMessage(keyblob, message, tag, builder);
+            } else if (name.find("rsa-key") != std::string::npos) {
+                builder.Digest(Digest::NONE).Padding(PaddingMode::NONE);
+                string signature = SignMessage(keyblob, message, builder);
+                LocalVerifyMessage(cert, message, signature, builder);
+            } else if (name.find("p256-key") != std::string::npos) {
+                builder.Digest(Digest::SHA1);
+                string signature = SignMessage(keyblob, message, builder);
+                LocalVerifyMessage(cert, message, signature, builder);
+            } else if (name.find("ed25519-key") != std::string::npos) {
+                builder.Digest(Digest::NONE);
+                string signature = SignMessage(keyblob, message, builder);
+                LocalVerifyMessage(cert, message, signature, builder);
+            } else if (name.find("x25519-key") != std::string::npos) {
+                // Generate EC key on same curve locally (with access to private key material).
+                uint8_t localPrivKeyData[32];
+                uint8_t localPubKeyData[32];
+                X25519_keypair(localPubKeyData, localPrivKeyData);
+                EVP_PKEY_Ptr localPrivKey(EVP_PKEY_new_raw_private_key(
+                        EVP_PKEY_X25519, nullptr, localPrivKeyData, sizeof(localPrivKeyData)));
+                // Get encoded form of the public part of the locally generated key.
+                unsigned char* p = nullptr;
+                int localPublicKeySize = i2d_PUBKEY(localPrivKey.get(), &p);
+                ASSERT_GT(localPublicKeySize, 0);
+                vector<uint8_t> localPublicKey(
+                        reinterpret_cast<const uint8_t*>(p),
+                        reinterpret_cast<const uint8_t*>(p + localPublicKeySize));
+                OPENSSL_free(p);
+
+                // Agree on a key between local and KeyMint.
+                string data;
+                ASSERT_EQ(ErrorCode::OK,
+                          Begin(KeyPurpose::AGREE_KEY, keyblob, builder, &out_params));
+                ASSERT_EQ(ErrorCode::OK,
+                          Finish(string(localPublicKey.begin(), localPublicKey.end()), &data));
+                vector<uint8_t> keymint_data(data.begin(), data.end());
+
+                // Extract the public key for the KeyMint key from the cert.
+                X509_Ptr kmKeyCert(parse_cert_blob(cert));
+                ASSERT_NE(kmKeyCert, nullptr);
+                EVP_PKEY_Ptr kmPubKey = EVP_PKEY_Ptr(X509_get_pubkey(kmKeyCert.get()));
+                ASSERT_NE(kmPubKey.get(), nullptr);
+
+                size_t kmPubKeySize = 32;
+                uint8_t kmPubKeyData[32];
+                ASSERT_EQ(1,
+                          EVP_PKEY_get_raw_public_key(kmPubKey.get(), kmPubKeyData, &kmPubKeySize));
+                ASSERT_EQ(kmPubKeySize, 32);
+
+                // Agree on a key between KeyMint and local.
+                uint8_t sharedKey[32];
+                ASSERT_EQ(1, X25519(sharedKey, localPrivKeyData, kmPubKeyData));
+                vector<uint8_t> local_data(sharedKey, sharedKey + 32);
+
+                // Both ways round should agree.
+                EXPECT_EQ(keymint_data, local_data);
+            } else if (name.find("-attest-key") != std::string::npos) {
+                // Covers rsa-attest-key, p256-attest-key, ed25519-attest-key.
+
+                // Use attestation key to sign RSA signing key
+                AttestationKey attest_key;
+                attest_key.keyBlob = keyblob;
+                attest_key.attestKeyParams = builder.vector_data();
+                attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
+                vector<uint8_t> attested_key_blob;
+                vector<KeyCharacteristics> attested_key_characteristics;
+                vector<Certificate> attested_key_cert_chain;
+                EXPECT_EQ(ErrorCode::OK,
+                          GenerateKey(AuthorizationSetBuilder()
+                                              .RsaSigningKey(2048, 65537)
+                                              .Authorization(TAG_NO_AUTH_REQUIRED)
+                                              .AttestationChallenge("challenge")
+                                              .AttestationApplicationId("app-id")
+                                              .SetDefaultValidity(),
+                                      attest_key, &attested_key_blob, &attested_key_characteristics,
+                                      &attested_key_cert_chain));
+                CheckedDeleteKey(&attested_key_blob);
+            } else {
+                FAIL() << "Unexpected name: " << name;
+            }
+        }
+    }
+}
+
+// This test target deletes any keys from the keyblob subdirectory that have rollback resistance
+// enabled.
+TEST_P(KeyBlobUpgradeTest, DeleteRRKeyBlobsAfter) {
+    std::string subdir = keyblob_subdir(keyblob_dir, GetParam(), /* create? */ false);
+    if (subdir.empty()) {
+        GTEST_SKIP() << "No keyblob directory provided with (e.g.) --keyblob_dir "
+                        "/data/local/tmp/keymint-blobs";
+    }
+
+    for (std::string name : keyblob_names(SecLevel())) {
+        for (bool with_hidden : {false, true}) {
+            auto builder = AuthorizationSetBuilder();
+            if (with_hidden) {
+                // Build a variant keyblob that requires app_id/app_data
+                builder.Authorization(TAG_APPLICATION_ID, "appid")
+                        .Authorization(TAG_APPLICATION_DATA, "appdata");
+                name += "-hidden";
+            }
+            if (!requires_rr(name)) {
+                std::cerr << "Skipping keyblob file '" << name
+                          << "' which does not use rollback resistance\n";
+                continue;
+            }
+            SCOPED_TRACE(testing::Message() << name);
+            std::vector<uint8_t> keyblob = load_keyblob(subdir, name);
+            if (keyblob.empty()) {
+                std::cerr << "Skipping missing keyblob file '" << name
+                          << "', assuming rollback resistance unavailable\n";
+                continue;
+            }
+
+            // Delete the key
+            ASSERT_EQ(ErrorCode::OK, DeleteKey(&keyblob));
+
+            // Remove all files relating to the deleted key.
+            std::cerr << "Deleting files for deleted key '" << name << ";";
+            delete_keyblob(subdir, name);
+
+            // Attempting to use the keyblob after deletion should fail.
+            AuthorizationSet out_params;
+            if (name.find("aes-key") != std::string::npos) {
+                builder.BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+                EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+                          Begin(KeyPurpose::ENCRYPT, keyblob, builder, &out_params));
+            } else {
+                FAIL() << "Unexpected name: " << name;
+            }
+        }
+    }
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(KeyBlobUpgradeTest);
+
+}  // namespace aidl::android::hardware::security::keymint::test
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 43ad30a..6c012fa 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -184,6 +184,7 @@
 
 bool KeyMintAidlTestBase::arm_deleteAllKeys = false;
 bool KeyMintAidlTestBase::dump_Attestations = false;
+std::string KeyMintAidlTestBase::keyblob_dir;
 
 uint32_t KeyMintAidlTestBase::boot_patch_level(
         const vector<KeyCharacteristics>& key_characteristics) {
@@ -946,9 +947,15 @@
                                              const AuthorizationSet& params) {
     SCOPED_TRACE("LocalVerifyMessage");
 
-    // Retrieve the public key from the leaf certificate.
     ASSERT_GT(cert_chain_.size(), 0);
-    X509_Ptr key_cert(parse_cert_blob(cert_chain_[0].encodedCertificate));
+    LocalVerifyMessage(cert_chain_[0].encodedCertificate, message, signature, params);
+}
+
+void KeyMintAidlTestBase::LocalVerifyMessage(const vector<uint8_t>& der_cert, const string& message,
+                                             const string& signature,
+                                             const AuthorizationSet& params) {
+    // Retrieve the public key from the leaf certificate.
+    X509_Ptr key_cert(parse_cert_blob(der_cert));
     ASSERT_TRUE(key_cert.get());
     EVP_PKEY_Ptr pub_key(X509_get_pubkey(key_cert.get()));
     ASSERT_TRUE(pub_key.get());
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index 5b09ca5..908eeab 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -64,6 +64,10 @@
     static bool arm_deleteAllKeys;
     static bool dump_Attestations;
 
+    // Directory to store/retrieve keyblobs, using subdirectories named for the
+    // KeyMint instance in question (e.g. "./default/", "./strongbox/").
+    static std::string keyblob_dir;
+
     void SetUp() override;
     void TearDown() override {
         if (key_blob_.size()) {
@@ -206,6 +210,8 @@
                        const string& signature, const AuthorizationSet& params);
     void VerifyMessage(const string& message, const string& signature,
                        const AuthorizationSet& params);
+    void LocalVerifyMessage(const vector<uint8_t>& der_cert, const string& message,
+                            const string& signature, const AuthorizationSet& params);
     void LocalVerifyMessage(const string& message, const string& signature,
                             const AuthorizationSet& params);
 
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 5a86283..2440977 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -1136,8 +1136,8 @@
  * that has been generated using an associate IRemotelyProvisionedComponent.
  */
 TEST_P(NewKeyGenerationTest, RsaWithRkpAttestation) {
-    if (AidlVersion() < 2) {
-        GTEST_SKIP() << "Only required starting with KeyMint v2";
+    if (get_vsr_api_level() < 32 || AidlVersion() < 2) {
+        GTEST_SKIP() << "Only required for VSR 12+ and KeyMint 2+";
     }
 
     // There should be an IRemotelyProvisionedComponent instance associated with the KeyMint
@@ -1214,8 +1214,8 @@
  * that has been generated using an associate IRemotelyProvisionedComponent.
  */
 TEST_P(NewKeyGenerationTest, EcdsaWithRkpAttestation) {
-    if (AidlVersion() < 2) {
-        GTEST_SKIP() << "Only required starting with KeyMint v2";
+    if (get_vsr_api_level() < 32 || AidlVersion() < 2) {
+        GTEST_SKIP() << "Only required for VSR 12+ and KeyMint 2+";
     }
 
     // There should be an IRemotelyProvisionedComponent instance associated with the KeyMint
@@ -8609,6 +8609,14 @@
     EXPECT_GE(AidlVersion(), 2) << "VSR 13+ requires KeyMint version 2";
 }
 
+TEST_P(VsrRequirementTest, Vsr14Test) {
+    int vsr_api_level = get_vsr_api_level();
+    if (vsr_api_level < 34) {
+        GTEST_SKIP() << "Applies only to VSR API level 34, this device is: " << vsr_api_level;
+    }
+    EXPECT_GE(AidlVersion(), 3) << "VSR 14+ requires KeyMint version 3";
+}
+
 INSTANTIATE_KEYMINT_AIDL_TEST(VsrRequirementTest);
 
 }  // namespace aidl::android::hardware::security::keymint::test
@@ -8641,6 +8649,15 @@
                 // interactions.
                 aidl::android::hardware::security::keymint::test::check_boot_pl = false;
             }
+            if (std::string(argv[i]) == "--keyblob_dir") {
+                if (i + 1 >= argc) {
+                    std::cerr << "Missing argument for --keyblob_dir\n";
+                    return 1;
+                }
+                aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase::keyblob_dir =
+                        std::string(argv[i + 1]);
+                ++i;
+            }
         }
     }
     return RUN_ALL_TESTS();
diff --git a/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
index 5485db3..c506667 100644
--- a/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
+++ b/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
@@ -115,11 +115,9 @@
 interface IRemotelyProvisionedComponent {
     const int STATUS_FAILED = 1;
     const int STATUS_INVALID_MAC = 2;
-    // --------- START: Versions 1 and 2 Only ----------
-    const int STATUS_PRODUCTION_KEY_IN_TEST_REQUEST = 3;
+    const int STATUS_PRODUCTION_KEY_IN_TEST_REQUEST = 3; // Versions 1 and 2 Only
     const int STATUS_TEST_KEY_IN_PRODUCTION_REQUEST = 4;
-    const int STATUS_INVALID_EEK = 5;
-    // --------- END: Versions 1 and 2 Only ------------
+    const int STATUS_INVALID_EEK = 5; // Versions 1 and 2 Only
     const int STATUS_REMOVED = 6;
 
     /**
@@ -347,8 +345,8 @@
      *     protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
      *     unprotected: {},
      *     payload: bstr .cbor Data / nil,
-     *     signature: bstr      ; PureEd25519(CDI_Leaf_Priv, bstr .cbor SignedDataSigStruct<Data>) /
-     *                          ; ECDSA(CDI_Leaf_Priv, bstr .cbor SignedDataSigStruct<Data>)
+     *     signature: bstr      ; PureEd25519(CDI_Leaf_Priv, SignedDataSigStruct<Data>) /
+     *                          ; ECDSA(CDI_Leaf_Priv, SignedDataSigStruct<Data>)
      * ]
      *
      * ; Sig_structure for SignedData
@@ -427,8 +425,8 @@
      *     protected : bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
      *     unprotected: {},
      *     payload: bstr .cbor DiceChainEntryPayload,
-     *     signature: bstr ; PureEd25519(SigningKey, bstr .cbor DiceChainEntryInput) /
-     *                     ; ECDSA(SigningKey, bstr .cbor DiceChainEntryInput)
+     *     signature: bstr ; PureEd25519(SigningKey, DiceChainEntryInput) /
+     *                     ; ECDSA(SigningKey, DiceChainEntryInput)
      *                     ; See RFC 8032 for details of how to encode the signature value
      *                     ; for Ed25519.
      * ]
@@ -442,12 +440,6 @@
      *
      * ; The following section defines some types that are reused throughout the above
      * ; data structures.
-     * PubKeyX25519 = {                 ; COSE_Key
-     *      1 : 1,                      ; Key type : Octet Key Pair
-     *     -1 : 4,                      ; Curve : X25519
-     *     -2 : bstr                    ; Sender X25519 public key
-     * }
-     *
      * PubKeyEd25519 = {                ; COSE_Key
      *     1 : 1,                       ; Key type : octet key pair
      *     3 : AlgorithmEdDSA,          ; Algorithm : EdDSA
@@ -455,13 +447,6 @@
      *     -2 : bstr                    ; X coordinate, little-endian
      * }
      *
-     * PubKeyEcdhP256 = {               ; COSE_Key
-     *      1 : 2,                      ; Key type : EC2
-     *      -1 : 1,                     ; Curve : P256
-     *      -2 : bstr                   ; Sender X coordinate
-     *      -3 : bstr                   ; Sender Y coordinate
-     * }
-     *
      * PubKeyECDSA256 = {               ; COSE_Key
      *     1 : 2,                       ; Key type : EC2
      *     3 : AlgorithmES256,          ; Algorithm : ECDSA w/ SHA-256
diff --git a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index cb1c692..aebcf67 100644
--- a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -783,4 +783,20 @@
 
 INSTANTIATE_REM_PROV_AIDL_TEST(CertificateRequestV2Test);
 
+using VsrRequirementTest = VtsRemotelyProvisionedComponentTests;
+
+INSTANTIATE_REM_PROV_AIDL_TEST(VsrRequirementTest);
+
+TEST_P(VsrRequirementTest, VsrEnforcementTest) {
+    RpcHardwareInfo hwInfo;
+    ASSERT_TRUE(provisionable_->getHardwareInfo(&hwInfo).isOk());
+    int vsr_api_level = get_vsr_api_level();
+    if (vsr_api_level < 34) {
+        GTEST_SKIP() << "Applies only to VSR API level 34 or newer, this device is: "
+                     << vsr_api_level;
+    }
+    EXPECT_GE(hwInfo.versionNumber, 3)
+            << "VSR 14+ requires IRemotelyProvisionedComponent v3 or newer.";
+}
+
 }  // namespace aidl::android::hardware::security::keymint::test
diff --git a/sensors/1.0/default/OWNERS b/sensors/1.0/default/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/sensors/1.0/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/sensors/1.0/vts/functional/OWNERS b/sensors/1.0/vts/functional/OWNERS
deleted file mode 100644
index e20125b..0000000
--- a/sensors/1.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 62965
-include ../../../common/vts/OWNERS
diff --git a/sensors/2.0/default/OWNERS b/sensors/2.0/default/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/sensors/2.0/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/sensors/2.0/multihal/OWNERS b/sensors/2.0/multihal/OWNERS
deleted file mode 100644
index e955670..0000000
--- a/sensors/2.0/multihal/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
\ No newline at end of file
diff --git a/sensors/2.0/vts/functional/OWNERS b/sensors/2.0/vts/functional/OWNERS
deleted file mode 100644
index e20125b..0000000
--- a/sensors/2.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 62965
-include ../../../common/vts/OWNERS
diff --git a/sensors/2.1/default/OWNERS b/sensors/2.1/default/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/sensors/2.1/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/sensors/2.1/multihal/OWNERS b/sensors/2.1/multihal/OWNERS
deleted file mode 100644
index e955670..0000000
--- a/sensors/2.1/multihal/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
\ No newline at end of file
diff --git a/sensors/2.1/vts/functional/OWNERS b/sensors/2.1/vts/functional/OWNERS
deleted file mode 100644
index e20125b..0000000
--- a/sensors/2.1/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 62965
-include ../../../common/vts/OWNERS
diff --git a/sensors/common/vts/OWNERS b/sensors/OWNERS
similarity index 83%
rename from sensors/common/vts/OWNERS
rename to sensors/OWNERS
index 1b9a2f8..e7ebd3e 100644
--- a/sensors/common/vts/OWNERS
+++ b/sensors/OWNERS
@@ -1,5 +1,5 @@
 # Bug component: 62965
-# Sensors team
+
 arthuri@google.com
 bduddie@google.com
 stange@google.com
diff --git a/sensors/aidl/default/OWNERS b/sensors/aidl/default/OWNERS
deleted file mode 100644
index e955670..0000000
--- a/sensors/aidl/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
\ No newline at end of file
diff --git a/sensors/aidl/multihal/OWNERS b/sensors/aidl/multihal/OWNERS
deleted file mode 100644
index e955670..0000000
--- a/sensors/aidl/multihal/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
\ No newline at end of file
diff --git a/sensors/aidl/vts/OWNERS b/sensors/aidl/vts/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/sensors/aidl/vts/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/sensors/common/default/2.X/OWNERS b/sensors/common/default/2.X/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/sensors/common/default/2.X/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/sensors/common/utils/OWNERS b/sensors/common/utils/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/sensors/common/utils/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/sensors/common/vts/utils/OWNERS b/sensors/common/vts/utils/OWNERS
deleted file mode 100644
index 892da15..0000000
--- a/sensors/common/vts/utils/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-# Sensors team
-arthuri@google.com
-bduddie@google.com
-stange@google.com
-
-# VTS team
-trong@google.com
-yim@google.com
diff --git a/tv/earc/aidl/Android.bp b/tv/earc/aidl/Android.bp
new file mode 100644
index 0000000..5db6032
--- /dev/null
+++ b/tv/earc/aidl/Android.bp
@@ -0,0 +1,29 @@
+// 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.
+
+package {
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.tv.earc",
+    vendor_available: true,
+    srcs: ["android/hardware/tv/earc/*.aidl"],
+    stability: "vintf",
+    backend: {
+        java: {
+            sdk_version: "module_current",
+        },
+    },
+}
diff --git a/tv/earc/aidl/OWNERS b/tv/earc/aidl/OWNERS
new file mode 100644
index 0000000..d9c6783
--- /dev/null
+++ b/tv/earc/aidl/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 826094
+include platform/frameworks/base:/core/java/android/hardware/hdmi/OWNERS
\ No newline at end of file
diff --git a/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArc.aidl b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArc.aidl
new file mode 100644
index 0000000..552bb46
--- /dev/null
+++ b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArc.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.tv.earc;
+@VintfStability
+interface IEArc {
+  void setEArcEnabled(in boolean enabled);
+  boolean isEArcEnabled();
+  void setCallback(in android.hardware.tv.earc.IEArcCallback callback);
+  android.hardware.tv.earc.IEArcStatus getState(in int portId);
+  byte[] getLastReportedAudioCapabilities(in int portId);
+}
diff --git a/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArcCallback.aidl b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArcCallback.aidl
new file mode 100644
index 0000000..ef99824
--- /dev/null
+++ b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArcCallback.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.tv.earc;
+@VintfStability
+interface IEArcCallback {
+  oneway void onStateChange(in android.hardware.tv.earc.IEArcStatus status, in int portId);
+  oneway void onCapabilitiesReported(in byte[] rawCapabilities, in int portId);
+}
diff --git a/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArcStatus.aidl b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArcStatus.aidl
new file mode 100644
index 0000000..729c657
--- /dev/null
+++ b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArcStatus.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.tv.earc;
+@Backing(type="byte") @VintfStability
+enum IEArcStatus {
+  STATUS_IDLE = 0,
+  STATUS_EARC_PENDING = 1,
+  STATUS_ARC_PENDING = 2,
+  STATUS_EARC_CONNECTED = 3,
+}
diff --git a/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/Result.aidl b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/Result.aidl
new file mode 100644
index 0000000..3679d3b
--- /dev/null
+++ b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/Result.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.tv.earc;
+@VintfStability
+enum Result {
+  SUCCESS = 0,
+  FAILURE_UNKNOWN = 1,
+  FAILURE_INVALID_ARGS = 2,
+  FAILURE_NOT_SUPPORTED = 4,
+}
diff --git a/tv/earc/aidl/android/hardware/tv/earc/IEArc.aidl b/tv/earc/aidl/android/hardware/tv/earc/IEArc.aidl
new file mode 100644
index 0000000..bb8dabf
--- /dev/null
+++ b/tv/earc/aidl/android/hardware/tv/earc/IEArc.aidl
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+package android.hardware.tv.earc;
+
+import android.hardware.tv.earc.IEArcCallback;
+import android.hardware.tv.earc.IEArcStatus;
+
+/**
+ * eARC HAL interface definition
+ */
+@VintfStability
+interface IEArc {
+    /**
+     * Function to enable or disable eARC in the device's driver and HAL. If enabled, the driver and
+     * HAL shall attempt to establish an eARC connection and inform the Android framework about
+     * updates with IEArcCallback callbacks. If disabled, the driver and HAL shall not attempt to
+     * establish an eARC connection and shall not send any IEArcCallback callbacks to the Android
+     * framework.
+     * The error status is set to
+     *         {@code SUCCESS} if the setting could be changed to the value passed.
+     *         {@code FAILURE_NOT_SUPPORTED} if the setting is not supported.
+     *         {@code FAILURE_INVALID_ARGS} if the setting value is invalid.
+     *         {@code FAILURE_UNKNOWN} if there was an unknown failure.
+     */
+    void setEArcEnabled(in boolean enabled);
+
+    /**
+     * Function to check if eARC is enabled in the device's driver and HAL.
+     */
+    boolean isEArcEnabled();
+
+    /**
+     * Function to set callback that the HAL will use to notify the system of connection state
+     * changes and capabilities of connected devices.
+     *
+     * @param callback The callback object to pass the events to the system. A previously registered
+     *        callback should be replaced by this new object. If callback is {@code null} the
+     *        previously registered callback should be deregistered.
+     */
+    void setCallback(in IEArcCallback callback);
+
+    /**
+     * Getter for the current eARC state of a port.
+     *
+     * @param portId The port ID for which the state is to be reported.
+     * @return The state of the port.
+     */
+    IEArcStatus getState(in int portId);
+
+    /**
+     * Getter for the most recent capabilities reported by the device connected to port.
+     *
+     * @param portId The port ID on which the device is connected.
+     * @return The raw, unparsed audio capabilities
+     */
+    byte[] getLastReportedAudioCapabilities(in int portId);
+}
diff --git a/tv/earc/aidl/android/hardware/tv/earc/IEArcCallback.aidl b/tv/earc/aidl/android/hardware/tv/earc/IEArcCallback.aidl
new file mode 100644
index 0000000..c70191f
--- /dev/null
+++ b/tv/earc/aidl/android/hardware/tv/earc/IEArcCallback.aidl
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+package android.hardware.tv.earc;
+
+import android.hardware.tv.earc.IEArcStatus;
+
+/**
+ * eARC HAL callback methods
+ */
+@VintfStability
+oneway interface IEArcCallback {
+    /**
+     * The callback function that must be called by the eARC driver and HAL implementation to notify
+     * the Android framework of an eARC status change.
+     * @param status The new status of the port
+     * @param portId The port ID for which the state change is being reported
+     */
+    void onStateChange(in IEArcStatus status, in int portId);
+
+    /**
+     * The callback function that must be called by the eARC driver and HAL implementation to
+     * notify the Android framework of the audio capabilities reported by the connected device. On
+     * every state change to {@code STATUS_EARC_CONNECTED}, the driver shall read the capabilities
+     * reported by the eARC RX. The onStateChange callback shall always be invoked first and the
+     * onCapabilitiesReported callback shall be invoked second.
+     * @param rawCapabilities The raw unparsed audio capabilities (Ref "Section 9.5.3.6 - eARC RX
+     *         Capabilities Data Structure" in HDMI 2.1 specification).
+     * @param portId The port ID for which the audio capabilities are being reported
+     */
+    void onCapabilitiesReported(in byte[] rawCapabilities, in int portId);
+}
diff --git a/tv/earc/aidl/android/hardware/tv/earc/IEArcStatus.aidl b/tv/earc/aidl/android/hardware/tv/earc/IEArcStatus.aidl
new file mode 100644
index 0000000..ecb1c85
--- /dev/null
+++ b/tv/earc/aidl/android/hardware/tv/earc/IEArcStatus.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+package android.hardware.tv.earc;
+
+/**
+ * eARC HAL connection states
+ */
+@VintfStability
+@Backing(type="byte")
+enum IEArcStatus {
+    STATUS_IDLE = 0,
+    STATUS_EARC_PENDING = 1,
+    STATUS_ARC_PENDING = 2,
+    STATUS_EARC_CONNECTED = 3,
+}
diff --git a/tv/earc/aidl/android/hardware/tv/earc/Result.aidl b/tv/earc/aidl/android/hardware/tv/earc/Result.aidl
new file mode 100644
index 0000000..054518a
--- /dev/null
+++ b/tv/earc/aidl/android/hardware/tv/earc/Result.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+package android.hardware.tv.earc;
+
+/**
+ * Result enum for return values. Used by the HDMI related AIDL.
+ */
+@VintfStability
+enum Result {
+    /**
+     * The eARC enabled setting was set successfully.
+     */
+    SUCCESS = 0,
+
+    /**
+     * The eARC enabled setting could not be set because of an unknown failure.
+     */
+    FAILURE_UNKNOWN = 1,
+
+    /**
+     * The eARC enabled setting could not be set because the arguments were invalid.
+     */
+    FAILURE_INVALID_ARGS = 2,
+
+    /**
+     * The eARC enabled setting could not be set because eARC feature is not supported.
+     */
+    FAILURE_NOT_SUPPORTED = 4,
+}
diff --git a/tv/earc/aidl/default/Android.bp b/tv/earc/aidl/default/Android.bp
new file mode 100644
index 0000000..399f029
--- /dev/null
+++ b/tv/earc/aidl/default/Android.bp
@@ -0,0 +1,58 @@
+// 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.
+
+package {
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_binary {
+    name: "android.hardware.tv.earc-service",
+    vintf_fragments: ["android.hardware.tv.earc-service.xml"],
+    relative_install_path: "hw",
+    vendor: true,
+    cflags: [
+        "-Wall",
+        "-Wextra",
+    ],
+    init_rc: ["android.hardware.tv.earc-service.rc"],
+    srcs: [
+        "serviceMock.cpp",
+        "EArcMock.cpp",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "liblog",
+        "libbase",
+        "libutils",
+        "libhardware",
+        "libhidlbase",
+        "android.hardware.tv.earc-V1-ndk",
+    ],
+}
+
+cc_fuzz {
+    name: "android.hardware.tv.earc-service_fuzzer",
+    defaults: ["service_fuzzer_defaults"],
+    static_libs: [
+        "android.hardware.tv.earc-V1-ndk",
+        "liblog",
+    ],
+    srcs: [
+        "fuzzer.cpp",
+        "EArcMock.cpp",
+    ],
+    fuzz_config: {
+        componentid: 826094,
+    },
+}
diff --git a/tv/earc/aidl/default/EArcMock.cpp b/tv/earc/aidl/default/EArcMock.cpp
new file mode 100644
index 0000000..9bccc18
--- /dev/null
+++ b/tv/earc/aidl/default/EArcMock.cpp
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "android.hardware.tv.earc"
+#include <android-base/logging.h>
+#include <fcntl.h>
+#include <utils/Log.h>
+
+#include "EArcMock.h"
+
+using ndk::ScopedAStatus;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace earc {
+namespace implementation {
+
+void EArcMock::serviceDied(void* cookie) {
+    ALOGE("EArcMock died");
+    auto eArc = static_cast<EArcMock*>(cookie);
+    eArc->mEArcEnabled = false;
+}
+
+ScopedAStatus EArcMock::setEArcEnabled(bool in_enabled) {
+    mEArcEnabled = in_enabled;
+    if (mEArcEnabled != in_enabled) {
+        return ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::FAILURE_UNKNOWN));
+    } else {
+        return ScopedAStatus::ok();
+    }
+}
+
+ScopedAStatus EArcMock::isEArcEnabled(bool* _aidl_return) {
+    *_aidl_return = mEArcEnabled;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus EArcMock::getState(int32_t portId, IEArcStatus* _aidl_return) {
+    // Maintain port connection status and update on hotplug event
+    if (portId <= mTotalPorts && portId >= 1) {
+        *_aidl_return = mPortStatus[portId];
+    } else {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus EArcMock::getLastReportedAudioCapabilities(int32_t portId,
+                                                         std::vector<uint8_t>* _aidl_return) {
+    if (portId <= mTotalPorts && portId >= 1) {
+        *_aidl_return = mCapabilities[portId];
+    } else {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus EArcMock::setCallback(const std::shared_ptr<IEArcCallback>& callback) {
+    if (mCallback != nullptr) {
+        mCallback = nullptr;
+    }
+
+    if (callback != nullptr) {
+        mCallback = callback;
+        AIBinder_linkToDeath(this->asBinder().get(), mDeathRecipient.get(), 0 /* cookie */);
+    }
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus EArcMock::reportCapabilities(const std::vector<uint8_t> capabilities,
+                                           int32_t portId) {
+    if (mCallback != nullptr) {
+        mCallback->onCapabilitiesReported(capabilities, portId);
+        return ScopedAStatus::ok();
+    } else {
+        return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
+    }
+}
+
+ScopedAStatus EArcMock::changeState(const IEArcStatus status, int32_t portId) {
+    if (mCallback != nullptr) {
+        mCallback->onStateChange(status, portId);
+        return ScopedAStatus::ok();
+    } else {
+        return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
+    }
+}
+
+EArcMock::EArcMock() {
+    ALOGE("[halimp_aidl] Opening a virtual eARC HAL for testing and virtual machine.");
+    mCallback = nullptr;
+    mCapabilities.resize(mTotalPorts);
+    mPortStatus.resize(mTotalPorts);
+    mPortStatus[0] = IEArcStatus::STATUS_IDLE;
+    mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(serviceDied));
+}
+
+}  // namespace implementation
+}  // namespace earc
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
diff --git a/tv/earc/aidl/default/EArcMock.h b/tv/earc/aidl/default/EArcMock.h
new file mode 100644
index 0000000..9081950
--- /dev/null
+++ b/tv/earc/aidl/default/EArcMock.h
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+#include <aidl/android/hardware/tv/earc/BnEArc.h>
+#include <aidl/android/hardware/tv/earc/Result.h>
+#include <algorithm>
+#include <vector>
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace earc {
+namespace implementation {
+
+using ::aidl::android::hardware::tv::earc::BnEArc;
+using ::aidl::android::hardware::tv::earc::IEArc;
+using ::aidl::android::hardware::tv::earc::IEArcCallback;
+using ::aidl::android::hardware::tv::earc::IEArcStatus;
+using ::aidl::android::hardware::tv::earc::Result;
+
+struct EArcMock : public BnEArc {
+    EArcMock();
+
+    ::ndk::ScopedAStatus setEArcEnabled(bool in_enabled) override;
+    ::ndk::ScopedAStatus isEArcEnabled(bool* _aidl_return) override;
+    ::ndk::ScopedAStatus setCallback(const std::shared_ptr<IEArcCallback>& in_callback) override;
+    ::ndk::ScopedAStatus getState(int32_t in_portId, IEArcStatus* _aidl_return) override;
+    ::ndk::ScopedAStatus getLastReportedAudioCapabilities(
+            int32_t in_portId, std::vector<uint8_t>* _aidl_return) override;
+    ::ndk::ScopedAStatus reportCapabilities(const std::vector<uint8_t> capabilities,
+                                            int32_t portId);
+    ::ndk::ScopedAStatus changeState(const IEArcStatus status, int32_t portId);
+
+  private:
+    static void* __threadLoop(void* data);
+    void threadLoop();
+
+  private:
+    static void serviceDied(void* cookie);
+    std::shared_ptr<IEArcCallback> mCallback;
+
+    // Variables for the virtual EARC hal impl
+    std::vector<std::vector<uint8_t>> mCapabilities;
+    std::vector<IEArcStatus> mPortStatus;
+    bool mEArcEnabled = true;
+
+    // Port configuration
+    int mTotalPorts = 1;
+
+    // Testing variables
+    pthread_t mThreadId = 0;
+
+    ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+};
+}  // namespace implementation
+}  // namespace earc
+}  // Namespace tv
+}  // namespace hardware
+}  // namespace android
diff --git a/tv/earc/aidl/default/android.hardware.tv.earc-service.rc b/tv/earc/aidl/default/android.hardware.tv.earc-service.rc
new file mode 100644
index 0000000..0d9063e
--- /dev/null
+++ b/tv/earc/aidl/default/android.hardware.tv.earc-service.rc
@@ -0,0 +1,5 @@
+service vendor.earc-default /vendor/bin/hw/android.hardware.tv.earc-service
+    interface aidl android.hardware.tv.earc.IEArc/default
+    class hal
+    user system
+    group system
diff --git a/tv/earc/aidl/default/android.hardware.tv.earc-service.xml b/tv/earc/aidl/default/android.hardware.tv.earc-service.xml
new file mode 100644
index 0000000..4d66d98
--- /dev/null
+++ b/tv/earc/aidl/default/android.hardware.tv.earc-service.xml
@@ -0,0 +1,10 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.tv.earc</name>
+        <version>1</version>
+        <interface>
+            <name>IEArc</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/tv/earc/aidl/default/fuzzer.cpp b/tv/earc/aidl/default/fuzzer.cpp
new file mode 100644
index 0000000..5036853
--- /dev/null
+++ b/tv/earc/aidl/default/fuzzer.cpp
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+#include <EArcMock.h>
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+using android::fuzzService;
+using android::hardware::tv::earc::implementation::EArcMock;
+using ndk::SharedRefBase;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    auto earcAidl = SharedRefBase::make<EArcMock>();
+
+    fuzzService(earcAidl->asBinder().get(), FuzzedDataProvider(data, size));
+
+    return 0;
+}
diff --git a/tv/earc/aidl/default/serviceMock.cpp b/tv/earc/aidl/default/serviceMock.cpp
new file mode 100644
index 0000000..1ea7262
--- /dev/null
+++ b/tv/earc/aidl/default/serviceMock.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "android.hardware.tv.earc-service-shim"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/Log.h>
+#include "EArcMock.h"
+
+using android::hardware::tv::earc::implementation::EArcMock;
+
+int main() {
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+
+    std::shared_ptr<EArcMock> earcAidl = ndk::SharedRefBase::make<EArcMock>();
+    const std::string instance = std::string() + EArcMock::descriptor + "/default";
+    binder_status_t status =
+            AServiceManager_addService(earcAidl->asBinder().get(), instance.c_str());
+    CHECK_EQ(status, STATUS_OK);
+
+    ABinderProcess_joinThreadPool();
+    return 0;
+}
diff --git a/tv/earc/aidl/vts/functional/Android.bp b/tv/earc/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..797547e
--- /dev/null
+++ b/tv/earc/aidl/vts/functional/Android.bp
@@ -0,0 +1,37 @@
+// 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.
+
+package {
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsHalTvEArcAidlTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalTvEArcAidlTargetTest.cpp"],
+    static_libs: [
+        "android.hardware.tv.earc-V1-ndk",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+    disable_framework: true,
+}
diff --git a/tv/earc/aidl/vts/functional/VtsHalTvEArcAidlTargetTest.cpp b/tv/earc/aidl/vts/functional/VtsHalTvEArcAidlTargetTest.cpp
new file mode 100644
index 0000000..12f48c3
--- /dev/null
+++ b/tv/earc/aidl/vts/functional/VtsHalTvEArcAidlTargetTest.cpp
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "EArc_hal_test"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/tv/earc/BnEArcCallback.h>
+#include <aidl/android/hardware/tv/earc/IEArc.h>
+#include <aidl/android/hardware/tv/earc/IEArcStatus.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+#include <sstream>
+#include <vector>
+
+using ::aidl::android::hardware::tv::earc::BnEArcCallback;
+using ::aidl::android::hardware::tv::earc::IEArc;
+using ::aidl::android::hardware::tv::earc::IEArcCallback;
+using ::aidl::android::hardware::tv::earc::IEArcStatus;
+using ::ndk::SpAIBinder;
+
+// The main test class for TV EARC HAL.
+class EArcTest : public ::testing::TestWithParam<std::string> {
+    static void serviceDied(void* /* cookie */) { ALOGE("VtsHalTvCecAidlTargetTest died"); }
+
+  public:
+    void SetUp() override {
+        eArc = IEArc::fromBinder(SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+        ASSERT_NE(eArc, nullptr);
+        ALOGI("%s: getService() for eArc is %s", __func__, eArc->isRemote() ? "remote" : "local");
+
+        eArcCallback = ::ndk::SharedRefBase::make<EArcCallback>();
+        ASSERT_NE(eArcCallback, nullptr);
+        eArcDeathRecipient =
+                ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(&serviceDied));
+        ASSERT_EQ(AIBinder_linkToDeath(eArc->asBinder().get(), eArcDeathRecipient.get(), 0),
+                  STATUS_OK);
+    }
+
+    class EArcCallback : public BnEArcCallback {
+      public:
+        ::ndk::ScopedAStatus onStateChange(IEArcStatus connected __unused,
+                                           int32_t portId __unused) {
+            return ::ndk::ScopedAStatus::ok();
+        };
+        ::ndk::ScopedAStatus onCapabilitiesReported(
+                const std::vector<uint8_t>& capabilities __unused, int32_t portId __unused) {
+            return ::ndk::ScopedAStatus::ok();
+        };
+    };
+
+    std::shared_ptr<IEArc> eArc;
+    std::shared_ptr<IEArcCallback> eArcCallback;
+    ::ndk::ScopedAIBinder_DeathRecipient eArcDeathRecipient;
+};
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EArcTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, EArcTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IEArc::descriptor)),
+                         android::PrintInstanceNameToString);
+
+TEST_P(EArcTest, setGetEArcEnabled) {
+    bool initial_state;
+    bool changed_state;
+    ASSERT_TRUE(eArc->isEArcEnabled(&initial_state).isOk());
+    ASSERT_TRUE(eArc->setEArcEnabled(!initial_state).isOk());
+    ASSERT_TRUE(eArc->isEArcEnabled(&changed_state).isOk());
+    ASSERT_TRUE(initial_state != changed_state);
+    ASSERT_TRUE(eArc->setEArcEnabled(initial_state).isOk());
+}
+
+TEST_P(EArcTest, SetCallback) {
+    ASSERT_TRUE(eArc->setCallback(eArcCallback).isOk());
+}
+
+TEST_P(EArcTest, GetState) {
+    IEArcStatus connectionStatus;
+    ASSERT_TRUE(eArc->getState(1, &connectionStatus).isOk());
+}
+
+TEST_P(EArcTest, GetLastReportedAudioCapabilities) {
+    std::vector<uint8_t> capabilities;
+    ASSERT_TRUE(eArc->getLastReportedAudioCapabilities(1, &capabilities).isOk());
+}
diff --git a/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HpdSignal.aidl b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HpdSignal.aidl
new file mode 100644
index 0000000..eef4025
--- /dev/null
+++ b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HpdSignal.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.tv.hdmi;
+@Backing(type="byte") @VintfStability
+enum HpdSignal {
+  HDMI_HPD_PHYSICAL = 0,
+  HDMI_HPD_STATUS_BIT = 1,
+}
diff --git a/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/IHdmi.aidl b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/IHdmi.aidl
index 3fc7f41..809d392 100644
--- a/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/IHdmi.aidl
+++ b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/IHdmi.aidl
@@ -37,4 +37,6 @@
   android.hardware.tv.hdmi.HdmiPortInfo[] getPortInfo();
   boolean isConnected(in int portId);
   void setCallback(in android.hardware.tv.hdmi.IHdmiCallback callback);
+  void setHpdSignal(android.hardware.tv.hdmi.HpdSignal signal);
+  android.hardware.tv.hdmi.HpdSignal getHpdSignal();
 }
diff --git a/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/Result.aidl b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/Result.aidl
new file mode 100644
index 0000000..b6b0eb3
--- /dev/null
+++ b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/Result.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.tv.hdmi;
+@VintfStability
+enum Result {
+  SUCCESS = 0,
+  FAILURE_UNKNOWN = 1,
+  FAILURE_INVALID_ARGS = 2,
+  FAILURE_INVALID_STATE = 3,
+  FAILURE_NOT_SUPPORTED = 4,
+}
diff --git a/tv/hdmi/aidl/android/hardware/tv/hdmi/HpdSignal.aidl b/tv/hdmi/aidl/android/hardware/tv/hdmi/HpdSignal.aidl
new file mode 100644
index 0000000..05963f2
--- /dev/null
+++ b/tv/hdmi/aidl/android/hardware/tv/hdmi/HpdSignal.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+package android.hardware.tv.hdmi;
+
+/**
+ * HPD (Hotplug Detection) Signal Types
+ */
+@VintfStability
+@Backing(type="byte")
+enum HpdSignal {
+    HDMI_HPD_PHYSICAL = 0,
+    HDMI_HPD_STATUS_BIT = 1,
+}
diff --git a/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmi.aidl b/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmi.aidl
index 5536846..457234d 100644
--- a/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmi.aidl
+++ b/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmi.aidl
@@ -17,6 +17,7 @@
 package android.hardware.tv.hdmi;
 
 import android.hardware.tv.hdmi.HdmiPortInfo;
+import android.hardware.tv.hdmi.HpdSignal;
 import android.hardware.tv.hdmi.IHdmiCallback;
 
 /**
@@ -48,4 +49,17 @@
      *        setCallback(null) should deregister the callback.
      */
     void setCallback(in IHdmiCallback callback);
+
+    /**
+     * Method to set the HPD (Hot Plug Detection) signal the HAL should use for HPD signaling (e.g.
+     * signaling EDID updates). By default, the HAL will use {@code HDMI_HPD_PHYSICAL} (the physical
+     * hotplug signal). When set to {@code HDMI_HPD_STATUS_BIT} the HAL should use the HDP status
+     * bit.
+     */
+    void setHpdSignal(HpdSignal signal);
+
+    /**
+     * Get the current signal the HAL is using for HPD
+     */
+    HpdSignal getHpdSignal();
 }
diff --git a/tv/hdmi/aidl/android/hardware/tv/hdmi/Result.aidl b/tv/hdmi/aidl/android/hardware/tv/hdmi/Result.aidl
new file mode 100644
index 0000000..d2a1fef
--- /dev/null
+++ b/tv/hdmi/aidl/android/hardware/tv/hdmi/Result.aidl
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+package android.hardware.tv.hdmi;
+
+/**
+ * Result enum for return values. Used by the HDMI related AIDL.
+ */
+@VintfStability
+enum Result {
+    /**
+     * The HPD Signal type was set successfully.
+     */
+    SUCCESS = 0,
+
+    /**
+     * The HPD Signal type could not be set because of an unknown failure.
+     */
+    FAILURE_UNKNOWN = 1,
+
+    /**
+     * The HPD Signal type could not be set because the arguments were invalid.
+     */
+    FAILURE_INVALID_ARGS = 2,
+
+    /**
+     * The HPD Signal type could not be set because the HAL is in an invalid state.
+     */
+    FAILURE_INVALID_STATE = 3,
+
+    /**
+     * The HPD Signal type could not be set as the signal type is not supported.
+     */
+    FAILURE_NOT_SUPPORTED = 4,
+}
diff --git a/tv/hdmi/aidl/default/HdmiMock.cpp b/tv/hdmi/aidl/default/HdmiMock.cpp
index bbc4705..7cd9bb7 100644
--- a/tv/hdmi/aidl/default/HdmiMock.cpp
+++ b/tv/hdmi/aidl/default/HdmiMock.cpp
@@ -67,6 +67,21 @@
     return ScopedAStatus::ok();
 }
 
+ScopedAStatus HdmiMock::setHpdSignal(HpdSignal signal) {
+    if (mHdmiThreadRun) {
+        mHpdSignal = signal;
+        return ScopedAStatus::ok();
+    } else {
+        return ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::FAILURE_INVALID_STATE));
+    }
+}
+
+ScopedAStatus HdmiMock::getHpdSignal(HpdSignal* _aidl_return) {
+    *_aidl_return = mHpdSignal;
+    return ScopedAStatus::ok();
+}
+
 void* HdmiMock::__threadLoop(void* user) {
     HdmiMock* const self = static_cast<HdmiMock*>(user);
     self->threadLoop();
diff --git a/tv/hdmi/aidl/default/HdmiMock.h b/tv/hdmi/aidl/default/HdmiMock.h
index 05795dd..51abaff 100644
--- a/tv/hdmi/aidl/default/HdmiMock.h
+++ b/tv/hdmi/aidl/default/HdmiMock.h
@@ -15,6 +15,7 @@
  */
 
 #include <aidl/android/hardware/tv/hdmi/BnHdmi.h>
+#include <aidl/android/hardware/tv/hdmi/Result.h>
 #include <algorithm>
 #include <vector>
 
@@ -29,8 +30,10 @@
 using ::aidl::android::hardware::tv::hdmi::BnHdmi;
 using ::aidl::android::hardware::tv::hdmi::HdmiPortInfo;
 using ::aidl::android::hardware::tv::hdmi::HdmiPortType;
+using ::aidl::android::hardware::tv::hdmi::HpdSignal;
 using ::aidl::android::hardware::tv::hdmi::IHdmi;
 using ::aidl::android::hardware::tv::hdmi::IHdmiCallback;
+using ::aidl::android::hardware::tv::hdmi::Result;
 
 #define HDMI_MSG_IN_FIFO "/dev/hdmi_in_pipe"
 #define MESSAGE_BODY_MAX_LENGTH 4
@@ -41,6 +44,8 @@
     ::ndk::ScopedAStatus getPortInfo(std::vector<HdmiPortInfo>* _aidl_return) override;
     ::ndk::ScopedAStatus isConnected(int32_t portId, bool* _aidl_return) override;
     ::ndk::ScopedAStatus setCallback(const std::shared_ptr<IHdmiCallback>& callback) override;
+    ::ndk::ScopedAStatus setHpdSignal(HpdSignal signal) override;
+    ::ndk::ScopedAStatus getHpdSignal(HpdSignal* _aidl_return) override;
 
     void printEventBuf(const char* msg_buf, int len);
 
@@ -62,6 +67,9 @@
     uint16_t mPhysicalAddress = 0xFFFF;
     int mTotalPorts = 1;
 
+    // HPD Signal being used
+    HpdSignal mHpdSignal = HpdSignal::HDMI_HPD_PHYSICAL;
+
     // Testing variables
     // Input file descriptor
     int mInputFile;
diff --git a/tv/hdmi/aidl/vts/functional/VtsHalTvHdmiAidlTargetTest.cpp b/tv/hdmi/aidl/vts/functional/VtsHalTvHdmiAidlTargetTest.cpp
index 78c2590..fd4d94f 100644
--- a/tv/hdmi/aidl/vts/functional/VtsHalTvHdmiAidlTargetTest.cpp
+++ b/tv/hdmi/aidl/vts/functional/VtsHalTvHdmiAidlTargetTest.cpp
@@ -31,6 +31,7 @@
 using ::aidl::android::hardware::tv::hdmi::BnHdmiCallback;
 using ::aidl::android::hardware::tv::hdmi::HdmiPortInfo;
 using ::aidl::android::hardware::tv::hdmi::HdmiPortType;
+using ::aidl::android::hardware::tv::hdmi::HpdSignal;
 using ::aidl::android::hardware::tv::hdmi::IHdmi;
 using ::aidl::android::hardware::tv::hdmi::IHdmiCallback;
 using ::ndk::SpAIBinder;
@@ -101,3 +102,18 @@
         ASSERT_TRUE(hdmi->isConnected(ports[i].portId, &connected).isOk());
     }
 }
+
+TEST_P(HdmiTest, HdpSignal) {
+    HpdSignal originalSignal;
+    HpdSignal signal = HpdSignal::HDMI_HPD_STATUS_BIT;
+    HpdSignal readSignal;
+    ASSERT_TRUE(hdmi->getHpdSignal(&originalSignal).isOk());
+    ASSERT_TRUE(hdmi->setHpdSignal(signal).isOk());
+    ASSERT_TRUE(hdmi->getHpdSignal(&readSignal).isOk());
+    EXPECT_EQ(readSignal, signal);
+    signal = HpdSignal::HDMI_HPD_PHYSICAL;
+    ASSERT_TRUE(hdmi->setHpdSignal(signal).isOk());
+    ASSERT_TRUE(hdmi->getHpdSignal(&readSignal).isOk());
+    EXPECT_EQ(readSignal, signal);
+    ASSERT_TRUE(hdmi->setHpdSignal(originalSignal).isOk());
+}
diff --git a/usb/1.0/default/OWNERS b/usb/1.0/default/OWNERS
deleted file mode 100644
index fefae56..0000000
--- a/usb/1.0/default/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-badhri@google.com
diff --git a/usb/1.0/vts/OWNERS b/usb/1.0/vts/OWNERS
deleted file mode 100644
index 54f268f..0000000
--- a/usb/1.0/vts/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-badhri@google.com
-yim@google.com
-trong@google.com
diff --git a/usb/1.1/vts/OWNERS b/usb/1.1/vts/OWNERS
deleted file mode 100644
index 54f268f..0000000
--- a/usb/1.1/vts/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-badhri@google.com
-yim@google.com
-trong@google.com
diff --git a/usb/1.2/vts/OWNERS b/usb/1.2/vts/OWNERS
deleted file mode 100644
index f60d39a..0000000
--- a/usb/1.2/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-badhri@google.com
-yim@google.com
diff --git a/usb/1.3/vts/OWNERS b/usb/OWNERS
similarity index 62%
rename from usb/1.3/vts/OWNERS
rename to usb/OWNERS
index a6a1e54..2b1d34d 100644
--- a/usb/1.3/vts/OWNERS
+++ b/usb/OWNERS
@@ -1,2 +1,4 @@
+# Bug component: 175220
+
 albertccwang@google.com
 badhri@google.com
diff --git a/usb/aidl/OWNERS b/usb/aidl/OWNERS
deleted file mode 100644
index fefae56..0000000
--- a/usb/aidl/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-badhri@google.com
diff --git a/vibrator/1.0/vts/OWNERS b/vibrator/1.0/vts/OWNERS
deleted file mode 100644
index 75b9a4b..0000000
--- a/vibrator/1.0/vts/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 345036
-michaelwr@google.com
-leungv@google.com
diff --git a/vibrator/1.1/vts/OWNERS b/vibrator/1.1/vts/OWNERS
deleted file mode 100644
index 44bfe56..0000000
--- a/vibrator/1.1/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 345036
-include ../../1.0/vts/OWNERS
diff --git a/vibrator/1.2/vts/OWNERS b/vibrator/1.2/vts/OWNERS
deleted file mode 100644
index 44bfe56..0000000
--- a/vibrator/1.2/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 345036
-include ../../1.0/vts/OWNERS
diff --git a/vibrator/1.3/example/OWNERS b/vibrator/1.3/example/OWNERS
deleted file mode 100644
index 4b34968..0000000
--- a/vibrator/1.3/example/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-eliptus@google.com
-michaelwr@google.com
diff --git a/vibrator/1.3/vts/OWNERS b/vibrator/1.3/vts/OWNERS
deleted file mode 100644
index 44bfe56..0000000
--- a/vibrator/1.3/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 345036
-include ../../1.0/vts/OWNERS
diff --git a/vibrator/aidl/OWNERS b/vibrator/OWNERS
similarity index 68%
rename from vibrator/aidl/OWNERS
rename to vibrator/OWNERS
index 3982c7b..05e2e73 100644
--- a/vibrator/aidl/OWNERS
+++ b/vibrator/OWNERS
@@ -1,4 +1,9 @@
 # Bug component: 345036
+
 include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS
+
 chasewu@google.com
+chrispaulo@google.com
+michaelwr@google.com
+nathankulczak@google.com
 taikuo@google.com