Merge "Revert^2 "[Aware] Support set cluster id in AIDL""
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 ef51361..e69306e 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -112,6 +112,7 @@
         "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",
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 a166e61..6a545c1 100644
--- a/audio/aidl/TEST_MAPPING
+++ b/audio/aidl/TEST_MAPPING
@@ -13,6 +13,9 @@
       "name": "VtsHalDownmixTargetTest"
     },
     {
+      "name": "VtsHalDynamicsProcessingTargetTest"
+    },
+    {
       "name": "VtsHalEnvironmentalReverbTargetTest"
     },
     {
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 a029d43..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();
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.effect/current/android/hardware/audio/effect/CommandId.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/CommandId.aidl
index 79299ee..86b69fa 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/CommandId.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/CommandId.aidl
@@ -37,14 +37,14 @@
   START = 0,
   STOP = 1,
   RESET = 2,
-  VENDOR_COMMAND_0 = 256,
-  VENDOR_COMMAND_1 = 257,
-  VENDOR_COMMAND_2 = 258,
-  VENDOR_COMMAND_3 = 259,
-  VENDOR_COMMAND_4 = 260,
-  VENDOR_COMMAND_5 = 261,
-  VENDOR_COMMAND_6 = 262,
-  VENDOR_COMMAND_7 = 263,
-  VENDOR_COMMAND_8 = 264,
-  VENDOR_COMMAND_9 = 265,
+  VENDOR_COMMAND_0 = 0x100,
+  VENDOR_COMMAND_1,
+  VENDOR_COMMAND_2,
+  VENDOR_COMMAND_3,
+  VENDOR_COMMAND_4,
+  VENDOR_COMMAND_5,
+  VENDOR_COMMAND_6,
+  VENDOR_COMMAND_7,
+  VENDOR_COMMAND_8,
+  VENDOR_COMMAND_9,
 }
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Downmix.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Downmix.aidl
index 76f8ce5..402441d 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Downmix.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Downmix.aidl
@@ -47,7 +47,7 @@
   }
   @VintfStability
   enum Type {
-    STRIP = 0,
-    FOLD = 1,
+    STRIP,
+    FOLD,
   }
 }
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/DynamicsProcessing.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/DynamicsProcessing.aidl
index ed4dc80..8e5b719 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/DynamicsProcessing.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/DynamicsProcessing.aidl
@@ -36,14 +36,14 @@
 union DynamicsProcessing {
   android.hardware.audio.effect.VendorExtension vendorExtension;
   android.hardware.audio.effect.DynamicsProcessing.EngineArchitecture engineArchitecture;
-  android.hardware.audio.effect.DynamicsProcessing.BandChannelConfig preEq;
-  android.hardware.audio.effect.DynamicsProcessing.BandChannelConfig postEq;
-  android.hardware.audio.effect.DynamicsProcessing.EqBandConfig preEqBand;
-  android.hardware.audio.effect.DynamicsProcessing.EqBandConfig postEqBand;
-  android.hardware.audio.effect.DynamicsProcessing.BandChannelConfig mbc;
-  android.hardware.audio.effect.DynamicsProcessing.MbcBandConfig mbcBand;
-  android.hardware.audio.effect.DynamicsProcessing.LimiterConfig limiter;
-  float inputGainDb;
+  android.hardware.audio.effect.DynamicsProcessing.ChannelConfig[] preEq;
+  android.hardware.audio.effect.DynamicsProcessing.ChannelConfig[] postEq;
+  android.hardware.audio.effect.DynamicsProcessing.EqBandConfig[] preEqBand;
+  android.hardware.audio.effect.DynamicsProcessing.EqBandConfig[] postEqBand;
+  android.hardware.audio.effect.DynamicsProcessing.ChannelConfig[] mbc;
+  android.hardware.audio.effect.DynamicsProcessing.MbcBandConfig[] mbcBand;
+  android.hardware.audio.effect.DynamicsProcessing.LimiterConfig[] limiter;
+  android.hardware.audio.effect.DynamicsProcessing.InputGain[] inputGain;
   @VintfStability
   union Id {
     int vendorExtensionTag;
@@ -52,37 +52,39 @@
   @VintfStability
   parcelable Capability {
     ParcelableHolder extension;
+    float minCutOffFreq;
+    float maxCutOffFreq;
   }
   enum ResolutionPreference {
-    FAVOR_FREQUENCY_RESOLUTION = 0,
-    FAVOR_TIME_RESOLUTION = 1,
+    FAVOR_FREQUENCY_RESOLUTION,
+    FAVOR_TIME_RESOLUTION,
   }
   @VintfStability
-  parcelable BandEnablement {
+  parcelable StageEnablement {
     boolean inUse;
     int bandCount;
   }
   @VintfStability
   parcelable EngineArchitecture {
     android.hardware.audio.effect.DynamicsProcessing.ResolutionPreference resolutionPreference = android.hardware.audio.effect.DynamicsProcessing.ResolutionPreference.FAVOR_FREQUENCY_RESOLUTION;
-    float preferredFrameDurationMs;
-    android.hardware.audio.effect.DynamicsProcessing.BandEnablement preEqBand;
-    android.hardware.audio.effect.DynamicsProcessing.BandEnablement postEqBand;
-    android.hardware.audio.effect.DynamicsProcessing.BandEnablement mbcBand;
+    float preferredProcessingDurationMs;
+    android.hardware.audio.effect.DynamicsProcessing.StageEnablement preEqStage;
+    android.hardware.audio.effect.DynamicsProcessing.StageEnablement postEqStage;
+    android.hardware.audio.effect.DynamicsProcessing.StageEnablement mbcStage;
     boolean limiterInUse;
   }
   @VintfStability
-  parcelable BandChannelConfig {
+  parcelable ChannelConfig {
     int channel;
-    android.hardware.audio.effect.DynamicsProcessing.BandEnablement enablement;
+    boolean enable;
   }
   @VintfStability
   parcelable EqBandConfig {
     int channel;
     int band;
     boolean enable;
-    float cutoffFrequency;
-    float gain;
+    float cutoffFrequencyHz;
+    float gainDb;
   }
   @VintfStability
   parcelable MbcBandConfig {
@@ -90,7 +92,6 @@
     int band;
     boolean enable;
     float cutoffFrequencyHz;
-    float gainDb;
     float attackTimeMs;
     float releaseTimeMs;
     float ratio;
@@ -105,7 +106,6 @@
   parcelable LimiterConfig {
     int channel;
     boolean enable;
-    boolean inUse;
     int linkGroup;
     float attackTimeMs;
     float releaseTimeMs;
@@ -113,4 +113,9 @@
     float thresholdDb;
     float postGainDb;
   }
+  @VintfStability
+  parcelable InputGain {
+    int channel;
+    float gainDb;
+  }
 }
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 0e61932..7f34f33 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,15 +44,15 @@
   int diffusionPm;
   int densityPm;
   boolean bypass;
-  const int MIN_ROOM_LEVEL_MB = -6000;
+  const int MIN_ROOM_LEVEL_MB = (-6000);
   const int MAX_ROOM_LEVEL_MB = 0;
-  const int MIN_ROOM_HF_LEVEL_MB = -4000;
+  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 MIN_LEVEL_MB = (-6000);
   const int MAX_LEVEL_MB = 0;
   const int MIN_DELAY_MS = 0;
   const int MAX_DELAY_MS = 65;
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..20f7e02 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 {
@@ -48,9 +48,9 @@
   }
   @Backing(type="int") @VintfStability
   enum VibratorScale {
-    MUTE = -100,
-    VERY_LOW = -2,
-    LOW = -1,
+    MUTE = (-100),
+    VERY_LOW = (-2),
+    LOW = (-1),
     NONE = 0,
     HIGH = 1,
     VERY_HIGH = 2,
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
index 223d95a..397f897 100644
--- 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
@@ -47,8 +47,8 @@
   }
   @Backing(type="int") @VintfStability
   enum Level {
-    LOW = 0,
-    MEDIUM = 1,
-    HIGH = 2,
+    LOW,
+    MEDIUM,
+    HIGH,
   }
 }
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/PresetReverb.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/PresetReverb.aidl
index 24a9ce1..4651742 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/PresetReverb.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/PresetReverb.aidl
@@ -38,13 +38,13 @@
   android.hardware.audio.effect.PresetReverb.Presets preset;
   @Backing(type="int") @VintfStability
   enum Presets {
-    NONE = 0,
-    SMALLROOM = 1,
-    MEDIUMROOM = 2,
-    LARGEROOM = 3,
-    MEDIUMHALL = 4,
-    LARGEHALL = 5,
-    PLATE = 6,
+    NONE,
+    SMALLROOM,
+    MEDIUMROOM,
+    LARGEROOM,
+    MEDIUMHALL,
+    LARGEHALL,
+    PLATE,
   }
   @VintfStability
   union Id {
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/State.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/State.aidl
index 3176b01..17f9814 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/State.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/State.aidl
@@ -34,7 +34,7 @@
 package android.hardware.audio.effect;
 @Backing(type="byte") @VintfStability
 enum State {
-  INIT = 0,
-  IDLE = 1,
-  PROCESSING = 2,
+  INIT,
+  IDLE,
+  PROCESSING,
 }
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 25f0b73..c8cb551 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
@@ -62,12 +62,12 @@
   @VintfStability
   enum ScalingMode {
     NORMALIZED = 0,
-    AS_PLAYED = 1,
+    AS_PLAYED,
   }
   @VintfStability
   enum MeasurementMode {
     NONE = 0,
-    PEAK_RMS = 1,
+    PEAK_RMS,
   }
   @VintfStability
   union GetOnlyParameters {
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 4779f1f..7bc1b9c 100644
--- a/audio/aidl/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/android/hardware/audio/core/IModule.aidl
@@ -21,6 +21,7 @@
 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;
@@ -86,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
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/stream-out-async-sm.gv b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
index e25b15a..501dc01 100644
--- a/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
+++ b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
@@ -30,6 +30,7 @@
     STANDBY -> PAUSED [label="burst"];                // producer -> active
     IDLE -> STANDBY [label="standby"];                // consumer -> passive
     IDLE -> TRANSFERRING [label="burst"];             // producer -> active
+    IDLE -> ACTIVE [label="burst"];                   // full write
     ACTIVE -> PAUSED [label="pause"];                 // consumer -> passive (not consuming)
     ACTIVE -> DRAINING [label="drain"];               // producer -> passive
     ACTIVE -> TRANSFERRING [label="burst"];           // early unblocking
@@ -45,6 +46,7 @@
     PAUSED -> IDLE [label="flush"];                   // producer -> passive, buffer is cleared
     DRAINING -> IDLE [label="←IStreamCallback.onDrainReady"];
     DRAINING -> TRANSFERRING [label="burst"];         // producer -> active
+    DRAINING -> ACTIVE [label="burst"];               // full write
     DRAINING -> DRAIN_PAUSED [label="pause"];         // consumer -> passive (not consuming)
     DRAIN_PAUSED -> DRAINING [label="start"];         // consumer -> active
     DRAIN_PAUSED -> TRANSFER_PAUSED [label="burst"];  // producer -> active
diff --git a/audio/aidl/android/hardware/audio/core/stream-out-sm.gv b/audio/aidl/android/hardware/audio/core/stream-out-sm.gv
index 6aa5c61..47e7fda 100644
--- a/audio/aidl/android/hardware/audio/core/stream-out-sm.gv
+++ b/audio/aidl/android/hardware/audio/core/stream-out-sm.gv
@@ -31,6 +31,7 @@
     ACTIVE -> ACTIVE [label="burst"];
     ACTIVE -> PAUSED [label="pause"];          // consumer -> passive (not consuming)
     ACTIVE -> DRAINING [label="drain"];        // producer -> passive
+    ACTIVE -> IDLE [label="drain"];            // synchronous drain
     PAUSED -> PAUSED [label="burst"];
     PAUSED -> ACTIVE [label="start"];          // consumer -> active
     PAUSED -> IDLE [label="flush"];            // producer -> passive, buffer is cleared
diff --git a/audio/aidl/android/hardware/audio/effect/DynamicsProcessing.aidl b/audio/aidl/android/hardware/audio/effect/DynamicsProcessing.aidl
index ee5dcad..6db3338 100644
--- a/audio/aidl/android/hardware/audio/effect/DynamicsProcessing.aidl
+++ b/audio/aidl/android/hardware/audio/effect/DynamicsProcessing.aidl
@@ -51,6 +51,14 @@
          * capability definition not enough.
          */
         ParcelableHolder extension;
+        /**
+         * Min Cut off frequency (in Hz) for all Bands.
+         */
+        float minCutOffFreq;
+        /**
+         * Max Cut off frequency (in Hz) for all Bands.
+         */
+        float maxCutOffFreq;
     }
 
     /**
@@ -68,16 +76,16 @@
     }
 
     /**
-     * Band enablement configuration.
+     * Stage enablement configuration.
      */
     @VintfStability
-    parcelable BandEnablement {
+    parcelable StageEnablement {
         /**
-         * True if multi-band stage is in use.
+         * True if stage is in use.
          */
         boolean inUse;
         /**
-         * Number of bands configured for this stage.
+         * Number of bands configured for this stage. Must be positive when inUse is true.
          */
         int bandCount;
     }
@@ -92,21 +100,22 @@
          */
         ResolutionPreference resolutionPreference = ResolutionPreference.FAVOR_FREQUENCY_RESOLUTION;
         /**
-         * Preferred frame duration in milliseconds (ms).
+         * Preferred processing duration in milliseconds (ms). Must not be negative, 0 means no
+         * preference.
          */
-        float preferredFrameDurationMs;
+        float preferredProcessingDurationMs;
         /**
          * PreEq stage (Multi-band Equalizer) configuration.
          */
-        BandEnablement preEqBand;
+        StageEnablement preEqStage;
         /**
          * PostEq stage (Multi-band Equalizer) configuration.
          */
-        BandEnablement postEqBand;
+        StageEnablement postEqStage;
         /**
          * MBC stage (Multi-band Compressor) configuration.
          */
-        BandEnablement mbcBand;
+        StageEnablement mbcStage;
         /**
          * True if Limiter stage is in use.
          */
@@ -114,18 +123,19 @@
     }
 
     /**
-     * Band enablement configuration for a specific channel.
+     * Enablement configuration for a specific channel.
      */
     @VintfStability
-    parcelable BandChannelConfig {
+    parcelable ChannelConfig {
         /**
-         * Channel index.
+         * Channel index. Must not be negative, and not exceed the channel count calculated from
+         * Parameter.common.input.base.channelMask.
          */
         int channel;
         /**
-         * Channel index.
+         * Channel enablement configuration. Can not be true if corresponding stage is not in use.
          */
-        BandEnablement enablement;
+        boolean enable;
     }
 
     /**
@@ -134,7 +144,8 @@
     @VintfStability
     parcelable EqBandConfig {
         /**
-         * Channel index.
+         * Channel index. Must not be negative, and not exceed the channel count calculated from
+         * Parameter.common.input.base.channelMask.
          */
         int channel;
         /**
@@ -142,17 +153,20 @@
          */
         int band;
         /**
-         * True if EQ stage is enabled.
+         * True if EQ band is enabled.
+         * If EngineArchitecture EQ stage inUse was set to false, then enable can not be set to
+         * true.
          */
         boolean enable;
         /**
-         * Topmost frequency number (in Hz) this band will process.
+         * Topmost frequency number (in Hz) this band will process. Must be in the range of
+         * [minCutOffFreq, maxCutOffFreq] defined in Capability.
          */
-        float cutoffFrequency;
+        float cutoffFrequencyHz;
         /**
          * Gain factor in decibels (dB).
          */
-        float gain;
+        float gainDb;
     }
 
     /**
@@ -161,51 +175,53 @@
     @VintfStability
     parcelable MbcBandConfig {
         /**
-         * Channel index.
+         * Channel index. Must not be negative, and not exceed the channel count calculated from
+         * Parameter.common.input.base.channelMask.
          */
         int channel;
         /**
-         * Band index, must in the range of [0, bandCount-1].
+         * Band index. Must be in the range of [0, bandCount-1].
          */
         int band;
         /**
-         * True if MBC stage is enabled.
+         * True if MBC band is enabled.
+         * If EngineArchitecture MBC inUse was set to false, then enable here can not be set to
+         * true.
          */
         boolean enable;
         /**
-         * Topmost frequency number (in Hz) this band will process.
+         * Topmost frequency number (in Hz) this band will process. Must be in the range of
+         * [minCutOffFreq, maxCutOffFreq] defined in Capability.
          */
         float cutoffFrequencyHz;
         /**
-         * Gain factor in decibels (dB).
-         */
-        float gainDb;
-        /**
-         * Attack Time for compressor in milliseconds (ms).
+         * Attack Time for compressor in milliseconds (ms). Must not be negative.
          */
         float attackTimeMs;
         /**
-         * Release Time for compressor in milliseconds (ms).
+         * Release Time for compressor in milliseconds (ms). Must not be negative.
          */
         float releaseTimeMs;
         /**
-         * Compressor ratio (N:1) (input:output).
+         * Compressor ratio (N:1) (input:output). Must not be negative.
          */
         float ratio;
         /**
-         * Compressor threshold measured in decibels (dB) from 0 dB Full Scale (dBFS).
+         * Compressor threshold measured in decibels (dB) from 0 dB Full Scale (dBFS).  Must not be
+         * positive.
          */
         float thresholdDb;
         /**
-         * Width in decibels (dB) around compressor threshold point.
+         * Width in decibels (dB) around compressor threshold point. Must not be negative.
          */
         float kneeWidthDb;
         /**
-         * Noise gate threshold in decibels (dB) from 0 dB Full Scale (dBFS).
+         * Noise gate threshold in decibels (dB) from 0 dB Full Scale (dBFS). Must not be positive.
          */
         float noiseGateThresholdDb;
         /**
-         * Expander ratio (1:N) (input:output) for signals below the Noise Gate Threshold.
+         * Expander ratio (1:N) (input:output) for signals below the Noise Gate Threshold. Must not
+         * be negative.
          */
         float expanderRatio;
         /**
@@ -224,36 +240,35 @@
     @VintfStability
     parcelable LimiterConfig {
         /**
-         * Channel index.
+         * Channel index. Must not be negative, and not exceed the channel count calculated from
+         * Parameter.common.input.base.channelMask.
          */
         int channel;
         /**
-         * True if Limiter stage is enabled.
+         * True if Limiter band is enabled.
+         * If EngineArchitecture limiterInUse was set to false, then enable can not be set to true.
          */
         boolean enable;
         /**
-         * True if Limiter stage is in use.
-         */
-        boolean inUse;
-        /**
          * Index of group assigned to this Limiter. Only limiters that share the same linkGroup
          * index will react together.
          */
         int linkGroup;
         /**
-         * Attack Time for compressor in milliseconds (ms).
+         * Attack Time for compressor in milliseconds (ms). Must not be negative.
          */
         float attackTimeMs;
         /**
-         * Release Time for compressor in milliseconds (ms).
+         * Release Time for compressor in milliseconds (ms). Must not be negative.
          */
         float releaseTimeMs;
         /**
-         * Compressor ratio (N:1) (input:output).
+         * Compressor ratio (N:1) (input:output). Must not be negative.
          */
         float ratio;
         /**
-         * Compressor threshold measured in decibels (dB) from 0 dB Full Scale (dBFS).
+         * Compressor threshold measured in decibels (dB) from 0 dB Full Scale (dBFS). Must not be
+         * positive.
          */
         float thresholdDb;
         /**
@@ -263,39 +278,55 @@
     }
 
     /**
+     * Input gain for a channel (specified by the channel index).
+     */
+    @VintfStability
+    parcelable InputGain {
+        /**
+         * Channel index. Must not be negative, and not exceed the channel count calculated from
+         * Parameter.common.input.base.channelMask.
+         */
+        int channel;
+        /**
+         * Gain applied to the input signal in decibels (dB). 0 dB means no change in level.
+         */
+        float gainDb;
+    }
+
+    /**
      * Effect engine architecture.
      */
     EngineArchitecture engineArchitecture;
     /**
-     * PreEq stage per channel configuration.
+     * PreEq stage per channel configuration. Only valid when pre EQ stage inUse is true.
      */
-    BandChannelConfig preEq;
+    ChannelConfig[] preEq;
     /**
-     * PostEq stage per channel configuration.
+     * PostEq stage per channel configuration. Only valid when post EQ stage inUse is true.
      */
-    BandChannelConfig postEq;
+    ChannelConfig[] postEq;
     /**
-     * PreEq stage per band configuration.
+     * PreEq stage per band configuration. Only valid when pre EQ stage inUse is true.
      */
-    EqBandConfig preEqBand;
+    EqBandConfig[] preEqBand;
     /**
-     * PostEq stage per band configuration.
+     * PostEq stage per band configuration. Only valid when post EQ stage inUse is true.
      */
-    EqBandConfig postEqBand;
+    EqBandConfig[] postEqBand;
     /**
-     * MBC stage per channel configuration.
+     * MBC stage per channel configuration. Only valid when MBC stage inUse is true.
      */
-    BandChannelConfig mbc;
+    ChannelConfig[] mbc;
     /**
-     * PostEq stage per band configuration.
+     * PostEq stage per band configuration. Only valid when MBC stage inUse is true.
      */
-    MbcBandConfig mbcBand;
+    MbcBandConfig[] mbcBand;
     /**
-     * Limiter stage configuration.
+     * Limiter stage configuration. Only valid when limiter stage inUse is true.
      */
-    LimiterConfig limiter;
+    LimiterConfig[] limiter;
     /**
-     * Input gain factor in decibels (dB). 0 dB means no change in level.
+     * Input gain factor.
      */
-    float inputGainDb;
+    InputGain[] inputGain;
 }
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/default/Android.bp b/audio/aidl/default/Android.bp
index 8cd56c0..1e6785f 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -62,6 +62,7 @@
     export_include_dirs: ["include"],
     srcs: [
         "AudioPolicyConfigXmlConverter.cpp",
+        "Bluetooth.cpp",
         "Config.cpp",
         "Configuration.cpp",
         "EngineConfigXmlConverter.cpp",
@@ -155,7 +156,7 @@
         "libbassboostsw",
         "libbundleaidl",
         "libdownmixaidl",
-        "libdynamicsprocessingsw",
+        "libdynamicsprocessingaidl",
         "libenvreverbsw",
         "libequalizersw",
         "libhapticgeneratoraidl",
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/Module.cpp b/audio/aidl/default/Module.cpp
index b58c562..13b04cd 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -25,6 +25,7 @@
 #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"
@@ -45,6 +46,7 @@
 using aidl::android::media::audio::common::AudioPortConfig;
 using aidl::android::media::audio::common::AudioPortExt;
 using aidl::android::media::audio::common::AudioProfile;
+using aidl::android::media::audio::common::Boolean;
 using aidl::android::media::audio::common::Int;
 using aidl::android::media::audio::common::PcmType;
 using android::hardware::audio::common::getFrameSizeInBytes;
@@ -137,12 +139,15 @@
         (flags.getTag() == AudioIoFlags::Tag::output &&
          !isBitPositionFlagSet(flags.get<AudioIoFlags::Tag::output>(),
                                AudioOutputFlags::MMAP_NOIRQ))) {
+        StreamContext::DebugParameters params{mDebug.streamTransientStateDelayMs,
+                                              mVendorDebug.forceTransientBurst,
+                                              mVendorDebug.forceSynchronousDrain};
         StreamContext temp(
                 std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
                 std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
                 portConfigIt->format.value(), portConfigIt->channelMask.value(),
                 std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
-                asyncCallback, mDebug.streamTransientStateDelayMs);
+                asyncCallback, params);
         if (temp.isValid()) {
             *out_context = std::move(temp);
         } else {
@@ -326,6 +331,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;
@@ -963,18 +980,69 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
+const std::string Module::VendorDebug::kForceTransientBurstName = "aosp.forceTransientBurst";
+const std::string Module::VendorDebug::kForceSynchronousDrainName = "aosp.forceSynchronousDrain";
+
 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);
+    bool allParametersKnown = true;
+    for (const auto& id : in_ids) {
+        if (id == VendorDebug::kForceTransientBurstName) {
+            VendorParameter forceTransientBurst{.id = id};
+            forceTransientBurst.ext.setParcelable(Boolean{mVendorDebug.forceTransientBurst});
+            _aidl_return->push_back(std::move(forceTransientBurst));
+        } else if (id == VendorDebug::kForceSynchronousDrainName) {
+            VendorParameter forceSynchronousDrain{.id = id};
+            forceSynchronousDrain.ext.setParcelable(Boolean{mVendorDebug.forceSynchronousDrain});
+            _aidl_return->push_back(std::move(forceSynchronousDrain));
+        } else {
+            allParametersKnown = false;
+            LOG(ERROR) << __func__ << ": unrecognized parameter \"" << id << "\"";
+        }
+    }
+    if (allParametersKnown) return ndk::ScopedAStatus::ok();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
 }
 
+namespace {
+
+template <typename W>
+bool extractParameter(const VendorParameter& p, decltype(W::value)* v) {
+    std::optional<W> value;
+    binder_status_t result = p.ext.getParcelable(&value);
+    if (result == STATUS_OK && value.has_value()) {
+        *v = value.value().value;
+        return true;
+    }
+    LOG(ERROR) << __func__ << ": failed to read the value of the parameter \"" << p.id
+               << "\": " << result;
+    return false;
+}
+
+}  // namespace
+
 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);
+    bool allParametersKnown = true;
+    for (const auto& p : in_parameters) {
+        if (p.id == VendorDebug::kForceTransientBurstName) {
+            if (!extractParameter<Boolean>(p, &mVendorDebug.forceTransientBurst)) {
+                return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+            }
+        } else if (p.id == VendorDebug::kForceSynchronousDrainName) {
+            if (!extractParameter<Boolean>(p, &mVendorDebug.forceSynchronousDrain)) {
+                return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+            }
+        } else {
+            allParametersKnown = false;
+            LOG(ERROR) << __func__ << ": unrecognized parameter \"" << p.id << "\"";
+        }
+    }
+    if (allParametersKnown) return ndk::ScopedAStatus::ok();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
 }
 
 ndk::ScopedAStatus Module::addDeviceEffect(
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index a490a2a..0520cba 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -402,7 +402,11 @@
                     usleep(1000);  // Simulate a blocking call into the driver.
                     populateReply(&reply, mIsConnected);
                     // Can switch the state to ERROR if a driver error occurs.
-                    switchToTransientState(StreamDescriptor::State::DRAINING);
+                    if (mState == StreamDescriptor::State::ACTIVE && mForceSynchronousDrain) {
+                        mState = StreamDescriptor::State::IDLE;
+                    } else {
+                        switchToTransientState(StreamDescriptor::State::DRAINING);
+                    }
                 } else if (mState == StreamDescriptor::State::TRANSFER_PAUSED) {
                     mState = StreamDescriptor::State::DRAIN_PAUSED;
                     populateReply(&reply, mIsConnected);
@@ -467,14 +471,19 @@
 
 bool StreamOutWorkerLogic::write(size_t clientSize, StreamDescriptor::Reply* reply) {
     const size_t readByteCount = mDataMQ->availableToRead();
-    // Amount of data that the HAL module is going to actually use.
-    const size_t byteCount = std::min({clientSize, readByteCount, mDataBufferSize});
     bool fatal = false;
     if (bool success = readByteCount > 0 ? mDataMQ->read(&mDataBuffer[0], readByteCount) : true) {
         const bool isConnected = mIsConnected;
         LOG(DEBUG) << __func__ << ": reading of " << readByteCount << " bytes from data MQ"
                    << " succeeded; connected? " << isConnected;
-        // Frames are consumed and counted regardless of connection status.
+        // Amount of data that the HAL module is going to actually use.
+        size_t byteCount = std::min({clientSize, readByteCount, mDataBufferSize});
+        if (byteCount >= mFrameSize && mForceTransientBurst) {
+            // In order to prevent the state machine from going to ACTIVE state,
+            // simulate partial write.
+            byteCount -= mFrameSize;
+        }
+        // Frames are consumed and counted regardless of the connection status.
         reply->fmqByteCount += byteCount;
         mFrameCount += byteCount / mFrameSize;
         populateReply(reply, isConnected);
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
index 7f06013..40b46e0 100644
--- a/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
+++ b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
@@ -54,7 +54,6 @@
         return EX_ILLEGAL_ARGUMENT;
     }
     *_aidl_return = AcousticEchoCancelerSw::kDescriptor;
-    LOG(ERROR) << __func__ << "xxx " << _aidl_return->toString();
     return EX_NONE;
 }
 
diff --git a/audio/aidl/default/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml
index 9670e9c..e460f89 100644
--- a/audio/aidl/default/audio_effects_config.xml
+++ b/audio/aidl/default/audio_effects_config.xml
@@ -33,7 +33,7 @@
         <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="dynamics_processing" path="libdynamicsprocessingaidl.so"/>
         <library name="equalizersw" path="libequalizersw.so"/>
         <library name="haptic_generator" path="libhapticgeneratoraidl.so"/>
         <library name="loudness_enhancer" path="libloudnessenhanceraidl.so"/>
@@ -72,7 +72,7 @@
             <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="dynamics_processing" library="dynamics_processing" uuid="e0e6539b-1781-7261-676f-6d7573696340"/>
         <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"/>
diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
index 39345a9..0ffbaa1 100644
--- a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
+++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
@@ -18,6 +18,7 @@
 #define LOG_TAG "AHAL_DynamicsProcessingSw"
 #include <Utils.h>
 #include <algorithm>
+#include <set>
 #include <unordered_set>
 
 #include <android-base/logging.h>
@@ -60,7 +61,8 @@
 namespace aidl::android::hardware::audio::effect {
 
 const std::string DynamicsProcessingSw::kEffectName = "DynamicsProcessingSw";
-const DynamicsProcessing::Capability DynamicsProcessingSw::kCapability;
+const DynamicsProcessing::Capability DynamicsProcessingSw::kCapability = {.minCutOffFreq = 220,
+                                                                          .maxCutOffFreq = 20000};
 const Descriptor DynamicsProcessingSw::kDescriptor = {
         .common = {.id = {.type = kDynamicsProcessingTypeUUID,
                           .uuid = kDynamicsProcessingSwImplUUID,
@@ -83,16 +85,143 @@
     RETURN_IF(Parameter::Specific::dynamicsProcessing != specific.getTag(), EX_ILLEGAL_ARGUMENT,
               "EffectNotSupported");
 
-    mSpecificParam = specific.get<Parameter::Specific::dynamicsProcessing>();
-    LOG(DEBUG) << __func__ << " success with: " << specific.toString();
-    return ndk::ScopedAStatus::ok();
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    LOG(INFO) << __func__ << specific.toString();
+    auto& dpParam = specific.get<Parameter::Specific::dynamicsProcessing>();
+    auto tag = dpParam.getTag();
+    switch (tag) {
+        case DynamicsProcessing::engineArchitecture: {
+            RETURN_IF(mContext->setEngineArchitecture(
+                              dpParam.get<DynamicsProcessing::engineArchitecture>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setEngineArchitectureFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::preEq: {
+            RETURN_IF(mContext->setPreEqChannelCfgs(dpParam.get<DynamicsProcessing::preEq>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setPreEqChannelCfgsFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::postEq: {
+            RETURN_IF(mContext->setPostEqChannelCfgs(dpParam.get<DynamicsProcessing::postEq>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setPostEqChannelCfgsFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::mbc: {
+            RETURN_IF(mContext->setMbcChannelCfgs(dpParam.get<DynamicsProcessing::mbc>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setMbcChannelCfgsFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::preEqBand: {
+            RETURN_IF(mContext->setPreEqBandCfgs(dpParam.get<DynamicsProcessing::preEqBand>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setPreEqBandCfgsFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::postEqBand: {
+            RETURN_IF(mContext->setPostEqBandCfgs(dpParam.get<DynamicsProcessing::postEqBand>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setPostEqBandCfgsFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::mbcBand: {
+            RETURN_IF(mContext->setMbcBandCfgs(dpParam.get<DynamicsProcessing::mbcBand>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setMbcBandCfgsFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::limiter: {
+            RETURN_IF(mContext->setLimiterCfgs(dpParam.get<DynamicsProcessing::limiter>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "limiterCfgsFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::inputGain: {
+            RETURN_IF(mContext->setInputGainCfgs(dpParam.get<DynamicsProcessing::inputGain>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "inputGainCfgFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case DynamicsProcessing::vendorExtension: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "DynamicsProcessingTagNotSupported");
+        }
+    }
 }
 
 ndk::ScopedAStatus DynamicsProcessingSw::getParameterSpecific(const Parameter::Id& id,
                                                               Parameter::Specific* specific) {
     auto tag = id.getTag();
     RETURN_IF(Parameter::Id::dynamicsProcessingTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
-    specific->set<Parameter::Specific::dynamicsProcessing>(mSpecificParam);
+    auto dpId = id.get<Parameter::Id::dynamicsProcessingTag>();
+    auto dpIdTag = dpId.getTag();
+    switch (dpIdTag) {
+        case DynamicsProcessing::Id::commonTag:
+            return getParameterDynamicsProcessing(dpId.get<DynamicsProcessing::Id::commonTag>(),
+                                                  specific);
+        case DynamicsProcessing::Id::vendorExtensionTag:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(dpIdTag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "DynamicsProcessingTagNotSupported");
+    }
+}
+
+ndk::ScopedAStatus DynamicsProcessingSw::getParameterDynamicsProcessing(
+        const DynamicsProcessing::Tag& tag, Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    DynamicsProcessing dpParam;
+    switch (tag) {
+        case DynamicsProcessing::Tag::engineArchitecture: {
+            dpParam.set<DynamicsProcessing::engineArchitecture>(mContext->getEngineArchitecture());
+            break;
+        }
+        case DynamicsProcessing::Tag::preEq: {
+            dpParam.set<DynamicsProcessing::preEq>(mContext->getPreEqChannelCfgs());
+            break;
+        }
+        case DynamicsProcessing::Tag::postEq: {
+            dpParam.set<DynamicsProcessing::postEq>(mContext->getPostEqChannelCfgs());
+            break;
+        }
+        case DynamicsProcessing::Tag::mbc: {
+            dpParam.set<DynamicsProcessing::mbc>(mContext->getMbcChannelCfgs());
+            break;
+        }
+        case DynamicsProcessing::Tag::preEqBand: {
+            dpParam.set<DynamicsProcessing::preEqBand>(mContext->getPreEqBandCfgs());
+            break;
+        }
+        case DynamicsProcessing::Tag::postEqBand: {
+            dpParam.set<DynamicsProcessing::postEqBand>(mContext->getPostEqBandCfgs());
+            break;
+        }
+        case DynamicsProcessing::Tag::mbcBand: {
+            dpParam.set<DynamicsProcessing::mbcBand>(mContext->getMbcBandCfgs());
+            break;
+        }
+        case DynamicsProcessing::Tag::limiter: {
+            dpParam.set<DynamicsProcessing::limiter>(mContext->getLimiterCfgs());
+            break;
+        }
+        case DynamicsProcessing::Tag::inputGain: {
+            dpParam.set<DynamicsProcessing::inputGain>(mContext->getInputGainCfgs());
+            break;
+        }
+        case DynamicsProcessing::vendorExtension: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "DynamicsProcessingTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::dynamicsProcessing>(dpParam);
+    LOG(INFO) << __func__ << specific->toString();
     return ndk::ScopedAStatus::ok();
 }
 
@@ -127,4 +256,252 @@
     return {STATUS_OK, samples, samples};
 }
 
+RetCode DynamicsProcessingSwContext::setCommon(const Parameter::Common& common) {
+    mCommon = common;
+    mChannelCount =
+            ::android::hardware::audio::common::getChannelCount(common.input.base.channelMask);
+    resizeChannels();
+    resizeBands();
+    LOG(INFO) << __func__ << mCommon.toString();
+    return RetCode::SUCCESS;
+}
+
+RetCode DynamicsProcessingSwContext::setEngineArchitecture(
+        const DynamicsProcessing::EngineArchitecture& cfg) {
+    RETURN_VALUE_IF(!validateEngineConfig(cfg), RetCode::ERROR_ILLEGAL_PARAMETER,
+                    "illegalEngineConfig");
+
+    if (mEngineSettings == cfg) {
+        LOG(INFO) << __func__ << " not change in engine, do nothing";
+        return RetCode::SUCCESS;
+    }
+    mEngineSettings = cfg;
+    resizeBands();
+    return RetCode::SUCCESS;
+}
+
+RetCode DynamicsProcessingSwContext::setChannelCfgs(
+        const std::vector<DynamicsProcessing::ChannelConfig>& cfgs,
+        std::vector<DynamicsProcessing::ChannelConfig>& targetCfgs,
+        const DynamicsProcessing::StageEnablement& stage) {
+    RETURN_VALUE_IF(!stage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER, "stageNotInUse");
+
+    RetCode ret = RetCode::SUCCESS;
+    std::unordered_set<int> channelSet;
+    for (auto& cfg : cfgs) {
+        if (cfg.channel < 0 || (size_t)cfg.channel >= mChannelCount) {
+            LOG(ERROR) << __func__ << " skip illegal channel config " << cfg.toString();
+            ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+            continue;
+        }
+        if (0 != channelSet.count(cfg.channel)) {
+            LOG(WARNING) << __func__ << " duplicated channel " << cfg.channel;
+            ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+        } else {
+            channelSet.insert(cfg.channel);
+        }
+        targetCfgs[cfg.channel] = cfg;
+    }
+    return ret;
+}
+
+RetCode DynamicsProcessingSwContext::setPreEqChannelCfgs(
+        const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
+    return setChannelCfgs(cfgs, mPreEqChCfgs, mEngineSettings.preEqStage);
+}
+
+RetCode DynamicsProcessingSwContext::setPostEqChannelCfgs(
+        const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
+    return setChannelCfgs(cfgs, mPostEqChCfgs, mEngineSettings.postEqStage);
+}
+
+RetCode DynamicsProcessingSwContext::setMbcChannelCfgs(
+        const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
+    return setChannelCfgs(cfgs, mMbcChCfgs, mEngineSettings.mbcStage);
+}
+
+RetCode DynamicsProcessingSwContext::setEqBandCfgs(
+        const std::vector<DynamicsProcessing::EqBandConfig>& cfgs,
+        std::vector<DynamicsProcessing::EqBandConfig>& targetCfgs,
+        const DynamicsProcessing::StageEnablement& stage,
+        const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig) {
+    RETURN_VALUE_IF(!stage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER, "eqStageNotInUse");
+
+    RetCode ret = RetCode::SUCCESS;
+    std::set<std::pair<int /* channel */, int /* band */>> bandSet;
+
+    for (auto& cfg : cfgs) {
+        if (0 != bandSet.count({cfg.channel, cfg.band})) {
+            LOG(WARNING) << __func__ << " duplicated band " << cfg.toString();
+            ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+        } else {
+            bandSet.insert({cfg.channel, cfg.band});
+        }
+        if (!validateEqBandConfig(cfg, mChannelCount, stage.bandCount, channelConfig)) {
+            LOG(WARNING) << __func__ << " skip invalid band " << cfg.toString();
+            ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+            continue;
+            ;
+        }
+        targetCfgs[cfg.channel * stage.bandCount + cfg.band] = cfg;
+    }
+    return ret;
+}
+
+RetCode DynamicsProcessingSwContext::setPreEqBandCfgs(
+        const std::vector<DynamicsProcessing::EqBandConfig>& cfgs) {
+    return setEqBandCfgs(cfgs, mPreEqChBands, mEngineSettings.preEqStage, mPreEqChCfgs);
+}
+
+RetCode DynamicsProcessingSwContext::setPostEqBandCfgs(
+        const std::vector<DynamicsProcessing::EqBandConfig>& cfgs) {
+    return setEqBandCfgs(cfgs, mPostEqChBands, mEngineSettings.postEqStage, mPostEqChCfgs);
+}
+
+RetCode DynamicsProcessingSwContext::setMbcBandCfgs(
+        const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs) {
+    RETURN_VALUE_IF(!mEngineSettings.mbcStage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER,
+                    "mbcNotInUse");
+
+    RetCode ret = RetCode::SUCCESS;
+    std::set<std::pair<int /* channel */, int /* band */>> bandSet;
+
+    int bandCount = mEngineSettings.mbcStage.bandCount;
+    std::vector<bool> filled(mChannelCount * bandCount, false);
+    for (auto& it : cfgs) {
+        if (0 != bandSet.count({it.channel, it.band})) {
+            LOG(WARNING) << __func__ << " duplicated band " << it.toString();
+            ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+        } else {
+            bandSet.insert({it.channel, it.band});
+        }
+        if (!validateMbcBandConfig(it, mChannelCount, mEngineSettings.mbcStage.bandCount,
+                                   mMbcChCfgs)) {
+            LOG(WARNING) << __func__ << " skip invalid band " << it.toString();
+            ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+            continue;
+            ;
+        }
+        mMbcChBands[it.channel * bandCount + it.band] = it;
+    }
+    return ret;
+}
+
+RetCode DynamicsProcessingSwContext::setLimiterCfgs(
+        const std::vector<DynamicsProcessing::LimiterConfig>& cfgs) {
+    RETURN_VALUE_IF(!mEngineSettings.limiterInUse, RetCode::ERROR_ILLEGAL_PARAMETER,
+                    "limiterNotInUse");
+
+    RetCode ret = RetCode::SUCCESS;
+    std::unordered_set<int> channelSet;
+
+    for (auto& it : cfgs) {
+        if (0 != channelSet.count(it.channel)) {
+            LOG(WARNING) << __func__ << " duplicated channel " << it.channel;
+            ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+        } else {
+            channelSet.insert(it.channel);
+        }
+        if (!validateLimiterConfig(it, mChannelCount)) {
+            LOG(WARNING) << __func__ << " skip invalid limiter " << it.toString();
+            ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+            continue;
+        }
+        mLimiterCfgs[it.channel] = it;
+    }
+    return ret;
+}
+
+void DynamicsProcessingSwContext::resizeChannels() {
+    if (mPreEqChCfgs.size() != mChannelCount) {
+        mPreEqChCfgs.resize(mChannelCount, {.channel = kInvalidChannelId});
+    }
+    if (mPostEqChCfgs.size() != mChannelCount) {
+        mPostEqChCfgs.resize(mChannelCount, {.channel = kInvalidChannelId});
+    }
+    if (mMbcChCfgs.size() != mChannelCount) {
+        mMbcChCfgs.resize(mChannelCount, {.channel = kInvalidChannelId});
+    }
+    if (mLimiterCfgs.size() != mChannelCount) {
+        mLimiterCfgs.resize(mChannelCount, {.channel = kInvalidChannelId});
+    }
+    if (mInputGainCfgs.size() != mChannelCount) {
+        mInputGainCfgs.resize(mChannelCount, {.channel = kInvalidChannelId});
+    }
+}
+
+void DynamicsProcessingSwContext::resizeBands() {
+    if (mPreEqChBands.size() != (size_t)(mChannelCount * mEngineSettings.preEqStage.bandCount)) {
+        mPreEqChBands.resize(mChannelCount * mEngineSettings.preEqStage.bandCount,
+                             {.channel = kInvalidChannelId});
+    }
+    if (mPostEqChBands.size() != (size_t)(mChannelCount * mEngineSettings.postEqStage.bandCount)) {
+        mPostEqChBands.resize(mChannelCount * mEngineSettings.postEqStage.bandCount,
+                              {.channel = kInvalidChannelId});
+    }
+    if (mMbcChBands.size() != (size_t)(mChannelCount * mEngineSettings.mbcStage.bandCount)) {
+        mMbcChBands.resize(mChannelCount * mEngineSettings.mbcStage.bandCount,
+                           {.channel = kInvalidChannelId});
+    }
+}
+
+RetCode DynamicsProcessingSwContext::setInputGainCfgs(
+        const std::vector<DynamicsProcessing::InputGain>& cfgs) {
+    for (const auto& cfg : cfgs) {
+        RETURN_VALUE_IF(cfg.channel < 0 || (size_t)cfg.channel >= mChannelCount,
+                        RetCode::ERROR_ILLEGAL_PARAMETER, "invalidChannel");
+        mInputGainCfgs[cfg.channel] = cfg;
+    }
+    return RetCode::SUCCESS;
+}
+
+std::vector<DynamicsProcessing::InputGain> DynamicsProcessingSwContext::getInputGainCfgs() {
+    std::vector<DynamicsProcessing::InputGain> ret;
+    std::copy_if(mInputGainCfgs.begin(), mInputGainCfgs.end(), std::back_inserter(ret),
+                 [&](const auto& gain) { return gain.channel != kInvalidChannelId; });
+    return ret;
+}
+
+bool DynamicsProcessingSwContext::validateCutoffFrequency(float freq) {
+    return freq >= DynamicsProcessingSw::kCapability.minCutOffFreq &&
+           freq <= DynamicsProcessingSw::kCapability.maxCutOffFreq;
+}
+
+bool DynamicsProcessingSwContext::validateStageEnablement(
+        const DynamicsProcessing::StageEnablement& enablement) {
+    return !enablement.inUse || (enablement.inUse && enablement.bandCount > 0);
+}
+
+bool DynamicsProcessingSwContext::validateEngineConfig(
+        const DynamicsProcessing::EngineArchitecture& engine) {
+    return engine.preferredProcessingDurationMs >= 0 &&
+           validateStageEnablement(engine.preEqStage) &&
+           validateStageEnablement(engine.postEqStage) && validateStageEnablement(engine.mbcStage);
+}
+
+bool DynamicsProcessingSwContext::validateEqBandConfig(
+        const DynamicsProcessing::EqBandConfig& band, int maxChannel, int maxBand,
+        const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig) {
+    return band.channel >= 0 && band.channel < maxChannel &&
+           (size_t)band.channel < channelConfig.size() && channelConfig[band.channel].enable &&
+           band.band >= 0 && band.band < maxBand && validateCutoffFrequency(band.cutoffFrequencyHz);
+}
+
+bool DynamicsProcessingSwContext::validateMbcBandConfig(
+        const DynamicsProcessing::MbcBandConfig& band, int maxChannel, int maxBand,
+        const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig) {
+    return band.channel >= 0 && band.channel < maxChannel &&
+           (size_t)band.channel < channelConfig.size() && channelConfig[band.channel].enable &&
+           band.band >= 0 && band.band < maxBand &&
+           validateCutoffFrequency(band.cutoffFrequencyHz) && band.attackTimeMs >= 0 &&
+           band.releaseTimeMs >= 0 && band.ratio >= 0 && band.thresholdDb <= 0 &&
+           band.kneeWidthDb <= 0 && band.noiseGateThresholdDb <= 0 && band.expanderRatio >= 0;
+}
+
+bool DynamicsProcessingSwContext::validateLimiterConfig(
+        const DynamicsProcessing::LimiterConfig& limiter, int maxChannel) {
+    return limiter.channel >= 0 && limiter.channel < maxChannel && limiter.attackTimeMs >= 0 &&
+           limiter.releaseTimeMs >= 0 && limiter.ratio >= 0 && limiter.thresholdDb <= 0;
+}
+
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
index 2ae46c5..e336df7 100644
--- a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
+++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
@@ -29,11 +29,77 @@
 class DynamicsProcessingSwContext final : public EffectContext {
   public:
     DynamicsProcessingSwContext(int statusDepth, const Parameter::Common& common)
-        : EffectContext(statusDepth, common) {
+        : EffectContext(statusDepth, common),
+          mChannelCount(::android::hardware::audio::common::getChannelCount(
+                  common.input.base.channelMask)),
+          mPreEqChCfgs(mChannelCount, {.channel = kInvalidChannelId}),
+          mPostEqChCfgs(mChannelCount, {.channel = kInvalidChannelId}),
+          mMbcChCfgs(mChannelCount, {.channel = kInvalidChannelId}),
+          mLimiterCfgs(mChannelCount, {.channel = kInvalidChannelId}) {
         LOG(DEBUG) << __func__;
     }
-    // TODO: add specific context here
-};
+
+    // utils
+    RetCode setChannelCfgs(const std::vector<DynamicsProcessing::ChannelConfig>& cfgs,
+                           std::vector<DynamicsProcessing::ChannelConfig>& targetCfgs,
+                           const DynamicsProcessing::StageEnablement& engineSetting);
+
+    RetCode setEqBandCfgs(const std::vector<DynamicsProcessing::EqBandConfig>& cfgs,
+                          std::vector<DynamicsProcessing::EqBandConfig>& targetCfgs,
+                          const DynamicsProcessing::StageEnablement& stage,
+                          const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig);
+
+    // set params
+    RetCode setCommon(const Parameter::Common& common) override;
+    RetCode setEngineArchitecture(const DynamicsProcessing::EngineArchitecture& cfg);
+    RetCode setPreEqChannelCfgs(const std::vector<DynamicsProcessing::ChannelConfig>& cfgs);
+    RetCode setPostEqChannelCfgs(const std::vector<DynamicsProcessing::ChannelConfig>& cfgs);
+    RetCode setMbcChannelCfgs(const std::vector<DynamicsProcessing::ChannelConfig>& cfgs);
+    RetCode setPreEqBandCfgs(const std::vector<DynamicsProcessing::EqBandConfig>& cfgs);
+    RetCode setPostEqBandCfgs(const std::vector<DynamicsProcessing::EqBandConfig>& cfgs);
+    RetCode setMbcBandCfgs(const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs);
+    RetCode setLimiterCfgs(const std::vector<DynamicsProcessing::LimiterConfig>& cfgs);
+    RetCode setInputGainCfgs(const std::vector<DynamicsProcessing::InputGain>& cfgs);
+
+    // get params
+    DynamicsProcessing::EngineArchitecture getEngineArchitecture() { return mEngineSettings; }
+    std::vector<DynamicsProcessing::ChannelConfig> getPreEqChannelCfgs() { return mPreEqChCfgs; }
+    std::vector<DynamicsProcessing::ChannelConfig> getPostEqChannelCfgs() { return mPostEqChCfgs; }
+    std::vector<DynamicsProcessing::ChannelConfig> getMbcChannelCfgs() { return mMbcChCfgs; }
+    std::vector<DynamicsProcessing::EqBandConfig> getPreEqBandCfgs() { return mPreEqChBands; }
+    std::vector<DynamicsProcessing::EqBandConfig> getPostEqBandCfgs() { return mPostEqChBands; }
+    std::vector<DynamicsProcessing::MbcBandConfig> getMbcBandCfgs() { return mMbcChBands; }
+    std::vector<DynamicsProcessing::LimiterConfig> getLimiterCfgs() { return mLimiterCfgs; }
+    std::vector<DynamicsProcessing::InputGain> getInputGainCfgs();
+
+  private:
+    static constexpr int32_t kInvalidChannelId = -1;
+    size_t mChannelCount = 0;
+    DynamicsProcessing::EngineArchitecture mEngineSettings;
+    // Channel config vector with size of mChannelCount
+    std::vector<DynamicsProcessing::ChannelConfig> mPreEqChCfgs;
+    std::vector<DynamicsProcessing::ChannelConfig> mPostEqChCfgs;
+    std::vector<DynamicsProcessing::ChannelConfig> mMbcChCfgs;
+    std::vector<DynamicsProcessing::LimiterConfig> mLimiterCfgs;
+    std::vector<DynamicsProcessing::InputGain> mInputGainCfgs;
+    // Band config vector with size of mChannelCount * bandCount
+    std::vector<DynamicsProcessing::EqBandConfig> mPreEqChBands;
+    std::vector<DynamicsProcessing::EqBandConfig> mPostEqChBands;
+    std::vector<DynamicsProcessing::MbcBandConfig> mMbcChBands;
+
+    bool validateCutoffFrequency(float freq);
+    bool validateStageEnablement(const DynamicsProcessing::StageEnablement& enablement);
+    bool validateEngineConfig(const DynamicsProcessing::EngineArchitecture& engine);
+    bool validateEqBandConfig(const DynamicsProcessing::EqBandConfig& band, int maxChannel,
+                              int maxBand,
+                              const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig);
+    bool validateMbcBandConfig(const DynamicsProcessing::MbcBandConfig& band, int maxChannel,
+                               int maxBand,
+                               const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig);
+    bool validateLimiterConfig(const DynamicsProcessing::LimiterConfig& limiter, int maxChannel);
+    void resizeChannels();
+    void resizeBands();
+};  // DynamicsProcessingSwContext
 
 class DynamicsProcessingSw final : public EffectImpl {
   public:
@@ -60,7 +126,9 @@
 
   private:
     std::shared_ptr<DynamicsProcessingSwContext> mContext;
-    /* parameters */
-    DynamicsProcessing mSpecificParam;
-};
+    ndk::ScopedAStatus getParameterDynamicsProcessing(const DynamicsProcessing::Tag& tag,
+                                                      Parameter::Specific* specific);
+
+};  // DynamicsProcessingSw
+
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
index f6211c4..3c3b66f 100644
--- a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
+++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
@@ -90,8 +90,8 @@
     auto tag = hgParam.getTag();
 
     switch (tag) {
-        case HapticGenerator::hapticScale: {
-            RETURN_IF(mContext->setHgHapticScale(hgParam.get<HapticGenerator::hapticScale>()) !=
+        case HapticGenerator::hapticScales: {
+            RETURN_IF(mContext->setHgHapticScales(hgParam.get<HapticGenerator::hapticScales>()) !=
                               RetCode::SUCCESS,
                       EX_ILLEGAL_ARGUMENT, "HapticScaleNotSupported");
             return ndk::ScopedAStatus::ok();
@@ -133,8 +133,8 @@
 
     HapticGenerator hgParam;
     switch (tag) {
-        case HapticGenerator::hapticScale: {
-            hgParam.set<HapticGenerator::hapticScale>(mContext->getHgHapticScale());
+        case HapticGenerator::hapticScales: {
+            hgParam.set<HapticGenerator::hapticScales>(mContext->getHgHapticScales());
             break;
         }
         case HapticGenerator::vibratorInfo: {
@@ -183,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 d9ec744..7159501 100644
--- a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
+++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
@@ -33,12 +33,8 @@
         LOG(DEBUG) << __func__;
     }
 
-    RetCode setHgHapticScale(const HapticGenerator::HapticScale& hapticScale) {
-        // All int values are valid for ID
-        mHapticScale = hapticScale;
-        return RetCode::SUCCESS;
-    }
-    HapticGenerator::HapticScale getHgHapticScale() const { return mHapticScale; }
+    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
@@ -54,7 +50,7 @@
     static constexpr float DEFAULT_RESONANT_FREQUENCY = 150.0f;
     static constexpr float DEFAULT_Q_FACTOR = 1.0f;
     static constexpr float DEFAULT_MAX_AMPLITUDE = 0.0f;
-    HapticGenerator::HapticScale mHapticScale = {0, HapticGenerator::VibratorScale::MUTE};
+    std::map<int /* trackID */, HapticGenerator::HapticScale> mHapticScales;
     HapticGenerator::VibratorInformation mVibratorInformation = {
             DEFAULT_RESONANT_FREQUENCY, DEFAULT_Q_FACTOR, DEFAULT_MAX_AMPLITUDE};
 };
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 faca61e..000a704 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -36,9 +36,17 @@
     explicit Module(Type type) : mType(type) {}
 
   private:
+    struct VendorDebug {
+        static const std::string kForceTransientBurstName;
+        static const std::string kForceSynchronousDrainName;
+        bool forceTransientBurst = false;
+        bool forceSynchronousDrain = false;
+    };
+
     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;
@@ -127,10 +135,13 @@
     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.
+    VendorDebug mVendorDebug;
+    // 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;
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index 5abd4de..2cf5951 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -62,12 +62,21 @@
     // Ensure that this value is not used by any of StreamDescriptor.State enums
     static constexpr int32_t STATE_CLOSED = -1;
 
+    struct DebugParameters {
+        // An extra delay for transient states, in ms.
+        int transientStateDelayMs = 0;
+        // Force the "burst" command to move the SM to the TRANSFERRING state.
+        bool forceTransientBurst = false;
+        // Force the "drain" command to be synchronous, going directly to the IDLE state.
+        bool forceSynchronousDrain = false;
+    };
+
     StreamContext() = default;
     StreamContext(std::unique_ptr<CommandMQ> commandMQ, std::unique_ptr<ReplyMQ> replyMQ,
                   const ::aidl::android::media::audio::common::AudioFormatDescription& format,
                   const ::aidl::android::media::audio::common::AudioChannelLayout& channelLayout,
                   std::unique_ptr<DataMQ> dataMQ, std::shared_ptr<IStreamCallback> asyncCallback,
-                  int transientStateDelayMs)
+                  DebugParameters debugParameters)
         : mCommandMQ(std::move(commandMQ)),
           mInternalCommandCookie(std::rand()),
           mReplyMQ(std::move(replyMQ)),
@@ -75,7 +84,7 @@
           mChannelLayout(channelLayout),
           mDataMQ(std::move(dataMQ)),
           mAsyncCallback(asyncCallback),
-          mTransientStateDelayMs(transientStateDelayMs) {}
+          mDebugParameters(debugParameters) {}
     StreamContext(StreamContext&& other)
         : mCommandMQ(std::move(other.mCommandMQ)),
           mInternalCommandCookie(other.mInternalCommandCookie),
@@ -83,8 +92,8 @@
           mFormat(other.mFormat),
           mChannelLayout(other.mChannelLayout),
           mDataMQ(std::move(other.mDataMQ)),
-          mAsyncCallback(other.mAsyncCallback),
-          mTransientStateDelayMs(other.mTransientStateDelayMs) {}
+          mAsyncCallback(std::move(other.mAsyncCallback)),
+          mDebugParameters(std::move(other.mDebugParameters)) {}
     StreamContext& operator=(StreamContext&& other) {
         mCommandMQ = std::move(other.mCommandMQ);
         mInternalCommandCookie = other.mInternalCommandCookie;
@@ -92,8 +101,8 @@
         mFormat = std::move(other.mFormat);
         mChannelLayout = std::move(other.mChannelLayout);
         mDataMQ = std::move(other.mDataMQ);
-        mAsyncCallback = other.mAsyncCallback;
-        mTransientStateDelayMs = other.mTransientStateDelayMs;
+        mAsyncCallback = std::move(other.mAsyncCallback);
+        mDebugParameters = std::move(other.mDebugParameters);
         return *this;
     }
 
@@ -107,10 +116,12 @@
     ::aidl::android::media::audio::common::AudioFormatDescription getFormat() const {
         return mFormat;
     }
+    bool getForceTransientBurst() const { return mDebugParameters.forceTransientBurst; }
+    bool getForceSynchronousDrain() const { return mDebugParameters.forceSynchronousDrain; }
     size_t getFrameSize() const;
     int getInternalCommandCookie() const { return mInternalCommandCookie; }
     ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
-    int getTransientStateDelayMs() const { return mTransientStateDelayMs; }
+    int getTransientStateDelayMs() const { return mDebugParameters.transientStateDelayMs; }
     bool isValid() const;
     void reset();
 
@@ -122,7 +133,7 @@
     ::aidl::android::media::audio::common::AudioChannelLayout mChannelLayout;
     std::unique_ptr<DataMQ> mDataMQ;
     std::shared_ptr<IStreamCallback> mAsyncCallback;
-    int mTransientStateDelayMs;
+    DebugParameters mDebugParameters;
 };
 
 class StreamWorkerCommonLogic : public ::android::hardware::audio::common::StreamLogic {
@@ -141,7 +152,9 @@
           mReplyMQ(context.getReplyMQ()),
           mDataMQ(context.getDataMQ()),
           mAsyncCallback(context.getAsyncCallback()),
-          mTransientStateDelayMs(context.getTransientStateDelayMs()) {}
+          mTransientStateDelayMs(context.getTransientStateDelayMs()),
+          mForceTransientBurst(context.getForceTransientBurst()),
+          mForceSynchronousDrain(context.getForceSynchronousDrain()) {}
     std::string init() override;
     void populateReply(StreamDescriptor::Reply* reply, bool isConnected) const;
     void populateReplyWrongState(StreamDescriptor::Reply* reply,
@@ -164,6 +177,8 @@
     std::shared_ptr<IStreamCallback> mAsyncCallback;
     const std::chrono::duration<int, std::milli> mTransientStateDelayMs;
     std::chrono::time_point<std::chrono::steady_clock> mTransientStateStart;
+    const bool mForceTransientBurst;
+    const bool mForceSynchronousDrain;
     // We use an array and the "size" field instead of a vector to be able to detect
     // memory allocation issues.
     std::unique_ptr<int8_t[]> mDataBuffer;
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 1f39db0..a3e7ff2 100644
--- a/audio/aidl/default/include/effect-impl/EffectContext.h
+++ b/audio/aidl/default/include/effect-impl/EffectContext.h
@@ -119,11 +119,11 @@
 
     virtual RetCode setCommon(const Parameter::Common& common) {
         mCommon = common;
-        LOG(ERROR) << __func__ << mCommon.toString();
+        LOG(INFO) << __func__ << mCommon.toString();
         return RetCode::SUCCESS;
     }
     virtual Parameter::Common getCommon() {
-        LOG(ERROR) << __func__ << mCommon.toString();
+        LOG(INFO) << __func__ << mCommon.toString();
         return mCommon;
     }
 
diff --git a/audio/aidl/default/include/effect-impl/EffectTypes.h b/audio/aidl/default/include/effect-impl/EffectTypes.h
index 58c8672..b100a2e 100644
--- a/audio/aidl/default/include/effect-impl/EffectTypes.h
+++ b/audio/aidl/default/include/effect-impl/EffectTypes.h
@@ -98,12 +98,13 @@
         }                                                                              \
     } while (0)
 
-#define RETURN_VALUE_IF(expr, ret, log)                                                          \
-    do {                                                                                         \
-        if (expr) {                                                                              \
-            LOG(ERROR) << __func__ << ":" << __LINE__ << " return with expr " << #expr << (log); \
-            return ret;                                                                          \
-        }                                                                                        \
+#define RETURN_VALUE_IF(expr, ret, log)                                                  \
+    do {                                                                                 \
+        if (expr) {                                                                      \
+            LOG(ERROR) << __func__ << ":" << __LINE__ << " return with expr \"" << #expr \
+                       << "\":" << (log);                                                \
+            return ret;                                                                  \
+        }                                                                                \
     } while (0)
 
 #define RETURN_IF_BINDER_EXCEPTION(functor)                                 \
diff --git a/audio/aidl/default/include/effect-impl/EffectUUID.h b/audio/aidl/default/include/effect-impl/EffectUUID.h
index 6eec29e..1a60829 100644
--- a/audio/aidl/default/include/effect-impl/EffectUUID.h
+++ b/audio/aidl/default/include/effect-impl/EffectUUID.h
@@ -135,6 +135,12 @@
                                                         0x11ed,
                                                         0x9b6a,
                                                         {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// e0e6539b-1781-7261-676f-6d7573696340
+static const AudioUuid kDynamicsProcessingImplUUID = {static_cast<int32_t>(0xe0e6539b),
+                                                      0x1781,
+                                                      0x7261,
+                                                      0x676f,
+                                                      {0x6d, 0x75, 0x73, 0x69, 0x63, 0x40}};
 // 1411e6d6-aecd-4021-a1cf-a6aceb0d71e5
 static const AudioUuid kHapticGeneratorTypeUUID = {static_cast<int32_t>(0x1411e6d6),
                                                    0xaecd,
diff --git a/audio/aidl/default/visualizer/VisualizerSw.cpp b/audio/aidl/default/visualizer/VisualizerSw.cpp
index 735180e..614988c 100644
--- a/audio/aidl/default/visualizer/VisualizerSw.cpp
+++ b/audio/aidl/default/visualizer/VisualizerSw.cpp
@@ -241,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 3c9e6d2..e9d46d7 100644
--- a/audio/aidl/default/visualizer/VisualizerSw.h
+++ b/audio/aidl/default/visualizer/VisualizerSw.h
@@ -38,40 +38,16 @@
         fill(mCaptureSampleBuffer.begin(), mCaptureSampleBuffer.end(), 0x80);
     }
 
-    RetCode setVsCaptureSize(int captureSize) {
-        if (captureSize < kMinCaptureSize || captureSize > kMaxCaptureSize) {
-            LOG(ERROR) << __func__ << " invalid captureSize " << captureSize;
-            return RetCode::ERROR_ILLEGAL_PARAMETER;
-        }
-        // TODO : Add implementation to apply new captureSize
-        mCaptureSize = captureSize;
-        return RetCode::SUCCESS;
-    }
+    RetCode setVsCaptureSize(int captureSize);
     int getVsCaptureSize() const { return mCaptureSize; }
 
-    RetCode setVsScalingMode(Visualizer::ScalingMode scalingMode) {
-        // TODO : Add implementation to apply new scalingMode
-        mScalingMode = scalingMode;
-        return RetCode::SUCCESS;
-    }
+    RetCode setVsScalingMode(Visualizer::ScalingMode scalingMode);
     Visualizer::ScalingMode getVsScalingMode() const { return mScalingMode; }
 
-    RetCode setVsMeasurementMode(Visualizer::MeasurementMode measurementMode) {
-        // TODO : Add implementation to apply new measurementMode
-        mMeasurementMode = measurementMode;
-        return RetCode::SUCCESS;
-    }
+    RetCode setVsMeasurementMode(Visualizer::MeasurementMode measurementMode);
     Visualizer::MeasurementMode getVsMeasurementMode() const { return mMeasurementMode; }
 
-    RetCode setVsLatency(int latency) {
-        if (latency < 0 || latency > kMaxLatencyMs) {
-            LOG(ERROR) << __func__ << " invalid latency " << latency;
-            return RetCode::ERROR_ILLEGAL_PARAMETER;
-        }
-        // TODO : Add implementation to modify latency
-        mLatency = latency;
-        return RetCode::SUCCESS;
-    }
+    RetCode setVsLatency(int latency);
 
     Visualizer::GetOnlyParameters::Measurement getVsMeasurement() const { return mMeasurement; }
     std::vector<uint8_t> getVsCaptureSampleBuffer() const { return mCaptureSampleBuffer; }
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index becdf1b..f9d12dd 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -81,6 +81,12 @@
 }
 
 cc_test {
+    name: "VtsHalDynamicsProcessingTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalDynamicsProcessingTest.cpp"],
+}
+
+cc_test {
     name: "VtsHalEnvironmentalReverbTargetTest",
     defaults: ["VtsHalAudioTargetTestDefaults"],
     srcs: ["VtsHalEnvironmentalReverbTargetTest.cpp"],
diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
index 50a93ce..d4f2811 100644
--- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -18,6 +18,7 @@
 #include <chrono>
 #include <cmath>
 #include <condition_variable>
+#include <forward_list>
 #include <limits>
 #include <memory>
 #include <mutex>
@@ -56,6 +57,7 @@
 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;
@@ -84,6 +86,9 @@
 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::Boolean;
+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;
@@ -123,7 +128,7 @@
         return WithDebugFlags(parent.mFlags);
     }
 
-    WithDebugFlags() {}
+    WithDebugFlags() = default;
     explicit WithDebugFlags(const ModuleDebug& initial) : mInitial(initial), mFlags(initial) {}
     WithDebugFlags(const WithDebugFlags&) = delete;
     WithDebugFlags& operator=(const WithDebugFlags&) = delete;
@@ -132,7 +137,10 @@
             EXPECT_IS_OK(mModule->setModuleDebug(mInitial));
         }
     }
-    void SetUp(IModule* module) { ASSERT_IS_OK(module->setModuleDebug(mFlags)); }
+    void SetUp(IModule* module) {
+        ASSERT_IS_OK(module->setModuleDebug(mFlags));
+        mModule = module;
+    }
     ModuleDebug& flags() { return mFlags; }
 
   private:
@@ -141,13 +149,65 @@
     IModule* mModule = nullptr;
 };
 
+template <typename T>
+class WithModuleParameter {
+  public:
+    WithModuleParameter(const std::string parameterId, const T& value)
+        : mParameterId(parameterId), mValue(value) {}
+    WithModuleParameter(const WithModuleParameter&) = delete;
+    WithModuleParameter& operator=(const WithModuleParameter&) = delete;
+    ~WithModuleParameter() {
+        if (mModule != nullptr) {
+            VendorParameter parameter{.id = mParameterId};
+            parameter.ext.setParcelable(mInitial);
+            EXPECT_IS_OK(mModule->setVendorParameters({parameter}, false));
+        }
+    }
+    ScopedAStatus SetUpNoChecks(IModule* module, bool failureExpected) {
+        std::vector<VendorParameter> parameters;
+        ScopedAStatus result = module->getVendorParameters({mParameterId}, &parameters);
+        if (result.isOk() && parameters.size() == 1) {
+            std::optional<T> maybeInitial;
+            binder_status_t status = parameters[0].ext.getParcelable(&maybeInitial);
+            if (status == STATUS_OK && maybeInitial.has_value()) {
+                mInitial = maybeInitial.value();
+                VendorParameter parameter{.id = mParameterId};
+                parameter.ext.setParcelable(mValue);
+                result = module->setVendorParameters({parameter}, false);
+                if (result.isOk()) {
+                    LOG(INFO) << __func__ << ": overriding parameter \"" << mParameterId
+                              << "\" with " << mValue.toString()
+                              << ", old value: " << mInitial.toString();
+                    mModule = module;
+                }
+            } else {
+                LOG(ERROR) << __func__ << ": error while retrieving the value of \"" << mParameterId
+                           << "\"";
+                return ScopedAStatus::fromStatus(status);
+            }
+        }
+        if (!result.isOk()) {
+            LOG(failureExpected ? INFO : ERROR)
+                    << __func__ << ": can not override vendor parameter \"" << mParameterId << "\""
+                    << result;
+        }
+        return result;
+    }
+
+  private:
+    const std::string mParameterId;
+    const T mValue;
+    IModule* mModule = nullptr;
+    T mInitial;
+};
+
 // For consistency, WithAudioPortConfig can start both with a non-existent
 // port config, and with an existing one. Existence is determined by the
 // id of the provided config. If it's not 0, then WithAudioPortConfig is
 // essentially a no-op wrapper.
 class WithAudioPortConfig {
   public:
-    WithAudioPortConfig() {}
+    WithAudioPortConfig() = default;
     explicit WithAudioPortConfig(const AudioPortConfig& config) : mInitialConfig(config) {}
     WithAudioPortConfig(const WithAudioPortConfig&) = delete;
     WithAudioPortConfig& operator=(const WithAudioPortConfig&) = delete;
@@ -299,26 +359,31 @@
 
     void SetUpImpl(const std::string& moduleName) {
         ASSERT_NO_FATAL_FAILURE(ConnectToService(moduleName));
-        debug.flags().simulateDeviceConnections = true;
-        ASSERT_NO_FATAL_FAILURE(debug.SetUp(module.get()));
     }
 
-    void TearDownImpl() {
-        if (module != nullptr) {
-            EXPECT_IS_OK(module->setModuleDebug(ModuleDebug{}));
-        }
-    }
+    void TearDownImpl() { debug.reset(); }
 
     void ConnectToService(const std::string& moduleName) {
+        ASSERT_EQ(module, nullptr);
+        ASSERT_EQ(debug, nullptr);
         module = IModule::fromBinder(binderUtil.connectToService(moduleName));
         ASSERT_NE(module, nullptr);
+        ASSERT_NO_FATAL_FAILURE(SetUpDebug());
     }
 
     void RestartService() {
         ASSERT_NE(module, nullptr);
         moduleConfig.reset();
+        debug.reset();
         module = IModule::fromBinder(binderUtil.restartService());
         ASSERT_NE(module, nullptr);
+        ASSERT_NO_FATAL_FAILURE(SetUpDebug());
+    }
+
+    void SetUpDebug() {
+        debug.reset(new WithDebugFlags());
+        debug->flags().simulateDeviceConnections = true;
+        ASSERT_NO_FATAL_FAILURE(debug->SetUp(module.get()));
     }
 
     void ApplyEveryConfig(const std::vector<AudioPortConfig>& configs) {
@@ -387,7 +452,7 @@
     std::shared_ptr<IModule> module;
     std::unique_ptr<ModuleConfig> moduleConfig;
     AudioHalBinderServiceUtil binderUtil;
-    WithDebugFlags debug;
+    std::unique_ptr<WithDebugFlags> debug;
 };
 
 class AudioCoreModule : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
@@ -462,6 +527,7 @@
     size_t getBufferSizeFrames() const { return mBufferSizeFrames; }
     CommandMQ* getCommandMQ() const { return mCommandMQ.get(); }
     DataMQ* getDataMQ() const { return mDataMQ.get(); }
+    size_t getFrameSizeBytes() const { return mFrameSizeBytes; }
     ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
 
   private:
@@ -501,10 +567,48 @@
     return std::to_string(static_cast<int32_t>(event));
 }
 
+// Note: we use a reference wrapper, not a pointer, because methods of std::*list
+// return references to inserted elements. This way, we can put a returned reference
+// into the children vector without any type conversions, and this makes DAG creation
+// code more clear.
+template <typename T>
+struct DagNode : public std::pair<T, std::vector<std::reference_wrapper<DagNode<T>>>> {
+    using Children = std::vector<std::reference_wrapper<DagNode>>;
+    DagNode(const T& t, const Children& c) : std::pair<T, Children>(t, c) {}
+    DagNode(T&& t, Children&& c) : std::pair<T, Children>(std::move(t), std::move(c)) {}
+    const T& datum() const { return this->first; }
+    Children& children() { return this->second; }
+    const Children& children() const { return this->second; }
+};
+// Since DagNodes do contain references to next nodes, node links provided
+// by the list are not used. Thus, the order of the nodes in the list is not
+// important, except that the starting node must be at the front of the list,
+// which means, it must always be added last.
+template <typename T>
+struct Dag : public std::forward_list<DagNode<T>> {
+    Dag() = default;
+    // We prohibit copying and moving Dag instances because implementing that
+    // is not trivial due to references between nodes.
+    Dag(const Dag&) = delete;
+    Dag(Dag&&) = delete;
+    Dag& operator=(const Dag&) = delete;
+    Dag& operator=(Dag&&) = delete;
+};
+
 // Transition to the next state happens either due to a command from the client,
 // or after an event received from the server.
 using TransitionTrigger = std::variant<StreamDescriptor::Command, StreamEventReceiver::Event>;
-using StateTransition = std::pair<TransitionTrigger, StreamDescriptor::State>;
+std::string toString(const TransitionTrigger& trigger) {
+    if (std::holds_alternative<StreamDescriptor::Command>(trigger)) {
+        return std::string("'")
+                .append(toString(std::get<StreamDescriptor::Command>(trigger).getTag()))
+                .append("' command");
+    }
+    return std::string("'")
+            .append(toString(std::get<StreamEventReceiver::Event>(trigger)))
+            .append("' event");
+}
+
 struct StateSequence {
     virtual ~StateSequence() = default;
     virtual void rewind() = 0;
@@ -514,6 +618,10 @@
     virtual void advance(StreamDescriptor::State state) = 0;
 };
 
+// Defines the current state and the trigger to transfer to the next one,
+// thus "state" is the "from" state.
+using StateTransitionFrom = std::pair<StreamDescriptor::State, TransitionTrigger>;
+
 static const StreamDescriptor::Command kGetStatusCommand =
         StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::getStatus>(Void{});
 static const StreamDescriptor::Command kStartCommand =
@@ -539,66 +647,65 @@
         StreamEventReceiver::Event::TransferReady;
 static const StreamEventReceiver::Event kDrainReadyEvent = StreamEventReceiver::Event::DrainReady;
 
-// Handle possible bifurcations:
-//   - on burst and on start: 'TRANSFERRING' -> {'ACTIVE', 'TRANSFERRING'}
-//   - on pause: 'TRANSFER_PAUSED' -> {'PAUSED', 'TRANSFER_PAUSED'}
-// It is assumed that the 'steps' provided on the construction contain the sequence
-// for the async case, which gets corrected in the case when the HAL decided to do
-// a synchronous transfer.
-class SmartStateSequence : public StateSequence {
+struct StateDag : public Dag<StateTransitionFrom> {
+    using Node = StateDag::reference;
+    using NextStates = StateDag::value_type::Children;
+
+    template <typename... Next>
+    Node makeNode(StreamDescriptor::State s, TransitionTrigger t, Next&&... next) {
+        return emplace_front(std::make_pair(s, t), NextStates{std::forward<Next>(next)...});
+    }
+    Node makeNodes(const std::vector<StateTransitionFrom>& v, Node last) {
+        auto helper = [&](auto i, auto&& h) -> Node {
+            if (i == v.end()) return last;
+            return makeNode(i->first, i->second, h(++i, h));
+        };
+        return helper(v.begin(), helper);
+    }
+    Node makeNodes(const std::vector<StateTransitionFrom>& v, StreamDescriptor::State f) {
+        return makeNodes(v, makeFinalNode(f));
+    }
+    Node makeFinalNode(StreamDescriptor::State s) {
+        // The actual command used here is irrelevant. Since it's the final node
+        // in the test sequence, no commands sent after reaching it.
+        return emplace_front(std::make_pair(s, kGetStatusCommand), NextStates{});
+    }
+};
+
+class StateSequenceFollower : public StateSequence {
   public:
-    explicit SmartStateSequence(const std::vector<StateTransition>& steps) : mSteps(steps) {}
-    explicit SmartStateSequence(std::vector<StateTransition>&& steps) : mSteps(std::move(steps)) {}
-    void rewind() override { mCurrentStep = 0; }
-    bool done() const override { return mCurrentStep >= mSteps.size(); }
-    TransitionTrigger getTrigger() override { return mSteps[mCurrentStep].first; }
+    explicit StateSequenceFollower(std::unique_ptr<StateDag> steps)
+        : mSteps(std::move(steps)), mCurrent(mSteps->front()) {}
+    void rewind() override { mCurrent = mSteps->front(); }
+    bool done() const override { return current().children().empty(); }
+    TransitionTrigger getTrigger() override { return current().datum().second; }
     std::set<StreamDescriptor::State> getExpectedStates() override {
-        std::set<StreamDescriptor::State> result = {getState()};
-        if (isBurstBifurcation() || isStartBifurcation()) {
-            result.insert(StreamDescriptor::State::ACTIVE);
-        } else if (isPauseBifurcation()) {
-            result.insert(StreamDescriptor::State::PAUSED);
-        }
+        std::set<StreamDescriptor::State> result;
+        std::transform(current().children().cbegin(), current().children().cend(),
+                       std::inserter(result, result.begin()),
+                       [](const auto& node) { return node.get().datum().first; });
+        LOG(DEBUG) << __func__ << ": " << ::android::internal::ToString(result);
         return result;
     }
     void advance(StreamDescriptor::State state) override {
-        if (isBurstBifurcation() && state == StreamDescriptor::State::ACTIVE &&
-            mCurrentStep + 1 < mSteps.size() &&
-            mSteps[mCurrentStep + 1].first == TransitionTrigger{kTransferReadyEvent}) {
-            mCurrentStep++;
+        if (auto it = std::find_if(
+                    current().children().cbegin(), current().children().cend(),
+                    [&](const auto& node) { return node.get().datum().first == state; });
+            it != current().children().cend()) {
+            LOG(DEBUG) << __func__ << ": " << toString(mCurrent.get().datum().first) << " -> "
+                       << toString(it->get().datum().first);
+            mCurrent = *it;
+        } else {
+            LOG(FATAL) << __func__ << ": state " << toString(state) << " is unexpected";
         }
-        mCurrentStep++;
     }
 
   private:
-    StreamDescriptor::State getState() const { return mSteps[mCurrentStep].second; }
-    bool isBurstBifurcation() {
-        return getTrigger() == TransitionTrigger{kBurstCommand} &&
-               getState() == StreamDescriptor::State::TRANSFERRING;
-    }
-    bool isPauseBifurcation() {
-        return getTrigger() == TransitionTrigger{kPauseCommand} &&
-               getState() == StreamDescriptor::State::TRANSFER_PAUSED;
-    }
-    bool isStartBifurcation() {
-        return getTrigger() == TransitionTrigger{kStartCommand} &&
-               getState() == StreamDescriptor::State::TRANSFERRING;
-    }
-    const std::vector<StateTransition> mSteps;
-    size_t mCurrentStep = 0;
+    StateDag::const_reference current() const { return mCurrent.get(); }
+    std::unique_ptr<StateDag> mSteps;
+    std::reference_wrapper<StateDag::value_type> mCurrent;
 };
 
-std::string toString(const TransitionTrigger& trigger) {
-    if (std::holds_alternative<StreamDescriptor::Command>(trigger)) {
-        return std::string("'")
-                .append(toString(std::get<StreamDescriptor::Command>(trigger).getTag()))
-                .append("' command");
-    }
-    return std::string("'")
-            .append(toString(std::get<StreamEventReceiver::Event>(trigger)))
-            .append("' event");
-}
-
 struct StreamLogicDriver {
     virtual ~StreamLogicDriver() = default;
     // Return 'true' to stop the worker.
@@ -924,7 +1031,7 @@
         return common->close();
     }
 
-    WithStream() {}
+    WithStream() = default;
     explicit WithStream(const AudioPortConfig& portConfig) : mPortConfig(portConfig) {}
     WithStream(const WithStream&) = delete;
     WithStream& operator=(const WithStream&) = delete;
@@ -1029,7 +1136,7 @@
 
 class WithAudioPatch {
   public:
-    WithAudioPatch() {}
+    WithAudioPatch() = default;
     WithAudioPatch(const AudioPortConfig& srcPortConfig, const AudioPortConfig& sinkPortConfig)
         : mSrcPortConfig(srcPortConfig), mSinkPortConfig(sinkPortConfig) {}
     WithAudioPatch(bool sinkIsCfg1, const AudioPortConfig& portConfig1,
@@ -1470,7 +1577,7 @@
         GTEST_SKIP() << "No external devices in the module.";
     }
     AudioPort ignored;
-    WithDebugFlags doNotSimulateConnections = WithDebugFlags::createNested(debug);
+    WithDebugFlags doNotSimulateConnections = WithDebugFlags::createNested(*debug);
     doNotSimulateConnections.flags().simulateDeviceConnections = false;
     ASSERT_NO_FATAL_FAILURE(doNotSimulateConnections.SetUp(module.get()));
     for (const auto& port : ports) {
@@ -1490,7 +1597,7 @@
     }
     WithDevicePortConnectedState portConnected(*ports.begin(), GenerateUniqueDeviceAddress());
     ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
-    ModuleDebug midwayDebugChange = debug.flags();
+    ModuleDebug midwayDebugChange = debug->flags();
     midwayDebugChange.simulateDeviceConnections = false;
     EXPECT_STATUS(EX_ILLEGAL_STATE, module->setModuleDebug(midwayDebugChange))
             << "when trying to disable connections simulation while having a connected device";
@@ -1775,6 +1882,89 @@
     }
 }
 
+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 {
@@ -1787,6 +1977,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";
@@ -1828,6 +2029,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:
@@ -2579,8 +2820,8 @@
 
 class StreamLogicDefaultDriver : public StreamLogicDriver {
   public:
-    explicit StreamLogicDefaultDriver(std::shared_ptr<StateSequence> commands)
-        : mCommands(commands) {
+    StreamLogicDefaultDriver(std::shared_ptr<StateSequence> commands, size_t frameSizeBytes)
+        : mCommands(commands), mFrameSizeBytes(frameSizeBytes) {
         mCommands->rewind();
     }
 
@@ -2599,7 +2840,10 @@
                 if (actualSize != nullptr) {
                     // In the output scenario, reduce slightly the fmqByteCount to verify
                     // that the HAL module always consumes all data from the MQ.
-                    if (maxDataSize > 1) maxDataSize--;
+                    if (maxDataSize > static_cast<int>(mFrameSizeBytes)) {
+                        LOG(DEBUG) << __func__ << ": reducing data size by " << mFrameSizeBytes;
+                        maxDataSize -= mFrameSizeBytes;
+                    }
                     *actualSize = maxDataSize;
                 }
                 command->set<StreamDescriptor::Command::Tag::burst>(maxDataSize);
@@ -2645,6 +2889,7 @@
 
   protected:
     std::shared_ptr<StateSequence> mCommands;
+    const size_t mFrameSizeBytes;
     std::optional<StreamDescriptor::State> mPreviousState;
     std::optional<int64_t> mPreviousFrames;
     bool mObservablePositionIncrease = false;
@@ -2693,7 +2938,7 @@
                 (!isNonBlocking && streamType == StreamTypeFilter::ASYNC)) {
                 continue;
             }
-            WithDebugFlags delayTransientStates = WithDebugFlags::createNested(debug);
+            WithDebugFlags delayTransientStates = WithDebugFlags::createNested(*debug);
             delayTransientStates.flags().streamTransientStateDelayMs =
                     std::get<NAMED_CMD_DELAY_MS>(std::get<PARAM_CMD_SEQ>(GetParam()));
             ASSERT_NO_FATAL_FAILURE(delayTransientStates.SetUp(module.get()));
@@ -2704,6 +2949,40 @@
             } else {
                 ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates));
             }
+            if (isNonBlocking) {
+                // Also try running the same sequence with "aosp.forceTransientBurst" set.
+                // This will only work with the default implementation. When it works, the stream
+                // tries always to move to the 'TRANSFERRING' state after a burst.
+                // This helps to check more paths for our test scenarios.
+                WithModuleParameter forceTransientBurst("aosp.forceTransientBurst", Boolean{true});
+                if (forceTransientBurst.SetUpNoChecks(module.get(), true /*failureExpected*/)
+                            .isOk()) {
+                    if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
+                        ASSERT_NO_FATAL_FAILURE(
+                                RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates));
+                    } else {
+                        ASSERT_NO_FATAL_FAILURE(
+                                RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates));
+                    }
+                }
+            } else if (!IOTraits<Stream>::is_input) {
+                // Also try running the same sequence with "aosp.forceSynchronousDrain" set.
+                // This will only work with the default implementation. When it works, the stream
+                // tries always to move to the 'IDLE' state after a drain.
+                // This helps to check more paths for our test scenarios.
+                WithModuleParameter forceSynchronousDrain("aosp.forceSynchronousDrain",
+                                                          Boolean{true});
+                if (forceSynchronousDrain.SetUpNoChecks(module.get(), true /*failureExpected*/)
+                            .isOk()) {
+                    if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
+                        ASSERT_NO_FATAL_FAILURE(
+                                RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates));
+                    } else {
+                        ASSERT_NO_FATAL_FAILURE(
+                                RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates));
+                    }
+                }
+            }
         }
     }
 
@@ -2724,7 +3003,8 @@
 
         WithStream<Stream> stream(patch.getPortConfig(IOTraits<Stream>::is_input));
         ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
-        StreamLogicDefaultDriver driver(commandsAndStates);
+        StreamLogicDefaultDriver driver(commandsAndStates,
+                                        stream.getContext()->getFrameSizeBytes());
         typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver,
                                                  stream.getEventReceiver());
 
@@ -2745,7 +3025,8 @@
                                      std::shared_ptr<StateSequence> commandsAndStates) {
         WithStream<Stream> stream(portConfig);
         ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
-        StreamLogicDefaultDriver driver(commandsAndStates);
+        StreamLogicDefaultDriver driver(commandsAndStates,
+                                        stream.getContext()->getFrameSizeBytes());
         typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver,
                                                  stream.getEventReceiver());
 
@@ -2998,6 +3279,17 @@
     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";
@@ -3044,6 +3336,10 @@
                          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);
@@ -3067,38 +3363,52 @@
 
 // TODO: Add async test cases for input once it is implemented.
 
-std::shared_ptr<StateSequence> makeBurstCommands(bool isSync, size_t burstCount) {
-    const auto burst =
-            isSync ? std::vector<StateTransition>{std::make_pair(kBurstCommand,
-                                                                 StreamDescriptor::State::ACTIVE)}
-                   : std::vector<StateTransition>{
-                             std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFERRING),
-                             std::make_pair(kTransferReadyEvent, StreamDescriptor::State::ACTIVE)};
-    std::vector<StateTransition> result{
-            std::make_pair(kStartCommand, StreamDescriptor::State::IDLE)};
-    for (size_t i = 0; i < burstCount; ++i) {
-        result.insert(result.end(), burst.begin(), burst.end());
+std::shared_ptr<StateSequence> makeBurstCommands(bool isSync) {
+    using State = StreamDescriptor::State;
+    auto d = std::make_unique<StateDag>();
+    StateDag::Node last = d->makeFinalNode(State::ACTIVE);
+    StateDag::Node active = d->makeNode(State::ACTIVE, kBurstCommand, last);
+    StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
+    if (!isSync) {
+        // Allow optional routing via the TRANSFERRING state on bursts.
+        active.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, last));
+        idle.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, active));
     }
-    return std::make_shared<SmartStateSequence>(result);
+    d->makeNode(State::STANDBY, kStartCommand, idle);
+    return std::make_shared<StateSequenceFollower>(std::move(d));
 }
 static const NamedCommandSequence kReadSeq =
-        std::make_tuple(std::string("Read"), 0, StreamTypeFilter::ANY, makeBurstCommands(true, 3));
-static const NamedCommandSequence kWriteSyncSeq = std::make_tuple(
-        std::string("Write"), 0, StreamTypeFilter::SYNC, makeBurstCommands(true, 3));
-static const NamedCommandSequence kWriteAsyncSeq = std::make_tuple(
-        std::string("Write"), 0, StreamTypeFilter::ASYNC, makeBurstCommands(false, 3));
+        std::make_tuple(std::string("Read"), 0, StreamTypeFilter::ANY, makeBurstCommands(true));
+static const NamedCommandSequence kWriteSyncSeq =
+        std::make_tuple(std::string("Write"), 0, StreamTypeFilter::SYNC, makeBurstCommands(true));
+static const NamedCommandSequence kWriteAsyncSeq =
+        std::make_tuple(std::string("Write"), 0, StreamTypeFilter::ASYNC, makeBurstCommands(false));
 
 std::shared_ptr<StateSequence> makeAsyncDrainCommands(bool isInput) {
-    return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
-            std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
-            std::make_pair(kBurstCommand, isInput ? StreamDescriptor::State::ACTIVE
-                                                  : StreamDescriptor::State::TRANSFERRING),
-            std::make_pair(isInput ? kDrainInCommand : kDrainOutAllCommand,
-                           StreamDescriptor::State::DRAINING),
-            isInput ? std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE)
-                    : std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFERRING),
-            std::make_pair(isInput ? kDrainInCommand : kDrainOutAllCommand,
-                           StreamDescriptor::State::DRAINING)});
+    using State = StreamDescriptor::State;
+    auto d = std::make_unique<StateDag>();
+    if (isInput) {
+        d->makeNodes({std::make_pair(State::STANDBY, kStartCommand),
+                      std::make_pair(State::IDLE, kBurstCommand),
+                      std::make_pair(State::ACTIVE, kDrainInCommand),
+                      std::make_pair(State::DRAINING, kStartCommand),
+                      std::make_pair(State::ACTIVE, kDrainInCommand)},
+                     State::DRAINING);
+    } else {
+        StateDag::Node draining =
+                d->makeNodes({std::make_pair(State::DRAINING, kBurstCommand),
+                              std::make_pair(State::TRANSFERRING, kDrainOutAllCommand)},
+                             State::DRAINING);
+        StateDag::Node idle =
+                d->makeNodes({std::make_pair(State::IDLE, kBurstCommand),
+                              std::make_pair(State::TRANSFERRING, kDrainOutAllCommand)},
+                             draining);
+        // If we get straight into ACTIVE on burst, no further testing is possible.
+        draining.children().push_back(d->makeFinalNode(State::ACTIVE));
+        idle.children().push_back(d->makeFinalNode(State::ACTIVE));
+        d->makeNode(State::STANDBY, kStartCommand, idle);
+    }
+    return std::make_shared<StateSequenceFollower>(std::move(d));
 }
 static const NamedCommandSequence kWriteDrainAsyncSeq =
         std::make_tuple(std::string("WriteDrain"), kStreamTransientStateTransitionDelayMs,
@@ -3107,58 +3417,92 @@
         std::string("Drain"), 0, StreamTypeFilter::ANY, makeAsyncDrainCommands(true));
 
 std::shared_ptr<StateSequence> makeDrainOutCommands(bool isSync) {
-    return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
-            std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
-            std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
-            std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAINING),
-            std::make_pair(isSync ? TransitionTrigger(kGetStatusCommand)
-                                  : TransitionTrigger(kDrainReadyEvent),
-                           StreamDescriptor::State::IDLE)});
+    using State = StreamDescriptor::State;
+    auto d = std::make_unique<StateDag>();
+    StateDag::Node last = d->makeFinalNode(State::IDLE);
+    StateDag::Node active = d->makeNodes(
+            {std::make_pair(State::ACTIVE, kDrainOutAllCommand),
+             std::make_pair(State::DRAINING, isSync ? TransitionTrigger(kGetStatusCommand)
+                                                    : TransitionTrigger(kDrainReadyEvent))},
+            last);
+    StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
+    if (!isSync) {
+        idle.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, active));
+    } else {
+        active.children().push_back(last);
+    }
+    d->makeNode(State::STANDBY, kStartCommand, idle);
+    return std::make_shared<StateSequenceFollower>(std::move(d));
 }
 static const NamedCommandSequence kDrainOutSyncSeq = std::make_tuple(
         std::string("Drain"), 0, StreamTypeFilter::SYNC, makeDrainOutCommands(true));
 static const NamedCommandSequence kDrainOutAsyncSeq = std::make_tuple(
         std::string("Drain"), 0, StreamTypeFilter::ASYNC, makeDrainOutCommands(false));
 
-std::shared_ptr<StateSequence> makeDrainOutPauseCommands(bool isSync) {
-    return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
-            std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
-            std::make_pair(kBurstCommand, isSync ? StreamDescriptor::State::ACTIVE
-                                                 : StreamDescriptor::State::TRANSFERRING),
-            std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAINING),
-            std::make_pair(kPauseCommand, StreamDescriptor::State::DRAIN_PAUSED),
-            std::make_pair(kStartCommand, StreamDescriptor::State::DRAINING),
-            std::make_pair(kPauseCommand, StreamDescriptor::State::DRAIN_PAUSED),
-            std::make_pair(kBurstCommand, isSync ? StreamDescriptor::State::PAUSED
-                                                 : StreamDescriptor::State::TRANSFER_PAUSED)});
+std::shared_ptr<StateSequence> makeDrainPauseOutCommands(bool isSync) {
+    using State = StreamDescriptor::State;
+    auto d = std::make_unique<StateDag>();
+    StateDag::Node draining = d->makeNodes({std::make_pair(State::DRAINING, kPauseCommand),
+                                            std::make_pair(State::DRAIN_PAUSED, kStartCommand),
+                                            std::make_pair(State::DRAINING, kPauseCommand),
+                                            std::make_pair(State::DRAIN_PAUSED, kBurstCommand)},
+                                           isSync ? State::PAUSED : State::TRANSFER_PAUSED);
+    StateDag::Node active = d->makeNode(State::ACTIVE, kDrainOutAllCommand, draining);
+    StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
+    if (!isSync) {
+        idle.children().push_back(d->makeNode(State::TRANSFERRING, kDrainOutAllCommand, draining));
+    } else {
+        // If we get straight into IDLE on drain, no further testing is possible.
+        active.children().push_back(d->makeFinalNode(State::IDLE));
+    }
+    d->makeNode(State::STANDBY, kStartCommand, idle);
+    return std::make_shared<StateSequenceFollower>(std::move(d));
 }
 static const NamedCommandSequence kDrainPauseOutSyncSeq =
         std::make_tuple(std::string("DrainPause"), kStreamTransientStateTransitionDelayMs,
-                        StreamTypeFilter::SYNC, makeDrainOutPauseCommands(true));
+                        StreamTypeFilter::SYNC, makeDrainPauseOutCommands(true));
 static const NamedCommandSequence kDrainPauseOutAsyncSeq =
         std::make_tuple(std::string("DrainPause"), kStreamTransientStateTransitionDelayMs,
-                        StreamTypeFilter::ASYNC, makeDrainOutPauseCommands(false));
+                        StreamTypeFilter::ASYNC, makeDrainPauseOutCommands(false));
 
 // This sequence also verifies that the capture / presentation position is not reset on standby.
 std::shared_ptr<StateSequence> makeStandbyCommands(bool isInput, bool isSync) {
-    return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
-            std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
-            std::make_pair(kStandbyCommand, StreamDescriptor::State::STANDBY),
-            std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
-            std::make_pair(kBurstCommand, isInput || isSync
-                                                  ? StreamDescriptor::State::ACTIVE
-                                                  : StreamDescriptor::State::TRANSFERRING),
-            std::make_pair(kPauseCommand, isInput || isSync
-                                                  ? StreamDescriptor::State::PAUSED
-                                                  : StreamDescriptor::State::TRANSFER_PAUSED),
-            std::make_pair(kFlushCommand, isInput ? StreamDescriptor::State::STANDBY
-                                                  : StreamDescriptor::State::IDLE),
-            std::make_pair(isInput ? kGetStatusCommand : kStandbyCommand,  // no-op for input
-                           StreamDescriptor::State::STANDBY),
-            std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
-            std::make_pair(kBurstCommand, isInput || isSync
-                                                  ? StreamDescriptor::State::ACTIVE
-                                                  : StreamDescriptor::State::TRANSFERRING)});
+    using State = StreamDescriptor::State;
+    auto d = std::make_unique<StateDag>();
+    if (isInput) {
+        d->makeNodes({std::make_pair(State::STANDBY, kStartCommand),
+                      std::make_pair(State::IDLE, kStandbyCommand),
+                      std::make_pair(State::STANDBY, kStartCommand),
+                      std::make_pair(State::IDLE, kBurstCommand),
+                      std::make_pair(State::ACTIVE, kPauseCommand),
+                      std::make_pair(State::PAUSED, kFlushCommand),
+                      std::make_pair(State::STANDBY, kStartCommand),
+                      std::make_pair(State::IDLE, kBurstCommand)},
+                     State::ACTIVE);
+    } else {
+        StateDag::Node idle3 =
+                d->makeNode(State::IDLE, kBurstCommand, d->makeFinalNode(State::ACTIVE));
+        StateDag::Node idle2 = d->makeNodes({std::make_pair(State::IDLE, kStandbyCommand),
+                                             std::make_pair(State::STANDBY, kStartCommand)},
+                                            idle3);
+        StateDag::Node active = d->makeNodes({std::make_pair(State::ACTIVE, kPauseCommand),
+                                              std::make_pair(State::PAUSED, kFlushCommand)},
+                                             idle2);
+        StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
+        if (!isSync) {
+            idle3.children().push_back(d->makeFinalNode(State::TRANSFERRING));
+            StateDag::Node transferring =
+                    d->makeNodes({std::make_pair(State::TRANSFERRING, kPauseCommand),
+                                  std::make_pair(State::TRANSFER_PAUSED, kFlushCommand)},
+                                 idle2);
+            idle.children().push_back(transferring);
+        }
+        d->makeNodes({std::make_pair(State::STANDBY, kStartCommand),
+                      std::make_pair(State::IDLE, kStandbyCommand),
+                      std::make_pair(State::STANDBY, kStartCommand)},
+                     idle);
+    }
+    return std::make_shared<StateSequenceFollower>(std::move(d));
 }
 static const NamedCommandSequence kStandbyInSeq = std::make_tuple(
         std::string("Standby"), 0, StreamTypeFilter::ANY, makeStandbyCommands(true, false));
@@ -3168,50 +3512,71 @@
         std::make_tuple(std::string("Standby"), kStreamTransientStateTransitionDelayMs,
                         StreamTypeFilter::ASYNC, makeStandbyCommands(false, false));
 
-static const NamedCommandSequence kPauseInSeq =
-        std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::ANY,
-                        std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
-                                std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
-                                std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
-                                std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
-                                std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
-                                std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
-                                std::make_pair(kFlushCommand, StreamDescriptor::State::STANDBY)}));
-static const NamedCommandSequence kPauseOutSyncSeq =
-        std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::SYNC,
-                        std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
-                                std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
-                                std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
-                                std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
-                                std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
-                                std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
-                                std::make_pair(kBurstCommand, StreamDescriptor::State::PAUSED),
-                                std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
-                                std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED)}));
-/* TODO: Figure out a better way for testing sync/async bursts
-static const NamedCommandSequence kPauseOutAsyncSeq = std::make_tuple(
-        std::string("Pause"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
-        std::make_shared<StaticStateSequence>(std::vector<StateTransition>{
-                std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
-                std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFERRING),
-                std::make_pair(kPauseCommand, StreamDescriptor::State::TRANSFER_PAUSED),
-                std::make_pair(kStartCommand, StreamDescriptor::State::TRANSFERRING),
-                std::make_pair(kPauseCommand, StreamDescriptor::State::TRANSFER_PAUSED),
-                std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAIN_PAUSED),
-                std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFER_PAUSED)}));
-*/
+std::shared_ptr<StateSequence> makePauseCommands(bool isInput, bool isSync) {
+    using State = StreamDescriptor::State;
+    auto d = std::make_unique<StateDag>();
+    if (isInput) {
+        d->makeNodes({std::make_pair(State::STANDBY, kStartCommand),
+                      std::make_pair(State::IDLE, kBurstCommand),
+                      std::make_pair(State::ACTIVE, kPauseCommand),
+                      std::make_pair(State::PAUSED, kBurstCommand),
+                      std::make_pair(State::ACTIVE, kPauseCommand),
+                      std::make_pair(State::PAUSED, kFlushCommand)},
+                     State::STANDBY);
+    } else {
+        StateDag::Node idle = d->makeNodes({std::make_pair(State::IDLE, kBurstCommand),
+                                            std::make_pair(State::ACTIVE, kPauseCommand),
+                                            std::make_pair(State::PAUSED, kStartCommand),
+                                            std::make_pair(State::ACTIVE, kPauseCommand),
+                                            std::make_pair(State::PAUSED, kBurstCommand),
+                                            std::make_pair(State::PAUSED, kStartCommand),
+                                            std::make_pair(State::ACTIVE, kPauseCommand)},
+                                           State::PAUSED);
+        if (!isSync) {
+            idle.children().push_back(
+                    d->makeNodes({std::make_pair(State::TRANSFERRING, kPauseCommand),
+                                  std::make_pair(State::TRANSFER_PAUSED, kStartCommand),
+                                  std::make_pair(State::TRANSFERRING, kPauseCommand),
+                                  std::make_pair(State::TRANSFER_PAUSED, kDrainOutAllCommand),
+                                  std::make_pair(State::DRAIN_PAUSED, kBurstCommand)},
+                                 State::TRANSFER_PAUSED));
+        }
+        d->makeNode(State::STANDBY, kStartCommand, idle);
+    }
+    return std::make_shared<StateSequenceFollower>(std::move(d));
+}
+static const NamedCommandSequence kPauseInSeq = std::make_tuple(
+        std::string("Pause"), 0, StreamTypeFilter::ANY, makePauseCommands(true, false));
+static const NamedCommandSequence kPauseOutSyncSeq = std::make_tuple(
+        std::string("Pause"), 0, StreamTypeFilter::SYNC, makePauseCommands(false, true));
+static const NamedCommandSequence kPauseOutAsyncSeq =
+        std::make_tuple(std::string("Pause"), kStreamTransientStateTransitionDelayMs,
+                        StreamTypeFilter::ASYNC, makePauseCommands(false, false));
 
 std::shared_ptr<StateSequence> makeFlushCommands(bool isInput, bool isSync) {
-    return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
-            std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
-            std::make_pair(kBurstCommand, isInput || isSync
-                                                  ? StreamDescriptor::State::ACTIVE
-                                                  : StreamDescriptor::State::TRANSFERRING),
-            std::make_pair(kPauseCommand, isInput || isSync
-                                                  ? StreamDescriptor::State::PAUSED
-                                                  : StreamDescriptor::State::TRANSFER_PAUSED),
-            std::make_pair(kFlushCommand, isInput ? StreamDescriptor::State::STANDBY
-                                                  : StreamDescriptor::State::IDLE)});
+    using State = StreamDescriptor::State;
+    auto d = std::make_unique<StateDag>();
+    if (isInput) {
+        d->makeNodes({std::make_pair(State::STANDBY, kStartCommand),
+                      std::make_pair(State::IDLE, kBurstCommand),
+                      std::make_pair(State::ACTIVE, kPauseCommand),
+                      std::make_pair(State::PAUSED, kFlushCommand)},
+                     State::STANDBY);
+    } else {
+        StateDag::Node last = d->makeFinalNode(State::IDLE);
+        StateDag::Node idle = d->makeNodes({std::make_pair(State::IDLE, kBurstCommand),
+                                            std::make_pair(State::ACTIVE, kPauseCommand),
+                                            std::make_pair(State::PAUSED, kFlushCommand)},
+                                           last);
+        if (!isSync) {
+            idle.children().push_back(
+                    d->makeNodes({std::make_pair(State::TRANSFERRING, kPauseCommand),
+                                  std::make_pair(State::TRANSFER_PAUSED, kFlushCommand)},
+                                 last));
+        }
+        d->makeNode(State::STANDBY, kStartCommand, idle);
+    }
+    return std::make_shared<StateSequenceFollower>(std::move(d));
 }
 static const NamedCommandSequence kFlushInSeq = std::make_tuple(
         std::string("Flush"), 0, StreamTypeFilter::ANY, makeFlushCommands(true, false));
@@ -3222,13 +3587,21 @@
                         StreamTypeFilter::ASYNC, makeFlushCommands(false, false));
 
 std::shared_ptr<StateSequence> makeDrainPauseFlushOutCommands(bool isSync) {
-    return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
-            std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
-            std::make_pair(kBurstCommand, isSync ? StreamDescriptor::State::ACTIVE
-                                                 : StreamDescriptor::State::TRANSFERRING),
-            std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAINING),
-            std::make_pair(kPauseCommand, StreamDescriptor::State::DRAIN_PAUSED),
-            std::make_pair(kFlushCommand, StreamDescriptor::State::IDLE)});
+    using State = StreamDescriptor::State;
+    auto d = std::make_unique<StateDag>();
+    StateDag::Node draining = d->makeNodes({std::make_pair(State::DRAINING, kPauseCommand),
+                                            std::make_pair(State::DRAIN_PAUSED, kFlushCommand)},
+                                           State::IDLE);
+    StateDag::Node active = d->makeNode(State::ACTIVE, kDrainOutAllCommand, draining);
+    StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
+    if (!isSync) {
+        idle.children().push_back(d->makeNode(State::TRANSFERRING, kDrainOutAllCommand, draining));
+    } else {
+        // If we get straight into IDLE on drain, no further testing is possible.
+        active.children().push_back(d->makeFinalNode(State::IDLE));
+    }
+    d->makeNode(State::STANDBY, kStartCommand, idle);
+    return std::make_shared<StateSequenceFollower>(std::move(d));
 }
 static const NamedCommandSequence kDrainPauseFlushOutSyncSeq =
         std::make_tuple(std::string("DrainPauseFlush"), kStreamTransientStateTransitionDelayMs,
diff --git a/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
new file mode 100644
index 0000000..9feff91
--- /dev/null
+++ b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
@@ -0,0 +1,1115 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/Vintf.h>
+
+#define LOG_TAG "VtsHalDynamicsProcessingTest"
+
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <Utils.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::DynamicsProcessing;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kDynamicsProcessingTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+class DynamicsProcessingTestHelper : public EffectHelper {
+  public:
+    DynamicsProcessingTestHelper(std::pair<std::shared_ptr<IFactory>, Descriptor> pair,
+                                 int32_t channelLayOut = AudioChannelLayout::LAYOUT_STEREO) {
+        std::tie(mFactory, mDescriptor) = pair;
+        mChannelLayout = channelLayOut;
+        mChannelCount = ::android::hardware::audio::common::getChannelCount(
+                AudioChannelLayout::make<AudioChannelLayout::layoutMask>(mChannelLayout));
+    }
+
+    // setup
+    void SetUpDynamicsProcessingEffect() {
+        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 */,
+                0x100 /* iFrameCount */, 0x100 /* oFrameCount */,
+                AudioChannelLayout::make<AudioChannelLayout::layoutMask>(mChannelLayout),
+                AudioChannelLayout::make<AudioChannelLayout::layoutMask>(mChannelLayout));
+        IEffect::OpenEffectReturn ret;
+        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+        ASSERT_NE(nullptr, mEffect);
+        mEngineConfigApplied = mEngineConfigPreset;
+    }
+
+    Parameter::Specific getDefaultParamSpecific() {
+        DynamicsProcessing dp = DynamicsProcessing::make<DynamicsProcessing::engineArchitecture>(
+                mEngineConfigPreset);
+        Parameter::Specific specific =
+                Parameter::Specific::make<Parameter::Specific::dynamicsProcessing>(dp);
+        return specific;
+    }
+
+    // teardown
+    void TearDownDynamicsProcessingEffect() {
+        ASSERT_NO_FATAL_FAILURE(close(mEffect));
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+    }
+
+    // utils functions for parameter checking
+    bool isParamValid(const DynamicsProcessing::Tag& tag, const DynamicsProcessing& dp,
+                      const Descriptor& desc);
+    bool isParamEqual(const DynamicsProcessing::Tag& tag, const DynamicsProcessing& dpRef,
+                      const DynamicsProcessing& dpTest);
+
+    bool isEnablementValid(const DynamicsProcessing::StageEnablement& enablement);
+    bool isEngineConfigValid(const DynamicsProcessing::EngineArchitecture& cfg);
+
+    bool isCutoffFrequencyValid(float freq, const DynamicsProcessing::Capability& cap);
+    bool isChannelConfigValid(const std::vector<DynamicsProcessing::ChannelConfig>& cfgs,
+                              bool stageInUse);
+
+    bool isPreEqBandConfigValid(const DynamicsProcessing::Capability& cap,
+                                const std::vector<DynamicsProcessing::EqBandConfig>& cfgs,
+                                bool stageInUse, int bandCount);
+    bool isPostEqBandConfigValid(const DynamicsProcessing::Capability& cap,
+                                 const std::vector<DynamicsProcessing::EqBandConfig>& cfgs,
+                                 bool stageInUse, int bandCount);
+    bool isMbcBandConfigValid(const DynamicsProcessing::Capability& cap,
+                              const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs,
+                              bool stageInUse, int bandCount);
+    bool isLimiterConfigValid(const std::vector<DynamicsProcessing::LimiterConfig>& cfgs,
+                              bool stageInUse);
+    bool isInputGainValid(const std::vector<DynamicsProcessing::InputGain>& cfgs);
+
+    bool isEngineConfigEqual(const DynamicsProcessing::EngineArchitecture& refCfg,
+                             const DynamicsProcessing::EngineArchitecture& testCfg);
+
+    template <typename T>
+    std::vector<T> filterEnabledVector(const std::vector<T>& vec);
+
+    template <typename T>
+    bool isAidlVectorEqualAfterFilter(const std::vector<T>& source, const std::vector<T>& target);
+
+    template <typename T>
+    bool isAidlVectorEqual(const std::vector<T>& source, const std::vector<T>& target);
+
+    // get set params and validate
+    void SetAndGetDynamicsProcessingParameters();
+
+    // enqueue test parameters
+    void addEngineConfig(const DynamicsProcessing::EngineArchitecture& cfg);
+    void addPreEqChannelConfig(const std::vector<DynamicsProcessing::ChannelConfig>& cfg);
+    void addPostEqChannelConfig(const std::vector<DynamicsProcessing::ChannelConfig>& cfg);
+    void addMbcChannelConfig(const std::vector<DynamicsProcessing::ChannelConfig>& cfg);
+    void addPreEqBandConfigs(const std::vector<DynamicsProcessing::EqBandConfig>& cfgs);
+    void addPostEqBandConfigs(const std::vector<DynamicsProcessing::EqBandConfig>& cfgs);
+    void addMbcBandConfigs(const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs);
+    void addLimiterConfig(const std::vector<DynamicsProcessing::LimiterConfig>& cfg);
+    void addInputGain(const std::vector<DynamicsProcessing::InputGain>& inputGain);
+
+    static constexpr float kPreferredProcessingDurationMs = 10.0f;
+    static constexpr int kBandCount = 5;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+    DynamicsProcessing::EngineArchitecture mEngineConfigApplied;
+    DynamicsProcessing::EngineArchitecture mEngineConfigPreset{
+            .resolutionPreference =
+                    DynamicsProcessing::ResolutionPreference::FAVOR_FREQUENCY_RESOLUTION,
+            .preferredProcessingDurationMs = kPreferredProcessingDurationMs,
+            .preEqStage = {.inUse = true, .bandCount = kBandCount},
+            .postEqStage = {.inUse = true, .bandCount = kBandCount},
+            .mbcStage = {.inUse = true, .bandCount = kBandCount},
+            .limiterInUse = true,
+    };
+
+    std::unordered_set<int /* channelId */> mPreEqChannelEnable;
+    std::unordered_set<int /* channelId */> mPostEqChannelEnable;
+    std::unordered_set<int /* channelId */> mMbcChannelEnable;
+    std::unordered_set<int /* channelId */> mLimiterChannelEnable;
+    static const std::set<std::vector<DynamicsProcessing::ChannelConfig>> kChannelConfigTestSet;
+    static const std::set<DynamicsProcessing::StageEnablement> kStageEnablementTestSet;
+    static const std::set<std::vector<DynamicsProcessing::InputGain>> kInputGainTestSet;
+
+  private:
+    int32_t mChannelLayout;
+    int mChannelCount;
+    std::vector<std::pair<DynamicsProcessing::Tag, DynamicsProcessing>> mTags;
+    void CleanUp() {
+        mTags.clear();
+        mPreEqChannelEnable.clear();
+        mPostEqChannelEnable.clear();
+        mMbcChannelEnable.clear();
+        mLimiterChannelEnable.clear();
+    }
+};
+
+// test value set for DynamicsProcessing::StageEnablement
+const std::set<DynamicsProcessing::StageEnablement>
+        DynamicsProcessingTestHelper::kStageEnablementTestSet = {
+                {.inUse = true, .bandCount = DynamicsProcessingTestHelper::kBandCount},
+                {.inUse = true, .bandCount = 0},
+                {.inUse = true, .bandCount = -1},
+                {.inUse = false, .bandCount = DynamicsProcessingTestHelper::kBandCount}};
+
+// test value set for DynamicsProcessing::ChannelConfig
+const std::set<std::vector<DynamicsProcessing::ChannelConfig>>
+        DynamicsProcessingTestHelper::kChannelConfigTestSet = {
+                {{.channel = -1, .enable = false},
+                 {.channel = 0, .enable = true},
+                 {.channel = 1, .enable = false},
+                 {.channel = 2, .enable = true}},
+
+                {{.channel = -1, .enable = false}, {.channel = 2, .enable = true}},
+
+                {{.channel = 0, .enable = true}, {.channel = 1, .enable = true}}};
+
+// test value set for DynamicsProcessing::InputGain
+const std::set<std::vector<DynamicsProcessing::InputGain>>
+        DynamicsProcessingTestHelper::kInputGainTestSet = {
+                {{.channel = 0, .gainDb = 10.f},
+                 {.channel = 1, .gainDb = 0.f},
+                 {.channel = 2, .gainDb = -10.f}},
+
+                {{.channel = -1, .gainDb = -10.f}, {.channel = -2, .gainDb = 10.f}},
+
+                {{.channel = -1, .gainDb = 10.f}, {.channel = 0, .gainDb = -10.f}}};
+
+bool DynamicsProcessingTestHelper::isParamValid(const DynamicsProcessing::Tag& tag,
+                                                const DynamicsProcessing& dp,
+                                                const Descriptor& desc) {
+    const DynamicsProcessing::Capability& dpCap =
+            desc.capability.get<Capability::dynamicsProcessing>();
+    switch (tag) {
+        case DynamicsProcessing::engineArchitecture: {
+            return isEngineConfigValid(dp.get<DynamicsProcessing::engineArchitecture>());
+        }
+        case DynamicsProcessing::preEq: {
+            return isChannelConfigValid(dp.get<DynamicsProcessing::preEq>(),
+                                        mEngineConfigApplied.preEqStage.inUse);
+        }
+        case DynamicsProcessing::postEq: {
+            return isChannelConfigValid(dp.get<DynamicsProcessing::postEq>(),
+                                        mEngineConfigApplied.postEqStage.inUse);
+        }
+        case DynamicsProcessing::mbc: {
+            return isChannelConfigValid(dp.get<DynamicsProcessing::mbc>(),
+                                        mEngineConfigApplied.mbcStage.inUse);
+        }
+        case DynamicsProcessing::preEqBand: {
+            return isPreEqBandConfigValid(dpCap, dp.get<DynamicsProcessing::preEqBand>(),
+                                          mEngineConfigApplied.preEqStage.inUse,
+                                          mEngineConfigApplied.preEqStage.bandCount);
+        }
+        case DynamicsProcessing::postEqBand: {
+            return isPostEqBandConfigValid(dpCap, dp.get<DynamicsProcessing::postEqBand>(),
+                                           mEngineConfigApplied.postEqStage.inUse,
+                                           mEngineConfigApplied.postEqStage.bandCount);
+        }
+        case DynamicsProcessing::mbcBand: {
+            return isMbcBandConfigValid(dpCap, dp.get<DynamicsProcessing::mbcBand>(),
+                                        mEngineConfigApplied.mbcStage.inUse,
+                                        mEngineConfigApplied.mbcStage.bandCount);
+        }
+        case DynamicsProcessing::limiter: {
+            return isLimiterConfigValid(dp.get<DynamicsProcessing::limiter>(),
+                                        mEngineConfigApplied.limiterInUse);
+        }
+        case DynamicsProcessing::inputGain: {
+            return isInputGainValid(dp.get<DynamicsProcessing::inputGain>());
+        }
+        case DynamicsProcessing::vendorExtension: {
+            return true;
+        }
+    }
+    return true;
+}
+
+bool DynamicsProcessingTestHelper::isParamEqual(const DynamicsProcessing::Tag& tag,
+                                                const DynamicsProcessing& dpRef,
+                                                const DynamicsProcessing& dpTest) {
+    switch (tag) {
+        case DynamicsProcessing::engineArchitecture: {
+            return isEngineConfigEqual(dpRef.get<DynamicsProcessing::engineArchitecture>(),
+                                       dpTest.get<DynamicsProcessing::engineArchitecture>());
+        }
+        case DynamicsProcessing::preEq: {
+            const auto& source = dpRef.get<DynamicsProcessing::preEq>();
+            const auto& target = dpTest.get<DynamicsProcessing::preEq>();
+            return isAidlVectorEqualAfterFilter<DynamicsProcessing::ChannelConfig>(source, target);
+        }
+        case DynamicsProcessing::postEq: {
+            return isAidlVectorEqualAfterFilter<DynamicsProcessing::ChannelConfig>(
+                    dpRef.get<DynamicsProcessing::postEq>(),
+                    dpTest.get<DynamicsProcessing::postEq>());
+        }
+        case DynamicsProcessing::mbc: {
+            return isAidlVectorEqualAfterFilter<DynamicsProcessing::ChannelConfig>(
+                    dpRef.get<DynamicsProcessing::mbc>(), dpTest.get<DynamicsProcessing::mbc>());
+        }
+        case DynamicsProcessing::preEqBand: {
+            return isAidlVectorEqualAfterFilter<DynamicsProcessing::EqBandConfig>(
+                    dpRef.get<DynamicsProcessing::preEqBand>(),
+                    dpTest.get<DynamicsProcessing::preEqBand>());
+        }
+        case DynamicsProcessing::postEqBand: {
+            return isAidlVectorEqualAfterFilter<DynamicsProcessing::EqBandConfig>(
+                    dpRef.get<DynamicsProcessing::postEqBand>(),
+                    dpTest.get<DynamicsProcessing::postEqBand>());
+        }
+        case DynamicsProcessing::mbcBand: {
+            return isAidlVectorEqualAfterFilter<DynamicsProcessing::MbcBandConfig>(
+                    dpRef.get<DynamicsProcessing::mbcBand>(),
+                    dpTest.get<DynamicsProcessing::mbcBand>());
+        }
+        case DynamicsProcessing::limiter: {
+            return isAidlVectorEqualAfterFilter<DynamicsProcessing::LimiterConfig>(
+                    dpRef.get<DynamicsProcessing::limiter>(),
+                    dpTest.get<DynamicsProcessing::limiter>());
+        }
+        case DynamicsProcessing::inputGain: {
+            return isAidlVectorEqual<DynamicsProcessing::InputGain>(
+                    dpRef.get<DynamicsProcessing::inputGain>(),
+                    dpTest.get<DynamicsProcessing::inputGain>());
+        }
+        case DynamicsProcessing::vendorExtension: {
+            return false;
+        }
+    }
+}
+
+bool DynamicsProcessingTestHelper::isEnablementValid(
+        const DynamicsProcessing::StageEnablement& enablement) {
+    return !enablement.inUse || (enablement.inUse && enablement.bandCount > 0);
+}
+
+bool DynamicsProcessingTestHelper::isEngineConfigValid(
+        const DynamicsProcessing::EngineArchitecture& cfg) {
+    return cfg.preferredProcessingDurationMs >= 0 && isEnablementValid(cfg.preEqStage) &&
+           isEnablementValid(cfg.postEqStage) && isEnablementValid(cfg.mbcStage);
+}
+
+bool DynamicsProcessingTestHelper::isChannelConfigValid(
+        const std::vector<DynamicsProcessing::ChannelConfig>& cfgs, bool stageInUse) {
+    std::unordered_set<int> channelSet;
+    if (!stageInUse) return false;
+    for (auto cfg : cfgs) {
+        if (cfg.channel < 0 || cfg.channel >= mChannelCount || 0 != channelSet.count(cfg.channel)) {
+            return false;
+        }
+        channelSet.insert(cfg.channel);
+    }
+    return true;
+}
+
+bool DynamicsProcessingTestHelper::isCutoffFrequencyValid(
+        float freq, const DynamicsProcessing::Capability& cap) {
+    return freq >= cap.minCutOffFreq && freq <= cap.maxCutOffFreq;
+}
+
+bool DynamicsProcessingTestHelper::isPreEqBandConfigValid(
+        const DynamicsProcessing::Capability& cap,
+        const std::vector<DynamicsProcessing::EqBandConfig>& cfgs, bool stageInUse, int bandCount) {
+    std::set<std::pair<int /* channelID */, int /* bandID */>> bandSet;
+    if (!stageInUse) return false;
+    for (auto cfg : cfgs) {
+        if (0 == mPreEqChannelEnable.count(cfg.channel) || cfg.channel < 0 ||
+            cfg.channel >= mChannelCount || cfg.band < 0 || cfg.band >= bandCount ||
+            !isCutoffFrequencyValid(cfg.cutoffFrequencyHz, cap) ||
+            0 != bandSet.count({cfg.channel, cfg.band})) {
+            return false;
+        }
+        bandSet.insert({cfg.channel, cfg.band});
+    }
+    return true;
+}
+
+bool DynamicsProcessingTestHelper::isPostEqBandConfigValid(
+        const DynamicsProcessing::Capability& cap,
+        const std::vector<DynamicsProcessing::EqBandConfig>& cfgs, bool stageInUse, int bandCount) {
+    std::set<std::pair<int /* channelID */, int /* bandID */>> bandSet;
+    // not able to set/get parameter when stage not in use.
+    if (!stageInUse) return false;
+    for (auto cfg : cfgs) {
+        if (0 == mPostEqChannelEnable.count(cfg.channel) || cfg.channel < 0 ||
+            cfg.channel >= mChannelCount || cfg.band < 0 || cfg.band >= bandCount ||
+            !isCutoffFrequencyValid(cfg.cutoffFrequencyHz, cap) ||
+            0 != bandSet.count({cfg.channel, cfg.band})) {
+            return false;
+        }
+        bandSet.insert({cfg.channel, cfg.band});
+    }
+    return true;
+}
+
+bool DynamicsProcessingTestHelper::isMbcBandConfigValid(
+        const DynamicsProcessing::Capability& cap,
+        const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs, bool stageInUse,
+        int bandCount) {
+    std::set<std::pair<int /* channelID */, int /* bandID */>> bandSet;
+    if (!stageInUse) return false;
+    for (auto cfg : cfgs) {
+        if (0 == mMbcChannelEnable.count(cfg.channel) || cfg.channel < 0 ||
+            cfg.channel >= mChannelCount || cfg.band < 0 || cfg.band >= bandCount ||
+            (cfg.attackTimeMs < 0) || cfg.releaseTimeMs < 0 || cfg.ratio < 0 ||
+            cfg.thresholdDb > 0 || cfg.kneeWidthDb < 0 || cfg.noiseGateThresholdDb > 0 ||
+            cfg.expanderRatio < 0 || !isCutoffFrequencyValid(cfg.cutoffFrequencyHz, cap) ||
+            0 != bandSet.count({cfg.channel, cfg.band})) {
+            return false;
+        }
+        bandSet.insert({cfg.channel, cfg.band});
+    }
+    return true;
+}
+
+bool DynamicsProcessingTestHelper::isLimiterConfigValid(
+        const std::vector<DynamicsProcessing::LimiterConfig>& cfgs, bool stageInUse) {
+    std::set<int> channelSet;
+    if (!stageInUse) return false;
+    for (auto cfg : cfgs) {
+        if (0 == mLimiterChannelEnable.count(cfg.channel) || cfg.channel < 0 ||
+            cfg.channel >= mChannelCount || cfg.attackTimeMs < 0 || cfg.releaseTimeMs < 0 ||
+            cfg.ratio < 0 || cfg.thresholdDb > 0 || 0 != channelSet.count(cfg.channel)) {
+            return false;
+        }
+        channelSet.insert(cfg.channel);
+    }
+    return true;
+}
+
+bool DynamicsProcessingTestHelper::isInputGainValid(
+        const std::vector<DynamicsProcessing::InputGain>& cfgs) {
+    std::set<int> channelSet;
+    for (auto cfg : cfgs) {
+        if (cfg.channel < 0 || cfg.channel >= mChannelCount || 0 != channelSet.count(cfg.channel)) {
+            return false;
+        }
+        channelSet.insert(cfg.channel);
+    }
+    return true;
+}
+
+bool DynamicsProcessingTestHelper::isEngineConfigEqual(
+        const DynamicsProcessing::EngineArchitecture& ref,
+        const DynamicsProcessing::EngineArchitecture& test) {
+    return ref == test;
+}
+
+template <typename T>
+std::vector<T> DynamicsProcessingTestHelper::filterEnabledVector(const std::vector<T>& vec) {
+    std::vector<T> ret;
+    std::copy_if(vec.begin(), vec.end(), std::back_inserter(ret),
+                 [](const auto& v) { return v.enable; });
+    return ret;
+}
+
+template <typename T>
+bool DynamicsProcessingTestHelper::isAidlVectorEqual(const std::vector<T>& source,
+                                                     const std::vector<T>& target) {
+    if (source.size() != target.size()) return false;
+
+    auto tempS = source;
+    auto tempT = target;
+    std::sort(tempS.begin(), tempS.end());
+    std::sort(tempT.begin(), tempT.end());
+    return tempS == tempT;
+}
+
+template <typename T>
+bool DynamicsProcessingTestHelper::isAidlVectorEqualAfterFilter(const std::vector<T>& source,
+                                                                const std::vector<T>& target) {
+    return isAidlVectorEqual<T>(filterEnabledVector<T>(source), filterEnabledVector<T>(target));
+}
+
+void DynamicsProcessingTestHelper::SetAndGetDynamicsProcessingParameters() {
+    for (auto& it : mTags) {
+        auto& tag = it.first;
+        auto& dp = it.second;
+
+        // validate parameter
+        Descriptor desc;
+        ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+        const bool valid = isParamValid(tag, dp, desc);
+        const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+        // set parameter
+        Parameter expectParam;
+        Parameter::Specific specific;
+        specific.set<Parameter::Specific::dynamicsProcessing>(dp);
+        expectParam.set<Parameter::specific>(specific);
+        ASSERT_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;
+            DynamicsProcessing::Id dpId;
+            dpId.set<DynamicsProcessing::Id::commonTag>(tag);
+            id.set<Parameter::Id::dynamicsProcessingTag>(dpId);
+            // if set success, then get should match
+            EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
+            Parameter::Specific specificTest = getParam.get<Parameter::specific>();
+            const auto& target = specificTest.get<Parameter::Specific::dynamicsProcessing>();
+            EXPECT_TRUE(isParamEqual(tag, dp, target)) << dp.toString() << "\n"
+                                                       << target.toString();
+            // update mEngineConfigApplied after setting successfully
+            if (tag == DynamicsProcessing::engineArchitecture) {
+                mEngineConfigApplied = target.get<DynamicsProcessing::engineArchitecture>();
+            }
+        }
+    }
+}
+
+void DynamicsProcessingTestHelper::addEngineConfig(
+        const DynamicsProcessing::EngineArchitecture& cfg) {
+    DynamicsProcessing dp;
+    dp.set<DynamicsProcessing::engineArchitecture>(cfg);
+    mTags.push_back({DynamicsProcessing::engineArchitecture, dp});
+}
+
+void DynamicsProcessingTestHelper::addPreEqChannelConfig(
+        const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
+    DynamicsProcessing dp;
+    dp.set<DynamicsProcessing::preEq>(cfgs);
+    mTags.push_back({DynamicsProcessing::preEq, dp});
+    for (auto& cfg : cfgs) {
+        if (cfg.enable) mPreEqChannelEnable.insert(cfg.channel);
+    }
+}
+
+void DynamicsProcessingTestHelper::addPostEqChannelConfig(
+        const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
+    DynamicsProcessing dp;
+    dp.set<DynamicsProcessing::postEq>(cfgs);
+    mTags.push_back({DynamicsProcessing::postEq, dp});
+    for (auto& cfg : cfgs) {
+        if (cfg.enable) mPostEqChannelEnable.insert(cfg.channel);
+    }
+}
+
+void DynamicsProcessingTestHelper::addMbcChannelConfig(
+        const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
+    DynamicsProcessing dp;
+    dp.set<DynamicsProcessing::mbc>(cfgs);
+    mTags.push_back({DynamicsProcessing::mbc, dp});
+    for (auto& cfg : cfgs) {
+        if (cfg.enable) mMbcChannelEnable.insert(cfg.channel);
+    }
+}
+
+void DynamicsProcessingTestHelper::addPreEqBandConfigs(
+        const std::vector<DynamicsProcessing::EqBandConfig>& cfgs) {
+    DynamicsProcessing dp;
+    dp.set<DynamicsProcessing::preEqBand>(cfgs);
+    mTags.push_back({DynamicsProcessing::preEqBand, dp});
+}
+
+void DynamicsProcessingTestHelper::addPostEqBandConfigs(
+        const std::vector<DynamicsProcessing::EqBandConfig>& cfgs) {
+    DynamicsProcessing dp;
+    dp.set<DynamicsProcessing::postEqBand>(cfgs);
+    mTags.push_back({DynamicsProcessing::postEqBand, dp});
+}
+
+void DynamicsProcessingTestHelper::addMbcBandConfigs(
+        const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs) {
+    DynamicsProcessing dp;
+    dp.set<DynamicsProcessing::mbcBand>(cfgs);
+    mTags.push_back({DynamicsProcessing::mbcBand, dp});
+}
+
+void DynamicsProcessingTestHelper::addLimiterConfig(
+        const std::vector<DynamicsProcessing::LimiterConfig>& cfgs) {
+    DynamicsProcessing dp;
+    dp.set<DynamicsProcessing::limiter>(cfgs);
+    mTags.push_back({DynamicsProcessing::limiter, dp});
+    for (auto& cfg : cfgs) {
+        if (cfg.enable) mLimiterChannelEnable.insert(cfg.channel);
+    }
+}
+
+void DynamicsProcessingTestHelper::addInputGain(
+        const std::vector<DynamicsProcessing::InputGain>& inputGains) {
+    DynamicsProcessing dp;
+    dp.set<DynamicsProcessing::inputGain>(inputGains);
+    mTags.push_back({DynamicsProcessing::inputGain, dp});
+}
+
+/**
+ * Test DynamicsProcessing Engine Configuration
+ */
+enum EngineArchitectureTestParamName {
+    ENGINE_TEST_INSTANCE_NAME,
+    ENGINE_TEST_RESOLUTION_PREFERENCE,
+    ENGINE_TEST_PREFERRED_DURATION,
+    ENGINE_TEST_STAGE_ENABLEMENT,
+    ENGINE_TEST_LIMITER_IN_USE
+};
+using EngineArchitectureTestParams = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
+                                                DynamicsProcessing::ResolutionPreference, float,
+                                                DynamicsProcessing::StageEnablement, bool>;
+
+void fillEngineArchConfig(DynamicsProcessing::EngineArchitecture& cfg,
+                          const EngineArchitectureTestParams& params) {
+    cfg.resolutionPreference = std::get<ENGINE_TEST_RESOLUTION_PREFERENCE>(params);
+    cfg.preferredProcessingDurationMs = std::get<ENGINE_TEST_PREFERRED_DURATION>(params);
+    cfg.preEqStage = cfg.postEqStage = cfg.mbcStage =
+            std::get<ENGINE_TEST_STAGE_ENABLEMENT>(params);
+    cfg.limiterInUse = std::get<ENGINE_TEST_LIMITER_IN_USE>(params);
+}
+
+class DynamicsProcessingTestEngineArchitecture
+    : public ::testing::TestWithParam<EngineArchitectureTestParams>,
+      public DynamicsProcessingTestHelper {
+  public:
+    DynamicsProcessingTestEngineArchitecture()
+        : DynamicsProcessingTestHelper(std::get<ENGINE_TEST_INSTANCE_NAME>(GetParam())) {
+        fillEngineArchConfig(mCfg, GetParam());
+    };
+
+    void SetUp() override { SetUpDynamicsProcessingEffect(); }
+
+    void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+    DynamicsProcessing::EngineArchitecture mCfg;
+};
+
+TEST_P(DynamicsProcessingTestEngineArchitecture, SetAndGetEngineArch) {
+    EXPECT_NO_FATAL_FAILURE(addEngineConfig(mCfg));
+    SetAndGetDynamicsProcessingParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        DynamicsProcessingTest, DynamicsProcessingTestEngineArchitecture,
+        ::testing::Combine(
+                testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                        IFactory::descriptor, kDynamicsProcessingTypeUUID)),
+                testing::Values(DynamicsProcessing::ResolutionPreference::FAVOR_TIME_RESOLUTION,
+                                DynamicsProcessing::ResolutionPreference::
+                                        FAVOR_FREQUENCY_RESOLUTION),  // variant
+                testing::Values(-10.f, 0.f, 10.f),                    // processing duration
+                testing::ValuesIn(
+                        DynamicsProcessingTestHelper::kStageEnablementTestSet),  // preEQ/postEQ/mbc
+                testing::Bool()),                                                // limiter enable
+        [](const auto& info) {
+            auto descriptor = std::get<ENGINE_TEST_INSTANCE_NAME>(info.param).second;
+            DynamicsProcessing::EngineArchitecture cfg;
+            fillEngineArchConfig(cfg, info.param);
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_Cfg_" + cfg.toString();
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestEngineArchitecture);
+
+/**
+ * Test DynamicsProcessing Input Gain
+ */
+enum InputGainTestParamName {
+    INPUT_GAIN_INSTANCE_NAME,
+    INPUT_GAIN_PARAM,
+};
+class DynamicsProcessingTestInputGain
+    : public ::testing::TestWithParam<std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
+                                                 std::vector<DynamicsProcessing::InputGain>>>,
+      public DynamicsProcessingTestHelper {
+  public:
+    DynamicsProcessingTestInputGain()
+        : DynamicsProcessingTestHelper(std::get<INPUT_GAIN_INSTANCE_NAME>(GetParam())),
+          mInputGain(std::get<INPUT_GAIN_PARAM>(GetParam())){};
+
+    void SetUp() override { SetUpDynamicsProcessingEffect(); }
+
+    void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+    const std::vector<DynamicsProcessing::InputGain> mInputGain;
+};
+
+TEST_P(DynamicsProcessingTestInputGain, SetAndGetInputGain) {
+    EXPECT_NO_FATAL_FAILURE(addInputGain(mInputGain));
+    SetAndGetDynamicsProcessingParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        DynamicsProcessingTest, DynamicsProcessingTestInputGain,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kDynamicsProcessingTypeUUID)),
+                           testing::ValuesIn(DynamicsProcessingTestInputGain::kInputGainTestSet)),
+        [](const auto& info) {
+            auto descriptor = std::get<INPUT_GAIN_INSTANCE_NAME>(info.param).second;
+            std::string gains =
+                    ::android::internal::ToString(std::get<INPUT_GAIN_PARAM>(info.param));
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_inputGains_" + gains;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestInputGain);
+
+/**
+ * Test DynamicsProcessing Limiter Config
+ */
+enum LimiterConfigTestParamName {
+    LIMITER_INSTANCE_NAME,
+    LIMITER_CHANNEL,
+    LIMITER_ENABLE,
+    LIMITER_LINK_GROUP,
+    LIMITER_ENGINE_IN_USE,
+    LIMITER_ADDITIONAL,
+};
+enum LimiterConfigTestAdditionalParam {
+    LIMITER_ATTACK_TIME,
+    LIMITER_RELEASE_TIME,
+    LIMITER_RATIO,
+    LIMITER_THRESHOLD,
+    LIMITER_POST_GAIN,
+    LIMITER_MAX_NUM,
+};
+using LimiterConfigTestAdditional = std::array<float, LIMITER_MAX_NUM>;
+// attachTime, releaseTime, ratio, thresh, postGain
+static constexpr std::array<LimiterConfigTestAdditional, 4> kLimiterConfigTestAdditionalParam = {
+        {{-1, -60, -2.5, -2, -3.14},
+         {-1, 60, -2.5, 2, -3.14},
+         {1, -60, 2.5, -2, 3.14},
+         {1, 60, 2.5, 2, 3.14}}};
+
+using LimiterConfigTestParams =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int32_t, bool, int32_t, bool,
+                   LimiterConfigTestAdditional>;
+
+void fillLimiterConfig(DynamicsProcessing::LimiterConfig& cfg,
+                       const LimiterConfigTestParams& params) {
+    const std::array<float, LIMITER_MAX_NUM> additional = std::get<LIMITER_ADDITIONAL>(params);
+    cfg.channel = std::get<LIMITER_CHANNEL>(params);
+    cfg.enable = std::get<LIMITER_ENABLE>(params);
+    cfg.linkGroup = std::get<LIMITER_LINK_GROUP>(params);
+    cfg.attackTimeMs = additional[LIMITER_ATTACK_TIME];
+    cfg.releaseTimeMs = additional[LIMITER_RELEASE_TIME];
+    cfg.ratio = additional[LIMITER_RATIO];
+    cfg.thresholdDb = additional[LIMITER_THRESHOLD];
+    cfg.postGainDb = additional[LIMITER_POST_GAIN];
+}
+
+class DynamicsProcessingTestLimiterConfig
+    : public ::testing::TestWithParam<LimiterConfigTestParams>,
+      public DynamicsProcessingTestHelper {
+  public:
+    DynamicsProcessingTestLimiterConfig()
+        : DynamicsProcessingTestHelper(std::get<LIMITER_INSTANCE_NAME>(GetParam())),
+          mLimiterInUseEngine(std::get<LIMITER_ENGINE_IN_USE>(GetParam())) {
+        fillLimiterConfig(mCfg, GetParam());
+    }
+
+    void SetUp() override { SetUpDynamicsProcessingEffect(); }
+
+    void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+    DynamicsProcessing::LimiterConfig mCfg;
+    bool mLimiterInUseEngine;
+};
+
+TEST_P(DynamicsProcessingTestLimiterConfig, SetAndGetLimiterConfig) {
+    mEngineConfigPreset.limiterInUse = mLimiterInUseEngine;
+    EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+    EXPECT_NO_FATAL_FAILURE(addLimiterConfig({mCfg}));
+    SetAndGetDynamicsProcessingParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        DynamicsProcessingTest, DynamicsProcessingTestLimiterConfig,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kDynamicsProcessingTypeUUID)),
+                           testing::Values(-1, 0, 1, 2),  // channel count
+                           testing::Bool(),               // enable
+                           testing::Values(3),            // link group
+                           testing::Bool(),               // engine limiter enable
+                           testing::ValuesIn(kLimiterConfigTestAdditionalParam)),  // Additional
+        [](const auto& info) {
+            auto descriptor = std::get<LIMITER_INSTANCE_NAME>(info.param).second;
+            DynamicsProcessing::LimiterConfig cfg;
+            fillLimiterConfig(cfg, info.param);
+            std::string engineLimiterInUse =
+                    std::to_string(std::get<LIMITER_ENGINE_IN_USE>(info.param));
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_limiterConfig_" +
+                               cfg.toString() + "_engineSetting_" + engineLimiterInUse;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestLimiterConfig);
+
+/**
+ * Test DynamicsProcessing ChannelConfig
+ */
+enum ChannelConfigTestParamName {
+    BAND_CHANNEL_TEST_INSTANCE_NAME,
+    BAND_CHANNEL_TEST_CHANNEL_CONFIG,
+    BAND_CHANNEL_TEST_ENGINE_IN_USE
+};
+using ChannelConfigTestParams = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
+                                           std::vector<DynamicsProcessing::ChannelConfig>, bool>;
+
+class DynamicsProcessingTestChannelConfig
+    : public ::testing::TestWithParam<ChannelConfigTestParams>,
+      public DynamicsProcessingTestHelper {
+  public:
+    DynamicsProcessingTestChannelConfig()
+        : DynamicsProcessingTestHelper(std::get<BAND_CHANNEL_TEST_INSTANCE_NAME>(GetParam())),
+          mCfg(std::get<BAND_CHANNEL_TEST_CHANNEL_CONFIG>(GetParam())),
+          mInUseEngine(std::get<BAND_CHANNEL_TEST_ENGINE_IN_USE>(GetParam())) {}
+
+    void SetUp() override { SetUpDynamicsProcessingEffect(); }
+
+    void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+    std::vector<DynamicsProcessing::ChannelConfig> mCfg;
+    const bool mInUseEngine;
+};
+
+TEST_P(DynamicsProcessingTestChannelConfig, SetAndGetPreEqChannelConfig) {
+    mEngineConfigPreset.preEqStage.inUse = mInUseEngine;
+    EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+    EXPECT_NO_FATAL_FAILURE(addPreEqChannelConfig(mCfg));
+    SetAndGetDynamicsProcessingParameters();
+}
+
+TEST_P(DynamicsProcessingTestChannelConfig, SetAndGetPostEqChannelConfig) {
+    mEngineConfigPreset.postEqStage.inUse = mInUseEngine;
+    EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+    EXPECT_NO_FATAL_FAILURE(addPostEqChannelConfig(mCfg));
+    SetAndGetDynamicsProcessingParameters();
+}
+
+TEST_P(DynamicsProcessingTestChannelConfig, SetAndGetMbcChannelConfig) {
+    mEngineConfigPreset.mbcStage.inUse = mInUseEngine;
+    EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+    EXPECT_NO_FATAL_FAILURE(addMbcChannelConfig(mCfg));
+    SetAndGetDynamicsProcessingParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        DynamicsProcessingTest, DynamicsProcessingTestChannelConfig,
+        ::testing::Combine(
+                testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                        IFactory::descriptor, kDynamicsProcessingTypeUUID)),
+                testing::ValuesIn(
+                        DynamicsProcessingTestHelper::kChannelConfigTestSet),  // channel config
+                testing::Bool()),                                              // Engine inUse
+        [](const auto& info) {
+            auto descriptor = std::get<BAND_CHANNEL_TEST_INSTANCE_NAME>(info.param).second;
+            std::string engineInUse =
+                    std::to_string(std::get<BAND_CHANNEL_TEST_ENGINE_IN_USE>(info.param));
+            std::string channelConfig = ::android::internal::ToString(
+                    std::get<BAND_CHANNEL_TEST_CHANNEL_CONFIG>(info.param));
+
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_" + channelConfig +
+                               "_engineInUse_" + engineInUse;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestChannelConfig);
+
+/**
+ * Test DynamicsProcessing EqBandConfig
+ */
+enum EqBandConfigTestParamName {
+    EQ_BAND_INSTANCE_NAME,
+    EQ_BAND_CHANNEL,
+    EQ_BAND_CHANNEL_ENABLE,
+    EQ_BAND_ENABLE,
+    EQ_BAND_CUT_OFF_FREQ,
+    EQ_BAND_GAIN,
+    EQ_BAND_STAGE_IN_USE
+};
+using EqBandConfigTestParams = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int32_t,
+                                          std::vector<DynamicsProcessing::ChannelConfig>, bool,
+                                          std::vector<std::pair<int, float>>, float, bool>;
+
+void fillEqBandConfig(std::vector<DynamicsProcessing::EqBandConfig>& cfgs,
+                      const EqBandConfigTestParams& params) {
+    const std::vector<std::pair<int, float>> cutOffFreqs = std::get<EQ_BAND_CUT_OFF_FREQ>(params);
+    int bandCount = cutOffFreqs.size();
+    cfgs.resize(bandCount);
+    for (int i = 0; i < bandCount; i++) {
+        cfgs[i].channel = std::get<EQ_BAND_CHANNEL>(params);
+        cfgs[i].band = cutOffFreqs[i].first;
+        cfgs[i].enable = std::get<EQ_BAND_ENABLE>(params);
+        cfgs[i].cutoffFrequencyHz = cutOffFreqs[i].second;
+        cfgs[i].gainDb = std::get<EQ_BAND_GAIN>(params);
+    }
+}
+
+class DynamicsProcessingTestEqBandConfig : public ::testing::TestWithParam<EqBandConfigTestParams>,
+                                           public DynamicsProcessingTestHelper {
+  public:
+    DynamicsProcessingTestEqBandConfig()
+        : DynamicsProcessingTestHelper(std::get<EQ_BAND_INSTANCE_NAME>(GetParam())),
+          mStageInUse(std::get<EQ_BAND_STAGE_IN_USE>(GetParam())),
+          mChannelConfig(std::get<EQ_BAND_CHANNEL_ENABLE>(GetParam())) {
+        fillEqBandConfig(mCfgs, GetParam());
+    }
+
+    void SetUp() override { SetUpDynamicsProcessingEffect(); }
+
+    void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+    std::vector<DynamicsProcessing::EqBandConfig> mCfgs;
+    const bool mStageInUse;
+    const std::vector<DynamicsProcessing::ChannelConfig> mChannelConfig;
+};
+
+TEST_P(DynamicsProcessingTestEqBandConfig, SetAndGetPreEqBandConfig) {
+    mEngineConfigPreset.preEqStage.inUse = mStageInUse;
+    mEngineConfigPreset.preEqStage.bandCount = mCfgs.size();
+    EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+    EXPECT_NO_FATAL_FAILURE(addPreEqChannelConfig(mChannelConfig));
+    EXPECT_NO_FATAL_FAILURE(addPreEqBandConfigs(mCfgs));
+    SetAndGetDynamicsProcessingParameters();
+}
+
+TEST_P(DynamicsProcessingTestEqBandConfig, SetAndGetPostEqBandConfig) {
+    mEngineConfigPreset.postEqStage.inUse = mStageInUse;
+    mEngineConfigPreset.postEqStage.bandCount = mCfgs.size();
+    EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+    EXPECT_NO_FATAL_FAILURE(addPostEqChannelConfig(mChannelConfig));
+    EXPECT_NO_FATAL_FAILURE(addPostEqBandConfigs(mCfgs));
+    SetAndGetDynamicsProcessingParameters();
+}
+
+std::vector<std::vector<std::pair<int, float>>> kBands{
+        {
+                {0, 600},
+                {1, 2000},
+                {2, 6000},
+                {3, 10000},
+                {4, 16000},
+        },  // 5 bands
+        {
+                {0, 800},
+                {3, 15000},
+                {2, 6000},
+                {1, 2000},
+        },  // 4 bands, unsorted
+        {
+                {0, 650},
+                {1, 2000},
+                {2, 6000},
+                {3, 10000},
+                {3, 16000},
+        },  // 5 bands, missing band
+        {
+                {0, 900},
+                {1, 8000},
+                {2, 4000},
+                {3, 12000},
+        },  // 4 bands, cutoff freq not increasing
+        {
+                {0, 450},
+                {1, 2000},
+                {7, 6000},
+                {3, 10000},
+                {4, 16000},
+        },  // bad band index
+        {
+                {0, 1},
+                {1, 8000},
+        },  // too low cutoff freq
+        {
+                {0, 1200},
+                {1, 80000},
+        },  // too high cutoff freq
+};
+
+INSTANTIATE_TEST_SUITE_P(
+        DynamicsProcessingTest, DynamicsProcessingTestEqBandConfig,
+        ::testing::Combine(
+                testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                        IFactory::descriptor, kDynamicsProcessingTypeUUID)),
+                testing::Values(-1, 0, 10),  // channel ID
+                testing::ValuesIn(
+                        DynamicsProcessingTestHelper::kChannelConfigTestSet),  // channel enable
+                testing::Bool(),                                               // band enable
+                testing::ValuesIn(kBands),       // cut off frequencies
+                testing::Values(-3.14f, 3.14f),  // gain
+                testing::Bool()),                // stage in use
+        [](const auto& info) {
+            auto descriptor = std::get<EQ_BAND_INSTANCE_NAME>(info.param).second;
+            std::vector<DynamicsProcessing::EqBandConfig> cfgs;
+            fillEqBandConfig(cfgs, info.param);
+            std::string enable =
+                    ::android::internal::ToString(std::get<EQ_BAND_CHANNEL_ENABLE>(info.param));
+            std::string bands = ::android::internal::ToString(cfgs);
+            std::string stageInUse = std::to_string(std::get<EQ_BAND_STAGE_IN_USE>(info.param));
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_" + enable + "_bands_" +
+                               bands + "_stageInUse_" + stageInUse;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestEqBandConfig);
+
+/**
+ * Test DynamicsProcessing MbcBandConfig
+ */
+
+enum MbcBandConfigParamName {
+    MBC_BAND_INSTANCE_NAME,
+    MBC_BAND_CHANNEL,
+    MBC_BAND_CHANNEL_CONFIG,
+    MBC_BAND_ENABLE,
+    MBC_BAND_CUTOFF_FREQ,
+    MBC_BAND_STAGE_IN_USE,
+    MBC_BAND_ADDITIONAL
+};
+enum MbcBandConfigAdditional {
+    MBC_ADD_ATTACK_TIME,
+    MBC_ADD_RELEASE_TIME,
+    MBC_ADD_RATIO,
+    MBC_ADD_THRESHOLD,
+    MBC_ADD_KNEE_WIDTH,
+    MBC_ADD_NOISE_GATE_THRESHOLD,
+    MBC_ADD_EXPENDER_RATIO,
+    MBC_ADD_PRE_GAIN,
+    MBC_ADD_POST_GAIN,
+    MBC_ADD_MAX_NUM
+};
+using TestParamsMbcBandConfigAdditional = std::array<float, MBC_ADD_MAX_NUM>;
+
+// attachTime, releaseTime, ratio, thresh, kneeWidth, noise, expander, preGain, postGain
+static constexpr std::array<TestParamsMbcBandConfigAdditional, 4> kMbcBandConfigAdditionalParam = {
+        {{-3, -10, -2, -2, -5, -90, -2.5, -2, -2},
+         {0, 0, 0, 0, 0, 0, 0, 0, 0},
+         {-3, 10, -2, 2, -5, 90, -2.5, 2, -2},
+         {3, 10, 2, 2, 5, 90, 2.5, 2, 2}}};
+
+using TestParamsMbcBandConfig =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int32_t,
+                   std::vector<DynamicsProcessing::ChannelConfig>, bool,
+                   std::vector<std::pair<int, float>>, bool, TestParamsMbcBandConfigAdditional>;
+
+void fillMbcBandConfig(std::vector<DynamicsProcessing::MbcBandConfig>& cfgs,
+                       const TestParamsMbcBandConfig& params) {
+    const std::vector<std::pair<int, float>> cutOffFreqs = std::get<MBC_BAND_CUTOFF_FREQ>(params);
+    const std::array<float, MBC_ADD_MAX_NUM> additional = std::get<MBC_BAND_ADDITIONAL>(params);
+    int bandCount = cutOffFreqs.size();
+    cfgs.resize(bandCount);
+    for (int i = 0; i < bandCount; i++) {
+        cfgs[i] = DynamicsProcessing::MbcBandConfig{
+                .channel = std::get<MBC_BAND_CHANNEL>(params),
+                .band = cutOffFreqs[i].first,
+                .enable = std::get<MBC_BAND_ENABLE>(params),
+                .cutoffFrequencyHz = cutOffFreqs[i].second,
+                .attackTimeMs = additional[MBC_ADD_ATTACK_TIME],
+                .releaseTimeMs = additional[MBC_ADD_RELEASE_TIME],
+                .ratio = additional[MBC_ADD_RATIO],
+                .thresholdDb = additional[MBC_ADD_THRESHOLD],
+                .kneeWidthDb = additional[MBC_ADD_KNEE_WIDTH],
+                .noiseGateThresholdDb = additional[MBC_ADD_NOISE_GATE_THRESHOLD],
+                .expanderRatio = additional[MBC_ADD_EXPENDER_RATIO],
+                .preGainDb = additional[MBC_ADD_PRE_GAIN],
+                .postGainDb = additional[MBC_ADD_POST_GAIN]};
+    }
+}
+
+class DynamicsProcessingTestMbcBandConfig
+    : public ::testing::TestWithParam<TestParamsMbcBandConfig>,
+      public DynamicsProcessingTestHelper {
+  public:
+    DynamicsProcessingTestMbcBandConfig()
+        : DynamicsProcessingTestHelper(std::get<MBC_BAND_INSTANCE_NAME>(GetParam())),
+          mStageInUse(std::get<MBC_BAND_STAGE_IN_USE>(GetParam())),
+          mChannelConfig(std::get<MBC_BAND_CHANNEL_CONFIG>(GetParam())) {
+        fillMbcBandConfig(mCfgs, GetParam());
+    }
+
+    void SetUp() override { SetUpDynamicsProcessingEffect(); }
+
+    void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+    std::vector<DynamicsProcessing::MbcBandConfig> mCfgs;
+    const bool mStageInUse;
+    const std::vector<DynamicsProcessing::ChannelConfig> mChannelConfig;
+};
+
+TEST_P(DynamicsProcessingTestMbcBandConfig, SetAndGetMbcBandConfig) {
+    mEngineConfigPreset.mbcStage.inUse = mStageInUse;
+    mEngineConfigPreset.mbcStage.bandCount = mCfgs.size();
+    EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+    EXPECT_NO_FATAL_FAILURE(addMbcChannelConfig(mChannelConfig));
+    EXPECT_NO_FATAL_FAILURE(addMbcBandConfigs(mCfgs));
+    SetAndGetDynamicsProcessingParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        DynamicsProcessingTest, DynamicsProcessingTestMbcBandConfig,
+        ::testing::Combine(
+                testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                        IFactory::descriptor, kDynamicsProcessingTypeUUID)),
+                testing::Values(-1, 0, 10),  // channel count
+                testing::ValuesIn(
+                        DynamicsProcessingTestHelper::kChannelConfigTestSet),  // channel config
+                testing::Bool(),                                               // enable
+                testing::ValuesIn(kBands),                          // cut off frequencies
+                testing::Bool(),                                    // stage in use
+                testing::ValuesIn(kMbcBandConfigAdditionalParam)),  // Additional
+        [](const auto& info) {
+            auto descriptor = std::get<MBC_BAND_INSTANCE_NAME>(info.param).second;
+            std::vector<DynamicsProcessing::MbcBandConfig> cfgs;
+            fillMbcBandConfig(cfgs, info.param);
+            std::string enable =
+                    ::android::internal::ToString(std::get<MBC_BAND_CHANNEL_CONFIG>(info.param));
+            std::string mbcBands = ::android::internal::ToString(cfgs);
+            std::string stageInUse = std::to_string(std::get<MBC_BAND_STAGE_IN_USE>(info.param));
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_enable_" + enable +
+                               "_bands_" + mbcBands + "_stageInUse_" + stageInUse;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestMbcBandConfig);
+
+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/VtsHalHapticGeneratorTargetTest.cpp b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
index d1f3b97..b8ea9c1 100644
--- a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
@@ -19,7 +19,9 @@
 #include <Utils.h>
 #include <aidl/Vintf.h>
 #include <android/binder_enums.h>
-#include <unordered_set>
+#include <map>
+#include <utility>
+#include <vector>
 
 #include "EffectHelper.h"
 
@@ -87,12 +89,11 @@
         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_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt, &ret, EX_NONE));
         ASSERT_NE(nullptr, mEffect);
     }
 
@@ -101,15 +102,6 @@
         ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
     }
 
-    Parameter::Specific getDefaultParamSpecific() {
-        HapticGenerator::HapticScale hapticScale = {.id = 0,
-                                                    .scale = HapticGenerator::VibratorScale::MUTE};
-        HapticGenerator hg = HapticGenerator::make<HapticGenerator::hapticScale>(hapticScale);
-        Parameter::Specific specific =
-                Parameter::Specific::make<Parameter::Specific::hapticGenerator>(hg);
-        return specific;
-    }
-
     static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
     std::shared_ptr<IFactory> mFactory;
     std::shared_ptr<IEffect> mEffect;
@@ -122,13 +114,13 @@
 
     void SetAndGetHapticGeneratorParameters() {
         for (auto& it : mTags) {
-            auto& tag = it.first;
-            auto& hg = it.second;
+            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>(hg);
+            specific.set<Parameter::Specific::hapticGenerator>(setHg);
             expectParam.set<Parameter::specific>(specific);
             EXPECT_STATUS(EX_NONE, mEffect->setParameter(expectParam)) << expectParam.toString();
 
@@ -139,15 +131,16 @@
             hgId.set<HapticGenerator::Id::commonTag>(tag);
             id.set<Parameter::Id::hapticGeneratorTag>(hgId);
             EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
-            EXPECT_EQ(expectParam, getParam);
+            EXPECT_EQ(expectParam, getParam) << expectParam.toString() << "\n"
+                                             << getParam.toString();
         }
     }
 
     void addHapticScaleParam(int id, HapticGenerator::VibratorScale scale) {
-        HapticGenerator hg;
-        HapticGenerator::HapticScale hapticScale = {.id = id, .scale = scale};
-        hg.set<HapticGenerator::hapticScale>(hapticScale);
-        mTags.push_back({HapticGenerator::hapticScale, hg});
+        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) {
@@ -161,7 +154,8 @@
     }
 
   private:
-    std::vector<std::pair<HapticGenerator::Tag, HapticGenerator>> mTags;
+    enum ParamTestEnum { PARAM_TEST_TAG, PARAM_TEST_TARGET };
+    std::vector<std::tuple<HapticGenerator::Tag, HapticGenerator>> mTags;
 
     void CleanUp() { mTags.clear(); }
 };
@@ -171,6 +165,12 @@
     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));
@@ -212,7 +212,7 @@
         ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
                                    IFactory::descriptor, kHapticGeneratorTypeUUID)),
                            testing::Values(MIN_ID - 1),
-                           testing::Values(HapticGenerator::VibratorScale::MUTE),
+                           testing::Values(HapticGenerator::VibratorScale::NONE),
                            testing::Values(MIN_FLOAT), testing::Values(MIN_FLOAT),
                            testing::Values(MIN_FLOAT)),
         [](const testing::TestParamInfo<HapticGeneratorParamTest::ParamType>& info) {
@@ -236,9 +236,202 @@
                     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);
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/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/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/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/audiocontrol/aidl/default/audiocontrol-default.xml b/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
index e82f6fa..3452ae9 100644
--- a/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
+++ b/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
@@ -1,5 +1,6 @@
 <manifest version="2.0" type="device">
     <hal format="aidl">
+        <version>2</version>
         <name>android.hardware.automotive.audiocontrol</name>
         <fqname>IAudioControl/default</fqname>
     </hal>
diff --git a/automotive/can/aidl/default/tools/configurator/canprototools.cpp b/automotive/can/aidl/default/tools/configurator/canprototools.cpp
index 2aea315..84edd94 100644
--- a/automotive/can/aidl/default/tools/configurator/canprototools.cpp
+++ b/automotive/can/aidl/default/tools/configurator/canprototools.cpp
@@ -51,15 +51,20 @@
     return std::string(buff, 0, std::min(n, got));
 }
 
-std::optional<CanBusConfig> parseConfigFile(const std::string& filepath) {
-    std::ifstream cfg_stream(filepath);
-
-    // text headers that would be present in a plaintext proto config file.
+/*
+  parseConfigFile *used to* contain the body of parseConfigStream. However, it seems there's some
+  sort of odd behavior with IstreamInputStream and/or TextFormat::Parse, which causes HW Address
+  Sanitizer to flag a "tag-mismatch" in this function. Having the ifstream defined in a wrapper
+  function seems to solve this problem. The exact cause of this problem is yet unknown, but probably
+  lies somewhere in the protobuf implementation.
+*/
+static __attribute__((noinline)) std::optional<CanBusConfig> parseConfigStream(
+        std::ifstream& cfg_stream) {
     static const std::array<std::string, 3> text_headers = {"buses", "#", "controller"};
     auto cfg_file_snippet = readString(cfg_stream, 10);
 
     if (!cfg_file_snippet.has_value()) {
-        LOG(ERROR) << "Can't open " << filepath << " for reading";
+        LOG(ERROR) << "Can't read config from stream (maybe failed to open file?)";
         return std::nullopt;
     }
     cfg_stream.seekg(0);
@@ -77,16 +82,25 @@
     if (text_format) {
         google::protobuf::io::IstreamInputStream pb_stream(&cfg_stream);
         if (!google::protobuf::TextFormat::Parse(&pb_stream, &config)) {
-            LOG(ERROR) << "Failed to parse (text format) " << filepath;
+            LOG(ERROR) << "Parsing text format config failed";
             return std::nullopt;
         }
     } else if (!config.ParseFromIstream(&cfg_stream)) {
-        LOG(ERROR) << "Failed to parse (binary format) " << filepath;
+        LOG(ERROR) << "Parsing binary format config failed";
         return std::nullopt;
     }
     return config;
 }
 
+std::optional<CanBusConfig> parseConfigFile(const std::string& filepath) {
+    std::ifstream cfg_stream(filepath);
+    auto cfg_maybe = parseConfigStream(cfg_stream);
+    if (!cfg_maybe.has_value()) {
+        LOG(ERROR) << "Failed to parse " << filepath;
+    }
+    return cfg_maybe;
+}
+
 std::optional<BusConfig> fromPbBus(const Bus& pb_bus) {
     BusConfig bus_cfg = {};
     bus_cfg.name = pb_bus.name();
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 9e4f252..83b0d94 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -2117,6 +2117,12 @@
         | VehicleArea:SEAT),
 
     /**
+     * DO NOT USE
+     *
+     * This property is defined as type VehicleArea:GLOBAL, which means all seats use the same
+     * value. Use SEAT_HEADREST_HEIGHT_POS_V2 instead which fixes this issue by being defined as
+     * type VehicleArea:SEAT.
+     *
      * Headrest height position
      *
      * Sets the headrest height.
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/EvStoppingMode.aidl
similarity index 87%
copy from radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
copy to automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/EvStoppingMode.aidl
index e89a40f..3be8d12 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/EvStoppingMode.aidl
@@ -31,10 +31,11 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.radio.network;
-@Backing(type="int") @JavaDerive(toString=true) @VintfStability
-enum LocationResponseType {
-  REJECTED = 0,
-  ACCEPTED_NO_LOCATION_PROVIDED = 1,
-  ACCEPTED_LOCATION_PROVIDED = 2,
+package android.hardware.automotive.vehicle;
+@Backing(type="int") @VintfStability
+enum EvStoppingMode {
+  OTHER = 0,
+  CREEP = 1,
+  ROLL = 2,
+  HOLD = 3,
 }
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
index c3b3e00..914787e 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -80,6 +80,7 @@
   IGNITION_STATE = 289408009,
   ABS_ACTIVE = 287310858,
   TRACTION_CONTROL_ACTIVE = 287310859,
+  EV_STOPPING_MODE = 289408013,
   HVAC_FAN_SPEED = 356517120,
   HVAC_FAN_DIRECTION = 356517121,
   HVAC_TEMPERATURE_CURRENT = 358614274,
@@ -155,11 +156,14 @@
   SEAT_LUMBAR_SIDE_SUPPORT_POS = 356518803,
   SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 356518804,
   SEAT_HEADREST_HEIGHT_POS = 289409941,
+  SEAT_HEADREST_HEIGHT_POS_V2 = 356518820,
   SEAT_HEADREST_HEIGHT_MOVE = 356518806,
   SEAT_HEADREST_ANGLE_POS = 356518807,
   SEAT_HEADREST_ANGLE_MOVE = 356518808,
   SEAT_HEADREST_FORE_AFT_POS = 356518809,
   SEAT_HEADREST_FORE_AFT_MOVE = 356518810,
+  SEAT_FOOTWELL_LIGHTS_STATE = 356518811,
+  SEAT_FOOTWELL_LIGHTS_SWITCH = 356518812,
   SEAT_EASY_ACCESS_ENABLED = 354421661,
   SEAT_AIRBAG_ENABLED = 354421662,
   SEAT_CUSHION_SIDE_SUPPORT_POS = 356518815,
@@ -195,6 +199,8 @@
   CABIN_LIGHTS_SWITCH = 289410818,
   READING_LIGHTS_STATE = 356519683,
   READING_LIGHTS_SWITCH = 356519684,
+  STEERING_WHEEL_LIGHTS_STATE = 289410828,
+  STEERING_WHEEL_LIGHTS_SWITCH = 289410829,
   SUPPORT_CUSTOMIZE_VENDOR_PERMISSION = 287313669,
   DISABLED_OPTIONAL_FEATURES = 286265094,
   INITIAL_USER_INFO = 299896583,
@@ -231,4 +237,14 @@
   GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT = 289410887,
   SUPPORTED_PROPERTY_IDS = 289476424,
   SHUTDOWN_REQUEST = 289410889,
+  AUTOMATIC_EMERGENCY_BRAKING_ENABLED = 287313920,
+  FORWARD_COLLISION_WARNING_ENABLED = 287313922,
+  BLIND_SPOT_WARNING_ENABLED = 287313924,
+  LANE_DEPARTURE_WARNING_ENABLED = 287313926,
+  LANE_KEEP_ASSIST_ENABLED = 287313928,
+  LANE_CENTERING_ASSIST_ENABLED = 287313930,
+  EMERGENCY_LANE_KEEP_ASSIST_ENABLED = 287313933,
+  ADAPTIVE_CRUISE_CONTROL_ENABLED = 287313935,
+  HANDS_ON_DETECTION_ENABLED = 287313941,
+  DRIVER_ATTENTION_MONITORING_ENABLED = 287313944,
 }
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/EvStoppingMode.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/EvStoppingMode.aidl
new file mode 100644
index 0000000..8c5ac46
--- /dev/null
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/EvStoppingMode.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.automotive.vehicle;
+
+/**
+ * Used by EV_STOPPING_MODE to enumerate the current state of the stopping mode.
+ *
+ * This enum may be extended to include more states in the future.
+ */
+@VintfStability
+@Backing(type="int")
+enum EvStoppingMode {
+    /**
+     * Other EV stopping mode. Ideally, this should never be used.
+     */
+    OTHER = 0,
+    /**
+     * Vehicle slowly moves forward when the brake pedal is released.
+     */
+    CREEP = 1,
+    /**
+     * Vehicle rolls freely when the brake pedal is released (similar to neutral gear).
+     */
+    ROLL = 2,
+    /**
+     * Vehicle stops and holds its position when the brake pedal is released.
+     */
+    HOLD = 3,
+}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
index 4d0b77b..e776154 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -603,6 +603,20 @@
     TRACTION_CONTROL_ACTIVE = 0x040B + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
     /**
+     * Represents property for the current stopping mode of the vehicle.
+     *
+     * For the global area ID (0), the VehicleAreaConfig#supportedEnumValues must be defined unless
+     * all enum values of EvStoppingMode are supported.
+     *
+     * The EvStoppingMode enum may be extended to include more states in the future.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     * @data_enum EvStoppingMode
+     */
+    EV_STOPPING_MODE =
+            0x040D + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+    /**
      * HVAC Properties
      *
      * Additional rules for mapping a zoned HVAC property (except
@@ -1760,7 +1774,11 @@
     SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 0x0B94 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
     /**
-     * Headrest height position
+     * (Deprecated) Headrest height position
+     *
+     * This property is deprecated because it is defined as type VehicleArea:GLOBAL, which means all
+     * seats use the same value. Use SEAT_HEADREST_HEIGHT_POS_V2 instead which fixes this issue by
+     * being defined as type VehicleArea:SEAT.
      *
      * Sets the headrest height.
      * Max value indicates tallest setting.
@@ -1771,6 +1789,25 @@
      */
     SEAT_HEADREST_HEIGHT_POS = 0x0B95 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+
+    /**
+     * Headrest height position
+     *
+     * Sets the headrest height for supported seats. VehiclePropConfig.areaConfigs specifies which
+     * seats are supported.
+     *
+     * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between
+     * minInt32Value and maxInt32Value must be supported. The maxInt32Value indicates the tallest
+     * setting and the minInt32Value indicates the shortest setting.
+     *
+     * This value is not in any particular unit but in a specified range of steps.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    SEAT_HEADREST_HEIGHT_POS_V2 =
+            0x0BA4 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
+
     /**
      * Headrest height move
      *
@@ -1824,6 +1861,48 @@
     SEAT_HEADREST_FORE_AFT_MOVE = 0x0B9A + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
     /**
+     * Represents property for the seat footwell lights state.
+     *
+     * SEAT_FOOTWELL_LIGHTS_STATE reflects the current state of the lights at any point in time.
+     * This is different from the function of SEAT_FOOTWELL_LIGHTS_SWITCH which represents the
+     * position of the switch controlling the lights. Therefore, SEAT_FOOTWELL_LIGHTS_STATE may not
+     * match the value of SEAT_FOOTWELL_LIGHTS_SWITCH (e.g. SEAT_FOOTWELL_LIGHTS_SWITCH=AUTOMATIC
+     * and SEAT_FOOTWELL_LIGHTS_STATE=ON).
+     *
+     * This property should only be implemented if SEAT_FOOTWELL_LIGHTS_STATE's value may be
+     * different from that of CABIN_LIGHTS_STATE.
+     *
+     * For each supported area ID, the VehicleAreaConfig#supportedEnumValues must be defined unless
+     * all enum values of VehicleLightState are supported.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ
+     * @data_enum VehicleLightState
+     */
+    SEAT_FOOTWELL_LIGHTS_STATE =
+            0x0B9B + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
+    /**
+     * Represents property for the seat footwell lights switch.
+     *
+     * SEAT_FOOTWELL_LIGHTS_SWITCH represents the position of the switch controlling the lights.
+     * This is different from the function of SEAT_FOOTWELL_LIGHTS_STATE which reflects the current
+     * state of the lights at any point in time. Therefore, SEAT_FOOTWELL_LIGHTS_SWITCH may not
+     * match the value of SEAT_FOOTWELL_LIGHTS_STATE (e.g. SEAT_FOOTWELL_LIGHTS_SWITCH=AUTOMATIC and
+     * SEAT_FOOTWELL_LIGHTS_STATE=ON).
+     *
+     * This property should only be implemented if SEAT_FOOTWELL_LIGHTS_SWITCH's value may be
+     * different from that of CABIN_LIGHTS_SWITCH.
+     *
+     * For each supported area ID, the VehicleAreaConfig#supportedEnumValues must be defined unless
+     * all enum values of VehicleLightSwitch are supported.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     * @data_enum VehicleLightSwitch
+     */
+    SEAT_FOOTWELL_LIGHTS_SWITCH =
+            0x0B9C + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
+    /**
      * Represents property for Seat easy access feature.
      *
      * If true, the seat will automatically adjust to make it easier for the occupant to enter and
@@ -2414,6 +2493,48 @@
     READING_LIGHTS_SWITCH = 0x0F04 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
     /**
+     * Steering wheel lights state
+     *
+     * Represents the current state of the steering wheel lights. This is different from
+     * STEERING_WHEEL_LIGHTS_SWITCH which represents the position of the switch controlling
+     * the lights. Therefore, STEERING_WHEEL_LIGHTS_STATE may not match the value of
+     * STEERING_WHEEL_LIGHTS_SWITCH (e.g. STEERING_WHEEL_LIGHTS_SWITCH=AUTOMATIC and
+     * STEERING_WHEEL_LIGHTS_STATE=ON).
+     *
+     * This property should only be implemented if STEERING_WHEEL_LIGHTS_STATE's value may be
+     * different from that of CABIN_LIGHTS_STATE.
+     *
+     * For the global area ID (0), the VehicleAreaConfig#supportedEnumValues must be defined unless
+     * all enum values of VehicleLightState are supported.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ
+     * @data_enum VehicleLightState
+     */
+    STEERING_WHEEL_LIGHTS_STATE =
+            0x0F0C + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+    /**
+     * Steering wheel lights switch
+     *
+     * Represents the position of the switch controlling the steering wheel lights. This is
+     * different from STEERING_WHEEL_LIGHTS_STATE which represents the current state of the steering
+     * wheel lights. Therefore, STEERING_WHEEL_LIGHTS_SWITCH may not match the value of
+     * STEERING_WHEEL_LIGHTS_STATE (e.g. STEERING_WHEEL_LIGHTS_SWITCH=AUTOMATIC and
+     * STEERING_WHEEL_LIGHTS_STATE=ON).
+     *
+     * This property should only be implemented if STEERING_WHEEL_LIGHTS_SWITCH's value may be
+     * different from that of CABIN_LIGHTS_SWITCH.
+     *
+     * For the global area ID (0), the VehicleAreaConfig#supportedEnumValues must be defined unless
+     * all enum values of VehicleLightSwitch are supported.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     * @data_enum VehicleLightSwitch
+     */
+    STEERING_WHEEL_LIGHTS_SWITCH =
+            0x0F0D + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+    /**
      * Support customize permissions for vendor properties
      *
      * Implement this property if vehicle hal support customize vendor permissions feature.
@@ -3296,4 +3417,183 @@
      */
     SHUTDOWN_REQUEST =
             0x0F49 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+
+    /***************************************************************************
+     * Start of ADAS Properties
+     * Allocate IDs in range of 0x1000 (inclusive) to 0x1100 (exclusive) for ADAS properties
+     **************************************************************************/
+
+    /**
+     * Enable or disable automatic emergency braking (AEB).
+     *
+     * Set true to enable AEB and false to disable AEB. When AEB is enabled, the ADAS system in the
+     * vehicle should be turned on and monitoring to avoid potential collisions.
+     *
+     * This property is defined as read_write, but OEMs have the option to implement it as read
+     * only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    AUTOMATIC_EMERGENCY_BRAKING_ENABLED =
+            0x1000 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /**
+     * Enable or disable forward collision warning (FCW).
+     *
+     * Set true to enable FCW and false to disable FCW. When FCW is enabled, the ADAS system in the
+     * vehicle should be turned on and monitoring for potential collisions.
+     *
+     * This property is defined as read_write, but OEMs have the option to implement it as read
+     * only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    FORWARD_COLLISION_WARNING_ENABLED =
+            0x1002 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /**
+     * Enable and disable blind spot warning (BSW).
+     *
+     * Set true to enable BSW and false to disable BSW. When BSW is enabled, the ADAS system in the
+     * vehicle should be turned on and monitoring for objects in the vehicle’s blind spots.
+     *
+     * This property is defined as read_write, but OEMs have the option to implement it as read
+     * only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    BLIND_SPOT_WARNING_ENABLED =
+            0x1004 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /**
+     * Enable or disable lane departure warning (LDW).
+     *
+     * Set true to enable LDW and false to disable LDW. When LDW is enabled, the ADAS system in the
+     * vehicle should be turned on and monitoring if the vehicle is approaching or crossing lane
+     * lines, in which case a warning will be given.
+     *
+     * This property is defined as read_write, but OEMs have the option to implement it as read
+     * only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    LANE_DEPARTURE_WARNING_ENABLED =
+            0x1006 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /**
+     * Enable or disable Lane Keep Assist (LKA).
+     *
+     * Set true to enable LKA and false to disable LKA. When LKA is enabled, the ADAS system in the
+     * vehicle should be turned on and monitoring if the driver unintentionally drifts toward or
+     * over the lane marking. If an unintentional lane departure is detected, the system applies
+     * steering control to return the vehicle into the current lane.
+     *
+     * This is different from Lane Centering Assist (LCA) which, when activated, applies continuous
+     * steering control to keep the vehicle centered in the current lane.
+     *
+     * This property is defined as read_write, but OEMs have the option to implement it as read
+     * only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    LANE_KEEP_ASSIST_ENABLED =
+            0x1008 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /**
+     * Enable or disable lane centering assist (LCA).
+     *
+     * Set true to enable LCA and false to disable LCA. When LCA is enabled, the ADAS system in the
+     * vehicle should be turned on and waiting for an activation signal from the driver. Once the
+     * feature is activated, the ADAS system should be steering the vehicle to keep it centered in
+     * its current lane.
+     *
+     * This is different from Lane Keep Assist (LKA) which monitors if the driver unintentionally
+     * drifts toward or over the lane marking. If an unintentional lane departure is detected, the
+     * system applies steering control to return the vehicle into the current lane.
+     *
+     * This property is defined as read_write, but OEMs have the option to implement it as read
+     * only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    LANE_CENTERING_ASSIST_ENABLED =
+            0x100A + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /*
+     * Enable or disable emergency lane keep assist (ELKA).
+     *
+     * Set true to enable ELKA and false to disable ELKA. When ELKA is enabled, the ADAS system in
+     * the vehicle should be on and monitoring for unsafe lane changes by the driver. When an unsafe
+     * maneuver is detected, ELKA alerts the driver and applies steering corrections to keep the
+     * vehicle in its original lane.
+     *
+     * This property is defined as read_write, but OEMs have the option to implement it as read
+     * only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    EMERGENCY_LANE_KEEP_ASSIST_ENABLED =
+            0x100D + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /**
+     * Enable or disable adaptive cruise control (ACC).
+     *
+     * Set true to enable ACC and false to disable ACC. When ACC is enabled, the ADAS system in the
+     * vehicle should be turned on and waiting for an activation signal from the driver. Once the
+     * feature is activated, the ADAS system in the car should be accelerating and braking in a way
+     * that allows the vehicle to maintain a set speed and to maintain a set distance gap from a
+     * leading vehicle.
+     *
+     * This property is defined as read_write, but OEMs have the option to implement it as read
+     * only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    ADAPTIVE_CRUISE_CONTROL_ENABLED =
+            0x100F + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /**
+     * Enable or disable hands on detection (HOD).
+     *
+     * Set true to enable HOD and false to disable HOD. When HOD is enabled, a system inside the
+     * vehicle should be monitoring the presence of the driver's hands on the steering wheel and
+     * send a warning if it detects that the driver's hands are no longer on the steering wheel.
+     *
+     * This property is defined as read_write, but OEMs have the option to implement it as read
+     * only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    HANDS_ON_DETECTION_ENABLED =
+            0x1015 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /**
+     * Enable or disable driver attention monitoring.
+     *
+     * Set true to enable driver attention monitoring and false to disable driver attention
+     * monitoring. When driver attention monitoring is enabled, a system inside the vehicle should
+     * be monitoring the attention level of the driver and should send a warning if it detects that
+     * the driver is distracted.
+     *
+     * This property is defined as read_write, but OEMs have the option to implement it as read
+     * only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    DRIVER_ATTENTION_MONITORING_ENABLED =
+            0x1018 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /***************************************************************************
+     * End of ADAS Properties
+     **************************************************************************/
 }
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
index 75b371f..8b77040 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
@@ -80,6 +80,7 @@
         {VehicleProperty::IGNITION_STATE, VehiclePropertyAccess::READ},
         {VehicleProperty::ABS_ACTIVE, VehiclePropertyAccess::READ},
         {VehicleProperty::TRACTION_CONTROL_ACTIVE, VehiclePropertyAccess::READ},
+        {VehicleProperty::EV_STOPPING_MODE, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::HVAC_FAN_SPEED, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::HVAC_FAN_DIRECTION, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::HVAC_TEMPERATURE_CURRENT, VehiclePropertyAccess::READ},
@@ -155,11 +156,14 @@
         {VehicleProperty::SEAT_LUMBAR_SIDE_SUPPORT_POS, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_LUMBAR_SIDE_SUPPORT_MOVE, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_HEADREST_HEIGHT_POS, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::SEAT_HEADREST_HEIGHT_POS_V2, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_HEADREST_HEIGHT_MOVE, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_HEADREST_ANGLE_POS, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_HEADREST_ANGLE_MOVE, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_HEADREST_FORE_AFT_POS, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_HEADREST_FORE_AFT_MOVE, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::SEAT_FOOTWELL_LIGHTS_STATE, VehiclePropertyAccess::READ},
+        {VehicleProperty::SEAT_FOOTWELL_LIGHTS_SWITCH, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_EASY_ACCESS_ENABLED, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_AIRBAG_ENABLED, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_POS, VehiclePropertyAccess::READ_WRITE},
@@ -195,6 +199,8 @@
         {VehicleProperty::CABIN_LIGHTS_SWITCH, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::READING_LIGHTS_STATE, VehiclePropertyAccess::READ},
         {VehicleProperty::READING_LIGHTS_SWITCH, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::STEERING_WHEEL_LIGHTS_STATE, VehiclePropertyAccess::READ},
+        {VehicleProperty::STEERING_WHEEL_LIGHTS_SWITCH, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SUPPORT_CUSTOMIZE_VENDOR_PERMISSION, VehiclePropertyAccess::READ},
         {VehicleProperty::DISABLED_OPTIONAL_FEATURES, VehiclePropertyAccess::READ},
         {VehicleProperty::INITIAL_USER_INFO, VehiclePropertyAccess::READ_WRITE},
@@ -231,6 +237,16 @@
         {VehicleProperty::GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT, VehiclePropertyAccess::READ},
         {VehicleProperty::SUPPORTED_PROPERTY_IDS, VehiclePropertyAccess::READ},
         {VehicleProperty::SHUTDOWN_REQUEST, VehiclePropertyAccess::WRITE},
+        {VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::BLIND_SPOT_WARNING_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::LANE_DEPARTURE_WARNING_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::LANE_KEEP_ASSIST_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::LANE_CENTERING_ASSIST_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::EMERGENCY_LANE_KEEP_ASSIST_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::ADAPTIVE_CRUISE_CONTROL_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::HANDS_ON_DETECTION_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::DRIVER_ATTENTION_MONITORING_ENABLED, VehiclePropertyAccess::READ_WRITE},
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
index 6e797b9..d7e87e2 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
@@ -80,6 +80,7 @@
         {VehicleProperty::IGNITION_STATE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::ABS_ACTIVE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::TRACTION_CONTROL_ACTIVE, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::EV_STOPPING_MODE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::HVAC_FAN_SPEED, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::HVAC_FAN_DIRECTION, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::HVAC_TEMPERATURE_CURRENT, VehiclePropertyChangeMode::ON_CHANGE},
@@ -155,11 +156,14 @@
         {VehicleProperty::SEAT_LUMBAR_SIDE_SUPPORT_POS, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_LUMBAR_SIDE_SUPPORT_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_HEADREST_HEIGHT_POS, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::SEAT_HEADREST_HEIGHT_POS_V2, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_HEADREST_HEIGHT_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_HEADREST_ANGLE_POS, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_HEADREST_ANGLE_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_HEADREST_FORE_AFT_POS, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_HEADREST_FORE_AFT_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::SEAT_FOOTWELL_LIGHTS_STATE, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::SEAT_FOOTWELL_LIGHTS_SWITCH, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_EASY_ACCESS_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_AIRBAG_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_POS, VehiclePropertyChangeMode::ON_CHANGE},
@@ -195,6 +199,8 @@
         {VehicleProperty::CABIN_LIGHTS_SWITCH, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::READING_LIGHTS_STATE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::READING_LIGHTS_SWITCH, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::STEERING_WHEEL_LIGHTS_STATE, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::STEERING_WHEEL_LIGHTS_SWITCH, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SUPPORT_CUSTOMIZE_VENDOR_PERMISSION, VehiclePropertyChangeMode::STATIC},
         {VehicleProperty::DISABLED_OPTIONAL_FEATURES, VehiclePropertyChangeMode::STATIC},
         {VehicleProperty::INITIAL_USER_INFO, VehiclePropertyChangeMode::ON_CHANGE},
@@ -231,6 +237,16 @@
         {VehicleProperty::GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT, VehiclePropertyChangeMode::STATIC},
         {VehicleProperty::SUPPORTED_PROPERTY_IDS, VehiclePropertyChangeMode::STATIC},
         {VehicleProperty::SHUTDOWN_REQUEST, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::BLIND_SPOT_WARNING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::LANE_DEPARTURE_WARNING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::LANE_KEEP_ASSIST_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::LANE_CENTERING_ASSIST_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::EMERGENCY_LANE_KEEP_ASSIST_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::ADAPTIVE_CRUISE_CONTROL_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::HANDS_ON_DETECTION_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::DRIVER_ATTENTION_MONITORING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
index 455d3d4..14600f0 100644
--- a/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
@@ -72,6 +72,7 @@
         Map.entry(VehicleProperty.IGNITION_STATE, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.ABS_ACTIVE, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.TRACTION_CONTROL_ACTIVE, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.EV_STOPPING_MODE, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.HVAC_FAN_SPEED, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.HVAC_FAN_DIRECTION, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.HVAC_TEMPERATURE_CURRENT, VehiclePropertyAccess.READ),
@@ -147,11 +148,14 @@
         Map.entry(VehicleProperty.SEAT_LUMBAR_SIDE_SUPPORT_POS, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_LUMBAR_SIDE_SUPPORT_MOVE, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_HEADREST_HEIGHT_POS, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.SEAT_HEADREST_HEIGHT_POS_V2, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_HEADREST_HEIGHT_MOVE, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_HEADREST_ANGLE_POS, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_HEADREST_ANGLE_MOVE, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_HEADREST_FORE_AFT_POS, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_HEADREST_FORE_AFT_MOVE, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.SEAT_FOOTWELL_LIGHTS_STATE, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.SEAT_FOOTWELL_LIGHTS_SWITCH, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_EASY_ACCESS_ENABLED, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_AIRBAG_ENABLED, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_CUSHION_SIDE_SUPPORT_POS, VehiclePropertyAccess.READ_WRITE),
@@ -187,6 +191,8 @@
         Map.entry(VehicleProperty.CABIN_LIGHTS_SWITCH, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.READING_LIGHTS_STATE, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.READING_LIGHTS_SWITCH, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.STEERING_WHEEL_LIGHTS_STATE, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.STEERING_WHEEL_LIGHTS_SWITCH, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SUPPORT_CUSTOMIZE_VENDOR_PERMISSION, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.DISABLED_OPTIONAL_FEATURES, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.INITIAL_USER_INFO, VehiclePropertyAccess.READ_WRITE),
@@ -222,7 +228,17 @@
         Map.entry(VehicleProperty.VEHICLE_CURB_WEIGHT, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.SUPPORTED_PROPERTY_IDS, VehiclePropertyAccess.READ),
-        Map.entry(VehicleProperty.SHUTDOWN_REQUEST, VehiclePropertyAccess.WRITE)
+        Map.entry(VehicleProperty.SHUTDOWN_REQUEST, VehiclePropertyAccess.WRITE),
+        Map.entry(VehicleProperty.AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.BLIND_SPOT_WARNING_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.LANE_DEPARTURE_WARNING_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.LANE_KEEP_ASSIST_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.LANE_CENTERING_ASSIST_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.EMERGENCY_LANE_KEEP_ASSIST_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.ADAPTIVE_CRUISE_CONTROL_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.HANDS_ON_DETECTION_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.DRIVER_ATTENTION_MONITORING_ENABLED, VehiclePropertyAccess.READ_WRITE)
     );
 
 }
diff --git a/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
index aaa344f..864f392 100644
--- a/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
@@ -72,6 +72,7 @@
         Map.entry(VehicleProperty.IGNITION_STATE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.ABS_ACTIVE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.TRACTION_CONTROL_ACTIVE, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.EV_STOPPING_MODE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.HVAC_FAN_SPEED, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.HVAC_FAN_DIRECTION, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.HVAC_TEMPERATURE_CURRENT, VehiclePropertyChangeMode.ON_CHANGE),
@@ -147,11 +148,14 @@
         Map.entry(VehicleProperty.SEAT_LUMBAR_SIDE_SUPPORT_POS, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_LUMBAR_SIDE_SUPPORT_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_HEADREST_HEIGHT_POS, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.SEAT_HEADREST_HEIGHT_POS_V2, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_HEADREST_HEIGHT_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_HEADREST_ANGLE_POS, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_HEADREST_ANGLE_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_HEADREST_FORE_AFT_POS, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_HEADREST_FORE_AFT_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.SEAT_FOOTWELL_LIGHTS_STATE, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.SEAT_FOOTWELL_LIGHTS_SWITCH, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_EASY_ACCESS_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_AIRBAG_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_CUSHION_SIDE_SUPPORT_POS, VehiclePropertyChangeMode.ON_CHANGE),
@@ -187,6 +191,8 @@
         Map.entry(VehicleProperty.CABIN_LIGHTS_SWITCH, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.READING_LIGHTS_STATE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.READING_LIGHTS_SWITCH, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.STEERING_WHEEL_LIGHTS_STATE, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.STEERING_WHEEL_LIGHTS_SWITCH, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SUPPORT_CUSTOMIZE_VENDOR_PERMISSION, VehiclePropertyChangeMode.STATIC),
         Map.entry(VehicleProperty.DISABLED_OPTIONAL_FEATURES, VehiclePropertyChangeMode.STATIC),
         Map.entry(VehicleProperty.INITIAL_USER_INFO, VehiclePropertyChangeMode.ON_CHANGE),
@@ -222,7 +228,17 @@
         Map.entry(VehicleProperty.VEHICLE_CURB_WEIGHT, VehiclePropertyChangeMode.STATIC),
         Map.entry(VehicleProperty.GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT, VehiclePropertyChangeMode.STATIC),
         Map.entry(VehicleProperty.SUPPORTED_PROPERTY_IDS, VehiclePropertyChangeMode.STATIC),
-        Map.entry(VehicleProperty.SHUTDOWN_REQUEST, VehiclePropertyChangeMode.ON_CHANGE)
+        Map.entry(VehicleProperty.SHUTDOWN_REQUEST, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.BLIND_SPOT_WARNING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.LANE_DEPARTURE_WARNING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.LANE_KEEP_ASSIST_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.LANE_CENTERING_ASSIST_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.EMERGENCY_LANE_KEEP_ASSIST_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.ADAPTIVE_CRUISE_CONTROL_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.HANDS_ON_DETECTION_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.DRIVER_ATTENTION_MONITORING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE)
     );
 
 }
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
index 20048a2..5521ed1 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
@@ -89,6 +89,7 @@
         {"SEAT_2_LEFT", SEAT_2_LEFT},
         {"SEAT_2_RIGHT", SEAT_2_RIGHT},
         {"SEAT_2_CENTER", SEAT_2_CENTER},
+        {"SEAT_2_LEFT_2_RIGHT_2_CENTER", SEAT_2_LEFT | SEAT_2_RIGHT | SEAT_2_CENTER},
         {"WHEEL_REAR_RIGHT", WHEEL_REAR_RIGHT},
         {"WHEEL_REAR_LEFT", WHEEL_REAR_LEFT},
         {"WHEEL_FRONT_RIGHT", WHEEL_FRONT_RIGHT},
@@ -107,7 +108,11 @@
         {"LIGHT_STATE_ON", LIGHT_STATE_ON},
         {"LIGHT_STATE_OFF", LIGHT_STATE_OFF},
         {"LIGHT_SWITCH_OFF", LIGHT_SWITCH_OFF},
+        {"LIGHT_SWITCH_ON", LIGHT_SWITCH_ON},
         {"LIGHT_SWITCH_AUTO", LIGHT_SWITCH_AUTO},
+        {"EV_STOPPING_MODE_CREEP", EV_STOPPING_MODE_CREEP},
+        {"EV_STOPPING_MODE_ROLL", EV_STOPPING_MODE_ROLL},
+        {"EV_STOPPING_MODE_HOLD", EV_STOPPING_MODE_HOLD},
         {"MIRROR_DRIVER_LEFT_RIGHT",
          toInt(VehicleAreaMirror::DRIVER_LEFT) | toInt(VehicleAreaMirror::DRIVER_RIGHT)},
 #ifdef ENABLE_VEHICLE_HAL_TEST_PROPERTIES
diff --git a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
index c17a2e2..8181769 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
+++ b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
@@ -861,6 +861,41 @@
             ]
         },
         {
+            "property": "VehicleProperty::SEAT_HEADREST_HEIGHT_POS_V2",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": "Constants::SEAT_1_LEFT",
+                    "minInt32Value": 0,
+                    "maxInt32Value": 10
+                },
+                {
+                    "areaId": "Constants::SEAT_1_RIGHT",
+                    "minInt32Value": 0,
+                    "maxInt32Value": 10
+                },
+                {
+                    "areaId": "Constants::SEAT_2_LEFT",
+                    "minInt32Value": 0,
+                    "maxInt32Value": 10
+                },
+                {
+                    "areaId": "Constants::SEAT_2_RIGHT",
+                    "minInt32Value": 0,
+                    "maxInt32Value": 10
+                },
+                {
+                    "areaId": "Constants::SEAT_2_CENTER",
+                    "minInt32Value": 0,
+                    "maxInt32Value": 10
+                }
+            ]
+        },
+        {
             "property": "VehicleProperty::SEAT_HEADREST_HEIGHT_MOVE",
             "defaultValue": {
                 "int32Values": [
@@ -1036,6 +1071,71 @@
             ]
         },
         {
+            "property": "VehicleProperty::SEAT_FOOTWELL_LIGHTS_STATE",
+            "defaultValue": {
+                "int32Values": [
+                    "Constants::LIGHT_STATE_OFF"
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": "Constants::SEAT_1_LEFT",
+                    "supportedEnumValues": [
+                        "Constants::LIGHT_STATE_OFF",
+                        "Constants::LIGHT_STATE_ON"
+                    ]
+                },
+                {
+                    "areaId": "Constants::SEAT_1_RIGHT",
+                    "supportedEnumValues": [
+                        "Constants::LIGHT_STATE_OFF",
+                        "Constants::LIGHT_STATE_ON"
+                    ]
+                },
+                {
+                    "areaId": "Constants::SEAT_2_LEFT_2_RIGHT_2_CENTER",
+                    "supportedEnumValues": [
+                        "Constants::LIGHT_STATE_OFF",
+                        "Constants::LIGHT_STATE_ON"
+                    ]
+                }
+            ]
+        },
+        {
+            "property": "VehicleProperty::SEAT_FOOTWELL_LIGHTS_SWITCH",
+            "defaultValue": {
+                "int32Values": [
+                    "Constants::LIGHT_SWITCH_OFF"
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": "Constants::SEAT_1_LEFT",
+                    "supportedEnumValues": [
+                        "Constants::LIGHT_SWITCH_OFF",
+                        "Constants::LIGHT_SWITCH_ON",
+                        "Constants::LIGHT_SWITCH_AUTO"
+                    ]
+                },
+                {
+                    "areaId": "Constants::SEAT_1_RIGHT",
+                    "supportedEnumValues": [
+                        "Constants::LIGHT_SWITCH_OFF",
+                        "Constants::LIGHT_SWITCH_ON",
+                        "Constants::LIGHT_SWITCH_AUTO"
+                    ]
+                },
+                {
+                    "areaId": "Constants::SEAT_2_LEFT_2_RIGHT_2_CENTER",
+                    "supportedEnumValues": [
+                        "Constants::LIGHT_SWITCH_OFF",
+                        "Constants::LIGHT_SWITCH_ON",
+                        "Constants::LIGHT_SWITCH_AUTO"
+                    ]
+                }
+            ]
+        },
+        {
             "property": "VehicleProperty::SEAT_EASY_ACCESS_ENABLED",
             "defaultValue": {
                 "int32Values": [
@@ -1588,6 +1688,24 @@
             ]
         },
         {
+            "property": "VehicleProperty::EV_STOPPING_MODE",
+            "defaultValue": {
+                "int32Values": [
+                    "Constants::EV_STOPPING_MODE_CREEP"
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": 0,
+                    "supportedEnumValues": [
+                        "Constants::EV_STOPPING_MODE_CREEP",
+                        "Constants::EV_STOPPING_MODE_ROLL",
+                        "Constants::EV_STOPPING_MODE_HOLD"
+                    ]
+                }
+            ]
+        },
+        {
             "property": "VehicleProperty::FUEL_LEVEL_LOW",
             "defaultValue": {
                 "int32Values": [
@@ -1626,6 +1744,77 @@
             }
         },
         {
+            "property": "VehicleProperty::HW_KEY_INPUT_V2",
+            "defaultValue": {
+                "int32Values": [
+                    0,
+                    0,
+                    0,
+                    0
+                ],
+                "int64Values": [
+                    0
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": "Constants::SEAT_1_LEFT"
+                },
+                {
+                    "areaId": "Constants::SEAT_1_RIGHT"
+                },
+                {
+                    "areaId": "Constants::SEAT_2_LEFT"
+                },
+                {
+                    "areaId": "Constants::SEAT_2_RIGHT"
+                },
+                {
+                    "areaId": "Constants::SEAT_2_CENTER"
+                }
+            ]
+        },
+        {
+            "property": "VehicleProperty::HW_MOTION_INPUT",
+            "defaultValue": {
+                "int32Values": [
+                    0,
+                    0,
+                    0,
+                    0,
+                    1,
+                    0,
+                    0
+                ],
+                "floatValues": [
+                    0,
+                    0,
+                    0,
+                    0
+                ],
+                "int64Values": [
+                    0
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": "Constants::SEAT_1_LEFT"
+                },
+                {
+                    "areaId": "Constants::SEAT_1_RIGHT"
+                },
+                {
+                    "areaId": "Constants::SEAT_2_LEFT"
+                },
+                {
+                    "areaId": "Constants::SEAT_2_RIGHT"
+                },
+                {
+                    "areaId": "Constants::SEAT_2_CENTER"
+                }
+            ]
+        },
+        {
             "property": "VehicleProperty::HW_ROTARY_INPUT",
             "defaultValue": {
                 "int32Values": [
@@ -1982,8 +2171,8 @@
                 160,
                 280,
                 5,
-                605,
-                825,
+                600,
+                840,
                 10
             ]
         },
@@ -2707,6 +2896,23 @@
             ]
         },
         {
+            "property": "VehicleProperty::STEERING_WHEEL_LIGHTS_STATE",
+            "defaultValue": {
+                "int32Values": [
+                    "Constants::LIGHT_STATE_ON"
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": 0,
+                    "supportedEnumValues": [
+                        "Constants::LIGHT_STATE_OFF",
+                        "Constants::LIGHT_STATE_ON"
+                    ]
+                }
+            ]
+        },
+        {
             "property": "VehicleProperty::HEADLIGHTS_SWITCH",
             "defaultValue": {
                 "int32Values": [
@@ -2780,6 +2986,24 @@
             ]
         },
         {
+            "property": "VehicleProperty::STEERING_WHEEL_LIGHTS_SWITCH",
+            "defaultValue": {
+                "int32Values": [
+                    "Constants::LIGHT_SWITCH_AUTO"
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": 0,
+                    "supportedEnumValues": [
+                        "Constants::LIGHT_SWITCH_OFF",
+                        "Constants::LIGHT_SWITCH_ON",
+                        "Constants::LIGHT_SWITCH_AUTO"
+                    ]
+                }
+            ]
+        },
+        {
             "property": "VehicleProperty::EVS_SERVICE_REQUEST",
             "defaultValue": {
                 "int32Values": [
@@ -2808,6 +3032,38 @@
             }
         },
         {
+            "property": "VehicleProperty::EMERGENCY_LANE_KEEP_ASSIST_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    1
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::ADAPTIVE_CRUISE_CONTROL_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    1
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::HANDS_ON_DETECTION_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    1
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::DRIVER_ATTENTION_MONITORING_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    1
+                ]
+            }
+        },
+        {
             "property": "VehicleProperty::INITIAL_USER_INFO"
         },
         {
@@ -2897,6 +3153,54 @@
                     "GsrComplianceRequirementType::GSR_COMPLIANCE_REQUIRED_V1"
                 ]
             }
+        },
+        {
+            "property": "VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::FORWARD_COLLISION_WARNING_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::BLIND_SPOT_WARNING_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::LANE_DEPARTURE_WARNING_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::LANE_KEEP_ASSIST_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::LANE_CENTERING_ASSIST_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            }
         }
     ]
 }
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
index e515bad..5e35b0f 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -240,6 +240,14 @@
     static aidl::android::hardware::automotive::vehicle::VehiclePropValue createHwInputKeyProp(
             aidl::android::hardware::automotive::vehicle::VehicleHwKeyInputAction action,
             int32_t keyCode, int32_t targetDisplay);
+    static aidl::android::hardware::automotive::vehicle::VehiclePropValue createHwKeyInputV2Prop(
+            int32_t area, int32_t targetDisplay, int32_t keyCode, int32_t action,
+            int32_t repeatCount);
+    static aidl::android::hardware::automotive::vehicle::VehiclePropValue createHwMotionInputProp(
+            int32_t area, int32_t display, int32_t inputType, int32_t action, int32_t buttonState,
+            int32_t pointerCount, int32_t pointerId[], int32_t toolType[], float xData[],
+            float yData[], float pressure[], float size[]);
+
     static std::string genFakeDataHelp();
     static std::string parseErrMsg(std::string fieldName, std::string value, std::string type);
 };
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index dd76524..6e085db 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -672,6 +672,14 @@
 
 --genfakedata --keypress [keyCode(int32)] [display[int32]]: Generate key press.
 
+--genfakedata --keyinputv2 [area(int32)] [display(int32)] [keyCode[int32]] [action[int32]]
+  [repeatCount(int32)]
+
+--genfakedata --motioninput [area(int32)] [display(int32)] [inputType[int32]] [action[int32]]
+  [buttonState(int32)] --pointer [pointerId(int32)] [toolType(int32)] [xData(float)] [yData(float)]
+  [pressure(float)] [size(float)]
+  Generate a motion input event. --pointer option can be specified multiple times.
+
 )";
 }
 
@@ -802,6 +810,135 @@
         onValueChangeCallback(
                 createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display));
         return "keypress event generated successfully";
+    } else if (command == "--keyinputv2") {
+        int32_t area;
+        int32_t display;
+        int32_t keyCode;
+        int32_t action;
+        int32_t repeatCount;
+        // --genfakedata --keyinputv2 [area(int32)] [display(int32)] [keyCode[int32]]
+        // [action[int32]] [repeatCount(int32)]
+        if (options.size() != 7) {
+            return "incorrect argument count, need 7 arguments for --genfakedata --keyinputv2\n";
+        }
+        if (!android::base::ParseInt(options[2], &area)) {
+            return parseErrMsg("area", options[2], "int");
+        }
+        if (!android::base::ParseInt(options[3], &display)) {
+            return parseErrMsg("display", options[3], "int");
+        }
+        if (!android::base::ParseInt(options[4], &keyCode)) {
+            return parseErrMsg("keyCode", options[4], "int");
+        }
+        if (!android::base::ParseInt(options[5], &action)) {
+            return parseErrMsg("action", options[5], "int");
+        }
+        if (!android::base::ParseInt(options[6], &repeatCount)) {
+            return parseErrMsg("repeatCount", options[6], "int");
+        }
+        // Send back to HAL
+        onValueChangeCallback(createHwKeyInputV2Prop(area, display, keyCode, action, repeatCount));
+        return StringPrintf(
+                "keyinputv2 event generated successfully with area:%d, display:%d,"
+                " keyCode:%d, action:%d, repeatCount:%d",
+                area, display, keyCode, action, repeatCount);
+
+    } else if (command == "--motioninput") {
+        int32_t area;
+        int32_t display;
+        int32_t inputType;
+        int32_t action;
+        int32_t buttonState;
+        int32_t pointerCount;
+
+        // --genfakedata --motioninput [area(int32)] [display(int32)] [inputType[int32]]
+        // [action[int32]] [buttonState(int32)] [pointerCount(int32)]
+        // --pointer [pointerId(int32)] [toolType(int32)] [xData(float)] [yData(float)]
+        // [pressure(float)] [size(float)]
+        int optionsSize = (int)options.size();
+        if (optionsSize / 7 < 2) {
+            return "incorrect argument count, need at least 14 arguments for --genfakedata "
+                   "--motioninput including at least 1 --pointer\n";
+        }
+
+        if (optionsSize % 7 != 0) {
+            return "incorrect argument count, need 6 arguments for every --pointer\n";
+        }
+        pointerCount = (int)optionsSize / 7 - 1;
+
+        if (!android::base::ParseInt(options[2], &area)) {
+            return parseErrMsg("area", options[2], "int");
+        }
+        if (!android::base::ParseInt(options[3], &display)) {
+            return parseErrMsg("display", options[3], "int");
+        }
+        if (!android::base::ParseInt(options[4], &inputType)) {
+            return parseErrMsg("inputType", options[4], "int");
+        }
+        if (!android::base::ParseInt(options[5], &action)) {
+            return parseErrMsg("action", options[5], "int");
+        }
+        if (!android::base::ParseInt(options[6], &buttonState)) {
+            return parseErrMsg("buttonState", options[6], "int");
+        }
+
+        int32_t pointerId[pointerCount];
+        int32_t toolType[pointerCount];
+        float xData[pointerCount];
+        float yData[pointerCount];
+        float pressure[pointerCount];
+        float size[pointerCount];
+
+        for (int i = 7, pc = 0; i < optionsSize; i += 7, pc += 1) {
+            int offset = i;
+            if (options[offset] != "--pointer") {
+                return "--pointer is needed for the motion input\n";
+            }
+            offset += 1;
+            if (!android::base::ParseInt(options[offset], &pointerId[pc])) {
+                return parseErrMsg("pointerId", options[offset], "int");
+            }
+            offset += 1;
+            if (!android::base::ParseInt(options[offset], &toolType[pc])) {
+                return parseErrMsg("toolType", options[offset], "int");
+            }
+            offset += 1;
+            if (!android::base::ParseFloat(options[offset], &xData[pc])) {
+                return parseErrMsg("xData", options[offset], "float");
+            }
+            offset += 1;
+            if (!android::base::ParseFloat(options[offset], &yData[pc])) {
+                return parseErrMsg("yData", options[offset], "float");
+            }
+            offset += 1;
+            if (!android::base::ParseFloat(options[offset], &pressure[pc])) {
+                return parseErrMsg("pressure", options[offset], "float");
+            }
+            offset += 1;
+            if (!android::base::ParseFloat(options[offset], &size[pc])) {
+                return parseErrMsg("size", options[offset], "float");
+            }
+        }
+
+        // Send back to HAL
+        onValueChangeCallback(createHwMotionInputProp(area, display, inputType, action, buttonState,
+                                                      pointerCount, pointerId, toolType, xData,
+                                                      yData, pressure, size));
+
+        std::string successMessage = StringPrintf(
+                "motion event generated successfully with area:%d, display:%d,"
+                " inputType:%d, action:%d, buttonState:%d, pointerCount:%d\n",
+                area, display, inputType, action, buttonState, pointerCount);
+        for (int i = 0; i < pointerCount; i++) {
+            successMessage += StringPrintf(
+                    "Pointer #%d {\n"
+                    " id:%d , tooltype:%d \n"
+                    " x:%f , y:%f\n"
+                    " pressure: %f, data: %f\n"
+                    "}\n",
+                    i, pointerId[i], toolType[i], xData[i], yData[i], pressure[i], size[i]);
+        }
+        return successMessage;
     }
 
     return StringPrintf("Unknown command: \"%s\"\n%s", command.c_str(), genFakeDataHelp().c_str());
@@ -819,6 +956,59 @@
     return value;
 }
 
+VehiclePropValue FakeVehicleHardware::createHwKeyInputV2Prop(int32_t area, int32_t targetDisplay,
+                                                             int32_t keyCode, int32_t action,
+                                                             int32_t repeatCount) {
+    VehiclePropValue value = {.prop = toInt(VehicleProperty::HW_KEY_INPUT_V2),
+                              .areaId = area,
+                              .timestamp = elapsedRealtimeNano(),
+                              .status = VehiclePropertyStatus::AVAILABLE,
+                              .value.int32Values = {targetDisplay, keyCode, action, repeatCount},
+                              .value.int64Values = {elapsedRealtimeNano()}};
+    return value;
+}
+
+VehiclePropValue FakeVehicleHardware::createHwMotionInputProp(
+        int32_t area, int32_t display, int32_t inputType, int32_t action, int32_t buttonState,
+        int32_t pointerCount, int32_t pointerId[], int32_t toolType[], float xData[], float yData[],
+        float pressure[], float size[]) {
+    std::vector<int> intValues;
+    intValues.push_back(display);
+    intValues.push_back(inputType);
+    intValues.push_back(action);
+    intValues.push_back(buttonState);
+    intValues.push_back(pointerCount);
+    for (int i = 0; i < pointerCount; i++) {
+        intValues.push_back(pointerId[i]);
+    }
+    for (int i = 0; i < pointerCount; i++) {
+        intValues.push_back(toolType[i]);
+    }
+
+    std::vector<float> floatValues;
+    for (int i = 0; i < pointerCount; i++) {
+        floatValues.push_back(xData[i]);
+    }
+    for (int i = 0; i < pointerCount; i++) {
+        floatValues.push_back(yData[i]);
+    }
+    for (int i = 0; i < pointerCount; i++) {
+        floatValues.push_back(pressure[i]);
+    }
+    for (int i = 0; i < pointerCount; i++) {
+        floatValues.push_back(size[i]);
+    }
+
+    VehiclePropValue value = {.prop = toInt(VehicleProperty::HW_MOTION_INPUT),
+                              .areaId = area,
+                              .timestamp = elapsedRealtimeNano(),
+                              .status = VehiclePropertyStatus::AVAILABLE,
+                              .value.int32Values = intValues,
+                              .value.floatValues = floatValues,
+                              .value.int64Values = {elapsedRealtimeNano()}};
+    return value;
+}
+
 void FakeVehicleHardware::eventFromVehicleBus(const VehiclePropValue& value) {
     mServerSidePropStore->writeValue(mValuePool->obtain(value));
 }
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
index 0184462..79990ad 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -1776,7 +1776,61 @@
              "failed to parse keyCode as int: \"0.1\""},
             {"genfakedata_keypress_invalid_display",
              {"--genfakedata", "--keypress", "1", "0.1"},
-             "failed to parse display as int: \"0.1\""}};
+             "failed to parse display as int: \"0.1\""},
+            {"genfakedata_keyinputv2_incorrect_arguments",
+             {"--genfakedata", "--keyinputv2", "1", "1"},
+             "incorrect argument count, need 7 arguments for --genfakedata --keyinputv2\n"},
+            {"genfakedata_keyinputv2_invalid_area",
+             {"--genfakedata", "--keyinputv2", "0.1", "1", "1", "1", "1"},
+             "failed to parse area as int: \"0.1\""},
+            {"genfakedata_keyinputv2_invalid_display",
+             {"--genfakedata", "--keyinputv2", "1", "0.1", "1", "1", "1"},
+             "failed to parse display as int: \"0.1\""},
+            {"genfakedata_keyinputv2_invalid_keycode",
+             {"--genfakedata", "--keyinputv2", "1", "1", "0.1", "1", "1"},
+             "failed to parse keyCode as int: \"0.1\""},
+            {"genfakedata_keyinputv2_invalid_action",
+             {"--genfakedata", "--keyinputv2", "1", "1", "1", "0.1", "1"},
+             "failed to parse action as int: \"0.1\""},
+            {"genfakedata_keyinputv2_invalid_repeatcount",
+             {"--genfakedata", "--keyinputv2", "1", "1", "1", "1", "0.1"},
+             "failed to parse repeatCount as int: \"0.1\""},
+            {"genfakedata_motioninput_invalid_argument_count",
+             {"--genfakedata", "--motioninput", "1", "1", "1", "1", "1"},
+             "incorrect argument count, need at least 14 arguments for --genfakedata "
+             "--motioninput including at least 1 --pointer\n"},
+            {"genfakedata_motioninput_pointer_invalid_argument_count",
+             {"--genfakedata", "--motioninput", "1", "1", "1", "1", "1", "--pointer", "1", "1", "1",
+              "1", "1", "1", "--pointer"},
+             "incorrect argument count, need 6 arguments for every --pointer\n"},
+            {"genfakedata_motioninput_invalid_area",
+             {"--genfakedata", "--motioninput", "0.1", "1", "1", "1", "1", "--pointer", "1", "1",
+              "1", "1", "1", "1"},
+             "failed to parse area as int: \"0.1\""},
+            {"genfakedata_motioninput_invalid_display",
+             {"--genfakedata", "--motioninput", "1", "0.1", "1", "1", "1", "--pointer", "1", "1",
+              "1", "1", "1", "1"},
+             "failed to parse display as int: \"0.1\""},
+            {"genfakedata_motioninput_invalid_inputtype",
+             {"--genfakedata", "--motioninput", "1", "1", "0.1", "1", "1", "--pointer", "1", "1",
+              "1", "1", "1", "1"},
+             "failed to parse inputType as int: \"0.1\""},
+            {"genfakedata_motioninput_invalid_action",
+             {"--genfakedata", "--motioninput", "1", "1", "1", "0.1", "1", "--pointer", "1", "1",
+              "1", "1", "1", "1"},
+             "failed to parse action as int: \"0.1\""},
+            {"genfakedata_motioninput_invalid_buttonstate",
+             {"--genfakedata", "--motioninput", "1", "1", "1", "1", "0.1", "--pointer", "1", "1",
+              "1.2", "1.2", "1.2", "1.2"},
+             "failed to parse buttonState as int: \"0.1\""},
+            {"genfakedata_motioninput_invalid_pointerid",
+             {"--genfakedata", "--motioninput", "1", "1", "1", "1", "1", "--pointer", "0.1", "1",
+              "1.2", "1", "1", "1"},
+             "failed to parse pointerId as int: \"0.1\""},
+            {"genfakedata_motioninput_invalid_tooltype",
+             {"--genfakedata", "--motioninput", "1", "1", "1", "1", "1", "--pointer", "1", "0.1",
+              "1.2", "1", "1", "1"},
+             "failed to parse toolType as int: \"0.1\""}};
 }
 
 TEST_P(FakeVehicleHardwareOptionsTest, testInvalidOptions) {
@@ -1965,6 +2019,78 @@
     EXPECT_EQ(2, events[1].value.int32Values[2]);
 }
 
+TEST_F(FakeVehicleHardwareTest, testDebugGenFakeDataKeyInputV2) {
+    std::vector<std::string> options = {"--genfakedata", "--keyinputv2", "1", "2", "3", "4", "5"};
+
+    DumpResult result = getHardware()->dump(options);
+
+    ASSERT_FALSE(result.callerShouldDumpState);
+    ASSERT_THAT(result.buffer, HasSubstr("successfully"));
+
+    auto events = getChangedProperties();
+    ASSERT_EQ(1u, events.size());
+    EXPECT_EQ(toInt(VehicleProperty::HW_KEY_INPUT_V2), events[0].prop);
+    ASSERT_EQ(4u, events[0].value.int32Values.size());
+    EXPECT_EQ(2, events[0].value.int32Values[0]);
+    EXPECT_EQ(3, events[0].value.int32Values[1]);
+    EXPECT_EQ(4, events[0].value.int32Values[2]);
+    EXPECT_EQ(5, events[0].value.int32Values[3]);
+    ASSERT_EQ(1u, events[0].value.int64Values.size());
+}
+
+TEST_F(FakeVehicleHardwareTest, testDebugGenFakeDataMotionInput) {
+    std::vector<std::string> options = {"--genfakedata",
+                                        "--motioninput",
+                                        "1",
+                                        "2",
+                                        "3",
+                                        "4",
+                                        "5",
+                                        "--pointer",
+                                        "11",
+                                        "22",
+                                        "33.3",
+                                        "44.4",
+                                        "55.5",
+                                        "66.6",
+                                        "--pointer",
+                                        "21",
+                                        "32",
+                                        "43.3",
+                                        "54.4",
+                                        "65.5",
+                                        "76.6"};
+
+    DumpResult result = getHardware()->dump(options);
+
+    ASSERT_FALSE(result.callerShouldDumpState);
+    ASSERT_THAT(result.buffer, HasSubstr("successfully"));
+
+    auto events = getChangedProperties();
+    ASSERT_EQ(1u, events.size());
+    EXPECT_EQ(toInt(VehicleProperty::HW_MOTION_INPUT), events[0].prop);
+    ASSERT_EQ(9u, events[0].value.int32Values.size());
+    EXPECT_EQ(2, events[0].value.int32Values[0]);
+    EXPECT_EQ(3, events[0].value.int32Values[1]);
+    EXPECT_EQ(4, events[0].value.int32Values[2]);
+    EXPECT_EQ(5, events[0].value.int32Values[3]);
+    EXPECT_EQ(2, events[0].value.int32Values[4]);
+    EXPECT_EQ(11, events[0].value.int32Values[5]);
+    EXPECT_EQ(21, events[0].value.int32Values[6]);
+    EXPECT_EQ(22, events[0].value.int32Values[7]);
+    EXPECT_EQ(32, events[0].value.int32Values[8]);
+    ASSERT_EQ(8u, events[0].value.floatValues.size());
+    EXPECT_FLOAT_EQ(33.3, events[0].value.floatValues[0]);
+    EXPECT_FLOAT_EQ(43.3, events[0].value.floatValues[1]);
+    EXPECT_FLOAT_EQ(44.4, events[0].value.floatValues[2]);
+    EXPECT_FLOAT_EQ(54.4, events[0].value.floatValues[3]);
+    EXPECT_FLOAT_EQ(55.5, events[0].value.floatValues[4]);
+    EXPECT_FLOAT_EQ(65.5, events[0].value.floatValues[5]);
+    EXPECT_FLOAT_EQ(66.6, events[0].value.floatValues[6]);
+    EXPECT_FLOAT_EQ(76.6, events[0].value.floatValues[7]);
+    ASSERT_EQ(1u, events[0].value.int64Values.size());
+}
+
 TEST_F(FakeVehicleHardwareTest, testGetEchoReverseBytes) {
     ASSERT_EQ(setValue(VehiclePropValue{
                       .prop = ECHO_REVERSE_BYTES,
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h b/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h
index bf27c95..7275ba3 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h
@@ -28,6 +28,7 @@
 namespace propertyutils_impl {
 
 // These names are not part of the API since we only expose ints.
+using ::aidl::android::hardware::automotive::vehicle::EvStoppingMode;
 using ::aidl::android::hardware::automotive::vehicle::PortLocationType;
 using ::aidl::android::hardware::automotive::vehicle::VehicleArea;
 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaDoor;
@@ -98,7 +99,11 @@
 constexpr int LIGHT_STATE_ON = toInt(propertyutils_impl::VehicleLightState::ON);
 constexpr int LIGHT_STATE_OFF = toInt(propertyutils_impl::VehicleLightState::OFF);
 constexpr int LIGHT_SWITCH_OFF = toInt(propertyutils_impl::VehicleLightSwitch::OFF);
+constexpr int LIGHT_SWITCH_ON = toInt(propertyutils_impl::VehicleLightSwitch::ON);
 constexpr int LIGHT_SWITCH_AUTO = toInt(propertyutils_impl::VehicleLightSwitch::AUTOMATIC);
+constexpr int EV_STOPPING_MODE_CREEP = toInt(propertyutils_impl::EvStoppingMode::CREEP);
+constexpr int EV_STOPPING_MODE_ROLL = toInt(propertyutils_impl::EvStoppingMode::ROLL);
+constexpr int EV_STOPPING_MODE_HOLD = toInt(propertyutils_impl::EvStoppingMode::HOLD);
 constexpr int WHEEL_FRONT_LEFT = toInt(propertyutils_impl::VehicleAreaWheel::LEFT_FRONT);
 constexpr int WHEEL_FRONT_RIGHT = toInt(propertyutils_impl::VehicleAreaWheel::RIGHT_FRONT);
 constexpr int WHEEL_REAR_LEFT = toInt(propertyutils_impl::VehicleAreaWheel::LEFT_REAR);
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
index 08e1990..0915701 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
@@ -20,6 +20,7 @@
 #include <aidl/android/hardware/automotive/vehicle/DiagnosticFloatSensorIndex.h>
 #include <aidl/android/hardware/automotive/vehicle/DiagnosticIntegerSensorIndex.h>
 #include <aidl/android/hardware/automotive/vehicle/EvConnectorType.h>
+#include <aidl/android/hardware/automotive/vehicle/EvStoppingMode.h>
 #include <aidl/android/hardware/automotive/vehicle/EvsServiceState.h>
 #include <aidl/android/hardware/automotive/vehicle/EvsServiceType.h>
 #include <aidl/android/hardware/automotive/vehicle/FuelType.h>
diff --git a/automotive/vehicle/aidl/impl/vhal/src/VehicleService.cpp b/automotive/vehicle/aidl/impl/vhal/src/VehicleService.cpp
index c8b5c65..f8a4e7d 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/VehicleService.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/VehicleService.cpp
@@ -27,6 +27,13 @@
 using ::android::hardware::automotive::vehicle::fake::FakeVehicleHardware;
 
 int main(int /* argc */, char* /* argv */[]) {
+    ALOGI("Starting thread pool...");
+    if (!ABinderProcess_setThreadPoolMaxThreadCount(4)) {
+        ALOGE("%s", "failed to set thread pool max thread count");
+        return 1;
+    }
+    ABinderProcess_startThreadPool();
+
     std::unique_ptr<FakeVehicleHardware> hardware = std::make_unique<FakeVehicleHardware>();
     std::shared_ptr<DefaultVehicleHal> vhal =
             ::ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
@@ -39,12 +46,6 @@
         return 1;
     }
 
-    if (!ABinderProcess_setThreadPoolMaxThreadCount(4)) {
-        ALOGE("%s", "failed to set thread pool max thread count");
-        return 1;
-    }
-    ABinderProcess_startThreadPool();
-
     ALOGI("Vehicle Service Ready");
 
     ABinderProcess_joinThreadPool();
diff --git a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
index 5595afe..1680442 100644
--- a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
+++ b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
@@ -481,12 +481,42 @@
                             actualPropertyType);
 }
 
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyEmergencyLaneKeepAssistEnabledConfig) {
+    verifyProperty(VehicleProperty::EMERGENCY_LANE_KEEP_ASSIST_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyAdaptiveCruiseControlEnabledConfig) {
+    verifyProperty(VehicleProperty::ADAPTIVE_CRUISE_CONTROL_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyHandsOnDetectionEnabledConfig) {
+    verifyProperty(VehicleProperty::HANDS_ON_DETECTION_ENABLED, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyDriverAttentionMonitoringEnabledConfig) {
+    verifyProperty(VehicleProperty::DRIVER_ATTENTION_MONITORING_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
 TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyEvBrakeRegenerationLevelConfig) {
     verifyProperty(VehicleProperty::EV_BRAKE_REGENERATION_LEVEL,
                    VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
                    VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::INT32);
 }
 
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyEvStoppingModeConfig) {
+    verifyProperty(VehicleProperty::EV_STOPPING_MODE, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
 TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyEvCurrentBatteryCapacityConfig) {
     verifyProperty(VehicleProperty::EV_CURRENT_BATTERY_CAPACITY, VehiclePropertyAccess::READ,
                    VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
@@ -547,6 +577,18 @@
                    VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
 }
 
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySteeringWheelLightsStateConfig) {
+    verifyProperty(VehicleProperty::STEERING_WHEEL_LIGHTS_STATE, VehiclePropertyAccess::READ,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySteeringWheelLightsSwitchConfig) {
+    verifyProperty(VehicleProperty::STEERING_WHEEL_LIGHTS_SWITCH, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
 TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyMirrorAutoFoldEnabledConfig) {
     verifyProperty(VehicleProperty::MIRROR_AUTO_FOLD_ENABLED, VehiclePropertyAccess::READ_WRITE,
                    VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
@@ -559,12 +601,30 @@
                    VehicleArea::MIRROR, VehiclePropertyType::BOOLEAN);
 }
 
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatHeadrestHeightPosV2Config) {
+    verifyProperty(VehicleProperty::SEAT_HEADREST_HEIGHT_POS_V2, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::SEAT, VehiclePropertyType::INT32);
+}
+
 TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatWalkInPosConfig) {
     verifyProperty(VehicleProperty::SEAT_WALK_IN_POS, VehiclePropertyAccess::READ_WRITE,
                    VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
                    VehicleArea::SEAT, VehiclePropertyType::INT32);
 }
 
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatFootwellLightsStateConfig) {
+    verifyProperty(VehicleProperty::SEAT_FOOTWELL_LIGHTS_STATE, VehiclePropertyAccess::READ,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::SEAT, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatFootwellLightsSwitchConfig) {
+    verifyProperty(VehicleProperty::SEAT_FOOTWELL_LIGHTS_SWITCH, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::SEAT, VehiclePropertyType::INT32);
+}
+
 TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatEasyAccessEnabledConfig) {
     verifyProperty(VehicleProperty::SEAT_EASY_ACCESS_ENABLED, VehiclePropertyAccess::READ_WRITE,
                    VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
@@ -601,6 +661,42 @@
                    VehicleArea::SEAT, VehiclePropertyType::INT32);
 }
 
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyAutomaticEmergencyBrakingEnabledConfig) {
+    verifyProperty(VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyForwardCollisionWarningEnabledConfig) {
+    verifyProperty(VehicleProperty::FORWARD_COLLISION_WARNING_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyBlindSpotWarningEnabledConfig) {
+    verifyProperty(VehicleProperty::BLIND_SPOT_WARNING_ENABLED, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyLaneDepartureWarningEnabledConfig) {
+    verifyProperty(VehicleProperty::LANE_DEPARTURE_WARNING_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyLaneKeepAssistEnabledConfig) {
+    verifyProperty(VehicleProperty::LANE_KEEP_ASSIST_ENABLED, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyLaneCenteringAssistEnabledConfig) {
+    verifyProperty(VehicleProperty::LANE_CENTERING_ASSIST_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
 std::vector<ServiceDescriptor> getDescriptors() {
     std::vector<ServiceDescriptor> descriptors;
     for (std::string name : getAidlHalInstanceNames(IVehicle::descriptor)) {
diff --git a/camera/device/3.2/default/convert.cpp b/camera/device/3.2/default/convert.cpp
index 06ad7e9..2075607 100644
--- a/camera/device/3.2/default/convert.cpp
+++ b/camera/device/3.2/default/convert.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "android.hardware.camera.device@3.2-convert-impl"
 #include <log/log.h>
+#include <system/camera_metadata.h>
 
 #include "include/convert.h"
 
@@ -43,6 +44,13 @@
         ALOGE("%s: input CameraMetadata is corrupt!", __FUNCTION__);
         return false;
     }
+
+    if (validate_camera_metadata_structure((camera_metadata_t*)data, /*expected_size=*/NULL) !=
+        OK) {
+        ALOGE("%s: Failed to validate the metadata structure", __FUNCTION__);
+        return false;
+    }
+
     *dst = (camera_metadata_t*) data;
     return true;
 }
diff --git a/camera/provider/aidl/vts/camera_aidl_test.h b/camera/provider/aidl/vts/camera_aidl_test.h
index 8b8a4bc..f13d6b2 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.h
+++ b/camera/provider/aidl/vts/camera_aidl_test.h
@@ -17,7 +17,10 @@
 #ifndef HARDWARE_INTERFACES_CAMERA_PROVIDER_AIDL_VTS_CAMERA_AIDL_TEST_H_
 #define HARDWARE_INTERFACES_CAMERA_PROVIDER_AIDL_VTS_CAMERA_AIDL_TEST_H_
 
+// TODO: LOG_TAG should not be in header
+#ifndef LOG_TAG
 #define LOG_TAG "camera_aidl_hal_test"
+#endif
 
 #include <string>
 #include <unordered_map>
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index e7bb282..9b2175a 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -78,6 +78,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.automotive.audiocontrol</name>
+        <version>2</version>
         <interface>
             <name>IAudioControl</name>
             <instance>default</instance>
@@ -306,6 +307,7 @@
             <instance>default</instance>
         </interface>
     </hal>
+    <!-- Either the native or the HIDL mapper HAL must exist on the device -->
     <hal format="hidl" optional="true">
         <name>android.hardware.graphics.mapper</name>
         <!-- New, non-Go devices should use 4.0, tested in vts_treble_vintf_vendor_test -->
@@ -616,6 +618,14 @@
             <instance>default</instance>
         </interface>
     </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.soundtrigger</name>
+        <version>2.3</version>
+        <interface>
+            <name>ISoundTriggerHw</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
     <hal format="aidl" optional="true">
          <name>android.hardware.soundtrigger3</name>
          <version>1</version>
@@ -656,6 +666,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>
@@ -765,4 +782,13 @@
             <instance>default</instance>
         </interface>
     </hal>
+    <!-- Either the native or the HIDL mapper HAL must exist on the device -->
+    <hal format="native" optional="true">
+        <name>mapper</name>
+        <version>5.0</version>
+        <interface>
+            <name>I</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+    </hal>
 </compatibility-matrix>
diff --git a/contexthub/1.0/default/OWNERS b/contexthub/1.0/default/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/contexthub/1.0/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/contexthub/1.1/default/OWNERS b/contexthub/1.1/default/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/contexthub/1.1/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/contexthub/1.1/vts/functional/OWNERS b/contexthub/1.1/vts/functional/OWNERS
deleted file mode 100644
index 2cf5bca..0000000
--- a/contexthub/1.1/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 156070
-include ../../../1.0/vts/functional/OWNERS
diff --git a/contexthub/1.2/default/OWNERS b/contexthub/1.2/default/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/contexthub/1.2/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/contexthub/1.2/vts/functional/OWNERS b/contexthub/1.2/vts/functional/OWNERS
deleted file mode 100644
index 2cf5bca..0000000
--- a/contexthub/1.2/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 156070
-include ../../../1.0/vts/functional/OWNERS
diff --git a/contexthub/1.0/vts/functional/OWNERS b/contexthub/OWNERS
similarity index 81%
rename from contexthub/1.0/vts/functional/OWNERS
rename to contexthub/OWNERS
index f254cd5..d5cfc2e 100644
--- a/contexthub/1.0/vts/functional/OWNERS
+++ b/contexthub/OWNERS
@@ -1,5 +1,4 @@
 # Bug component: 156070
-#Context Hub team
 arthuri@google.com
 bduddie@google.com
 stange@google.com
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
index 272d768..c1f4df8 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
@@ -46,5 +46,6 @@
   void onHostEndpointConnected(in android.hardware.contexthub.HostEndpointInfo hostEndpointInfo);
   void onHostEndpointDisconnected(char hostEndpointId);
   long[] getPreloadedNanoappIds();
+  void onNanSessionStateChanged(in boolean state);
   const int EX_CONTEXT_HUB_UNSPECIFIED = -1;
 }
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl
index f81f7cf..e72ae73 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl
@@ -38,4 +38,6 @@
   void handleContextHubMessage(in android.hardware.contexthub.ContextHubMessage msg, in String[] msgContentPerms);
   void handleContextHubAsyncEvent(in android.hardware.contexthub.AsyncEventType evt);
   void handleTransactionResult(in int transactionId, in boolean success);
+  void handleNanSessionRequest(in boolean enable);
+  const int CONTEXTHUB_NAN_TRANSACTION_TIMEOUT_MS = 10000;
 }
diff --git a/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl b/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
index 9fa67a5..7f50730 100644
--- a/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
@@ -204,6 +204,19 @@
     long[] getPreloadedNanoappIds();
 
     /**
+     * Invoked when the state of the NAN session requested through handleNanSessionRequest()
+     * changes. This function may be invoked without a corresponding handleNanSessionRequest to
+     * indicate if a NAN session was terminated without a request due to resource limitations.
+     *
+     * If the state becomes disabled without an explicit request from the HAL, the HAL MUST
+     * explicitly invoke handleNanSessionRequest() at a later point in time to attempt to
+     * re-enable NAN.
+     *
+     * @param state True if the NAN session is currently enabled.
+     */
+    void onNanSessionStateChanged(in boolean state);
+
+    /**
      * Error codes that are used as service specific errors with the AIDL return
      * value EX_SERVICE_SPECIFIC.
      */
diff --git a/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl b/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl
index e385d48..cff1893 100644
--- a/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl
@@ -74,4 +74,25 @@
      *
      */
     void handleTransactionResult(in int transactionId, in boolean success);
+
+    /**
+     * This callback is passed by the Contexthub service to the HAL implementation to allow the HAL
+     * to request a WiFi NAN session is created to allow the Contexthub to be able to utilize NAN
+     * functionality.
+     *
+     * onNanSessionStateChanged() will be invoked asynchronously after the NAN session request has
+     * been completed. This must be done within CONTEXTHUB_NAN_TRANSACTION_TIMEOUT_MS. If the
+     * request times out, onNanSessionStateChanged() will be invoked with the state that the session
+     * was previously in.
+     *
+     * @param enable Whether the NAN session should be enabled or disabled depending on whether the
+     *        Contexthub needs access to NAN.
+     */
+    void handleNanSessionRequest(in boolean enable);
+
+    /**
+     * Amount of time, in milliseconds, that a handleNanSessionRequest can be pending before the
+     * Contexthub service must respond.
+     */
+    const int CONTEXTHUB_NAN_TRANSACTION_TIMEOUT_MS = 10000;
 }
diff --git a/contexthub/aidl/default/ContextHub.cpp b/contexthub/aidl/default/ContextHub.cpp
index ac1dc46..615ac5c 100644
--- a/contexthub/aidl/default/ContextHub.cpp
+++ b/contexthub/aidl/default/ContextHub.cpp
@@ -87,6 +87,10 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ScopedAStatus ContextHub::onNanSessionStateChanged(bool /*sin_state*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
 ScopedAStatus ContextHub::registerCallback(int32_t in_contextHubId,
                                            const std::shared_ptr<IContextHubCallback>& in_cb) {
     if (in_contextHubId == kMockHubId) {
diff --git a/contexthub/aidl/default/include/contexthub-impl/ContextHub.h b/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
index 4aeb948..b3998b9 100644
--- a/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
+++ b/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
@@ -47,6 +47,7 @@
     ::ndk::ScopedAStatus onHostEndpointConnected(const HostEndpointInfo& in_info) override;
 
     ::ndk::ScopedAStatus onHostEndpointDisconnected(char16_t in_hostEndpointId) override;
+    ::ndk::ScopedAStatus onNanSessionStateChanged(bool in_state) override;
 
   private:
     static constexpr uint32_t kMockHubId = 0;
diff --git a/contexthub/aidl/vts/OWNERS b/contexthub/aidl/vts/OWNERS
deleted file mode 100644
index 150818d..0000000
--- a/contexthub/aidl/vts/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file:/contexthub/common/vts/OWNERS
diff --git a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
index 8104f27..4731648 100644
--- a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
+++ b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
@@ -100,6 +100,8 @@
     Status handleTransactionResult(int32_t /* transactionId */, bool /* success */) override {
         return Status::ok();
     }
+
+    Status handleNanSessionRequest(bool /* enable */) override { return Status::ok(); }
 };
 
 TEST_P(ContextHubAidl, TestRegisterCallback) {
@@ -131,6 +133,8 @@
         return Status::ok();
     }
 
+    Status handleNanSessionRequest(bool /* enable */) override { return Status::ok(); }
+
     std::promise<std::vector<NanoappInfo>> promise;
 };
 
@@ -194,6 +198,8 @@
         return Status::ok();
     }
 
+    Status handleNanSessionRequest(bool /* enable */) override { return Status::ok(); }
+
     uint32_t expectedTransactionId = 0;
     std::promise<bool> promise;
 };
@@ -354,6 +360,11 @@
     ASSERT_TRUE(contextHub->onHostEndpointDisconnected(kHostEndpointId).isOk());
 }
 
+TEST_P(ContextHubAidl, TestNanSessionStateChange) {
+    ASSERT_TRUE(contextHub->onNanSessionStateChanged(true /*state*/).isOk());
+    ASSERT_TRUE(contextHub->onNanSessionStateChanged(false /*state*/).isOk());
+}
+
 std::string PrintGeneratedTest(const testing::TestParamInfo<ContextHubAidl::ParamType>& info) {
     return std::string("CONTEXT_HUB_ID_") + std::to_string(std::get<1>(info.param));
 }
diff --git a/contexthub/common/default/1.X/OWNERS b/contexthub/common/default/1.X/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/contexthub/common/default/1.X/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/contexthub/common/vts/OWNERS b/contexthub/common/vts/OWNERS
deleted file mode 100644
index 161b2f0..0000000
--- a/contexthub/common/vts/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-#Context Hub team
-arthuri@google.com
-bduddie@google.com
-stange@google.com
-
-#VTS team
-dshi@google.com
-trong@google.com
diff --git a/current.txt b/current.txt
index 0fb8b49..fbdd3fe 100644
--- a/current.txt
+++ b/current.txt
@@ -932,5 +932,6 @@
 # ABI preserving changes to HALs during Android U
 2aa559cda86c358c6429114ef6bc72c1b43281e98f9eb6b4df5e7073c8d05767 android.hardware.automotive.vehicle@2.0::types
 42abd285a4293dadb8c89bc63b90cae2872fbffe90c4517aa3ea4965e8aecff7 android.hardware.graphics.common@1.2::types
+4f1a02d21a22104c734f71cdbba19b6f7e93d4ee107ff79f0dbdd171a8430e0e android.hardware.automotive.vehicle@2.0::types
 
 # There will be no more HIDL HALs. Use AIDL instead.
diff --git a/gnss/aidl/android/hardware/gnss/GnssData.aidl b/gnss/aidl/android/hardware/gnss/GnssData.aidl
index 492ba31..1bd8d48 100644
--- a/gnss/aidl/android/hardware/gnss/GnssData.aidl
+++ b/gnss/aidl/android/hardware/gnss/GnssData.aidl
@@ -104,7 +104,7 @@
      * True indicates that the GNSS chipset switches off duty cycling. In such mode, no clock
      * discontinuities are expected and, when supported, carrier phase should be continuous in good
      * signal conditions. All non-blocklisted, healthy constellations, satellites and frequency
-     * bands must be tracked and reported in this mode.
+     * bands that are meaningful to positioning accuracy must be tracked and reported in this mode.
      *
      * False indicates that the GNSS chipset optimizes power via duty cycling, constellations and
      * frequency limits, etc.
diff --git a/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl b/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl
index 4316407..33e9008 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl
@@ -36,9 +36,9 @@
          * If true, GNSS chipset must switch off duty cycling. In such mode no clock discontinuities
          * are expected and, when supported, carrier phase should be continuous in good signal
          * conditions. All non-blocklisted, healthy constellations, satellites and frequency bands
-         * that the chipset supports must be reported in this mode. The GNSS chipset is allowed to
-         * consume more power in this mode. If false, API must optimize power via duty cycling,
-         * constellations and frequency limits, etc.
+         * that are meaningful to positioning accuracy must be tracked and reported in this mode.
+         * The GNSS chipset is allowed to consume more power in this mode. If false, API must
+         * optimize power via duty cycling, constellations and frequency limits, etc.
          */
         boolean enableFullTracking;
 
diff --git a/graphics/Android.bp b/graphics/Android.bp
index 4898dbe..2fbcb41 100644
--- a/graphics/Android.bp
+++ b/graphics/Android.bp
@@ -21,6 +21,9 @@
     static_libs: [
         "android.hardware.graphics.allocator-V2-ndk",
     ],
+    defaults: [
+        "android.hardware.graphics.common-ndk_static",
+    ],
 }
 
 cc_defaults {
@@ -28,6 +31,9 @@
     shared_libs: [
         "android.hardware.graphics.allocator-V2-ndk",
     ],
+    defaults: [
+        "android.hardware.graphics.common-ndk_shared",
+    ],
 }
 
 cc_defaults {
diff --git a/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
index 980e246..49c2497 100644
--- a/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
+++ b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
@@ -41,4 +41,5 @@
   android.hardware.graphics.common.PixelFormat format = android.hardware.graphics.common.PixelFormat.UNSPECIFIED;
   android.hardware.graphics.common.BufferUsage usage = android.hardware.graphics.common.BufferUsage.CPU_READ_NEVER;
   long reservedSize;
+  android.hardware.graphics.common.ExtendableType[] additionalOptions;
 }
diff --git a/graphics/allocator/aidl/android/hardware/graphics/allocator/AllocationResult.aidl b/graphics/allocator/aidl/android/hardware/graphics/allocator/AllocationResult.aidl
index 0774e25..76f1c95 100644
--- a/graphics/allocator/aidl/android/hardware/graphics/allocator/AllocationResult.aidl
+++ b/graphics/allocator/aidl/android/hardware/graphics/allocator/AllocationResult.aidl
@@ -18,13 +18,17 @@
 
 import android.hardware.common.NativeHandle;
 
- /**
+/**
  * Result of an IAllocator::allocate call.
  *
  * @sa +ndk libnativewindow#AHardwareBuffer_Desc
  */
 @VintfStability
 parcelable AllocationResult {
+    /**
+     * The number of pixels between two consecutive rows of an allocated buffer, when the concept
+     * of consecutive rows is defined. Otherwise, it has no meaning.
+     */
     int stride;
     NativeHandle[] buffers;
-}
\ No newline at end of file
+}
diff --git a/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl b/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
index ffc50b8..50aa2b7 100644
--- a/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
+++ b/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
@@ -17,6 +17,7 @@
 package android.hardware.graphics.allocator;
 
 import android.hardware.graphics.common.BufferUsage;
+import android.hardware.graphics.common.ExtendableType;
 import android.hardware.graphics.common.PixelFormat;
 
 @VintfStability
@@ -54,6 +55,9 @@
     /**
      * Buffer usage mask; valid flags can be found in the definition of
      * BufferUsage.aidl in graphics/common
+     *
+     * The allocator must report isSupported() == false and reject any allocations
+     * with unrecognized buffer usages.
      */
     BufferUsage usage = BufferUsage.CPU_READ_NEVER;
 
@@ -62,4 +66,16 @@
      * See getReservedRegion for more information.
      */
     long reservedSize;
+
+    /**
+     * Extensible additional options that can be set.
+     *
+     * This is intended for options that do not change the overall usage, but which do impact
+     * how a buffer is allocated. An example of this is compression level, such as for
+     * the EGL_EXT_surface_compression extension.
+     *
+     * The allocator must report isSupported() == false and reject any allocations
+     * with unrecognized options.
+     */
+    ExtendableType[] additionalOptions;
 }
diff --git a/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp b/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
index 09f1c15..4778020 100644
--- a/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
+++ b/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
@@ -217,6 +217,8 @@
         }
         return ret;
     }
+
+    int32_t allocatorVersion() const { return mIAllocatorVersion; }
 };
 
 BufferHandle::~BufferHandle() {
@@ -309,6 +311,62 @@
     EXPECT_GE(buffer->stride(), 64);
 }
 
+TEST_P(GraphicsAllocatorAidlTests, RejectsUnknownUsages) {
+    if (allocatorVersion() < 2) {
+        GTEST_SKIP() << "Must be version 2+";
+        return;
+    }
+
+    constexpr auto FirstInvalidV2Usage = static_cast<BufferUsage>(1LL << 33);
+
+    BufferUsage invalidUsage;
+    if (allocatorVersion() == 2) {
+        invalidUsage = FirstInvalidV2Usage;
+    } else {
+        GTEST_FAIL() << "Unknown version " << allocatorVersion();
+    }
+
+    BufferDescriptorInfo info{
+            .name = {"CPU_8888"},
+            .width = 64,
+            .height = 64,
+            .layerCount = 1,
+            .format = PixelFormat::RGBA_8888,
+            .usage = BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
+            .reservedSize = 0,
+    };
+
+    // First make sure we can allocate a known usage buffer as expected
+    EXPECT_TRUE(isSupported(info));
+    EXPECT_TRUE(allocate(info));
+
+    // Now add the unknown bit and verify it's rejected
+    info.usage |= invalidUsage;
+    EXPECT_FALSE(isSupported(info)) << "isSupported() returned true for unknown-to-HAL usage";
+    EXPECT_FALSE(allocate(info)) << "allocate succeeded for unknown-to-HAL usage";
+}
+
+TEST_P(GraphicsAllocatorAidlTests, RejectsUnknownOptions) {
+    if (allocatorVersion() < 2) {
+        GTEST_SKIP() << "Must be version 2+";
+        return;
+    }
+
+    BufferDescriptorInfo info{
+            .name = {"CPU_8888"},
+            .width = 64,
+            .height = 64,
+            .layerCount = 1,
+            .format = PixelFormat::RGBA_8888,
+            .usage = BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
+            .reservedSize = 0,
+    };
+    info.additionalOptions.push_back({"android.hardware.graphics.common.NotARealOption", 1});
+
+    EXPECT_FALSE(isSupported(info)) << "isSupported() returned true for unknown-to-HAL option";
+    EXPECT_FALSE(allocate(info)) << "allocate succeeded for unknown-to-HAL option";
+}
+
 TEST_P(GraphicsFrontBufferTests, FrontBufferGpuToCpu) {
     BufferDescriptorInfo info{
             .name = {"CPU_8888"},
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/StandardMetadataType.aidl
index 06b31a2..6e2e106 100644
--- a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/StandardMetadataType.aidl
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/StandardMetadataType.aidl
@@ -58,4 +58,5 @@
   CTA861_3 = 20,
   SMPTE2094_40 = 21,
   SMPTE2094_10 = 22,
+  STRIDE = 23,
 }
diff --git a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
index 4bca795..8cfdae6 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
@@ -368,4 +368,17 @@
      * If this is unset when encoded into a byte stream, the byte stream is empty.
      */
     SMPTE2094_10 = 22,
+
+    /**
+     * Can be used to get the stride in pixels of the buffer allocation. This is the number of
+     * pixels between two consecutive rows of an allocated buffer, when the concept of consecutive
+     * rows is defined. Otherwise, it has no meaning.
+     *
+     * Must match the value returned in android.hardware.graphics.allocator.AllocationResult#stride
+     *
+     * This is required metadata in mapper5 and should be read-only.
+     *
+     * The metadata type is a uint32_t.
+     */
+    STRIDE = 23,
 }
diff --git a/graphics/composer/aidl/vts/VtsComposerClient.cpp b/graphics/composer/aidl/vts/VtsComposerClient.cpp
index 00b578b..43f4b84 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.cpp
+++ b/graphics/composer/aidl/vts/VtsComposerClient.cpp
@@ -404,14 +404,31 @@
                 return {std::move(configs.first), vtsDisplays};
             }
             for (int config : configs.second) {
-                auto status = updateDisplayProperties(&vtsDisplay, config);
+                auto status = addDisplayConfig(&vtsDisplay, config);
                 if (!status.isOk()) {
-                    ALOGE("Unable to get the displays for test, failed to update the properties "
+                    ALOGE("Unable to get the displays for test, failed to add config "
                           "for display %" PRId64,
                           display);
                     return {std::move(status), vtsDisplays};
                 }
             }
+
+            auto config = getActiveConfig(display);
+            if (!config.first.isOk()) {
+                ALOGE("Unable to get the displays for test, failed to get active config "
+                      "for display %" PRId64, display);
+                return {std::move(config.first), vtsDisplays};
+            }
+
+            auto status = updateDisplayProperties(&vtsDisplay, config.second);
+            if (!status.isOk()) {
+                ALOGE("Unable to get the displays for test, "
+                      "failed to update the properties "
+                      "for display %" PRId64,
+                      display);
+                return {std::move(status), vtsDisplays};
+            }
+
             vtsDisplays.emplace_back(vtsDisplay);
             addDisplayToDisplayResources(display, /*isVirtual*/ false);
         }
@@ -420,7 +437,7 @@
     }
 }
 
-ScopedAStatus VtsComposerClient::updateDisplayProperties(VtsDisplay* vtsDisplay, int32_t config) {
+ScopedAStatus VtsComposerClient::addDisplayConfig(VtsDisplay* vtsDisplay, int32_t config) {
     const auto width =
             getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::WIDTH);
     const auto height =
@@ -431,7 +448,6 @@
             getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::CONFIG_GROUP);
     if (width.first.isOk() && height.first.isOk() && vsyncPeriod.first.isOk() &&
         configGroup.first.isOk()) {
-        vtsDisplay->setDimensions(width.second, height.second);
         vtsDisplay->addDisplayConfig(config, {vsyncPeriod.second, configGroup.second});
         return ScopedAStatus::ok();
     }
@@ -442,6 +458,21 @@
     return ScopedAStatus::fromServiceSpecificError(IComposerClient::EX_BAD_CONFIG);
 }
 
+ScopedAStatus VtsComposerClient::updateDisplayProperties(VtsDisplay* vtsDisplay, int32_t config) {
+    const auto width =
+            getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::WIDTH);
+    const auto height =
+            getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::HEIGHT);
+    if (width.first.isOk() && height.first.isOk()) {
+        vtsDisplay->setDimensions(width.second, height.second);
+        return ScopedAStatus::ok();
+    }
+
+    LOG(ERROR) << "Failed to update display property for width: " << width.first.isOk()
+               << ", height: " << height.first.isOk();
+    return ScopedAStatus::fromServiceSpecificError(IComposerClient::EX_BAD_CONFIG);
+}
+
 ScopedAStatus VtsComposerClient::addDisplayToDisplayResources(int64_t display, bool isVirtual) {
     if (mDisplayResources.insert({display, DisplayResource(isVirtual)}).second) {
         return ScopedAStatus::ok();
diff --git a/graphics/composer/aidl/vts/VtsComposerClient.h b/graphics/composer/aidl/vts/VtsComposerClient.h
index e61fde9..c4bc464 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.h
+++ b/graphics/composer/aidl/vts/VtsComposerClient.h
@@ -178,6 +178,7 @@
     std::pair<ScopedAStatus, OverlayProperties> getOverlaySupport();
 
   private:
+    ScopedAStatus addDisplayConfig(VtsDisplay* vtsDisplay, int32_t config);
     ScopedAStatus updateDisplayProperties(VtsDisplay* vtsDisplay, int32_t config);
 
     ScopedAStatus addDisplayToDisplayResources(int64_t display, bool isVirtual);
diff --git a/graphics/mapper/stable-c/Android.bp b/graphics/mapper/stable-c/Android.bp
index fa3087a..1d01a02 100644
--- a/graphics/mapper/stable-c/Android.bp
+++ b/graphics/mapper/stable-c/Android.bp
@@ -33,6 +33,13 @@
     export_header_lib_headers: [
         "libarect_headers",
     ],
+    // TODO(b/214400477) Remove apex_available
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media.swcodec",
+        "test_com.android.media.swcodec",
+    ],
+    min_sdk_version: "29",
 }
 
 cc_library_shared {
@@ -66,6 +73,13 @@
         "libbase_headers",
         "libimapper_stablec",
     ],
+    // TODO(b/214400477) Remove apex_available
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media.swcodec",
+        "test_com.android.media.swcodec",
+    ],
+    min_sdk_version: "29",
 }
 
 cc_test {
diff --git a/graphics/mapper/stable-c/README.md b/graphics/mapper/stable-c/README.md
new file mode 100644
index 0000000..30f3ccc
--- /dev/null
+++ b/graphics/mapper/stable-c/README.md
@@ -0,0 +1,110 @@
+# IMapper "stable-c" HAL
+
+Starting with gralloc version 5, IMapper is now exposed as a C API instead of through HIDL or AIDL.
+This is due to HIDL being deprecated, and AIDL not wanting to support a pass-through mode & pointers
+for just a couple of clients such as IMapper. So instead a stable C API is used to fill this gap.
+
+## Implementing
+
+To provide an implementation a library implementing the AIMapper API interface should be provided
+in `/vendor/lib[64]/hw/mapper.<imapper_suffix>.so`. The `<imapper_suffix>` should be specified
+as the `<instance>` in the VINTF manifest `<interface>` section. For example:
+```xml
+<manifest version="1.0" type="device">
+    <hal format="native">
+        <name>mapper</name>
+        <version>5.0</version>
+        <interface>
+            <name>I</name>
+            <instance>minigbm</instance>
+        </interface>
+    </hal>
+</manifest>
+```
+defines that the IMapper 5.0 library is provided by `/vendor/lib[64]/hw/mapper.minigbm.so`.
+
+This library must export the following `extern "C"` symbols:
+
+### `ANDROID_HAL_STABLEC_VERSION`
+
+This is a uint32_t that should simply be set to the exported AIMapper version. For example:
+```c++
+extern "C" uint32_t ANDROID_HAL_STABLEC_VERSION = AIMAPPER_VERSION_5;
+```
+
+### `AIMapper_loadIMapper`
+
+This is what should actually load the HAL interface. The full type signature is
+```c++
+extern "C" AIMapper_Error AIMapper_loadIMapper(AIMapper* _Nullable* _Nonnull outImplementation)
+```
+
+See `include/android/hardware/graphics/mapper/IMapper.h` for complete documentation on what
+this function must return.
+
+To make it easier to implement this C API, a header-only helper library is provided called
+`libimapper_providerutils`. This library handles mapping from the C API struct to a C++ class
+as well as provides helpers for encoding & decoding metadata, largely replacing the role that
+`libgralloctypes` filled with IMapper 4.
+
+To use this library, create a class that extends from `IMapperV5Impl` and use `IMapperProvider` to
+implement `AIMapper_loadIMapper`:
+
+```c++
+// The IMapper interface itself
+#include <android/hardware/graphics/mapper/IMapper.h>
+// Helpers for reading & writing metadata
+#include <android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h>
+// Helper for providing the implementation interface
+#include <android/hardware/graphics/mapper/utils/IMapperProvider.h>
+
+// Define an IMapperV5 implementation
+class CrosGrallocMapperV5 final : public vendor::mapper::IMapperV5Impl {
+    // Override all the methods of IMapperV5Impl
+      AIMapper_Error importBuffer(const native_handle_t* _Nonnull handle,
+                              buffer_handle_t _Nullable* _Nonnull outBufferHandle) override;
+      [etc...]
+};
+
+// Expose the required C symbols
+
+extern "C" uint32_t ANDROID_HAL_STABLEC_VERSION = AIMAPPER_VERSION_5;
+
+extern "C" AIMapper_Error AIMapper_loadIMapper(AIMapper* _Nullable* _Nonnull outImplementation) {
+    // Define an IMapperProvider for our V5 implementation
+    static vendor::mapper::IMapperProvider<CrosGrallocMapperV5> provider;
+    return provider.load(outImplementation);
+}
+```
+
+A complete example, including using IMapperMetadataTypes, can be found in the cuttlefish
+implementation in `//external/minigbm/cros_gralloc/mapper_stablec`
+
+### Testing
+
+As with HIDL & AIDL HALs, a VTS test is provided to validate the implementation. It is found in the
+`vts` folder and may be run using `$ atest VtsHalGraphicsMapperStableC_TargetTest`
+
+## Using
+
+It is strongly recommended that clients use either the `AHardwareBuffer` (preferred) or
+`GraphicBufferMapper` (from libui) APIs to use the mapper HAL rather than attempting to use
+`AIMapper` directly.
+
+## Version changes
+
+### Version 5
+
+* Initial introduction of this HAL interface
+* Largely feature-equivalent to IMapper4
+* Requires allocator-V2
+* Removes `BufferDescriptorInfo`;
+* IsSupported has moved to IAllocator
+* Removes `validateBufferSize`, validation is instead handled by clients using metadata queries
+* Getting the following StandardMetadataType is now mandatory:
+  * STRIDE
+* Setting the following StandardMetadataTypes is now mandatory:
+  * DATASPACE
+  * SMPTE2086
+  * CTA861_3
+  * BLEND_MODE
diff --git a/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h b/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h
index 25af6d1..0e6d3dc 100644
--- a/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h
+++ b/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h
@@ -563,9 +563,12 @@
 DEFINE_TYPE(CTA861_3, std::optional<Cta861_3>);
 DEFINE_TYPE(SMPTE2094_10, std::optional<std::vector<uint8_t>>);
 DEFINE_TYPE(SMPTE2094_40, std::optional<std::vector<uint8_t>>);
+DEFINE_TYPE(STRIDE, uint32_t);
 
 #undef DEFINE_TYPE
 
+#if defined(__cplusplus) && __cplusplus >= 202002L
+
 template <typename F, std::size_t... I>
 void invokeWithStandardMetadata(F&& f, StandardMetadataType type, std::index_sequence<I...>) {
     // Setup the jump table, mapping from each type to a springboard that invokes the template
@@ -620,4 +623,6 @@
     return retVal;
 }
 
+#endif
+
 }  // namespace android::hardware::graphics::mapper
\ No newline at end of file
diff --git a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
index 85246ee..2c06353 100644
--- a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
+++ b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
@@ -154,6 +154,7 @@
     std::shared_ptr<IAllocator> mAllocator;
     AIMapper* mIMapper = nullptr;
     AIMapper_loadIMapperFn mIMapperLoader;
+    int32_t* mIMapperHALVersion = nullptr;
 
   protected:
     void Initialize(std::shared_ptr<IAllocator> allocator) {
@@ -171,10 +172,12 @@
         ASSERT_NE(nullptr, mIMapperLoader) << "AIMapper_locaIMapper missing from " << lib_name;
         ASSERT_EQ(AIMAPPER_ERROR_NONE, mIMapperLoader(&mIMapper));
         ASSERT_NE(mIMapper, nullptr);
+        mIMapperHALVersion = (int32_t*)dlsym(so, "ANDROID_HAL_MAPPER_VERSION");
     }
 
   public:
     AIMapper_loadIMapperFn getIMapperLoader() const { return mIMapperLoader; }
+    int32_t* getHalVersion() const { return mIMapperHALVersion; }
 
     std::unique_ptr<BufferAllocation> allocate(const BufferDescriptorInfo& descriptorInfo) {
         AllocationResult result;
@@ -557,6 +560,15 @@
     void TearDown() override {}
 };
 
+TEST_P(GraphicsMapperStableCTests, VersionChecks) {
+    ASSERT_NE(nullptr, getHalVersion()) << "Resolving ANDROID_HAL_MAPPER_VERSION symbol failed";
+    int32_t halVersion = *getHalVersion();
+    EXPECT_EQ(halVersion, AIMAPPER_VERSION_5) << "Unrecognized ANDROID_HAL_MAPPER_VERSION";
+    EXPECT_EQ(mapper()->version, AIMAPPER_VERSION_5) << "Unrecognized AIMapper::version";
+    EXPECT_EQ(halVersion, mapper()->version)
+            << "AIMapper version & ANDROID_HAL_MAPPER_VERSION don't agree";
+}
+
 TEST_P(GraphicsMapperStableCTests, AllV5CallbacksDefined) {
     ASSERT_GE(mapper()->version, AIMAPPER_VERSION_5);
 
@@ -1557,6 +1569,16 @@
     }
 }
 
+TEST_P(GraphicsMapperStableCTests, GetStride) {
+    auto buffer = allocateGeneric();
+    ASSERT_TRUE(buffer);
+    auto bufferHandle = buffer->import();
+    ASSERT_TRUE(bufferHandle);
+    auto value = getStandardMetadata<StandardMetadataType::STRIDE>(*bufferHandle);
+    ASSERT_TRUE(value.has_value());
+    EXPECT_EQ(buffer->stride(), *value);
+}
+
 TEST_P(GraphicsMapperStableCTests, SupportsRequiredGettersSetters) {
     auto buffer = allocateGeneric();
     ASSERT_TRUE(buffer);
@@ -1587,6 +1609,7 @@
             StandardMetadataType::BLEND_MODE,
             StandardMetadataType::SMPTE2086,
             StandardMetadataType::CTA861_3,
+            StandardMetadataType::STRIDE,
     };
 
     std::vector<StandardMetadataType> requiredSetters = {
diff --git a/radio/aidl/Android.bp b/radio/aidl/Android.bp
index 9caa97a..e8cebd7 100644
--- a/radio/aidl/Android.bp
+++ b/radio/aidl/Android.bp
@@ -163,7 +163,12 @@
             enabled: true,
         },
         java: {
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.btservices",
+            ],
             sdk_version: "module_current",
+            min_sdk_version: "Tiramisu",
         },
     },
 
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl
index be06c47..382ddd8 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl
@@ -81,6 +81,4 @@
   oneway void isNullCipherAndIntegrityEnabled(in int serial);
   oneway void isN1ModeEnabled(in int serial);
   oneway void setN1ModeEnabled(in int serial, boolean enable);
-  oneway void setLocationPrivacySetting(in int serial, in boolean shareLocation);
-  oneway void getLocationPrivacySetting(in int serial);
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkIndication.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkIndication.aidl
index 229f3e2..0f017ea 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkIndication.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkIndication.aidl
@@ -49,5 +49,4 @@
   oneway void suppSvcNotify(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.network.SuppSvcNotification suppSvc);
   oneway void voiceRadioTechChanged(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.RadioTechnology rat);
   oneway void emergencyNetworkScanResult(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.network.EmergencyRegResult result);
-  oneway void onNetworkInitiatedLocationResult(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.network.LocationResponseType locationResponseType);
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl
index 009fdd3..bfe8fa3 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl
@@ -80,6 +80,4 @@
   oneway void isNullCipherAndIntegrityEnabledResponse(in android.hardware.radio.RadioResponseInfo info, in boolean isEnabled);
   oneway void isN1ModeEnabledResponse(in android.hardware.radio.RadioResponseInfo info, boolean isEnabled);
   oneway void setN1ModeEnabledResponse(in android.hardware.radio.RadioResponseInfo info);
-  oneway void setLocationPrivacySettingResponse(in android.hardware.radio.RadioResponseInfo info);
-  oneway void getLocationPrivacySettingResponse(in android.hardware.radio.RadioResponseInfo info, boolean shareLocation);
 }
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
index 86b6eca..f22cdb0 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
@@ -555,30 +555,4 @@
      * Response function is IRadioNetworkResponse.setN1ModeEnabledResponse()
      */
     void setN1ModeEnabled(in int serial, boolean enable);
-
-    /**
-     * This API updates the current user setting of sharing the location data. This value must be
-     * used by radio before honoring a network initiated location request for non emergency use
-     * cases. The radio shall ignore this setting during emergency call, emergency SMS or emergency
-     * call back modes and continue to provide the location information to the network initiated
-     * location requests.
-     *
-     * @param serial Serial number of request.
-     * @param shareLocation Whether to share location data to the network or not. true means the
-     *         radio is allowed to provide location data for any network initiated locations
-     *         request. false means the radio must not share location data for any network initiated
-     *         location requests for non-emergency use cases.
-     *
-     * Response function is IRadioNetworkResponse.setLocationPrivacySettingResponse()
-     */
-    void setLocationPrivacySetting(in int serial, in boolean shareLocation);
-
-    /**
-     * Request the current setting of sharing the location data.
-     *
-     * @param serial Serial number of request.
-     *
-     * Response function is IRadioNetworkResponse.getLocationPrivacySettingResponse()
-     */
-    void getLocationPrivacySetting(in int serial);
 }
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl
index 2891496..47d932d 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl
@@ -21,14 +21,13 @@
 import android.hardware.radio.network.BarringInfo;
 import android.hardware.radio.network.CellIdentity;
 import android.hardware.radio.network.CellInfo;
-import android.hardware.radio.network.EmergencyRegResult;
 import android.hardware.radio.network.LinkCapacityEstimate;
-import android.hardware.radio.network.LocationResponseType;
 import android.hardware.radio.network.NetworkScanResult;
 import android.hardware.radio.network.PhoneRestrictedState;
 import android.hardware.radio.network.PhysicalChannelConfig;
 import android.hardware.radio.network.SignalStrength;
 import android.hardware.radio.network.SuppSvcNotification;
+import android.hardware.radio.network.EmergencyRegResult;
 
 /**
  * Interface declaring unsolicited radio indications for network APIs.
@@ -200,13 +199,4 @@
      * @param result the result of the Emergency Network Scan
      */
     void emergencyNetworkScanResult(in RadioIndicationType type, in EmergencyRegResult result);
-
-    /**
-     * Reports the result of the network initiated location request.
-     *
-     * @param type Type of radio indication
-     * @param locationResponseType result of the network initiated location request.
-     */
-    void onNetworkInitiatedLocationResult(
-            in RadioIndicationType type, in LocationResponseType locationResponseType);
 }
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
index f186df7..457b5b9 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
@@ -622,6 +622,7 @@
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:MODEM_ERR
+     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void setNullCipherAndIntegrityEnabledResponse(in RadioResponseInfo info);
 
@@ -666,26 +667,4 @@
      *   RadioError:INVALID_STATE
      */
     void setN1ModeEnabledResponse(in RadioResponseInfo info);
-
-    /**
-     * @param info Response info struct containing response type, serial no. and error
-     *
-     * Valid errors returned:
-     *   RadioError:NONE
-     *   RadioError:RADIO_NOT_AVAILABLE
-     *   RadioError:INTERNAL_ERR
-     */
-    void setLocationPrivacySettingResponse(in RadioResponseInfo info);
-
-    /**
-     * @param info Response info struct containing response type, serial no. and error
-     * @param shareLocation Indicates whether the location sharing is allowed or not, True if
-     *         allowed else false.
-     *
-     * Valid errors returned:
-     *   RadioError:NONE
-     *   RadioError:RADIO_NOT_AVAILABLE
-     *   RadioError:INTERNAL_ERR
-     */
-    void getLocationPrivacySettingResponse(in RadioResponseInfo info, boolean shareLocation);
 }
diff --git a/radio/aidl/android/hardware/radio/network/LocationResponseType.aidl b/radio/aidl/android/hardware/radio/network/LocationResponseType.aidl
deleted file mode 100644
index 0c502d0..0000000
--- a/radio/aidl/android/hardware/radio/network/LocationResponseType.aidl
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.network;
-
-@VintfStability
-@Backing(type="int")
-@JavaDerive(toString=true)
-enum LocationResponseType {
-    /**
-     * Network initiated Location request rejected by modem because the user has not given
-     * permission for this use case
-     */
-    REJECTED = 0,
-    /**
-     * Network initiated Location request is accepted by modem however no location information has
-     * been shared to network due to a failure
-     */
-    ACCEPTED_NO_LOCATION_PROVIDED = 1,
-    /**
-     * Network initiated Location request is accepted and location information is provided to the
-     * network by modem
-     */
-    ACCEPTED_LOCATION_PROVIDED = 2,
-}
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
index 7dbb27b..d57c83d 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
@@ -108,9 +108,6 @@
     ::ndk::ScopedAStatus setNullCipherAndIntegrityEnabled(int32_t serial, bool enabled) override;
     ::ndk::ScopedAStatus isNullCipherAndIntegrityEnabled(int32_t serial) override;
 
-    ::ndk::ScopedAStatus setLocationPrivacySetting(int32_t serial, bool shareLocation) override;
-    ::ndk::ScopedAStatus getLocationPrivacySetting(int32_t serial) override;
-
   protected:
     std::shared_ptr<::aidl::android::hardware::radio::network::IRadioNetworkResponse> respond();
 
diff --git a/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp b/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
index e6a44d1..a379eec 100644
--- a/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
+++ b/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
@@ -372,18 +372,4 @@
     respond()->setN1ModeEnabledResponse(notSupported(serial));
     return ok();
 }
-
-ScopedAStatus RadioNetwork::setLocationPrivacySetting(int32_t serial, bool /*shareLocation*/) {
-    LOG_CALL << serial;
-    LOG(ERROR) << " setLocationPrivacySetting is unsupported by HIDL HALs";
-    respond()->setLocationPrivacySettingResponse(notSupported(serial));
-    return ok();
-}
-
-ScopedAStatus RadioNetwork::getLocationPrivacySetting(int32_t serial) {
-    LOG_CALL << serial;
-    LOG(ERROR) << " getLocationPrivacySetting is unsupported by HIDL HALs";
-    respond()->getLocationPrivacySettingResponse(notSupported(serial), false);
-    return ok();
-}
 }  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/vts/VtsHalRadioTargetTest.cpp b/radio/aidl/vts/VtsHalRadioTargetTest.cpp
index c25f930..33a0d7d 100644
--- a/radio/aidl/vts/VtsHalRadioTargetTest.cpp
+++ b/radio/aidl/vts/VtsHalRadioTargetTest.cpp
@@ -56,7 +56,7 @@
         testing::ValuesIn(android::getAidlHalInstanceNames(IRadioNetwork::descriptor)),
         android::PrintInstanceNameToString);
 
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(RadioSapTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SapTest);
 INSTANTIATE_TEST_SUITE_P(PerInstance, SapTest,
                          testing::ValuesIn(android::getAidlHalInstanceNames(ISap::descriptor)),
                          android::PrintInstanceNameToString);
diff --git a/radio/aidl/vts/radio_network_indication.cpp b/radio/aidl/vts/radio_network_indication.cpp
index 7178982..ae3bd4b 100644
--- a/radio/aidl/vts/radio_network_indication.cpp
+++ b/radio/aidl/vts/radio_network_indication.cpp
@@ -97,8 +97,3 @@
         RadioIndicationType /*type*/, const EmergencyRegResult& /*result*/) {
     return ndk::ScopedAStatus::ok();
 }
-
-ndk::ScopedAStatus RadioNetworkIndication::onNetworkInitiatedLocationResult(
-        RadioIndicationType /*type*/, LocationResponseType /*locationResponseType*/) {
-    return ndk::ScopedAStatus::ok();
-}
diff --git a/radio/aidl/vts/radio_network_response.cpp b/radio/aidl/vts/radio_network_response.cpp
index 35e4202..25d45a5 100644
--- a/radio/aidl/vts/radio_network_response.cpp
+++ b/radio/aidl/vts/radio_network_response.cpp
@@ -320,17 +320,3 @@
     parent_network.notify(info.serial);
     return ndk::ScopedAStatus::ok();
 }
-
-ndk::ScopedAStatus RadioNetworkResponse::setLocationPrivacySettingResponse(
-        const RadioResponseInfo& info) {
-    rspInfo = info;
-    parent_network.notify(info.serial);
-    return ndk::ScopedAStatus::ok();
-}
-
-ndk::ScopedAStatus RadioNetworkResponse::getLocationPrivacySettingResponse(
-        const RadioResponseInfo& info, bool /*shareLocation*/) {
-    rspInfo = info;
-    parent_network.notify(info.serial);
-    return ndk::ScopedAStatus::ok();
-}
diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
index 658fcf7..3d6dbe7 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -2021,8 +2021,8 @@
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
 
-    ASSERT_TRUE(CheckAnyOfErrors(
-            radioRsp_network->rspInfo.error,
-            {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+                                 {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+                                  RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
     LOG(DEBUG) << "isNullCipherAndIntegrityEnabled finished";
 }
diff --git a/radio/aidl/vts/radio_network_utils.h b/radio/aidl/vts/radio_network_utils.h
index 496ec03..601f044 100644
--- a/radio/aidl/vts/radio_network_utils.h
+++ b/radio/aidl/vts/radio_network_utils.h
@@ -169,12 +169,6 @@
             const RadioResponseInfo& info, bool isEnabled) override;
 
     virtual ndk::ScopedAStatus setN1ModeEnabledResponse(const RadioResponseInfo& info) override;
-
-    virtual ndk::ScopedAStatus setLocationPrivacySettingResponse(
-            const RadioResponseInfo& info) override;
-
-    virtual ndk::ScopedAStatus getLocationPrivacySettingResponse(const RadioResponseInfo& info,
-                                                                 bool shareLocation) override;
 };
 
 /* Callback class for radio network indication */
@@ -232,9 +226,6 @@
 
     virtual ndk::ScopedAStatus emergencyNetworkScanResult(
             RadioIndicationType type, const EmergencyRegResult& result) override;
-
-    virtual ndk::ScopedAStatus onNetworkInitiatedLocationResult(
-            RadioIndicationType type, LocationResponseType locationResponseType) override;
 };
 
 // The main test class for Radio AIDL Network.
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 ca18082..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
@@ -8649,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..ff710f1 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;
 
     /**
@@ -224,7 +222,7 @@
      *                2 : bstr             ; KID : EEK ID
      *                3 : -25,             ; Algorithm : ECDH-ES + HKDF-256
      *                -1 : 4,              ; Curve : X25519
-     *                -2 : bstr            ; X25519 public key
+     *                -2 : bstr            ; X25519 public key, little-endian
      *            }
      *
      *            EekP256 = {              ; COSE_Key
@@ -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,9 @@
      *
      * ; 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
-     * }
-     *
+     * ; NOTE: Integer encoding is different for Ed25519 and P256 keys:
+     * ;       - Ed25519 is LE: https://www.rfc-editor.org/rfc/rfc8032#section-3.1
+     * ;       - P256 is BE: https://www.secg.org/sec1-v2.pdf#page=19 (section 2.3.7)
      * PubKeyEd25519 = {                ; COSE_Key
      *     1 : 1,                       ; Key type : octet key pair
      *     3 : AlgorithmEdDSA,          ; Algorithm : EdDSA
@@ -455,19 +450,12 @@
      *     -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
      *     -1 : 1,                      ; Curve: P256
-     *     -2 : bstr,                   ; X coordinate
-     *     -3 : bstr                    ; Y coordinate
+     *     -2 : bstr,                   ; X coordinate, big-endian
+     *     -3 : bstr                    ; Y coordinate, big-endian
      * }
      *
      * AlgorithmES256 = -7
diff --git a/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl b/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
index 275e322..1e41d1b 100644
--- a/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
+++ b/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
@@ -36,12 +36,15 @@
      *     ]
      *
      *     ; NOTE: -70000 is deprecated for v3 HAL implementations.
+     *     ; NOTE: Integer encoding is different for Ed25519 and P256 keys:
+     *     ;       - Ed25519 is LE: https://www.rfc-editor.org/rfc/rfc8032#section-3.1
+     *     ;       - P256 is BE: https://www.secg.org/sec1-v2.pdf#page=19 (section 2.3.7)
      *     PublicKey = {               ; COSE_Key
      *         1 : 2,                  ; Key type : EC2
      *         3 : -7,                 ; Algorithm : ES256
      *         -1 : 1,                 ; Curve : P256
-     *         -2 : bstr,              ; X coordinate, little-endian
-     *         -3 : bstr,              ; Y coordinate, little-endian
+     *         -2 : bstr,              ; X coordinate, big-endian
+     *         -3 : bstr,              ; Y coordinate, big-endian
      *         -70000 : nil            ; Presence indicates this is a test key. If set, K_mac is
      *                                 ; all zeros.
      *     },
diff --git a/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl b/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl
index d59508b..3f699bc 100644
--- a/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl
+++ b/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl
@@ -209,7 +209,7 @@
      *     PubKeyX25519 = {                 ; COSE_Key
      *          1 : 1,                      ; Key type : Octet Key Pair
      *         -1 : 4,                      ; Curve : X25519
-     *         -2 : bstr                    ; Sender X25519 public key
+     *         -2 : bstr                    ; Sender X25519 public key, little-endian
      *     }
      *
      *     PubKeyEd25519 = {                ; COSE_Key
@@ -222,16 +222,16 @@
      *     PubKeyEcdhP256 = {               ; COSE_Key
      *          1 : 2,                      ; Key type : EC2
      *          -1 : 1,                     ; Curve : P256
-     *          -2 : bstr                   ; Sender X coordinate
-     *          -3 : bstr                   ; Sender Y coordinate
+     *          -2 : bstr                   ; Sender X coordinate, big-endian
+     *          -3 : bstr                   ; Sender Y coordinate, big-endian
      *     }
      *
      *     PubKeyECDSA256 = {               ; COSE_Key
      *         1 : 2,                       ; Key type : EC2
      *         3 : AlgorithmES256,          ; Algorithm : ECDSA w/ SHA-256
      *         -1 : 1,                      ; Curve: P256
-     *         -2 : bstr,                   ; X coordinate
-     *         -3 : bstr                    ; Y coordinate
+     *         -2 : bstr,                   ; X coordinate, big-endian
+     *         -3 : bstr                    ; Y coordinate, big-endian
      *     }
      *
      *     AlgorithmES256 = -7
diff --git a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index aebcf67..bbda56d 100644
--- a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -223,6 +223,20 @@
     ASSERT_TRUE(provisionable_->getHardwareInfo(&hwInfo).isOk());
 
     const std::set<int> validCurves = {RpcHardwareInfo::CURVE_P256, RpcHardwareInfo::CURVE_25519};
+    // First check for the implementations that supports only IRPC V3+.
+    if (rpcHardwareInfo.versionNumber >= VERSION_WITHOUT_TEST_MODE) {
+        bytevec keysToSignMac;
+        DeviceInfo deviceInfo;
+        ProtectedData protectedData;
+        auto status = provisionable_->generateCertificateRequest(false, {}, {}, {}, &deviceInfo,
+                                                                 &protectedData, &keysToSignMac);
+        if (!status.isOk() &&
+            (status.getServiceSpecificError() == BnRemotelyProvisionedComponent::STATUS_REMOVED)) {
+            ASSERT_EQ(hwInfo.supportedEekCurve, RpcHardwareInfo::CURVE_NONE)
+                    << "Invalid curve: " << hwInfo.supportedEekCurve;
+            return;
+        }
+    }
     ASSERT_EQ(validCurves.count(hwInfo.supportedEekCurve), 1)
             << "Invalid curve: " << hwInfo.supportedEekCurve;
 }
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/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArc.aidl
similarity index 82%
copy from radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
copy to tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArc.aidl
index e89a40f..552bb46 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
+++ b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArc.aidl
@@ -31,10 +31,12 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.radio.network;
-@Backing(type="int") @JavaDerive(toString=true) @VintfStability
-enum LocationResponseType {
-  REJECTED = 0,
-  ACCEPTED_NO_LOCATION_PROVIDED = 1,
-  ACCEPTED_LOCATION_PROVIDED = 2,
+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/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArcCallback.aidl
similarity index 86%
copy from radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
copy to tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArcCallback.aidl
index e89a40f..ef99824 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
+++ b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArcCallback.aidl
@@ -31,10 +31,9 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.radio.network;
-@Backing(type="int") @JavaDerive(toString=true) @VintfStability
-enum LocationResponseType {
-  REJECTED = 0,
-  ACCEPTED_NO_LOCATION_PROVIDED = 1,
-  ACCEPTED_LOCATION_PROVIDED = 2,
+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/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArcStatus.aidl
similarity index 87%
copy from radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
copy to tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArcStatus.aidl
index e89a40f..729c657 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
+++ b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArcStatus.aidl
@@ -31,10 +31,11 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.radio.network;
-@Backing(type="int") @JavaDerive(toString=true) @VintfStability
-enum LocationResponseType {
-  REJECTED = 0,
-  ACCEPTED_NO_LOCATION_PROVIDED = 1,
-  ACCEPTED_LOCATION_PROVIDED = 2,
+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/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/Result.aidl
similarity index 87%
rename from radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
rename to tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/Result.aidl
index e89a40f..3679d3b 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
+++ b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/Result.aidl
@@ -31,10 +31,11 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.radio.network;
-@Backing(type="int") @JavaDerive(toString=true) @VintfStability
-enum LocationResponseType {
-  REJECTED = 0,
-  ACCEPTED_NO_LOCATION_PROVIDED = 1,
-  ACCEPTED_LOCATION_PROVIDED = 2,
+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/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HpdSignal.aidl
similarity index 87%
copy from radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
copy to tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HpdSignal.aidl
index e89a40f..eef4025 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
+++ b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HpdSignal.aidl
@@ -31,10 +31,9 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.radio.network;
-@Backing(type="int") @JavaDerive(toString=true) @VintfStability
-enum LocationResponseType {
-  REJECTED = 0,
-  ACCEPTED_NO_LOCATION_PROVIDED = 1,
-  ACCEPTED_LOCATION_PROVIDED = 2,
+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/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/Result.aidl
similarity index 87%
copy from radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
copy to tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/Result.aidl
index e89a40f..b6b0eb3 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
+++ b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/Result.aidl
@@ -31,10 +31,12 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.radio.network;
-@Backing(type="int") @JavaDerive(toString=true) @VintfStability
-enum LocationResponseType {
-  REJECTED = 0,
-  ACCEPTED_NO_LOCATION_PROVIDED = 1,
-  ACCEPTED_LOCATION_PROVIDED = 2,
+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/tv/tuner/aidl/default/Frontend.cpp b/tv/tuner/aidl/default/Frontend.cpp
index 0573d08..997d9de 100644
--- a/tv/tuner/aidl/default/Frontend.cpp
+++ b/tv/tuner/aidl/default/Frontend.cpp
@@ -182,7 +182,9 @@
     // Reset callback
     mCallback = nullptr;
     mIsLocked = false;
-    mTuner->removeFrontend(mId);
+    if (mTuner != nullptr) {
+        mTuner->removeFrontend(mId);
+    }
     mTuner = nullptr;
 
     return ::ndk::ScopedAStatus::ok();
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/usb/aidl/vts/VtsAidlUsbTargetTest.cpp b/usb/aidl/vts/VtsAidlUsbTargetTest.cpp
index d87f1f4..aec9954 100644
--- a/usb/aidl/vts/VtsAidlUsbTargetTest.cpp
+++ b/usb/aidl/vts/VtsAidlUsbTargetTest.cpp
@@ -307,7 +307,7 @@
       }
     }
   }
-  EXPECT_LE(1, disabledCount);
+  EXPECT_GE(1, disabledCount);
   ALOGI("UsbAidlTest DataStatusCheck end");
 }
 
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
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
index f800e8f..2ebe145 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
@@ -80,24 +80,25 @@
   void startLoggingToDebugRingBuffer(in String ringName, in android.hardware.wifi.WifiDebugRingBufferVerboseLevel verboseLevel, in int maxIntervalInSec, in int minDataSizeInBytes);
   void stopLoggingToDebugRingBuffer();
   void triggerSubsystemRestart();
-  const int NO_POWER_CAP_CONSTANT = 2147483647;
+  void enableStaChannelForPeerNetwork(in android.hardware.wifi.IWifiChip.ChannelCategoryMask channelCategoryEnableFlag);
+  const int NO_POWER_CAP_CONSTANT = 0x7FFFFFFF;
   @Backing(type="int") @VintfStability
   enum ChipCapabilityMask {
-    DEBUG_MEMORY_FIRMWARE_DUMP = 1,
-    DEBUG_MEMORY_DRIVER_DUMP = 2,
-    DEBUG_RING_BUFFER_CONNECT_EVENT = 4,
-    DEBUG_RING_BUFFER_POWER_EVENT = 8,
-    DEBUG_RING_BUFFER_WAKELOCK_EVENT = 16,
-    DEBUG_RING_BUFFER_VENDOR_DATA = 32,
-    DEBUG_HOST_WAKE_REASON_STATS = 64,
-    DEBUG_ERROR_ALERTS = 128,
-    SET_TX_POWER_LIMIT = 256,
-    D2D_RTT = 512,
-    D2AP_RTT = 1024,
-    USE_BODY_HEAD_SAR = 2048,
-    SET_LATENCY_MODE = 4096,
-    P2P_RAND_MAC = 8192,
-    WIGIG = 16384,
+    DEBUG_MEMORY_FIRMWARE_DUMP = (1 << 0),
+    DEBUG_MEMORY_DRIVER_DUMP = (1 << 1),
+    DEBUG_RING_BUFFER_CONNECT_EVENT = (1 << 2),
+    DEBUG_RING_BUFFER_POWER_EVENT = (1 << 3),
+    DEBUG_RING_BUFFER_WAKELOCK_EVENT = (1 << 4),
+    DEBUG_RING_BUFFER_VENDOR_DATA = (1 << 5),
+    DEBUG_HOST_WAKE_REASON_STATS = (1 << 6),
+    DEBUG_ERROR_ALERTS = (1 << 7),
+    SET_TX_POWER_LIMIT = (1 << 8),
+    D2D_RTT = (1 << 9),
+    D2AP_RTT = (1 << 10),
+    USE_BODY_HEAD_SAR = (1 << 11),
+    SET_LATENCY_MODE = (1 << 12),
+    P2P_RAND_MAC = (1 << 13),
+    WIGIG = (1 << 14),
   }
   @VintfStability
   parcelable ChipConcurrencyCombinationLimit {
@@ -129,9 +130,9 @@
   }
   @Backing(type="int") @VintfStability
   enum CoexRestriction {
-    WIFI_DIRECT = 1,
-    SOFTAP = 2,
-    WIFI_AWARE = 4,
+    WIFI_DIRECT = (1 << 0),
+    SOFTAP = (1 << 1),
+    WIFI_AWARE = (1 << 2),
   }
   @VintfStability
   parcelable CoexUnsafeChannel {
@@ -159,8 +160,13 @@
   }
   @Backing(type="int") @VintfStability
   enum UsableChannelFilter {
-    CELLULAR_COEXISTENCE = 1,
-    CONCURRENCY = 2,
-    NAN_INSTANT_MODE = 4,
+    CELLULAR_COEXISTENCE = (1 << 0),
+    CONCURRENCY = (1 << 1),
+    NAN_INSTANT_MODE = (1 << 2),
+  }
+  @Backing(type="int") @VintfStability
+  enum ChannelCategoryMask {
+    INDOOR_CHANNEL = (1 << 0),
+    DFS_CHANNEL = (1 << 1),
   }
 }
diff --git a/wifi/aidl/android/hardware/wifi/IWifiChip.aidl b/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
index 64692af..5ffea56 100644
--- a/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
+++ b/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
@@ -1106,4 +1106,29 @@
      *         |WifiStatusCode.ERROR_UNKNOWN|
      */
     void triggerSubsystemRestart();
+
+    /**
+     * Channel category mask.
+     */
+    @VintfStability
+    @Backing(type="int")
+    enum ChannelCategoryMask {
+        INDOOR_CHANNEL = 1 << 0,
+        DFS_CHANNEL = 1 << 1,
+    }
+
+    /**
+     * API to enable or disable the feature of allowing current STA-connected channel for WFA GO,
+     * SAP and Aware when the regulatory allows.
+     * If the channel category is enabled and allowed by the regulatory, the HAL method
+     * getUsableChannels() will contain the current STA-connected channel if that channel belongs
+     * to that category.
+     * @param channelCategoryEnableFlag bitmask of |ChannelCategoryMask|.
+     *        For each bit, 1 enables the channel category and 0 disables that channel category.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.FAILURE_UNKNOWN|
+     */
+    void enableStaChannelForPeerNetwork(in ChannelCategoryMask channelCategoryEnableFlag);
 }
diff --git a/wifi/aidl/default/aidl_struct_util.cpp b/wifi/aidl/default/aidl_struct_util.cpp
index 6869ac3..ba7d2db 100644
--- a/wifi/aidl/default/aidl_struct_util.cpp
+++ b/wifi/aidl/default/aidl_struct_util.cpp
@@ -3314,6 +3314,19 @@
     return true;
 }
 
+uint32_t convertAidlChannelCategoryToLegacy(uint32_t aidl_channel_category_mask) {
+    uint32_t channel_category_mask = 0;
+    if (aidl_channel_category_mask &
+        static_cast<int32_t>(IWifiChip::ChannelCategoryMask::INDOOR_CHANNEL)) {
+        channel_category_mask |= legacy_hal::WIFI_INDOOR_CHANNEL;
+    }
+    if (aidl_channel_category_mask &
+        static_cast<int32_t>(IWifiChip::ChannelCategoryMask::DFS_CHANNEL)) {
+        channel_category_mask |= legacy_hal::WIFI_DFS_CHANNEL;
+    }
+    return channel_category_mask;
+}
+
 }  // namespace aidl_struct_util
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wifi/aidl/default/aidl_struct_util.h b/wifi/aidl/default/aidl_struct_util.h
index e478fed..6407d32 100644
--- a/wifi/aidl/default/aidl_struct_util.h
+++ b/wifi/aidl/default/aidl_struct_util.h
@@ -200,6 +200,7 @@
 bool convertLegacyNanBootstrappingConfirmIndToAidl(
         const legacy_hal::NanBootstrappingConfirmInd& legacy_ind,
         NanBootstrappingConfirmInd* aidl_ind);
+uint32_t convertAidlChannelCategoryToLegacy(uint32_t aidl_channel_category_mask);
 }  // namespace aidl_struct_util
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wifi/aidl/default/wifi_chip.cpp b/wifi/aidl/default/wifi_chip.cpp
index 4061699..5597001 100644
--- a/wifi/aidl/default/wifi_chip.cpp
+++ b/wifi/aidl/default/wifi_chip.cpp
@@ -34,6 +34,7 @@
 using aidl::android::hardware::wifi::IfaceType;
 using aidl::android::hardware::wifi::IWifiChip;
 using CoexRestriction = aidl::android::hardware::wifi::IWifiChip::CoexRestriction;
+using ChannelCategoryMask = aidl::android::hardware::wifi::IWifiChip::ChannelCategoryMask;
 using android::base::unique_fd;
 
 constexpr char kCpioMagic[] = "070701";
@@ -685,6 +686,13 @@
                            &WifiChip::getWifiChipCapabilitiesInternal, _aidl_return);
 }
 
+ndk::ScopedAStatus WifiChip::enableStaChannelForPeerNetwork(
+        ChannelCategoryMask in_channelCategoryEnableFlag) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::enableStaChannelForPeerNetworkInternal,
+                           in_channelCategoryEnableFlag);
+}
+
 void WifiChip::invalidateAndRemoveAllIfaces() {
     invalidateAndClearBridgedApAll();
     invalidateAndClearAll(ap_ifaces_);
@@ -1428,6 +1436,14 @@
     return {aidl_chip_capabilities, ndk::ScopedAStatus::ok()};
 }
 
+ndk::ScopedAStatus WifiChip::enableStaChannelForPeerNetworkInternal(
+        ChannelCategoryMask channelCategoryEnableFlag) {
+    auto legacy_status = legacy_hal_.lock()->enableStaChannelForPeerNetwork(
+            aidl_struct_util::convertAidlChannelCategoryToLegacy(
+                    static_cast<uint32_t>(channelCategoryEnableFlag)));
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
 ndk::ScopedAStatus WifiChip::triggerSubsystemRestartInternal() {
     auto legacy_status = legacy_hal_.lock()->triggerSubsystemRestart();
     return createWifiStatusFromLegacyError(legacy_status);
diff --git a/wifi/aidl/default/wifi_chip.h b/wifi/aidl/default/wifi_chip.h
index 7b04e85..c69c7fe 100644
--- a/wifi/aidl/default/wifi_chip.h
+++ b/wifi/aidl/default/wifi_chip.h
@@ -145,6 +145,8 @@
     ndk::ScopedAStatus getSupportedRadioCombinationsMatrix(
             WifiRadioCombinationMatrix* _aidl_return) override;
     ndk::ScopedAStatus getWifiChipCapabilities(WifiChipCapabilities* _aidl_return) override;
+    ndk::ScopedAStatus enableStaChannelForPeerNetwork(
+            ChannelCategoryMask in_channelCategoryEnableFlag) override;
     binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
 
   private:
@@ -214,6 +216,8 @@
     ndk::ScopedAStatus setCountryCodeInternal(const std::array<uint8_t, 2>& in_code);
     std::pair<std::vector<WifiUsableChannel>, ndk::ScopedAStatus> getUsableChannelsInternal(
             WifiBand band, WifiIfaceMode ifaceModeMask, UsableChannelFilter filterMask);
+    ndk::ScopedAStatus enableStaChannelForPeerNetworkInternal(
+            ChannelCategoryMask channelCategoryEnableFlag);
     ndk::ScopedAStatus handleChipConfiguration(std::unique_lock<std::recursive_mutex>* lock,
                                                int32_t mode_id);
     ndk::ScopedAStatus registerDebugRingBufferCallback();
diff --git a/wifi/aidl/default/wifi_legacy_hal.cpp b/wifi/aidl/default/wifi_legacy_hal.cpp
index 54e91d4..f03835f 100644
--- a/wifi/aidl/default/wifi_legacy_hal.cpp
+++ b/wifi/aidl/default/wifi_legacy_hal.cpp
@@ -1835,6 +1835,11 @@
     return {status, chip_capabilities};
 }
 
+wifi_error WifiLegacyHal::enableStaChannelForPeerNetwork(uint32_t channelCategoryEnableFlag) {
+    return global_func_table_.wifi_enable_sta_channel_for_peer_network(global_handle_,
+                                                                       channelCategoryEnableFlag);
+}
+
 void WifiLegacyHal::invalidate() {
     global_handle_ = nullptr;
     iface_name_to_handle_.clear();
diff --git a/wifi/aidl/default/wifi_legacy_hal.h b/wifi/aidl/default/wifi_legacy_hal.h
index 5620280..2300cb7 100644
--- a/wifi/aidl/default/wifi_legacy_hal.h
+++ b/wifi/aidl/default/wifi_legacy_hal.h
@@ -256,12 +256,14 @@
 using ::WIFI_CHAN_WIDTH_80;
 using ::WIFI_CHAN_WIDTH_80P80;
 using ::WIFI_CHAN_WIDTH_INVALID;
+using ::wifi_channel_category;
 using ::wifi_channel_info;
 using ::wifi_channel_stat;
 using ::wifi_channel_width;
 using ::wifi_chip_capabilities;
 using ::wifi_coex_restriction;
 using ::wifi_coex_unsafe_channel;
+using ::WIFI_DFS_CHANNEL;
 using ::WIFI_DUAL_STA_NON_TRANSIENT_UNBIASED;
 using ::WIFI_DUAL_STA_TRANSIENT_PREFER_PRIMARY;
 using ::wifi_error;
@@ -278,6 +280,7 @@
 using ::WIFI_ERROR_UNKNOWN;
 using ::wifi_gscan_capabilities;
 using ::wifi_hal_fn;
+using ::WIFI_INDOOR_CHANNEL;
 using ::wifi_information_element;
 using ::WIFI_INTERFACE_IBSS;
 using ::WIFI_INTERFACE_MESH;
@@ -755,6 +758,7 @@
     wifi_error getWifiCachedScanResults(const std::string& iface_name,
                                         const CachedScanResultsCallbackHandlers& handler);
     std::pair<wifi_error, wifi_chip_capabilities> getWifiChipCapabilities();
+    wifi_error enableStaChannelForPeerNetwork(uint32_t channelCategoryEnableFlag);
 
   private:
     // Retrieve interface handles for all the available interfaces.
diff --git a/wifi/aidl/default/wifi_legacy_hal_stubs.cpp b/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
index a0cb2c0..11da373 100644
--- a/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
@@ -172,6 +172,7 @@
     populateStubFor(&hal_fn->wifi_enable_tx_power_limits);
     populateStubFor(&hal_fn->wifi_get_cached_scan_results);
     populateStubFor(&hal_fn->wifi_get_chip_capabilities);
+    populateStubFor(&hal_fn->wifi_enable_sta_channel_for_peer_network);
     return true;
 }