Merge "Default accel Z direction value to +9.8"
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index e58ae6a..8c32f14 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -91,12 +91,14 @@
     name: "android.hardware.audio.core",
     vendor_available: true,
     srcs: [
+        "android/hardware/audio/core/AudioMode.aidl",
         "android/hardware/audio/core/AudioPatch.aidl",
         "android/hardware/audio/core/AudioRoute.aidl",
         "android/hardware/audio/core/IConfig.aidl",
         "android/hardware/audio/core/IModule.aidl",
         "android/hardware/audio/core/IStreamIn.aidl",
         "android/hardware/audio/core/IStreamOut.aidl",
+        "android/hardware/audio/core/ITelephony.aidl",
         "android/hardware/audio/core/MmapBufferDescriptor.aidl",
         "android/hardware/audio/core/ModuleDebug.aidl",
         "android/hardware/audio/core/StreamDescriptor.aidl",
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/AudioMode.aidl
similarity index 77%
copy from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
copy to audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/AudioMode.aidl
index 5ff45f8..336f9b5 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/AudioMode.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -31,15 +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.security.keymint;
-/* @hide */
-@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
-parcelable RpcHardwareInfo {
-  int versionNumber;
-  @utf8InCpp String rpcAuthorName;
-  int supportedEekCurve = 0;
-  @nullable @utf8InCpp String uniqueId;
-  const int CURVE_NONE = 0;
-  const int CURVE_P256 = 1;
-  const int CURVE_25519 = 2;
+package android.hardware.audio.core;
+@Backing(type="int") @VintfStability
+enum AudioMode {
+  NORMAL = 0,
+  RINGTONE = 1,
+  IN_CALL = 2,
+  IN_COMMUNICATION = 3,
+  CALL_SCREEN = 4,
 }
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 a8bbb15..be382c5 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
@@ -35,6 +35,7 @@
 @VintfStability
 interface IModule {
   void setModuleDebug(in android.hardware.audio.core.ModuleDebug debug);
+  @nullable android.hardware.audio.core.ITelephony getTelephony();
   android.media.audio.common.AudioPort connectExternalDevice(in android.media.audio.common.AudioPort templateIdAndAdditionalData);
   void disconnectExternalDevice(int portId);
   android.hardware.audio.core.AudioPatch[] getAudioPatches();
@@ -49,6 +50,15 @@
   boolean setAudioPortConfig(in android.media.audio.common.AudioPortConfig requested, out android.media.audio.common.AudioPortConfig suggested);
   void resetAudioPatch(int patchId);
   void resetAudioPortConfig(int portConfigId);
+  boolean getMasterMute();
+  void setMasterMute(boolean mute);
+  float getMasterVolume();
+  void setMasterVolume(float volume);
+  boolean getMicMute();
+  void setMicMute(boolean mute);
+  void updateAudioMode(android.hardware.audio.core.AudioMode mode);
+  void updateScreenRotation(android.hardware.audio.core.IModule.ScreenRotation rotation);
+  void updateScreenState(boolean isTurnedOn);
   @VintfStability
   parcelable OpenInputStreamArguments {
     int portConfigId;
@@ -72,4 +82,11 @@
     android.hardware.audio.core.IStreamOut stream;
     android.hardware.audio.core.StreamDescriptor desc;
   }
+  @Backing(type="int") @VintfStability
+  enum ScreenRotation {
+    DEG_0 = 0,
+    DEG_90 = 1,
+    DEG_180 = 2,
+    DEG_270 = 3,
+  }
 }
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.aidl
similarity index 77%
copy from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
copy to audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.aidl
index 5ff45f8..a8c58c1 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -31,15 +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.security.keymint;
-/* @hide */
-@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
-parcelable RpcHardwareInfo {
-  int versionNumber;
-  @utf8InCpp String rpcAuthorName;
-  int supportedEekCurve = 0;
-  @nullable @utf8InCpp String uniqueId;
-  const int CURVE_NONE = 0;
-  const int CURVE_P256 = 1;
-  const int CURVE_25519 = 2;
+package android.hardware.audio.core;
+@VintfStability
+interface ITelephony {
+  android.hardware.audio.core.AudioMode[] getSupportedAudioModes();
+  void switchAudioMode(android.hardware.audio.core.AudioMode mode);
 }
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl
index db1ac22..3a77ad1 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl
@@ -39,16 +39,31 @@
   int frameSizeBytes;
   long bufferSizeFrames;
   android.hardware.audio.core.StreamDescriptor.AudioBuffer audio;
-  const int COMMAND_BURST = 1;
+  const int LATENCY_UNKNOWN = -1;
   @FixedSize @VintfStability
   parcelable Position {
     long frames;
     long timeNs;
   }
+  @Backing(type="int") @VintfStability
+  enum State {
+    STANDBY = 1,
+    IDLE = 2,
+    ACTIVE = 3,
+    PAUSED = 4,
+    DRAINING = 5,
+    DRAIN_PAUSED = 6,
+    ERROR = 100,
+  }
   @FixedSize @VintfStability
-  parcelable Command {
-    int code;
-    int fmqByteCount;
+  union Command {
+    int hal_reserved_exit;
+    android.media.audio.common.Void start;
+    int burst;
+    android.media.audio.common.Void drain;
+    android.media.audio.common.Void standby;
+    android.media.audio.common.Void pause;
+    android.media.audio.common.Void flush;
   }
   @FixedSize @VintfStability
   parcelable Reply {
@@ -57,6 +72,8 @@
     android.hardware.audio.core.StreamDescriptor.Position observable;
     android.hardware.audio.core.StreamDescriptor.Position hardware;
     int latencyMs;
+    int xrunFrames;
+    android.hardware.audio.core.StreamDescriptor.State state = android.hardware.audio.core.StreamDescriptor.State.STANDBY;
   }
   @VintfStability
   union AudioBuffer {
diff --git a/audio/aidl/android/hardware/audio/core/AudioMode.aidl b/audio/aidl/android/hardware/audio/core/AudioMode.aidl
new file mode 100644
index 0000000..0943a55
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/AudioMode.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.core;
+
+/**
+ * The audio mode describes states of the audio system of the device that
+ * can significantly affect the rules of audio routing, volume control, etc.
+ * The audio mode is controlled by the framework, however the HAL has some
+ * flexibility in the choice of modes to support, see 'IModule.updateAudioMode'.
+ */
+@VintfStability
+@Backing(type="int")
+enum AudioMode {
+    /** No active calls. */
+    NORMAL = 0,
+    /** The device is playing the ringtone. */
+    RINGTONE = 1,
+    /** The call is handled by the telephony stack ("voice call"). */
+    IN_CALL = 2,
+    /** The call is handled by an application ("VoIP call"). */
+    IN_COMMUNICATION = 3,
+    /** Call screening is in progress. */
+    CALL_SCREEN = 4,
+}
diff --git a/audio/aidl/android/hardware/audio/core/IModule.aidl b/audio/aidl/android/hardware/audio/core/IModule.aidl
index 735f87f..be40051 100644
--- a/audio/aidl/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/android/hardware/audio/core/IModule.aidl
@@ -18,10 +18,12 @@
 
 import android.hardware.audio.common.SinkMetadata;
 import android.hardware.audio.common.SourceMetadata;
+import android.hardware.audio.core.AudioMode;
 import android.hardware.audio.core.AudioPatch;
 import android.hardware.audio.core.AudioRoute;
 import android.hardware.audio.core.IStreamIn;
 import android.hardware.audio.core.IStreamOut;
+import android.hardware.audio.core.ITelephony;
 import android.hardware.audio.core.ModuleDebug;
 import android.hardware.audio.core.StreamDescriptor;
 import android.media.audio.common.AudioOffloadInfo;
@@ -60,6 +62,19 @@
     void setModuleDebug(in ModuleDebug debug);
 
     /**
+     * Retrieve the interface to control telephony audio.
+     *
+     * If the HAL module supports telephony functions, it must return an
+     * instance of the ITelephony interface. The same instance must be returned
+     * during the lifetime of the HAL module. If the HAL module does not support
+     * telephony, a null must be returned, without throwing any errors.
+     *
+     * @return An instance of the ITelephony interface implementation.
+     * @throws EX_ILLEGAL_STATE If there was an error creating an instance.
+     */
+    @nullable ITelephony getTelephony();
+
+    /**
      * 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
@@ -263,6 +278,9 @@
      * be completing with an error, although data (zero filled) will still be
      * provided.
      *
+     * After the stream has been opened, it remains in the STANDBY state, see
+     * StreamDescriptor for more details.
+     *
      * @return An opened input stream and the associated descriptor.
      * @param args The pack of arguments, see 'OpenInputStreamArguments' parcelable.
      * @throws EX_ILLEGAL_ARGUMENT In the following cases:
@@ -325,6 +343,9 @@
      * StreamDescriptor will be completing with an error, although the data
      * will still be accepted and immediately discarded.
      *
+     * After the stream has been opened, it remains in the STANDBY state, see
+     * StreamDescriptor for more details.
+     *
      * @return An opened output stream and the associated descriptor.
      * @param args The pack of arguments, see 'OpenOutputStreamArguments' parcelable.
      * @throws EX_ILLEGAL_ARGUMENT In the following cases:
@@ -481,4 +502,140 @@
      *                          - If the port config is used by a patch.
      */
     void resetAudioPortConfig(int portConfigId);
+
+    /**
+     * Get the current state of audio output muting.
+     *
+     * If the HAL module supports muting its combined output completely,
+     * this method returns whether muting is currently enabled.
+     *
+     * Note that muting operates independently from the master volume.
+     *
+     * @return Whether the output from the module is muted.
+     * @throws EX_UNSUPPORTED_OPERATION If muting of combined output
+     *                                  is not supported by the module.
+     */
+    boolean getMasterMute();
+
+    /**
+     * Set the current value of the audio output muting.
+     *
+     * If the HAL module supports muting its combined output completely, this
+     * method controls the mute. Note that for modules supporting telephony,
+     * muting does not affect the voice call.
+     *
+     * For HAL modules not supporting this operation, it's functionality is
+     * typically emulated by the client, in the digital domain.
+     *
+     * @param mute Whether the output from the module is muted.
+     * @throws EX_UNSUPPORTED_OPERATION If muting of combined output
+     *                                  is not supported by the module.
+     */
+    void setMasterMute(boolean mute);
+
+    /**
+     * Get the current value of the audio output attenuation.
+     *
+     * If the HAL module supports attenuating the level its combined output,
+     * this method returns the current attenuation value.
+     *
+     * @return Volume 1.0f means no attenuation (unity), 0.0f is mute.
+     * @throws EX_UNSUPPORTED_OPERATION If attenuation of combined output
+     *                                  is not supported by the module.
+     */
+    float getMasterVolume();
+
+    /**
+     * Set the current value of the audio output attenuation.
+     *
+     * If the HAL module supports attenuating the level its combined output,
+     * this method sets the attenuation value. Note that for modules supporting
+     * telephony, the attenuation of the voice call volume is set separately
+     * via ITelephony interface.
+     *
+     * For HAL modules not supporting this operation, it's functionality is
+     * typically emulated by the client, in the digital domain.
+     *
+     * @param volume The new value, 1.0f means no attenuation (unity), 0.0f is mute.
+     * @throws EX_ILLEGAL_ARGUMENT If the value of the volume is outside of
+     *                             accepted range.
+     * @throws EX_UNSUPPORTED_OPERATION If attenuation of combined output
+     *                                  is not supported by the module.
+     */
+    void setMasterVolume(float volume);
+
+    /**
+     * Get the current state of audio input muting.
+     *
+     * If the HAL module supports muting its external input, this method returns
+     * whether muting is currently enabled.
+     *
+     * @return Whether the input is muted.
+     * @throws EX_UNSUPPORTED_OPERATION If muting of input is not supported by
+     *                                  the module.
+     */
+    boolean getMicMute();
+
+    /**
+     * Set the current value of the audio input muting.
+     *
+     * If the HAL module supports muting its external input, this method
+     * controls the mute.
+     *
+     * For HAL modules not supporting this operation, it's functionality is
+     * emulated by the client.
+     *
+     * @param mute Whether input is muted.
+     * @throws EX_UNSUPPORTED_OPERATION If muting of input is not supported by
+     *                                  the module.
+     */
+    void setMicMute(boolean mute);
+
+    /**
+     * Notify the HAL module on the change of the current audio mode.
+     *
+     * The current audio mode is always controlled by the client. This is an
+     * informative notification sent to all modules, no reply is needed. The HAL
+     * module should silently ignore this notification if it does not need to
+     * be aware of the current audio mode.
+     *
+     * The client sends this notification to all HAL modules after successfully
+     * switching the telephony module by calling the 'ITelephony.switchAudioMode'
+     * method.
+     *
+     * @param mode The current mode.
+     */
+    void updateAudioMode(AudioMode mode);
+
+    @VintfStability
+    @Backing(type="int")
+    enum ScreenRotation {
+        /** Natural orientation. */
+        DEG_0 = 0,
+        DEG_90 = 1,
+        /** Upside down. */
+        DEG_180 = 2,
+        DEG_270 = 3,
+    }
+    /**
+     * Notify the HAL module on the change of the screen rotation.
+     *
+     * Informs the HAL of the current orientation of the device screen. This
+     * information can be used to optimize the output of built-in speakers.
+     * This is an informative notification sent to all modules, no reply is
+     * needed.
+     *
+     * @param rotation The current rotation.
+     */
+    void updateScreenRotation(ScreenRotation rotation);
+
+    /**
+     * Notify the HAL module on the change of the screen state.
+     *
+     * Informs the HAL whether the screen of the device is turned on. This is an
+     * informative notification sent to all modules, no reply is needed.
+     *
+     * @param isTurnedOn True if the screen is turned on.
+     */
+    void updateScreenState(boolean isTurnedOn);
 }
diff --git a/audio/aidl/android/hardware/audio/core/ITelephony.aidl b/audio/aidl/android/hardware/audio/core/ITelephony.aidl
new file mode 100644
index 0000000..a872c7c
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/ITelephony.aidl
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.core;
+
+import android.hardware.audio.core.AudioMode;
+
+/**
+ * An instance of ITelephony manages settings which are specific to voice calls
+ * and SMS messaging functionality. This interface is optional to implement and
+ * provide by the vendor. It needs to be provided only if the device actually
+ * supports telephony.
+ */
+@VintfStability
+interface ITelephony {
+    /**
+     * Return the list of supported audio modes.
+     *
+     * The first 4 AudioModes: NORMAL, RINGTONE, IN_CALL, IN_COMMUNICATION must
+     * be supported by all implementations.
+     *
+     * This method is only called once, during the audio system initialization,
+     * and must return the same result all the time.
+     *
+     * @return The list of supported audio modes.
+     */
+    AudioMode[] getSupportedAudioModes();
+
+    /**
+     * Switch the HAL into a new audio mode.
+     *
+     * The current audio mode is always controlled by the client. The HAL must
+     * accept all modes returned by 'getSupportedAudioModes' and reject the
+     * rest. The HAL must return from this method only after switching itself
+     * to the specified mode, or throw an error if there was a problem during
+     * switching.
+     *
+     * @param mode The mode to switch to.
+     * @throws EX_UNSUPPORTED_OPERATION If the HAL does not support the specified mode.
+     * @throws EX_ILLEGAL_STATE If there was an error during switching.
+     */
+    void switchAudioMode(AudioMode mode);
+}
diff --git a/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl b/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
index 2b1ed8c..2b1fc99 100644
--- a/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
+++ b/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
@@ -19,6 +19,7 @@
 import android.hardware.audio.core.MmapBufferDescriptor;
 import android.hardware.common.fmq.MQDescriptor;
 import android.hardware.common.fmq.SynchronizedReadWrite;
+import android.media.audio.common.Void;
 
 /**
  * Stream descriptor contains fast message queues and buffers used for sending
@@ -33,6 +34,72 @@
  * internal components of the stream while serving commands invoked via the
  * stream's AIDL interface and commands invoked via the command queue of the
  * descriptor.
+ *
+ * There is a state machine defined for the stream, which executes on the
+ * thread handling the commands from the queue. The states are defined based
+ * on the model of idealized producer and consumer connected via a ring buffer.
+ * For input streams, the "producer" is hardware, the "consumer" is software,
+ * for outputs streams it's the opposite. When the producer is active, but
+ * the buffer is full, the following actions are possible:
+ *  - if the consumer is active, the producer blocks until there is space,
+ *    this behavior is only possible for software producers;
+ *  - if the consumer is passive:
+ *    - the producer can preserve the buffer contents—a s/w producer can
+ *      keep the data on their side, while a h/w producer can only drop captured
+ *      data in this case;
+ *    - or the producer overwrites old data in the buffer.
+ * Similarly, when an active consumer faces an empty buffer, it can:
+ *  - block until there is data (producer must be active), only possible
+ *    for software consumers;
+ *  - walk away with no data; when the consumer is hardware, it must emit
+ *    silence in this case.
+ *
+ * The model is defined below, note the asymmetry regarding the 'IDLE' state
+ * between input and output streams:
+ *
+ *  Producer | Buffer state | Consumer | Applies | State
+ *  active?  |              | active?  | to      |
+ * ==========|==============|==========|=========|==============================
+ *  No       | Empty        | No       | Both    | STANDBY
+ * ----------|--------------|----------|---------|-----------------------------
+ *  Yes      | Filling up   | No       | Input   | IDLE, overwrite behavior
+ * ----------|--------------|----------|---------|-----------------------------
+ *  No       | Empty        | Yes†     | Output  | IDLE, h/w emits silence
+ * ----------|--------------|----------|---------|-----------------------------
+ *  Yes      | Not empty    | Yes      | Both    | ACTIVE, s/w x-runs counted
+ * ----------|--------------|----------|---------|-----------------------------
+ *  Yes      | Filling up   | No       | Input   | PAUSED, drop behavior
+ * ----------|--------------|----------|---------|-----------------------------
+ *  Yes      | Filling up   | No†      | Output  | PAUSED, s/w stops writing once
+ *           |              |          |         | the buffer is filled up;
+ *           |              |          |         | h/w emits silence.
+ * ----------|--------------|----------|---------|-----------------------------
+ *  No       | Not empty    | Yes      | Both    | DRAINING
+ * ----------|--------------|----------|---------|-----------------------------
+ *  No       | Not empty    | No†      | Output  | DRAIN_PAUSED,
+ *           |              |          |         | h/w emits silence.
+ *
+ * † - note that for output, "buffer empty, h/w consuming" has the same outcome
+ *     as "buffer not empty, h/w not consuming", but logically these conditions
+ *     are different.
+ *
+ * State machines of both input and output streams start from the 'STANDBY'
+ * state.  Transitions between states happen naturally with changes in the
+ * states of the model elements. For simplicity, we restrict the change to one
+ * element only, for example, in the 'STANDBY' state, either the producer or the
+ * consumer can become active, but not both at the same time. States 'STANDBY',
+ * 'IDLE', 'READY', and '*PAUSED' are "stable"—they require an external event,
+ * whereas a change from the 'DRAINING' state can happen with time as the buffer
+ * gets empty.
+ *
+ * The state machine for input streams is defined in the `stream-in-sm.gv` file,
+ * for output streams—in the `stream-out-sm.gv` file. State machines define how
+ * commands (from the enum 'CommandCode') trigger state changes. The full list
+ * of states and commands is defined by constants of the 'State' enum. Note that
+ * the 'CLOSED' state does not have a constant in the interface because the
+ * client can never observe a stream with a functioning command queue in this
+ * state. The 'ERROR' state is a special state which the state machine enters
+ * when an unrecoverable hardware error is detected by the HAL module.
  */
 @JavaDerive(equals=true, toString=true)
 @VintfStability
@@ -55,30 +122,97 @@
         long timeNs;
     }
 
-    /**
-     * The command used for audio I/O, see 'AudioBuffer'. For MMap No IRQ mode
-     * this command only provides updated positions and latency because actual
-     * audio I/O is done via the 'AudioBuffer.mmap' shared buffer.
-     */
-    const int COMMAND_BURST = 1;
+    @VintfStability
+    @Backing(type="int")
+    enum State {
+        /**
+         * 'STANDBY' is the initial state of the stream, entered after
+         * opening. Since both the producer and the consumer are inactive in
+         * this state, it allows the HAL module to put associated hardware into
+         * "standby" mode to save power.
+         */
+        STANDBY = 1,
+        /**
+         * In the 'IDLE' state the audio hardware is active. For input streams,
+         * the hardware is filling buffer with captured data, overwriting old
+         * contents on buffer wraparounds. For output streams, the buffer is
+         * still empty, and the hardware is outputting zeroes. The HAL module
+         * must not account for any under- or overruns as the client is not
+         * expected to perform audio I/O.
+         */
+        IDLE = 2,
+        /**
+         * The active state of the stream in which it handles audio I/O. The HAL
+         * module can assume that the audio I/O will be periodic, thus inability
+         * of the client to provide or consume audio data on time must be
+         * considered as an under- or overrun and indicated via the 'xrunFrames'
+         * field of the reply.
+         */
+        ACTIVE = 3,
+        /**
+         * In the 'PAUSED' state the consumer is inactive. For input streams,
+         * the hardware stops updating the buffer as soon as it fills up (this
+         * is the difference from the 'IDLE' state). For output streams,
+         * "inactivity" of hardware means that it does not consume audio data,
+         * but rather emits silence.
+         */
+        PAUSED = 4,
+        /**
+         * In the 'DRAINING' state the producer is inactive, the consumer is
+         * finishing up on the buffer contents, emptying it up. As soon as it
+         * gets empty, the stream transfers itself into the next state.
+         */
+        DRAINING = 5,
+        /**
+         * Used for output streams only, pauses draining. This state is similar
+         * to the 'PAUSED' state, except that the client is not adding any
+         * new data. If it emits a 'BURST' command, this brings the stream
+         * into the regular 'PAUSED' state.
+         */
+        DRAIN_PAUSED = 6,
+        /**
+         * The ERROR state is entered when the stream has encountered an
+         * irrecoverable error from the lower layer. After entering it, the
+         * stream can only be closed.
+         */
+        ERROR = 100,
+    }
 
     /**
      * Used for sending commands to the HAL module. The client writes into
      * the queue, the HAL module reads. The queue can only contain a single
      * command.
+     *
+     * Variants of type 'Void' correspond to commands without
+     * arguments. Variants of other types correspond to commands with an
+     * argument. Would in future a need for a command with multiple argument
+     * arise, a Parcelable type should be used for the corresponding variant.
      */
     @VintfStability
     @FixedSize
-    parcelable Command {
+    union Command {
         /**
-         * One of COMMAND_* codes.
+         * Reserved for the HAL implementation to allow unblocking the wait on a
+         * command and exiting the I/O thread. A command of this variant must
+         * never be sent from the client side. To prevent that, the
+         * implementation must pass a random cookie as the command argument,
+         * which is only known to the implementation.
          */
-        int code;
+        int hal_reserved_exit;
         /**
-         * For output streams: the amount of bytes that the client requests the
-         *   HAL module to read from the 'audio.fmq' queue.
-         * For input streams: the amount of bytes requested by the client to
-         *   read from the hardware into the 'audio.fmq' queue.
+         * See the state machines on the applicability of this command to
+         * different states.
+         */
+        Void start;
+        /**
+         * The 'burst' command used for audio I/O, see 'AudioBuffer'. The value
+         * specifies:
+         *
+         *  - for output streams: the amount of bytes that the client requests the
+         *    HAL module to use out of the data contained in the 'audio.fmq' queue.
+         *
+         *  - for input streams: the amount of bytes requested by the client to
+         *    read from the hardware into the 'audio.fmq' queue.
          *
          * In both cases it is allowed for this field to contain any
          * non-negative number. The value 0 can be used if the client only needs
@@ -90,12 +224,54 @@
          * return the amount of actually read or written data via the
          * 'Reply.fmqByteCount' field. Thus, only attempts to pass a negative
          * number must be constituted as a client's error.
+         *
+         * Differences for the MMap No IRQ mode:
+         *
+         *  - this command only provides updated positions and latency because
+         *    actual audio I/O is done via the 'AudioBuffer.mmap' shared buffer.
+         *    The client does not synchronize reads and writes into the buffer
+         *    with sending of this command.
+         *
+         *  - the value must always be set to 0.
          */
-        int fmqByteCount;
+        int burst;
+        /**
+         * See the state machines on the applicability of this command to
+         * different states.
+         */
+        Void drain;
+        /**
+         * See the state machines on the applicability of this command to
+         * different states.
+         *
+         * Note that it's left on the discretion of the HAL implementation to
+         * assess all the necessary conditions that could prevent hardware from
+         * being suspended. Even if it can not be suspended, the state machine
+         * must still enter the 'STANDBY' state for consistency. Since the
+         * buffer must remain empty in this state, even if capturing hardware is
+         * still active, captured data must be discarded.
+         */
+        Void standby;
+        /**
+         * See the state machines on the applicability of this command to
+         * different states.
+         */
+        Void pause;
+        /**
+         * See the state machines on the applicability of this command to
+         * different states.
+         */
+        Void flush;
     }
     MQDescriptor<Command, SynchronizedReadWrite> command;
 
     /**
+     * The value used for the 'Reply.latencyMs' field when the effective
+     * latency can not be reported by the HAL module.
+     */
+    const int LATENCY_UNKNOWN = -1;
+
+    /**
      * Used for providing replies to commands. The HAL module writes into
      * the queue, the client reads. The queue can only contain a single reply,
      * corresponding to the last command sent by the client.
@@ -107,29 +283,42 @@
          * One of Binder STATUS_* statuses:
          *  - STATUS_OK: the command has completed successfully;
          *  - STATUS_BAD_VALUE: invalid value in the 'Command' structure;
-         *  - STATUS_INVALID_OPERATION: the mix port is not connected
-         *                              to any producer or consumer, thus
-         *                              positions can not be reported;
+         *  - STATUS_INVALID_OPERATION: the command is not applicable in the
+         *                              current state of the stream, or to this
+         *                              type of the stream;
+         *  - STATUS_NO_INIT: positions can not be reported because the mix port
+         *                    is not connected to any producer or consumer, or
+         *                    because the HAL module does not support positions
+         *                    reporting for this AudioSource (on input streams).
          *  - STATUS_NOT_ENOUGH_DATA: a read or write error has
          *                            occurred for the 'audio.fmq' queue;
-         *
          */
         int status;
         /**
-         * For output streams: the amount of bytes actually consumed by the HAL
-         *   module from the 'audio.fmq' queue.
+         * Used with the 'burst' command only.
+         *
+         * For output streams: the amount of bytes of data actually consumed
+         *   by the HAL module.
          * For input streams: the amount of bytes actually provided by the HAL
          *   in the 'audio.fmq' queue.
          *
-         * The returned value must not exceed the value passed in the
-         * 'fmqByteCount' field of the corresponding command or be negative.
+         * The returned value must not exceed the value passed as the
+         * argument of the corresponding command, or be negative.
          */
         int fmqByteCount;
         /**
+         * It is recommended to report the current position for any command.
+         * If the position can not be reported, the 'status' field must be
+         * set to 'NO_INIT'.
+         *
          * For output streams: the moment when the specified stream position
          *   was presented to an external observer (i.e. presentation position).
          * For input streams: the moment when data at the specified stream position
          *   was acquired (i.e. capture position).
+         *
+         * The observable position must never be reset by the HAL module.
+         * The data type of the frame counter is large enough to support
+         * continuous counting for years of operation.
          */
         Position observable;
         /**
@@ -138,9 +327,22 @@
          */
         Position hardware;
         /**
-         * Current latency reported by the hardware.
+         * Current latency reported by the hardware. It is recommended to
+         * report the current latency for any command. If the value of latency
+         * can not be determined, this field must be set to 'LATENCY_UNKNOWN'.
          */
         int latencyMs;
+        /**
+         * Number of frames lost due to an underrun (for input streams),
+         * or not provided on time (for output streams) for the **previous**
+         * transfer operation.
+         */
+        int xrunFrames;
+        /**
+         * The state that the stream was in while the HAL module was sending the
+         * reply.
+         */
+        State state = State.STANDBY;
     }
     MQDescriptor<Reply, SynchronizedReadWrite> reply;
 
@@ -170,42 +372,59 @@
     @VintfStability
     union AudioBuffer {
         /**
-         * The fast message queue used for all modes except MMap No IRQ.  Both
-         * reads and writes into this queue are non-blocking because access to
-         * this queue is synchronized via the 'command' and 'reply' queues as
-         * described below. The queue nevertheless uses 'SynchronizedReadWrite'
-         * because there is only one reader, and the reading position must be
-         * shared.
+         * The fast message queue used for BURST commands in all modes except
+         * MMap No IRQ. Both reads and writes into this queue are non-blocking
+         * because access to this queue is synchronized via the 'command' and
+         * 'reply' queues as described below. The queue nevertheless uses
+         * 'SynchronizedReadWrite' because there is only one reader, and the
+         * reading position must be shared.
+         *
+         * Note that the fast message queue is a transient buffer, only used for
+         * data transfer. Neither of the sides can use it to store any data
+         * outside of the 'BURST' operation. The consumer must always retrieve
+         * all data available in the fast message queue, even if it can not use
+         * it. The producer must re-send any unconsumed data on the next
+         * transfer operation. This restriction is posed in order to make the
+         * fast message queue fully transparent from the latency perspective.
          *
          * For output streams the following sequence of operations is used:
          *  1. The client writes audio data into the 'audio.fmq' queue.
-         *  2. The client writes the 'BURST' command into the 'command' queue,
+         *  2. The client writes the BURST command into the 'command' queue,
          *     and hangs on waiting on a read from the 'reply' queue.
          *  3. The high priority thread in the HAL module wakes up due to 2.
-         *  4. The HAL module reads the command and audio data.
+         *  4. The HAL module reads the command and audio data. According
+         *     to the statement above, the HAL module must always read
+         *     from the FMQ all the data it contains. The amount of data that
+         *     the HAL module has actually consumed is indicated to the client
+         *     via the 'reply.fmqByteCount' field.
          *  5. The HAL module writes the command status and current positions
          *     into 'reply' queue, and hangs on waiting on a read from
          *     the 'command' queue.
          *  6. The client wakes up due to 5. and reads the reply.
          *
          * For input streams the following sequence of operations is used:
-         *  1. The client writes the 'BURST' command into the 'command' queue,
+         *  1. The client writes the BURST command into the 'command' queue,
          *     and hangs on waiting on a read from the 'reply' queue.
          *  2. The high priority thread in the HAL module wakes up due to 1.
          *  3. The HAL module writes audio data into the 'audio.fmq' queue.
+         *     The value of 'reply.fmqByteCount' must be the equal to the amount
+         *     of data in the queue.
          *  4. The HAL module writes the command status and current positions
          *     into 'reply' queue, and hangs on waiting on a read from
          *     the 'command' queue.
          *  5. The client wakes up due to 4.
-         *  6. The client reads the reply and audio data.
+         *  6. The client reads the reply and audio data. The client must
+         *     always read from the FMQ all the data it contains.
+         *
          */
         MQDescriptor<byte, SynchronizedReadWrite> fmq;
         /**
          * MMap buffers are shared directly with the DSP, which operates
-         * independently from the CPU. Writes and reads into these buffers
-         * are not synchronized with 'command' and 'reply' queues. However,
-         * the client still uses the 'BURST' command for obtaining current
-         * positions from the HAL module.
+         * independently from the CPU. Writes and reads into these buffers are
+         * not synchronized with 'command' and 'reply' queues. However, the
+         * client still uses the same commands for controlling the audio data
+         * exchange and for obtaining current positions and latency from the HAL
+         * module.
          */
         MmapBufferDescriptor mmap;
     }
diff --git a/audio/aidl/android/hardware/audio/core/stream-in-sm.gv b/audio/aidl/android/hardware/audio/core/stream-in-sm.gv
new file mode 100644
index 0000000..805dc32
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/stream-in-sm.gv
@@ -0,0 +1,42 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// To render: dot -Tpng stream-in-sm.gv -o stream-in-sm.png
+digraph stream_in_state_machine {
+    node [shape=doublecircle style=filled fillcolor=black width=0.5] I;
+    node [shape=point width=0.5] F;
+    node [shape=oval width=1];
+    node [fillcolor=lightgreen] STANDBY;  // buffer is empty
+    node [fillcolor=tomato] CLOSED;
+    node [fillcolor=tomato] ERROR;
+    node [style=dashed] ANY_STATE;
+    node [fillcolor=lightblue style=filled];
+    I -> STANDBY;
+    STANDBY -> IDLE [label="start"];    // producer -> active
+    IDLE -> STANDBY [label="standby"];  // producer -> passive, buffer is cleared
+    IDLE -> ACTIVE [label="burst"];     // consumer -> active
+    ACTIVE -> ACTIVE [label="burst"];
+    ACTIVE -> PAUSED [label="pause"];   // consumer -> passive
+    ACTIVE -> DRAINING [label="drain"]; // producer -> passive
+    PAUSED -> ACTIVE [label="burst"];   // consumer -> active
+    PAUSED -> STANDBY [label="flush"];  // producer -> passive, buffer is cleared
+    DRAINING -> DRAINING [label="burst"];
+    DRAINING -> ACTIVE [label="start"];  // producer -> active
+    DRAINING -> STANDBY [label="<empty buffer>"];  // consumer deactivates
+    IDLE -> ERROR [label="<hardware failure>"];
+    ACTIVE -> ERROR [label="<hardware failure>"];
+    PAUSED -> ERROR [label="<hardware failure>"];
+    ANY_STATE -> CLOSED [label="→IStream*.close"];
+    CLOSED -> F;
+}
diff --git a/audio/aidl/android/hardware/audio/core/stream-out-sm.gv b/audio/aidl/android/hardware/audio/core/stream-out-sm.gv
new file mode 100644
index 0000000..6aa5c61
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/stream-out-sm.gv
@@ -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.
+
+// To render: dot -Tpng stream-out-sm.gv -o stream-out-sm.png
+digraph stream_out_state_machine {
+    node [shape=doublecircle style=filled fillcolor=black width=0.5] I;
+    node [shape=point width=0.5] F;
+    node [shape=oval width=1];
+    node [fillcolor=lightgreen] STANDBY;  // buffer is empty
+    node [fillcolor=lightgreen] IDLE;     // buffer is empty
+    node [fillcolor=tomato] CLOSED;
+    node [fillcolor=tomato] ERROR;
+    node [style=dashed] ANY_STATE;
+    node [fillcolor=lightblue style=filled];
+    I -> STANDBY;
+    STANDBY -> IDLE [label="start"];           // consumer -> active
+    STANDBY -> PAUSED [label="burst"];         // producer -> active
+    IDLE -> STANDBY [label="standby"];         // consumer -> passive
+    IDLE -> ACTIVE [label="burst"];            // producer -> active
+    ACTIVE -> ACTIVE [label="burst"];
+    ACTIVE -> PAUSED [label="pause"];          // consumer -> passive (not consuming)
+    ACTIVE -> DRAINING [label="drain"];        // producer -> passive
+    PAUSED -> PAUSED [label="burst"];
+    PAUSED -> ACTIVE [label="start"];          // consumer -> active
+    PAUSED -> IDLE [label="flush"];            // producer -> passive, buffer is cleared
+    DRAINING -> IDLE [label="<empty buffer>"];
+    DRAINING -> ACTIVE [label="burst"];        // producer -> active
+    DRAINING -> DRAIN_PAUSED [label="pause"];  // consumer -> passive (not consuming)
+    DRAIN_PAUSED -> DRAINING [label="start"];  // consumer -> active
+    DRAIN_PAUSED -> PAUSED [label="burst"];    // producer -> active
+    DRAIN_PAUSED -> IDLE [label="flush"];      // buffer is cleared
+    IDLE -> ERROR [label="<hardware failure>"];
+    ACTIVE -> ERROR [label="<hardware failure>"];
+    DRAINING -> ERROR [label="<hardware failure>"];
+    ANY_STATE -> CLOSED [label="→IStream*.close"];
+    CLOSED -> F;
+}
diff --git a/audio/aidl/common/StreamWorker.cpp b/audio/aidl/common/StreamWorker.cpp
index 9bca760..dda0e4a 100644
--- a/audio/aidl/common/StreamWorker.cpp
+++ b/audio/aidl/common/StreamWorker.cpp
@@ -44,6 +44,10 @@
             mWorkerStateChangeRequest = true;
         }
     }
+    join();
+}
+
+void ThreadController::join() {
     if (mWorker.joinable()) {
         mWorker.join();
     }
diff --git a/audio/aidl/common/include/StreamWorker.h b/audio/aidl/common/include/StreamWorker.h
index 6260eca..ab2ec26 100644
--- a/audio/aidl/common/include/StreamWorker.h
+++ b/audio/aidl/common/include/StreamWorker.h
@@ -39,6 +39,9 @@
     ~ThreadController() { stop(); }
 
     bool start(const std::string& name, int priority);
+    // Note: 'pause' and 'resume' methods should only be used on the "driving" side.
+    // In the case of audio HAL I/O, the driving side is the client, because the HAL
+    // implementation always blocks on getting a command.
     void pause() { switchWorkerStateSync(WorkerState::RUNNING, WorkerState::PAUSE_REQUESTED); }
     void resume() { switchWorkerStateSync(WorkerState::PAUSED, WorkerState::RESUME_REQUESTED); }
     bool hasError() {
@@ -50,6 +53,10 @@
         return mError;
     }
     void stop();
+    // Direct use of 'join' assumes that the StreamLogic is not intended
+    // to run forever, and is guaranteed to exit by itself. This normally
+    // only happen in tests.
+    void join();
     bool waitForAtLeastOneCycle();
 
     // Only used by unit tests.
@@ -133,7 +140,8 @@
     void resume() { mThread.resume(); }
     bool hasError() { return mThread.hasError(); }
     std::string getError() { return mThread.getError(); }
-    void stop() { return mThread.stop(); }
+    void stop() { mThread.stop(); }
+    void join() { mThread.join(); }
     bool waitForAtLeastOneCycle() { return mThread.waitForAtLeastOneCycle(); }
 
     // Only used by unit tests.
diff --git a/audio/aidl/common/tests/streamworker_tests.cpp b/audio/aidl/common/tests/streamworker_tests.cpp
index e3e484d..8ea8424 100644
--- a/audio/aidl/common/tests/streamworker_tests.cpp
+++ b/audio/aidl/common/tests/streamworker_tests.cpp
@@ -160,6 +160,14 @@
     EXPECT_TRUE(worker.hasNoWorkerCycleCalled(kWorkerIdleCheckTime));
 }
 
+TEST_P(StreamWorkerTest, WorkerJoin) {
+    ASSERT_TRUE(worker.start());
+    stream.setStopStatus();
+    worker.join();
+    EXPECT_FALSE(worker.hasError());
+    EXPECT_TRUE(worker.hasNoWorkerCycleCalled(kWorkerIdleCheckTime));
+}
+
 TEST_P(StreamWorkerTest, WorkerError) {
     ASSERT_TRUE(worker.start());
     stream.setErrorStatus();
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index d34d68c..2b9ed5b 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -39,6 +39,7 @@
         "Configuration.cpp",
         "Module.cpp",
         "Stream.cpp",
+        "Telephony.cpp",
     ],
     visibility: [
         ":__subpackages__",
@@ -65,6 +66,7 @@
     name: "aidlaudioeffectservice_defaults",
     defaults: [
         "latest_android_media_audio_common_types_ndk_shared",
+        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     vendor: true,
     shared_libs: [
@@ -77,10 +79,10 @@
         "libutils",
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
-        "android.hardware.audio.effect-V1-ndk",
     ],
     header_libs: [
         "libaudioaidl_headers",
+        "libaudio_system_headers",
         "libsystem_headers",
     ],
     cflags: [
@@ -107,18 +109,22 @@
     defaults: ["aidlaudioeffectservice_defaults"],
     shared_libs: [
         "libbassboostsw",
+        "libbundleaidl",
         "libdynamicsprocessingsw",
+        "libenvreverbsw",
         "libequalizersw",
         "libhapticgeneratorsw",
         "libloudnessenhancersw",
-        "libreverbsw",
+        "libpresetreverbsw",
+        "libtinyxml2",
         "libvirtualizersw",
         "libvisualizersw",
         "libvolumesw",
     ],
     srcs: [
-        "EffectMain.cpp",
+        "EffectConfig.cpp",
         "EffectFactory.cpp",
+        "EffectMain.cpp",
     ],
 }
 
diff --git a/audio/aidl/default/EffectConfig.cpp b/audio/aidl/default/EffectConfig.cpp
new file mode 100644
index 0000000..e1427ec
--- /dev/null
+++ b/audio/aidl/default/EffectConfig.cpp
@@ -0,0 +1,165 @@
+/*
+ * 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_EffectConfig"
+#include <android-base/logging.h>
+
+#include "effectFactory-impl/EffectConfig.h"
+
+using aidl::android::media::audio::common::AudioUuid;
+
+namespace aidl::android::hardware::audio::effect {
+
+EffectConfig::EffectConfig(const std::string& file) {
+    tinyxml2::XMLDocument doc;
+    doc.LoadFile(file.c_str());
+    LOG(DEBUG) << __func__ << " loading " << file;
+    // parse the xml file into maps
+    if (doc.Error()) {
+        LOG(ERROR) << __func__ << " tinyxml2 failed to load " << file
+                   << " error: " << doc.ErrorStr();
+        return;
+    }
+
+    auto registerFailure = [&](bool result) { mSkippedElements += result ? 0 : 1; };
+
+    for (auto& xmlConfig : getChildren(doc, "audio_effects_conf")) {
+        // Parse library
+        for (auto& xmlLibraries : getChildren(xmlConfig, "libraries")) {
+            for (auto& xmlLibrary : getChildren(xmlLibraries, "library")) {
+                registerFailure(parseLibrary(xmlLibrary));
+            }
+        }
+
+        // Parse effects
+        for (auto& xmlEffects : getChildren(xmlConfig, "effects")) {
+            for (auto& xmlEffect : getChildren(xmlEffects)) {
+                registerFailure(parseEffect(xmlEffect));
+            }
+        }
+
+        // Parse pre processing chains
+        for (auto& xmlPreprocess : getChildren(xmlConfig, "preprocess")) {
+            for (auto& xmlStream : getChildren(xmlPreprocess, "stream")) {
+                registerFailure(parseStream(xmlStream));
+            }
+        }
+
+        // Parse post processing chains
+        for (auto& xmlPostprocess : getChildren(xmlConfig, "postprocess")) {
+            for (auto& xmlStream : getChildren(xmlPostprocess, "stream")) {
+                registerFailure(parseStream(xmlStream));
+            }
+        }
+    }
+    LOG(DEBUG) << __func__ << " successfully parsed " << file << ", skipping " << mSkippedElements
+               << " element(s)";
+}
+
+std::vector<std::reference_wrapper<const tinyxml2::XMLElement>> EffectConfig::getChildren(
+        const tinyxml2::XMLNode& node, const char* childTag) {
+    std::vector<std::reference_wrapper<const tinyxml2::XMLElement>> children;
+    for (auto* child = node.FirstChildElement(childTag); child != nullptr;
+         child = child->NextSiblingElement(childTag)) {
+        children.emplace_back(*child);
+    }
+    return children;
+}
+
+bool EffectConfig::parseLibrary(const tinyxml2::XMLElement& xml) {
+    const char* name = xml.Attribute("name");
+    RETURN_VALUE_IF(!name, false, "noNameAttribute");
+    const char* path = xml.Attribute("path");
+    RETURN_VALUE_IF(!path, false, "noPathAttribute");
+
+    mLibraryMap[name] = path;
+    LOG(DEBUG) << __func__ << " " << name << " : " << path;
+    return true;
+}
+
+bool EffectConfig::parseEffect(const tinyxml2::XMLElement& xml) {
+    struct EffectLibraries effectLibraries;
+    std::vector<LibraryUuid> libraryUuids;
+    std::string name = xml.Attribute("name");
+    RETURN_VALUE_IF(name == "", false, "effectsNoName");
+
+    LOG(DEBUG) << __func__ << dump(xml);
+    struct LibraryUuid libraryUuid;
+    if (std::strcmp(xml.Name(), "effectProxy") == 0) {
+        // proxy lib and uuid
+        RETURN_VALUE_IF(!parseLibraryUuid(xml, libraryUuid, true), false, "parseProxyLibFailed");
+        effectLibraries.proxyLibrary = libraryUuid;
+        // proxy effect libs and UUID
+        auto xmlProxyLib = xml.FirstChildElement();
+        RETURN_VALUE_IF(!xmlProxyLib, false, "noLibForProxy");
+        while (xmlProxyLib) {
+            struct LibraryUuid tempLibraryUuid;
+            RETURN_VALUE_IF(!parseLibraryUuid(*xmlProxyLib, tempLibraryUuid), false,
+                            "parseEffectLibFailed");
+            libraryUuids.push_back(std::move(tempLibraryUuid));
+            xmlProxyLib = xmlProxyLib->NextSiblingElement();
+        }
+    } else {
+        // expect only one library if not proxy
+        RETURN_VALUE_IF(!parseLibraryUuid(xml, libraryUuid), false, "parseEffectLibFailed");
+        libraryUuids.push_back(std::move(libraryUuid));
+    }
+
+    effectLibraries.libraries = std::move(libraryUuids);
+    mEffectsMap[name] = std::move(effectLibraries);
+    return true;
+}
+
+bool EffectConfig::parseStream(const tinyxml2::XMLElement& xml) {
+    LOG(DEBUG) << __func__ << dump(xml);
+    const char* type = xml.Attribute("type");
+    RETURN_VALUE_IF(!type, false, "noTypeInProcess");
+    RETURN_VALUE_IF(0 != mProcessingMap.count(type), false, "duplicateType");
+
+    for (auto& apply : getChildren(xml, "apply")) {
+        const char* name = apply.get().Attribute("effect");
+        RETURN_VALUE_IF(!name, false, "noEffectAttribute");
+        mProcessingMap[type].push_back(name);
+        LOG(DEBUG) << __func__ << " " << type << " : " << name;
+    }
+    return true;
+}
+
+bool EffectConfig::parseLibraryUuid(const tinyxml2::XMLElement& xml,
+                                    struct LibraryUuid& libraryUuid, bool isProxy) {
+    // Retrieve library name only if not effectProxy element
+    if (!isProxy) {
+        const char* name = xml.Attribute("library");
+        RETURN_VALUE_IF(!name, false, "noLibraryAttribute");
+        libraryUuid.name = name;
+    }
+
+    const char* uuid = xml.Attribute("uuid");
+    RETURN_VALUE_IF(!uuid, false, "noUuidAttribute");
+    RETURN_VALUE_IF(!stringToUuid(uuid, &libraryUuid.uuid), false, "invalidUuidAttribute");
+
+    LOG(DEBUG) << __func__ << (isProxy ? " proxy " : libraryUuid.name) << " : "
+               << libraryUuid.uuid.toString();
+    return true;
+}
+
+const char* EffectConfig::dump(const tinyxml2::XMLElement& element,
+                               tinyxml2::XMLPrinter&& printer) const {
+    element.Accept(&printer);
+    return printer.CStr();
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/EffectFactory.cpp b/audio/aidl/default/EffectFactory.cpp
index e03dda3..820b447 100644
--- a/audio/aidl/default/EffectFactory.cpp
+++ b/audio/aidl/default/EffectFactory.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "AHAL_EffectFactory"
 #include <android-base/logging.h>
 #include <dlfcn.h>
+#include <unordered_set>
 
 #include "effect-impl/EffectTypes.h"
 #include "effect-impl/EffectUUID.h"
@@ -26,22 +27,9 @@
 
 namespace aidl::android::hardware::audio::effect {
 
-Factory::Factory() {
-    // TODO: get list of library UUID and name from audio_effect.xml.
-    openEffectLibrary(EqualizerTypeUUID, EqualizerSwImplUUID, std::nullopt, "libequalizersw.so");
-    openEffectLibrary(EqualizerTypeUUID, EqualizerBundleImplUUID, std::nullopt, "libbundleaidl.so");
-    openEffectLibrary(BassBoostTypeUUID, BassBoostSwImplUUID, std::nullopt, "libbassboostsw.so");
-    openEffectLibrary(DynamicsProcessingTypeUUID, DynamicsProcessingSwImplUUID, std::nullopt,
-                      "libdynamicsprocessingsw.so");
-    openEffectLibrary(HapticGeneratorTypeUUID, HapticGeneratorSwImplUUID, std::nullopt,
-                      "libhapticgeneratorsw.so");
-    openEffectLibrary(LoudnessEnhancerTypeUUID, LoudnessEnhancerSwImplUUID, std::nullopt,
-                      "libloudnessenhancersw.so");
-    openEffectLibrary(ReverbTypeUUID, ReverbSwImplUUID, std::nullopt, "libreverbsw.so");
-    openEffectLibrary(VirtualizerTypeUUID, VirtualizerSwImplUUID, std::nullopt,
-                      "libvirtualizersw.so");
-    openEffectLibrary(VisualizerTypeUUID, VisualizerSwImplUUID, std::nullopt, "libvisualizersw.so");
-    openEffectLibrary(VolumeTypeUUID, VolumeSwImplUUID, std::nullopt, "libvolumesw.so");
+Factory::Factory(const std::string& file) : mConfig(EffectConfig(file)) {
+    LOG(DEBUG) << __func__ << " with config file: " << file;
+    loadEffectLibs();
 }
 
 Factory::~Factory() {
@@ -62,7 +50,7 @@
                                          const std::optional<AudioUuid>& in_proxy_uuid,
                                          std::vector<Descriptor::Identity>* _aidl_return) {
     std::copy_if(
-            mIdentityList.begin(), mIdentityList.end(), std::back_inserter(*_aidl_return),
+            mIdentitySet.begin(), mIdentitySet.end(), std::back_inserter(*_aidl_return),
             [&](auto& desc) {
                 return (!in_type_uuid.has_value() || in_type_uuid.value() == desc.type) &&
                        (!in_impl_uuid.has_value() || in_impl_uuid.value() == desc.uuid) &&
@@ -172,8 +160,7 @@
     return status;
 }
 
-void Factory::openEffectLibrary(const AudioUuid& type, const AudioUuid& impl,
-                                const std::optional<AudioUuid>& proxy, const std::string& libName) {
+void Factory::openEffectLibrary(const AudioUuid& impl, const std::string& libName) {
     std::function<void(void*)> dlClose = [](void* handle) -> void {
         if (handle && dlclose(handle)) {
             LOG(ERROR) << "dlclose failed " << dlerror();
@@ -187,19 +174,51 @@
         return;
     }
 
-    LOG(DEBUG) << __func__ << " dlopen lib:" << libName << " for uuid:\ntype:" << type.toString()
-               << "\nimpl:" << impl.toString()
-               << "\nproxy:" << (proxy.has_value() ? proxy.value().toString() : "null")
+    LOG(DEBUG) << __func__ << " dlopen lib:" << libName << "\nimpl:" << impl.toString()
                << "\nhandle:" << libHandle;
     mEffectLibMap.insert({impl, std::make_pair(std::move(libHandle), nullptr)});
+}
 
-    Descriptor::Identity id;
-    id.type = type;
-    id.uuid = impl;
-    if (proxy.has_value()) {
-        id.proxy = proxy.value();
+void Factory::createIdentityWithConfig(const EffectConfig::LibraryUuid& configLib,
+                                       const AudioUuid& typeUuid,
+                                       const std::optional<AudioUuid> proxyUuid) {
+    static const auto& libMap = mConfig.getLibraryMap();
+    const std::string& libName = configLib.name;
+    if (auto path = libMap.find(libName); path != libMap.end()) {
+        Descriptor::Identity id;
+        id.type = typeUuid;
+        id.uuid = configLib.uuid;
+        id.proxy = proxyUuid;
+        LOG(DEBUG) << __func__ << ": typeUuid " << id.type.toString() << "\nimplUuid "
+                   << id.uuid.toString() << " proxyUuid "
+                   << (proxyUuid.has_value() ? proxyUuid->toString() : "null");
+        openEffectLibrary(id.uuid, path->second);
+        mIdentitySet.insert(std::move(id));
+    } else {
+        LOG(ERROR) << __func__ << ": library " << libName << " not exist!";
+        return;
     }
-    mIdentityList.push_back(id);
+}
+
+void Factory::loadEffectLibs() {
+    const auto& configEffectsMap = mConfig.getEffectsMap();
+    for (const auto& configEffects : configEffectsMap) {
+        if (auto typeUuid = kUuidNameTypeMap.find(configEffects.first /* effect name */);
+            typeUuid != kUuidNameTypeMap.end()) {
+            const auto& configLibs = configEffects.second;
+            std::optional<AudioUuid> proxyUuid;
+            if (configLibs.proxyLibrary.has_value()) {
+                const auto& proxyLib = configLibs.proxyLibrary.value();
+                proxyUuid = proxyLib.uuid;
+            }
+            for (const auto& configLib : configLibs.libraries) {
+                createIdentityWithConfig(configLib, typeUuid->second, proxyUuid);
+            }
+        } else {
+            LOG(ERROR) << __func__ << ": can not find type UUID for effect " << configEffects.first
+                       << " skipping!";
+        }
+    }
 }
 
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/EffectMain.cpp b/audio/aidl/default/EffectMain.cpp
index 3219dd6..ca81204 100644
--- a/audio/aidl/default/EffectMain.cpp
+++ b/audio/aidl/default/EffectMain.cpp
@@ -19,21 +19,31 @@
 #include <android-base/logging.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
+#include <system/audio_config.h>
+
+/** Default name of effect configuration file. */
+static const char* kDefaultConfigName = "audio_effects_config.xml";
 
 int main() {
     // This is a debug implementation, always enable debug logging.
     android::base::SetMinimumLogSeverity(::android::base::DEBUG);
     ABinderProcess_setThreadPoolMaxThreadCount(0);
 
+    auto configFile = android::audio_find_readable_configuration_file(kDefaultConfigName);
+    if (configFile == "") {
+        LOG(ERROR) << __func__ << ": config file " << kDefaultConfigName << " not found!";
+        return EXIT_FAILURE;
+    }
+    LOG(DEBUG) << __func__ << ": start factory with configFile:" << configFile;
     auto effectFactory =
-            ndk::SharedRefBase::make<aidl::android::hardware::audio::effect::Factory>();
+            ndk::SharedRefBase::make<aidl::android::hardware::audio::effect::Factory>(configFile);
 
     std::string serviceName = std::string() + effectFactory->descriptor + "/default";
     binder_status_t status =
             AServiceManager_addService(effectFactory->asBinder().get(), serviceName.c_str());
     CHECK_EQ(STATUS_OK, status);
-    LOG(DEBUG) << __func__ << ": effectFactoryName:" << serviceName;
 
+    LOG(DEBUG) << __func__ << ": effectFactory: " << serviceName << " start";
     ABinderProcess_joinThreadPool();
     return EXIT_FAILURE;  // should not reach
 }
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index deaca49..6863fe3 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -25,6 +25,7 @@
 #include <aidl/android/media/audio/common/AudioOutputFlags.h>
 
 #include "core-impl/Module.h"
+#include "core-impl/Telephony.h"
 #include "core-impl/utils.h"
 
 using aidl::android::hardware::audio::common::SinkMetadata;
@@ -245,6 +246,15 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Module::getTelephony(std::shared_ptr<ITelephony>* _aidl_return) {
+    if (mTelephony == nullptr) {
+        mTelephony = ndk::SharedRefBase::make<Telephony>();
+    }
+    *_aidl_return = mTelephony;
+    LOG(DEBUG) << __func__ << ": returning instance of ITelephony: " << _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;
@@ -779,4 +789,60 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
 }
 
+ndk::ScopedAStatus Module::getMasterMute(bool* _aidl_return) {
+    *_aidl_return = mMasterMute;
+    LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::setMasterMute(bool in_mute) {
+    LOG(DEBUG) << __func__ << ": " << in_mute;
+    mMasterMute = in_mute;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::getMasterVolume(float* _aidl_return) {
+    *_aidl_return = mMasterVolume;
+    LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::setMasterVolume(float in_volume) {
+    LOG(DEBUG) << __func__ << ": " << in_volume;
+    if (in_volume >= 0.0f && in_volume <= 1.0f) {
+        mMasterVolume = in_volume;
+        return ndk::ScopedAStatus::ok();
+    }
+    LOG(ERROR) << __func__ << ": invalid master volume value: " << in_volume;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+}
+
+ndk::ScopedAStatus Module::getMicMute(bool* _aidl_return) {
+    *_aidl_return = mMicMute;
+    LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::setMicMute(bool in_mute) {
+    LOG(DEBUG) << __func__ << ": " << in_mute;
+    mMicMute = in_mute;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::updateAudioMode(AudioMode in_mode) {
+    // No checks for supported audio modes here, it's an informative notification.
+    LOG(DEBUG) << __func__ << ": " << toString(in_mode);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::updateScreenRotation(ScreenRotation in_rotation) {
+    LOG(DEBUG) << __func__ << ": " << toString(in_rotation);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::updateScreenState(bool in_isTurnedOn) {
+    LOG(DEBUG) << __func__ << ": " << in_isTurnedOn;
+    return ndk::ScopedAStatus::ok();
+}
+
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index 312df72..21dc4b6 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -85,126 +85,344 @@
     return "";
 }
 
+void StreamWorkerCommonLogic::populateReply(StreamDescriptor::Reply* reply,
+                                            bool isConnected) const {
+    if (isConnected) {
+        reply->status = STATUS_OK;
+        reply->observable.frames = mFrameCount;
+        reply->observable.timeNs = ::android::elapsedRealtimeNano();
+    } else {
+        reply->status = STATUS_NO_INIT;
+    }
+}
+
 const std::string StreamInWorkerLogic::kThreadName = "reader";
 
 StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() {
     StreamDescriptor::Command command{};
     if (!mCommandMQ->readBlocking(&command, 1)) {
         LOG(ERROR) << __func__ << ": reading of command from MQ failed";
+        mState = StreamDescriptor::State::ERROR;
         return Status::ABORT;
     }
     StreamDescriptor::Reply reply{};
-    if (command.code == StreamContext::COMMAND_EXIT &&
-        command.fmqByteCount == mInternalCommandCookie) {
-        LOG(DEBUG) << __func__ << ": received EXIT command";
-        // This is an internal command, no need to reply.
-        return Status::EXIT;
-    } else if (command.code == StreamDescriptor::COMMAND_BURST && command.fmqByteCount >= 0) {
-        LOG(DEBUG) << __func__ << ": received BURST read command for " << command.fmqByteCount
-                   << " bytes";
-        usleep(3000);  // Simulate a blocking call into the driver.
-        const size_t byteCount = std::min({static_cast<size_t>(command.fmqByteCount),
-                                           mDataMQ->availableToWrite(), mDataBufferSize});
-        const bool isConnected = mIsConnected;
-        // Simulate reading of data, or provide zeroes if the stream is not connected.
-        for (size_t i = 0; i < byteCount; ++i) {
-            using buffer_type = decltype(mDataBuffer)::element_type;
-            constexpr int kBufferValueRange = std::numeric_limits<buffer_type>::max() -
-                                              std::numeric_limits<buffer_type>::min() + 1;
-            mDataBuffer[i] = isConnected ? (std::rand() % kBufferValueRange) +
-                                                   std::numeric_limits<buffer_type>::min()
-                                         : 0;
-        }
-        bool success = byteCount > 0 ? mDataMQ->write(&mDataBuffer[0], byteCount) : true;
-        if (success) {
-            LOG(DEBUG) << __func__ << ": writing of " << byteCount << " bytes into data MQ"
-                       << " succeeded; connected? " << isConnected;
-            // Frames are provided and counted regardless of connection status.
-            reply.fmqByteCount = byteCount;
-            mFrameCount += byteCount / mFrameSize;
-            if (isConnected) {
-                reply.status = STATUS_OK;
-                reply.observable.frames = mFrameCount;
-                reply.observable.timeNs = ::android::elapsedRealtimeNano();
+    reply.status = STATUS_BAD_VALUE;
+    using Tag = StreamDescriptor::Command::Tag;
+    switch (command.getTag()) {
+        case Tag::hal_reserved_exit:
+            if (const int32_t cookie = command.get<Tag::hal_reserved_exit>();
+                cookie == mInternalCommandCookie) {
+                LOG(DEBUG) << __func__ << ": received EXIT command";
+                setClosed();
+                // This is an internal command, no need to reply.
+                return Status::EXIT;
             } else {
+                LOG(WARNING) << __func__ << ": EXIT command has a bad cookie: " << cookie;
+            }
+            break;
+        case Tag::start:
+            LOG(DEBUG) << __func__ << ": received START read command";
+            if (mState == StreamDescriptor::State::STANDBY ||
+                mState == StreamDescriptor::State::DRAINING) {
+                populateReply(&reply, mIsConnected);
+                mState = mState == StreamDescriptor::State::STANDBY
+                                 ? StreamDescriptor::State::IDLE
+                                 : StreamDescriptor::State::ACTIVE;
+            } else {
+                LOG(WARNING) << __func__ << ": START command can not be handled in the state "
+                             << toString(mState);
                 reply.status = STATUS_INVALID_OPERATION;
             }
-        } else {
-            LOG(WARNING) << __func__ << ": writing of " << byteCount
-                         << " bytes of data to MQ failed";
-            reply.status = STATUS_NOT_ENOUGH_DATA;
-        }
-        reply.latencyMs = Module::kLatencyMs;
-    } else {
-        LOG(WARNING) << __func__ << ": invalid command (" << command.toString()
-                     << ") or count: " << command.fmqByteCount;
-        reply.status = STATUS_BAD_VALUE;
+            break;
+        case Tag::burst:
+            if (const int32_t fmqByteCount = command.get<Tag::burst>(); fmqByteCount >= 0) {
+                LOG(DEBUG) << __func__ << ": received BURST read command for " << fmqByteCount
+                           << " bytes";
+                if (mState == StreamDescriptor::State::IDLE ||
+                    mState == StreamDescriptor::State::ACTIVE ||
+                    mState == StreamDescriptor::State::PAUSED ||
+                    mState == StreamDescriptor::State::DRAINING) {
+                    if (!read(fmqByteCount, &reply)) {
+                        mState = StreamDescriptor::State::ERROR;
+                    }
+                    if (mState == StreamDescriptor::State::IDLE ||
+                        mState == StreamDescriptor::State::PAUSED) {
+                        mState = StreamDescriptor::State::ACTIVE;
+                    } else if (mState == StreamDescriptor::State::DRAINING) {
+                        // To simplify the reference code, we assume that the read operation
+                        // has consumed all the data remaining in the hardware buffer.
+                        // TODO: Provide parametrization on the duration of draining to test
+                        //       handling of commands during the 'DRAINING' state.
+                        mState = StreamDescriptor::State::STANDBY;
+                    }
+                } else {
+                    LOG(WARNING) << __func__ << ": BURST command can not be handled in the state "
+                                 << toString(mState);
+                    reply.status = STATUS_INVALID_OPERATION;
+                }
+            } else {
+                LOG(WARNING) << __func__ << ": invalid burst byte count: " << fmqByteCount;
+            }
+            break;
+        case Tag::drain:
+            LOG(DEBUG) << __func__ << ": received DRAIN read command";
+            if (mState == StreamDescriptor::State::ACTIVE) {
+                usleep(1000);  // Simulate a blocking call into the driver.
+                populateReply(&reply, mIsConnected);
+                // Can switch the state to ERROR if a driver error occurs.
+                mState = StreamDescriptor::State::DRAINING;
+            } else {
+                LOG(WARNING) << __func__ << ": DRAIN command can not be handled in the state "
+                             << toString(mState);
+                reply.status = STATUS_INVALID_OPERATION;
+            }
+            break;
+        case Tag::standby:
+            LOG(DEBUG) << __func__ << ": received STANDBY read command";
+            if (mState == StreamDescriptor::State::IDLE) {
+                usleep(1000);  // Simulate a blocking call into the driver.
+                populateReply(&reply, mIsConnected);
+                // Can switch the state to ERROR if a driver error occurs.
+                mState = StreamDescriptor::State::STANDBY;
+            } else {
+                LOG(WARNING) << __func__ << ": FLUSH command can not be handled in the state "
+                             << toString(mState);
+                reply.status = STATUS_INVALID_OPERATION;
+            }
+            break;
+        case Tag::pause:
+            LOG(DEBUG) << __func__ << ": received PAUSE read command";
+            if (mState == StreamDescriptor::State::ACTIVE) {
+                usleep(1000);  // Simulate a blocking call into the driver.
+                populateReply(&reply, mIsConnected);
+                // Can switch the state to ERROR if a driver error occurs.
+                mState = StreamDescriptor::State::PAUSED;
+            } else {
+                LOG(WARNING) << __func__ << ": PAUSE command can not be handled in the state "
+                             << toString(mState);
+                reply.status = STATUS_INVALID_OPERATION;
+            }
+            break;
+        case Tag::flush:
+            LOG(DEBUG) << __func__ << ": received FLUSH read command";
+            if (mState == StreamDescriptor::State::PAUSED) {
+                usleep(1000);  // Simulate a blocking call into the driver.
+                populateReply(&reply, mIsConnected);
+                // Can switch the state to ERROR if a driver error occurs.
+                mState = StreamDescriptor::State::STANDBY;
+            } else {
+                LOG(WARNING) << __func__ << ": FLUSH command can not be handled in the state "
+                             << toString(mState);
+                reply.status = STATUS_INVALID_OPERATION;
+            }
+            break;
     }
+    reply.state = mState;
     LOG(DEBUG) << __func__ << ": writing reply " << reply.toString();
     if (!mReplyMQ->writeBlocking(&reply, 1)) {
         LOG(ERROR) << __func__ << ": writing of reply " << reply.toString() << " to MQ failed";
+        mState = StreamDescriptor::State::ERROR;
         return Status::ABORT;
     }
     return Status::CONTINUE;
 }
 
+bool StreamInWorkerLogic::read(size_t clientSize, StreamDescriptor::Reply* reply) {
+    // Can switch the state to ERROR if a driver error occurs.
+    const size_t byteCount = std::min({clientSize, mDataMQ->availableToWrite(), mDataBufferSize});
+    const bool isConnected = mIsConnected;
+    bool fatal = false;
+    // Simulate reading of data, or provide zeroes if the stream is not connected.
+    for (size_t i = 0; i < byteCount; ++i) {
+        using buffer_type = decltype(mDataBuffer)::element_type;
+        constexpr int kBufferValueRange = std::numeric_limits<buffer_type>::max() -
+                                          std::numeric_limits<buffer_type>::min() + 1;
+        mDataBuffer[i] = isConnected ? (std::rand() % kBufferValueRange) +
+                                               std::numeric_limits<buffer_type>::min()
+                                     : 0;
+    }
+    usleep(3000);  // Simulate a blocking call into the driver.
+    // Set 'fatal = true' if a driver error occurs.
+    if (bool success = byteCount > 0 ? mDataMQ->write(&mDataBuffer[0], byteCount) : true; success) {
+        LOG(DEBUG) << __func__ << ": writing of " << byteCount << " bytes into data MQ"
+                   << " succeeded; connected? " << isConnected;
+        // Frames are provided and counted regardless of connection status.
+        reply->fmqByteCount += byteCount;
+        mFrameCount += byteCount / mFrameSize;
+        populateReply(reply, isConnected);
+    } else {
+        LOG(WARNING) << __func__ << ": writing of " << byteCount << " bytes of data to MQ failed";
+        reply->status = STATUS_NOT_ENOUGH_DATA;
+    }
+    reply->latencyMs = Module::kLatencyMs;
+    return !fatal;
+}
+
 const std::string StreamOutWorkerLogic::kThreadName = "writer";
 
 StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {
     StreamDescriptor::Command command{};
     if (!mCommandMQ->readBlocking(&command, 1)) {
         LOG(ERROR) << __func__ << ": reading of command from MQ failed";
+        mState = StreamDescriptor::State::ERROR;
         return Status::ABORT;
     }
     StreamDescriptor::Reply reply{};
-    if (command.code == StreamContext::COMMAND_EXIT &&
-        command.fmqByteCount == mInternalCommandCookie) {
-        LOG(DEBUG) << __func__ << ": received EXIT command";
-        // This is an internal command, no need to reply.
-        return Status::EXIT;
-    } else if (command.code == StreamDescriptor::COMMAND_BURST && command.fmqByteCount >= 0) {
-        LOG(DEBUG) << __func__ << ": received BURST write command for " << command.fmqByteCount
-                   << " bytes";
-        const size_t byteCount = std::min({static_cast<size_t>(command.fmqByteCount),
-                                           mDataMQ->availableToRead(), mDataBufferSize});
-        bool success = byteCount > 0 ? mDataMQ->read(&mDataBuffer[0], byteCount) : true;
-        if (success) {
-            const bool isConnected = mIsConnected;
-            LOG(DEBUG) << __func__ << ": reading of " << byteCount << " bytes from data MQ"
-                       << " succeeded; connected? " << isConnected;
-            // Frames are consumed and counted regardless of connection status.
-            reply.fmqByteCount = byteCount;
-            mFrameCount += byteCount / mFrameSize;
-            if (isConnected) {
-                reply.status = STATUS_OK;
-                reply.observable.frames = mFrameCount;
-                reply.observable.timeNs = ::android::elapsedRealtimeNano();
+    reply.status = STATUS_BAD_VALUE;
+    using Tag = StreamDescriptor::Command::Tag;
+    switch (command.getTag()) {
+        case Tag::hal_reserved_exit:
+            if (const int32_t cookie = command.get<Tag::hal_reserved_exit>();
+                cookie == mInternalCommandCookie) {
+                LOG(DEBUG) << __func__ << ": received EXIT command";
+                setClosed();
+                // This is an internal command, no need to reply.
+                return Status::EXIT;
             } else {
+                LOG(WARNING) << __func__ << ": EXIT command has a bad cookie: " << cookie;
+            }
+            break;
+        case Tag::start:
+            LOG(DEBUG) << __func__ << ": received START write command";
+            switch (mState) {
+                case StreamDescriptor::State::STANDBY:
+                    mState = StreamDescriptor::State::IDLE;
+                    break;
+                case StreamDescriptor::State::PAUSED:
+                    mState = StreamDescriptor::State::ACTIVE;
+                    break;
+                case StreamDescriptor::State::DRAIN_PAUSED:
+                    mState = StreamDescriptor::State::PAUSED;
+                    break;
+                default:
+                    LOG(WARNING) << __func__ << ": START command can not be handled in the state "
+                                 << toString(mState);
+                    reply.status = STATUS_INVALID_OPERATION;
+            }
+            if (reply.status != STATUS_INVALID_OPERATION) {
+                populateReply(&reply, mIsConnected);
+            }
+            break;
+        case Tag::burst:
+            if (const int32_t fmqByteCount = command.get<Tag::burst>(); fmqByteCount >= 0) {
+                LOG(DEBUG) << __func__ << ": received BURST write command for " << fmqByteCount
+                           << " bytes";
+                if (mState !=
+                    StreamDescriptor::State::ERROR) {  // BURST can be handled in all valid states
+                    if (!write(fmqByteCount, &reply)) {
+                        mState = StreamDescriptor::State::ERROR;
+                    }
+                    if (mState == StreamDescriptor::State::STANDBY ||
+                        mState == StreamDescriptor::State::DRAIN_PAUSED) {
+                        mState = StreamDescriptor::State::PAUSED;
+                    } else if (mState == StreamDescriptor::State::IDLE ||
+                               mState == StreamDescriptor::State::DRAINING) {
+                        mState = StreamDescriptor::State::ACTIVE;
+                    }  // When in 'ACTIVE' and 'PAUSED' do not need to change the state.
+                } else {
+                    LOG(WARNING) << __func__ << ": BURST command can not be handled in the state "
+                                 << toString(mState);
+                    reply.status = STATUS_INVALID_OPERATION;
+                }
+            } else {
+                LOG(WARNING) << __func__ << ": invalid burst byte count: " << fmqByteCount;
+            }
+            break;
+        case Tag::drain:
+            LOG(DEBUG) << __func__ << ": received DRAIN write command";
+            if (mState == StreamDescriptor::State::ACTIVE) {
+                usleep(1000);  // Simulate a blocking call into the driver.
+                populateReply(&reply, mIsConnected);
+                // Can switch the state to ERROR if a driver error occurs.
+                mState = StreamDescriptor::State::IDLE;
+                // Since there is no actual hardware that would be draining the buffer,
+                // in order to simplify the reference code, we assume that draining
+                // happens instantly, thus skipping the 'DRAINING' state.
+                // TODO: Provide parametrization on the duration of draining to test
+                //       handling of commands during the 'DRAINING' state.
+            } else {
+                LOG(WARNING) << __func__ << ": DRAIN command can not be handled in the state "
+                             << toString(mState);
                 reply.status = STATUS_INVALID_OPERATION;
             }
-            usleep(3000);  // Simulate a blocking call into the driver.
-        } else {
-            LOG(WARNING) << __func__ << ": reading of " << byteCount
-                         << " bytes of data from MQ failed";
-            reply.status = STATUS_NOT_ENOUGH_DATA;
-        }
-        reply.latencyMs = Module::kLatencyMs;
-    } else {
-        LOG(WARNING) << __func__ << ": invalid command (" << command.toString()
-                     << ") or count: " << command.fmqByteCount;
-        reply.status = STATUS_BAD_VALUE;
+            break;
+        case Tag::standby:
+            LOG(DEBUG) << __func__ << ": received STANDBY write command";
+            if (mState == StreamDescriptor::State::IDLE) {
+                usleep(1000);  // Simulate a blocking call into the driver.
+                populateReply(&reply, mIsConnected);
+                // Can switch the state to ERROR if a driver error occurs.
+                mState = StreamDescriptor::State::STANDBY;
+            } else {
+                LOG(WARNING) << __func__ << ": STANDBY command can not be handled in the state "
+                             << toString(mState);
+                reply.status = STATUS_INVALID_OPERATION;
+            }
+            break;
+        case Tag::pause:
+            LOG(DEBUG) << __func__ << ": received PAUSE write command";
+            if (mState == StreamDescriptor::State::ACTIVE ||
+                mState == StreamDescriptor::State::DRAINING) {
+                populateReply(&reply, mIsConnected);
+                mState = mState == StreamDescriptor::State::ACTIVE
+                                 ? StreamDescriptor::State::PAUSED
+                                 : StreamDescriptor::State::DRAIN_PAUSED;
+            } else {
+                LOG(WARNING) << __func__ << ": PAUSE command can not be handled in the state "
+                             << toString(mState);
+                reply.status = STATUS_INVALID_OPERATION;
+            }
+            break;
+        case Tag::flush:
+            LOG(DEBUG) << __func__ << ": received FLUSH write command";
+            if (mState == StreamDescriptor::State::PAUSED ||
+                mState == StreamDescriptor::State::DRAIN_PAUSED) {
+                populateReply(&reply, mIsConnected);
+                mState = StreamDescriptor::State::IDLE;
+            } else {
+                LOG(WARNING) << __func__ << ": FLUSH command can not be handled in the state "
+                             << toString(mState);
+                reply.status = STATUS_INVALID_OPERATION;
+            }
+            break;
     }
+    reply.state = mState;
     LOG(DEBUG) << __func__ << ": writing reply " << reply.toString();
     if (!mReplyMQ->writeBlocking(&reply, 1)) {
         LOG(ERROR) << __func__ << ": writing of reply " << reply.toString() << " to MQ failed";
+        mState = StreamDescriptor::State::ERROR;
         return Status::ABORT;
     }
     return Status::CONTINUE;
 }
 
+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.
+        reply->fmqByteCount += byteCount;
+        mFrameCount += byteCount / mFrameSize;
+        populateReply(reply, isConnected);
+        usleep(3000);  // Simulate a blocking call into the driver.
+        // Set 'fatal = true' if a driver error occurs.
+    } else {
+        LOG(WARNING) << __func__ << ": reading of " << readByteCount
+                     << " bytes of data from MQ failed";
+        reply->status = STATUS_NOT_ENOUGH_DATA;
+    }
+    reply->latencyMs = Module::kLatencyMs;
+    return !fatal;
+}
+
 template <class Metadata, class StreamWorker>
 StreamCommon<Metadata, StreamWorker>::~StreamCommon() {
-    if (!mIsClosed) {
+    if (!isClosed()) {
         LOG(ERROR) << __func__ << ": stream was not closed prior to destruction, resource leak";
         stopWorker();
         // The worker and the context should clean up by themselves via destructors.
@@ -214,13 +432,13 @@
 template <class Metadata, class StreamWorker>
 ndk::ScopedAStatus StreamCommon<Metadata, StreamWorker>::close() {
     LOG(DEBUG) << __func__;
-    if (!mIsClosed) {
+    if (!isClosed()) {
         stopWorker();
         LOG(DEBUG) << __func__ << ": joining the worker thread...";
         mWorker.stop();
         LOG(DEBUG) << __func__ << ": worker thread joined";
         mContext.reset();
-        mIsClosed = true;
+        mWorker.setClosed();
         return ndk::ScopedAStatus::ok();
     } else {
         LOG(ERROR) << __func__ << ": stream was already closed";
@@ -231,13 +449,14 @@
 template <class Metadata, class StreamWorker>
 void StreamCommon<Metadata, StreamWorker>::stopWorker() {
     if (auto commandMQ = mContext.getCommandMQ(); commandMQ != nullptr) {
-        LOG(DEBUG) << __func__ << ": asking the worker to stop...";
-        StreamDescriptor::Command cmd;
-        cmd.code = StreamContext::COMMAND_EXIT;
-        cmd.fmqByteCount = mContext.getInternalCommandCookie();
-        // FIXME: This can block in the case when the client wrote a command
-        // while the stream worker's cycle is not running. Need to revisit
-        // when implementing standby and pause/resume.
+        LOG(DEBUG) << __func__ << ": asking the worker to exit...";
+        auto cmd =
+                StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::hal_reserved_exit>(
+                        mContext.getInternalCommandCookie());
+        // Note: never call 'pause' and 'resume' methods of StreamWorker
+        // in the HAL implementation. These methods are to be used by
+        // the client side only. Preventing the worker loop from running
+        // on the HAL side can cause a deadlock.
         if (!commandMQ->writeBlocking(&cmd, 1)) {
             LOG(ERROR) << __func__ << ": failed to write exit command to the MQ";
         }
@@ -248,7 +467,7 @@
 template <class Metadata, class StreamWorker>
 ndk::ScopedAStatus StreamCommon<Metadata, StreamWorker>::updateMetadata(const Metadata& metadata) {
     LOG(DEBUG) << __func__;
-    if (!mIsClosed) {
+    if (!isClosed()) {
         mMetadata = metadata;
         return ndk::ScopedAStatus::ok();
     }
diff --git a/audio/aidl/default/Telephony.cpp b/audio/aidl/default/Telephony.cpp
new file mode 100644
index 0000000..1854b35
--- /dev/null
+++ b/audio/aidl/default/Telephony.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_to_string.h>
+#define LOG_TAG "AHAL_Telephony"
+#include <android-base/logging.h>
+
+#include "core-impl/Telephony.h"
+
+namespace aidl::android::hardware::audio::core {
+
+ndk::ScopedAStatus Telephony::getSupportedAudioModes(std::vector<AudioMode>* _aidl_return) {
+    *_aidl_return = mSupportedAudioModes;
+    LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Telephony::switchAudioMode(AudioMode in_mode) {
+    if (std::find(mSupportedAudioModes.begin(), mSupportedAudioModes.end(), in_mode) !=
+        mSupportedAudioModes.end()) {
+        LOG(DEBUG) << __func__ << ": " << toString(in_mode);
+        return ndk::ScopedAStatus::ok();
+    }
+    LOG(ERROR) << __func__ << ": unsupported mode " << toString(in_mode);
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml
new file mode 100644
index 0000000..f4ac8fe
--- /dev/null
+++ b/audio/aidl/default/audio_effects_config.xml
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<audio_effects_conf version="2.0" xmlns="http://schemas.android.com/audio/audio_effects_conf/v2_0">
+    <!-- Overview.
+         This example config file was copy from existing one: frameworks/av/media/libeffects/data/
+         audio_effects.xml, with effect library names updated to AIDL libraries we currently have.
+
+         All "library" attributes in "effect" element must must match a "library" element with the
+         same value of the "name" attribute.
+         All "effect" attributes in "preprocess" and "postprocess" element must match an "effect"
+         element with the same value of the "name" attribute.
+
+         AIDL EffectFactory are relying on the "name" attribute in "effect" element to identify the
+         effect type, so it's necessary to have the mapping from name to effect type UUID. Make
+         sure to either use existing effect name as key of
+         ::android::hardware::audio::effect::kUuidNameTypeMap, or add a new {name, typeUUID} map
+         item to the kUuidNameTypeMap.
+
+         Existing audio_effects.xml should working without any change as long as:
+         1. "path" attribute of "library" element matches with the actual effect library name.
+         2. "name" attribute of "effect" and "effectProxy" element correctly added as key of
+            kUuidNameTypeMap, with value matches Identity.type in Descriptor.aidl.
+         3. "uuid" attribute of "effect" element matches Identity.uuid in Descriptor.aidl.
+         4. "uuid" attribute of "effectProxy" element matches Identity.proxy in Descriptor.aidl.
+    -->
+
+    <!-- List of effect libraries to load.
+         Each library element must contain a "name" attribute and a "path" attribute giving the
+         name of a library .so file on the target device.
+    -->
+    <libraries>
+        <library name="bassboostsw" path="libbassboostsw.so"/>
+        <library name="bundle" path="libbundleaidl.so"/>
+        <library name="dynamics_processingsw" path="libdynamicsprocessingsw.so"/>
+        <library name="equalizersw" path="libequalizersw.so"/>
+        <library name="haptic_generatorsw" path="libhapticgeneratorsw.so"/>
+        <library name="loudness_enhancersw" path="libloudnessenhancersw.so"/>
+        <library name="env_reverbsw" path="libenvreverbsw.so"/>
+        <library name="preset_reverbsw" path="libpresetreverbsw.so"/>
+        <library name="virtualizersw" path="libvirtualizersw.so"/>
+        <library name="visualizersw" path="libvisualizersw.so"/>
+        <library name="volumesw" path="libvolumesw.so"/>
+    </libraries>
+
+    <!-- list of effects to load.
+         Each "effect" element must contain a "name", "library" and a "uuid" attribute.
+         The value of the "library" attribute must correspond to the name of one library element in
+         the "libraries" element.
+         The "name" attribute used to specific effect type, and should be mapping to a key of
+         aidl::android::hardware::audio::effect::kUuidNameTypeMap.
+         The "uuid" attribute is the implementation specific UUID as specified by the effect vendor.
+
+         Effect proxy can be supported with "effectProxy" element, each sub-element should contain
+         "library" and "uuid" attribute, all other attributes were ignored. Framework side use
+         result of IFactory.queryEffects() to decide which effect implementation should be part of
+         proxy and which not.
+
+         Only "name", "library", and "uuid" attributes in "effects" element are meaningful and
+         parsed out by EffectConfig class, all other attributes are ignored.
+         Only "name" and "uuid" attributes in "effectProxy" element are meaningful and parsed out
+         by EffectConfig class, all other attributes are ignored.
+    -->
+
+    <effects>
+        <effect name="bassboost" library="bassboostsw" uuid="fa8181f2-588b-11ed-9b6a-0242ac120002"/>
+        <effect name="dynamics_processing" library="dynamics_processingsw" uuid="fa818d78-588b-11ed-9b6a-0242ac120002"/>
+        <effect name="haptic_generator" library="haptic_generatorsw" uuid="fa819110-588b-11ed-9b6a-0242ac120002"/>
+        <effect name="loudness_enhancer" library="loudness_enhancersw" uuid="fa819610-588b-11ed-9b6a-0242ac120002"/>
+        <effect name="env_reverb" library="env_reverbsw" uuid="fa819886-588b-11ed-9b6a-0242ac120002"/>
+        <effect name="preset_reverb" library="preset_reverbsw" uuid="fa8199c6-588b-11ed-9b6a-0242ac120002"/>
+        <effect name="virtualizer" library="virtualizersw" uuid="fa819d86-588b-11ed-9b6a-0242ac120002"/>
+        <effect name="visualizer" library="visualizersw" uuid="fa81a0f6-588b-11ed-9b6a-0242ac120002"/>
+        <effect name="volume" library="volumesw" uuid="fa81a718-588b-11ed-9b6a-0242ac120002"/>
+        <effectProxy name="equalizer" uuid="c8e70ecd-48ca-456e-8a4f-0002a5d5c51b">
+            <libsw library="equalizersw" uuid="0bed4300-847d-11df-bb17-0002a5d5c51b"/>
+            <libsw library="bundle" uuid="ce772f20-847d-11df-bb17-0002a5d5c51b"/>
+        </effectProxy>
+    </effects>
+
+    <!-- Audio pre processor configurations.
+         The pre processor configuration is described in a "preprocess" element and consists in a
+         list of elements each describing pre processor settings for a given use case or "stream".
+         Each stream element has a "type" attribute corresponding to the input source used.
+         Valid types are these defined in system/hardware/interfaces/media/aidl/android/media/audio/
+         common/AudioSource.aidl.
+         Each "stream" element contains a list of "apply" elements indicating one effect to apply.
+         The effect to apply is designated by its name in the "effects" elements.
+         If there are more than one effect apply to one stream, the audio framework will apply them
+         in the same equence as they listed in "stream" element.
+
+        <preprocess>
+            <stream type="voice_communication">
+                <apply effect="aec"/>
+                <apply effect="ns"/>
+            </stream>
+        </preprocess>
+    -->
+
+    <!-- Audio post processor configurations.
+         The post processor configuration is described in a "postprocess" element and consists in a
+         list of elements each describing post processor settings for a given use case or "stream".
+         Each stream element has a "type" attribute corresponding to the stream type used.
+         Valid types are these defined in system/hardware/interfaces/media/aidl/android/media/audio/
+         common/AudioStreamType.aidl.
+         Each "stream" element contains a list of "apply" elements indicating one effect to apply.
+         The effect to apply is designated by its name in the "effects" elements.
+         If there are more than one effect apply to one stream, the audio framework will apply them
+         in the same equence as they listed in "stream" element.
+
+        <postprocess>
+            <stream type="music">
+                <apply effect="music_post_proc"/>
+            </stream>
+            <stream type="voice_call">
+                <apply effect="voice_post_proc"/>
+            </stream>
+            <stream type="notification">
+                <apply effect="notification_post_proc"/>
+            </stream>
+        </postprocess>
+    -->
+
+</audio_effects_conf>
diff --git a/audio/aidl/default/bassboost/BassBoostSw.cpp b/audio/aidl/default/bassboost/BassBoostSw.cpp
index 3c39824..c52d16f 100644
--- a/audio/aidl/default/bassboost/BassBoostSw.cpp
+++ b/audio/aidl/default/bassboost/BassBoostSw.cpp
@@ -26,14 +26,14 @@
 #include "BassBoostSw.h"
 
 using aidl::android::hardware::audio::effect::BassBoostSw;
-using aidl::android::hardware::audio::effect::BassBoostSwImplUUID;
 using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kBassBoostSwImplUUID;
 using aidl::android::hardware::audio::effect::State;
 using aidl::android::media::audio::common::AudioUuid;
 
 extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
                                            std::shared_ptr<IEffect>* instanceSpp) {
-    if (!in_impl_uuid || *in_impl_uuid != BassBoostSwImplUUID) {
+    if (!in_impl_uuid || *in_impl_uuid != kBassBoostSwImplUUID) {
         LOG(ERROR) << __func__ << "uuid not supported";
         return EX_ILLEGAL_ARGUMENT;
     }
diff --git a/audio/aidl/default/bassboost/BassBoostSw.h b/audio/aidl/default/bassboost/BassBoostSw.h
index fe9c640..90a8887 100644
--- a/audio/aidl/default/bassboost/BassBoostSw.h
+++ b/audio/aidl/default/bassboost/BassBoostSw.h
@@ -39,8 +39,8 @@
   public:
     BassBoostSw() { LOG(DEBUG) << __func__; }
     ~BassBoostSw() {
+        cleanUp();
         LOG(DEBUG) << __func__;
-        releaseContext();
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
@@ -57,13 +57,14 @@
     const BassBoost::Capability kCapability;
     /* Effect descriptor */
     const Descriptor kDescriptor = {
-            .common = {.id = {.type = BassBoostTypeUUID,
-                              .uuid = BassBoostSwImplUUID,
+            .common = {.id = {.type = kBassBoostTypeUUID,
+                              .uuid = kBassBoostSwImplUUID,
                               .proxy = std::nullopt},
                        .flags = {.type = Flags::Type::INSERT,
                                  .insert = Flags::Insert::FIRST,
                                  .volume = Flags::Volume::CTRL},
-                       .name = "BassBoostSw"},
+                       .name = "BassBoostSw",
+                       .implementor = "The Android Open Source Project"},
             .capability = Capability::make<Capability::bassBoost>(kCapability)};
 
     /* parameters */
diff --git a/audio/aidl/default/config/audio_policy_configuration.xsd b/audio/aidl/default/config/audio_policy_configuration.xsd
new file mode 100644
index 0000000..823b217
--- /dev/null
+++ b/audio/aidl/default/config/audio_policy_configuration.xsd
@@ -0,0 +1,827 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+         Licensed under the Apache License, Version 2.0 (the "License");
+         you may not use this file except in compliance with the License.
+         You may obtain a copy of the License at
+
+                    http://www.apache.org/licenses/LICENSE-2.0
+
+         Unless required by applicable law or agreed to in writing, software
+         distributed under the License is distributed on an "AS IS" BASIS,
+         WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+         See the License for the specific language governing permissions and
+         limitations under the License.
+-->
+<xs:schema version="2.0"
+           elementFormDefault="qualified"
+           attributeFormDefault="unqualified"
+           xmlns:xs="http://www.w3.org/2001/XMLSchema">
+    <!-- List the config versions supported by audio policy. -->
+    <xs:simpleType name="version">
+        <xs:restriction base="xs:decimal">
+            <xs:enumeration value="7.0"/>
+            <xs:enumeration value="7.1"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="halVersion">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Version of the interface the hal implements. Note that this
+                relates to legacy HAL API versions since HIDL APIs are versioned
+                using other mechanisms.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:decimal">
+            <!-- List of HAL versions supported by the framework. -->
+            <xs:enumeration value="2.0"/>
+            <xs:enumeration value="3.0"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:element name="audioPolicyConfiguration">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element name="globalConfiguration" type="globalConfiguration"/>
+                <xs:element name="modules" type="modules" maxOccurs="unbounded"/>
+                <xs:element name="volumes" type="volumes" maxOccurs="unbounded"/>
+                <xs:element name="surroundSound" type="surroundSound" minOccurs="0" />
+            </xs:sequence>
+            <xs:attribute name="version" type="version"/>
+        </xs:complexType>
+        <xs:key name="moduleNameKey">
+            <xs:selector xpath="modules/module"/>
+            <xs:field xpath="@name"/>
+        </xs:key>
+        <xs:unique name="volumeTargetUniqueness">
+            <xs:selector xpath="volumes/volume"/>
+            <xs:field xpath="@stream"/>
+            <xs:field xpath="@deviceCategory"/>
+        </xs:unique>
+        <xs:key name="volumeCurveNameKey">
+            <xs:selector xpath="volumes/reference"/>
+            <xs:field xpath="@name"/>
+        </xs:key>
+        <xs:keyref name="volumeCurveRef" refer="volumeCurveNameKey">
+            <xs:selector xpath="volumes/volume"/>
+            <xs:field xpath="@ref"/>
+        </xs:keyref>
+    </xs:element>
+    <xs:complexType name="globalConfiguration">
+        <xs:attribute name="speaker_drc_enabled" type="xs:boolean" use="required"/>
+        <xs:attribute name="call_screen_mode_supported" type="xs:boolean" use="optional"/>
+        <xs:attribute name="engine_library" type="engineSuffix" use="optional"/>
+    </xs:complexType>
+    <xs:complexType name="modules">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                There should be one section per audio HW module present on the platform.
+                Each <module/> contains two mandatory tags: “halVersion” and “name”.
+                The module "name" is the same as in previous .conf file.
+                Each module must contain the following sections:
+                 - <devicePorts/>: a list of device descriptors for all
+                   input and output devices accessible via this module.
+                   This contains both permanently attached devices and removable devices.
+                 - <mixPorts/>: listing all output and input streams exposed by the audio HAL
+                 - <routes/>: list of possible connections between input
+                   and output devices or between stream and devices.
+                   A <route/> is defined by a set of 3 attributes:
+                        -"type": mux|mix means all sources are mutual exclusive (mux) or can be mixed (mix)
+                        -"sink": the sink involved in this route
+                        -"sources": all the sources than can be connected to the sink via this route
+                 - <attachedDevices/>: permanently attached devices.
+                   The attachedDevices section is a list of devices names.
+                   Their names correspond to device names defined in "devicePorts" section.
+                 - <defaultOutputDevice/> is the device to be used when no policy rule applies
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="module" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:sequence>
+                        <xs:element name="attachedDevices" type="attachedDevices" minOccurs="0">
+                            <xs:unique name="attachedDevicesUniqueness">
+                                <xs:selector xpath="item"/>
+                                <xs:field xpath="."/>
+                            </xs:unique>
+                        </xs:element>
+                        <xs:element name="defaultOutputDevice" type="xs:token" minOccurs="0"/>
+                        <xs:element name="mixPorts" type="mixPorts" minOccurs="0"/>
+                        <xs:element name="devicePorts" type="devicePorts" minOccurs="0"/>
+                        <xs:element name="routes" type="routes" minOccurs="0"/>
+                    </xs:sequence>
+                    <xs:attribute name="name" type="xs:string" use="required"/>
+                    <xs:attribute name="halVersion" type="halVersion" use="required"/>
+                </xs:complexType>
+                <xs:unique name="mixPortNameUniqueness">
+                    <xs:selector xpath="mixPorts/mixPort"/>
+                    <xs:field xpath="@name"/>
+                </xs:unique>
+                <xs:key name="devicePortNameKey">
+                    <xs:selector xpath="devicePorts/devicePort"/>
+                    <xs:field xpath="@tagName"/>
+                </xs:key>
+                <xs:unique name="devicePortUniqueness">
+                    <xs:selector xpath="devicePorts/devicePort"/>
+                    <xs:field xpath="@type"/>
+                    <xs:field xpath="@address"/>
+                </xs:unique>
+                <xs:keyref name="defaultOutputDeviceRef" refer="devicePortNameKey">
+                    <xs:selector xpath="defaultOutputDevice"/>
+                    <xs:field xpath="."/>
+                </xs:keyref>
+                <xs:keyref name="attachedDeviceRef" refer="devicePortNameKey">
+                    <xs:selector xpath="attachedDevices/item"/>
+                    <xs:field xpath="."/>
+                </xs:keyref>
+                <!-- The following 3 constraints try to make sure each sink port
+                     is reference in one an only one route. -->
+                <xs:key name="routeSinkKey">
+                    <!-- predicate [@type='sink'] does not work in xsd 1.0 -->
+                    <xs:selector xpath="devicePorts/devicePort|mixPorts/mixPort"/>
+                    <xs:field xpath="@tagName|@name"/>
+                </xs:key>
+                <xs:keyref name="routeSinkRef" refer="routeSinkKey">
+                    <xs:selector xpath="routes/route"/>
+                    <xs:field xpath="@sink"/>
+                </xs:keyref>
+                <xs:unique name="routeUniqueness">
+                    <xs:selector xpath="routes/route"/>
+                    <xs:field xpath="@sink"/>
+                </xs:unique>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="attachedDevices">
+        <xs:sequence>
+            <xs:element name="item" type="xs:token" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:simpleType name="audioInOutFlag">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+              The flags indicate suggested stream attributes supported by the profile.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_DIRECT" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_PRIMARY" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_FAST" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_DEEP_BUFFER" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_NON_BLOCKING" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_HW_AV_SYNC" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_TTS" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_RAW" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_SYNC" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_DIRECT_PCM" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_MMAP_NOIRQ" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_VOIP_RX" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_INCALL_MUSIC" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_SPATIALIZER" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_ULTRASOUND" />
+            <xs:enumeration value="AUDIO_INPUT_FLAG_FAST" />
+            <xs:enumeration value="AUDIO_INPUT_FLAG_HW_HOTWORD" />
+            <xs:enumeration value="AUDIO_INPUT_FLAG_RAW" />
+            <xs:enumeration value="AUDIO_INPUT_FLAG_SYNC" />
+            <xs:enumeration value="AUDIO_INPUT_FLAG_MMAP_NOIRQ" />
+            <xs:enumeration value="AUDIO_INPUT_FLAG_VOIP_TX" />
+            <xs:enumeration value="AUDIO_INPUT_FLAG_HW_AV_SYNC" />
+            <xs:enumeration value="AUDIO_INPUT_FLAG_DIRECT" />
+            <xs:enumeration value="AUDIO_INPUT_FLAG_ULTRASOUND" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="audioInOutFlags">
+        <xs:list itemType="audioInOutFlag" />
+    </xs:simpleType>
+    <xs:simpleType name="role">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="sink"/>
+            <xs:enumeration value="source"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="mixPorts">
+        <xs:sequence>
+            <xs:element name="mixPort" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:sequence>
+                        <xs:element name="profile" type="profile" minOccurs="0" maxOccurs="unbounded"/>
+                        <xs:element name="gains" type="gains" minOccurs="0"/>
+                    </xs:sequence>
+                    <xs:attribute name="name" type="xs:token" use="required"/>
+                    <xs:attribute name="role" type="role" use="required"/>
+                    <xs:attribute name="flags" type="audioInOutFlags"/>
+                    <xs:attribute name="maxOpenCount" type="xs:unsignedInt"/>
+                    <xs:attribute name="maxActiveCount" type="xs:unsignedInt"/>
+                    <xs:attribute name="preferredUsage" type="audioUsageList">
+                        <xs:annotation>
+                            <xs:documentation xml:lang="en">
+                                When choosing the mixPort of an audio track, the audioPolicy
+                                first considers the mixPorts with a preferredUsage including
+                                the track AudioUsage preferred .
+                                If non support the track format, the other mixPorts are considered.
+                                Eg: a <mixPort preferredUsage="AUDIO_USAGE_MEDIA" /> will receive
+                                    the audio of all apps playing with a MEDIA usage.
+                                    It may receive audio from ALARM if there are no audio compatible
+                                    <mixPort preferredUsage="AUDIO_USAGE_ALARM" />.
+                             </xs:documentation>
+                        </xs:annotation>
+                    </xs:attribute>
+                    <xs:attribute name="recommendedMuteDurationMs" type="xs:unsignedInt"/>
+                </xs:complexType>
+                <xs:unique name="mixPortProfileUniqueness">
+                    <xs:selector xpath="profile"/>
+                    <xs:field xpath="format"/>
+                    <xs:field xpath="samplingRate"/>
+                    <xs:field xpath="channelMasks"/>
+                </xs:unique>
+                <xs:unique name="mixPortGainUniqueness">
+                    <xs:selector xpath="gains/gain"/>
+                    <xs:field xpath="@name"/>
+                </xs:unique>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:simpleType name="audioDevice">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_DEVICE_NONE"/>
+
+            <xs:enumeration value="AUDIO_DEVICE_OUT_EARPIECE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADPHONE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI_EARC"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_DIGITAL"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_USB_ACCESSORY"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_USB_DEVICE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_REMOTE_SUBMIX"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_TELEPHONY_TX"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_LINE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI_ARC"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_SPDIF"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_FM"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_LINE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER_SAFE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_IP"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BUS"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_PROXY"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_USB_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_HEARING_AID"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_ECHO_CANCELLER"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLE_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLE_SPEAKER"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLE_BROADCAST"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_DEFAULT"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_STUB"/>
+
+            <xs:enumeration value="AUDIO_DEVICE_IN_COMMUNICATION"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_AMBIENT"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BUILTIN_MIC"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_WIRED_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_HDMI"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_AUX_DIGITAL"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_VOICE_CALL"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_TELEPHONY_RX"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BACK_MIC"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_REMOTE_SUBMIX"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_USB_ACCESSORY"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_USB_DEVICE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_FM_TUNER"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_TV_TUNER"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_LINE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_SPDIF"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_A2DP"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_LOOPBACK"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_IP"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BUS"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_PROXY"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_USB_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_BLE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_HDMI_ARC"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_HDMI_EARC"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_ECHO_REFERENCE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BLE_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_DEFAULT"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_STUB"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="vendorExtension">
+        <!-- Vendor extension names must be prefixed by "VX_" to distinguish them from
+             AOSP values. Vendors must namespace their names to avoid conflicts. The
+             namespace part must only use capital latin characters and decimal digits and
+             consist of at least 3 characters. The part of the extension name after the
+             namespace may in addition include underscores. Example for a hypothetical
+             Google virtual reality device:
+
+                 <devicePort tagName="VR" type="VX_GOOGLE_VR" role="sink" />
+        -->
+        <xs:restriction base="xs:string">
+            <xs:pattern value="VX_[A-Z0-9]{3,}_[_A-Z0-9]+"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="extendableAudioDevice">
+        <xs:union memberTypes="audioDevice vendorExtension"/>
+    </xs:simpleType>
+    <xs:simpleType name="audioFormat">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_FORMAT_DEFAULT" />
+            <xs:enumeration value="AUDIO_FORMAT_PCM_16_BIT" />
+            <xs:enumeration value="AUDIO_FORMAT_PCM_8_BIT"/>
+            <xs:enumeration value="AUDIO_FORMAT_PCM_32_BIT"/>
+            <xs:enumeration value="AUDIO_FORMAT_PCM_8_24_BIT"/>
+            <xs:enumeration value="AUDIO_FORMAT_PCM_FLOAT"/>
+            <xs:enumeration value="AUDIO_FORMAT_PCM_24_BIT_PACKED"/>
+            <xs:enumeration value="AUDIO_FORMAT_MP3"/>
+            <xs:enumeration value="AUDIO_FORMAT_AMR_NB"/>
+            <xs:enumeration value="AUDIO_FORMAT_AMR_WB"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_MAIN"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_SSR"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LTP"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_HE_V1"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_SCALABLE"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ERLC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LD"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_HE_V2"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ELD"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_XHE"/>
+            <xs:enumeration value="AUDIO_FORMAT_HE_AAC_V1"/>
+            <xs:enumeration value="AUDIO_FORMAT_HE_AAC_V2"/>
+            <xs:enumeration value="AUDIO_FORMAT_VORBIS"/>
+            <xs:enumeration value="AUDIO_FORMAT_OPUS"/>
+            <xs:enumeration value="AUDIO_FORMAT_AC3"/>
+            <xs:enumeration value="AUDIO_FORMAT_E_AC3"/>
+            <xs:enumeration value="AUDIO_FORMAT_E_AC3_JOC"/>
+            <xs:enumeration value="AUDIO_FORMAT_DTS"/>
+            <xs:enumeration value="AUDIO_FORMAT_DTS_HD"/>
+            <xs:enumeration value="AUDIO_FORMAT_IEC61937"/>
+            <xs:enumeration value="AUDIO_FORMAT_DOLBY_TRUEHD"/>
+            <xs:enumeration value="AUDIO_FORMAT_EVRC"/>
+            <xs:enumeration value="AUDIO_FORMAT_EVRCB"/>
+            <xs:enumeration value="AUDIO_FORMAT_EVRCWB"/>
+            <xs:enumeration value="AUDIO_FORMAT_EVRCNW"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADIF"/>
+            <xs:enumeration value="AUDIO_FORMAT_WMA"/>
+            <xs:enumeration value="AUDIO_FORMAT_WMA_PRO"/>
+            <xs:enumeration value="AUDIO_FORMAT_AMR_WB_PLUS"/>
+            <xs:enumeration value="AUDIO_FORMAT_MP2"/>
+            <xs:enumeration value="AUDIO_FORMAT_QCELP"/>
+            <xs:enumeration value="AUDIO_FORMAT_DSD"/>
+            <xs:enumeration value="AUDIO_FORMAT_FLAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_ALAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_APE"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_MAIN"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_SSR"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LTP"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_HE_V1"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_SCALABLE"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_ERLC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LD"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_HE_V2"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_ELD"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_XHE"/>
+            <xs:enumeration value="AUDIO_FORMAT_SBC"/>
+            <xs:enumeration value="AUDIO_FORMAT_APTX"/>
+            <xs:enumeration value="AUDIO_FORMAT_APTX_HD"/>
+            <xs:enumeration value="AUDIO_FORMAT_AC4"/>
+            <xs:enumeration value="AUDIO_FORMAT_LDAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_MAT"/>
+            <xs:enumeration value="AUDIO_FORMAT_MAT_1_0"/>
+            <xs:enumeration value="AUDIO_FORMAT_MAT_2_0"/>
+            <xs:enumeration value="AUDIO_FORMAT_MAT_2_1"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LATM"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_LC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_HE_V1"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_HE_V2"/>
+            <xs:enumeration value="AUDIO_FORMAT_CELT"/>
+            <xs:enumeration value="AUDIO_FORMAT_APTX_ADAPTIVE"/>
+            <xs:enumeration value="AUDIO_FORMAT_LHDC"/>
+            <xs:enumeration value="AUDIO_FORMAT_LHDC_LL"/>
+            <xs:enumeration value="AUDIO_FORMAT_APTX_TWSP"/>
+            <xs:enumeration value="AUDIO_FORMAT_LC3"/>
+            <xs:enumeration value="AUDIO_FORMAT_MPEGH_BL_L3"/>
+            <xs:enumeration value="AUDIO_FORMAT_MPEGH_BL_L4"/>
+            <xs:enumeration value="AUDIO_FORMAT_MPEGH_LC_L3"/>
+            <xs:enumeration value="AUDIO_FORMAT_MPEGH_LC_L4"/>
+            <xs:enumeration value="AUDIO_FORMAT_IEC60958"/>
+            <xs:enumeration value="AUDIO_FORMAT_DTS_UHD"/>
+            <xs:enumeration value="AUDIO_FORMAT_DRA"/>
+            <xs:enumeration value="AUDIO_FORMAT_APTX_ADAPTIVE_QLEA"/>
+            <xs:enumeration value="AUDIO_FORMAT_APTX_ADAPTIVE_R4"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="extendableAudioFormat">
+        <xs:union memberTypes="audioFormat vendorExtension"/>
+    </xs:simpleType>
+    <xs:simpleType name="audioUsage">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Audio usage specifies the intended use case for the sound being played.
+                Please consult frameworks/base/media/java/android/media/AudioAttributes.java
+                for the description of each value.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_USAGE_UNKNOWN" />
+            <xs:enumeration value="AUDIO_USAGE_MEDIA" />
+            <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION" />
+            <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING" />
+            <xs:enumeration value="AUDIO_USAGE_ALARM" />
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION" />
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE" />
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_EVENT" />
+            <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" />
+            <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" />
+            <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" />
+            <xs:enumeration value="AUDIO_USAGE_GAME" />
+            <xs:enumeration value="AUDIO_USAGE_VIRTUAL_SOURCE" />
+            <xs:enumeration value="AUDIO_USAGE_ASSISTANT" />
+            <xs:enumeration value="AUDIO_USAGE_CALL_ASSISTANT" />
+            <xs:enumeration value="AUDIO_USAGE_EMERGENCY" />
+            <xs:enumeration value="AUDIO_USAGE_SAFETY" />
+            <xs:enumeration value="AUDIO_USAGE_VEHICLE_STATUS" />
+            <xs:enumeration value="AUDIO_USAGE_ANNOUNCEMENT" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="audioUsageList">
+        <xs:list itemType="audioUsage"/>
+    </xs:simpleType>
+    <xs:simpleType name="audioContentType">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Audio content type expresses the general category of the content.
+                Please consult frameworks/base/media/java/android/media/AudioAttributes.java
+                for the description of each value.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_CONTENT_TYPE_UNKNOWN"/>
+            <xs:enumeration value="AUDIO_CONTENT_TYPE_SPEECH"/>
+            <xs:enumeration value="AUDIO_CONTENT_TYPE_MUSIC"/>
+            <xs:enumeration value="AUDIO_CONTENT_TYPE_MOVIE"/>
+            <xs:enumeration value="AUDIO_CONTENT_TYPE_SONIFICATION"/>
+            <xs:enumeration value="AUDIO_CONTENT_TYPE_ULTRASOUND"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="samplingRates">
+        <xs:list itemType="xs:nonNegativeInteger" />
+    </xs:simpleType>
+    <xs:simpleType name="audioChannelMask">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Audio channel mask specifies presence of particular channels.
+                There are two representations:
+                - representation position (traditional discrete channel specification,
+                  e.g. "left", "right");
+                - indexed (this is similar to "tracks" in audio mixing, channels
+                  are represented using numbers).
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_CHANNEL_NONE"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_MONO"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_STEREO"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_2POINT1"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_TRI"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_TRI_BACK"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_3POINT1"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_2POINT0POINT2"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_2POINT1POINT2"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_3POINT0POINT2"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_3POINT1POINT2"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_QUAD"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_QUAD_BACK"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_QUAD_SIDE"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_SURROUND"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_PENTA"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_5POINT1"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_5POINT1_BACK"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_5POINT1_SIDE"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_5POINT1POINT2"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_5POINT1POINT4"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_6POINT1"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_7POINT1"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_7POINT1POINT2"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_7POINT1POINT4"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_9POINT1POINT4"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_9POINT1POINT6"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_13POINT_360RA"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_22POINT2"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_MONO_HAPTIC_A"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_STEREO_HAPTIC_A"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_HAPTIC_AB"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_MONO_HAPTIC_AB"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_STEREO_HAPTIC_AB"/>
+            <xs:enumeration value="AUDIO_CHANNEL_IN_MONO"/>
+            <xs:enumeration value="AUDIO_CHANNEL_IN_STEREO"/>
+            <xs:enumeration value="AUDIO_CHANNEL_IN_FRONT_BACK"/>
+            <xs:enumeration value="AUDIO_CHANNEL_IN_6"/>
+            <xs:enumeration value="AUDIO_CHANNEL_IN_2POINT0POINT2"/>
+            <xs:enumeration value="AUDIO_CHANNEL_IN_2POINT1POINT2"/>
+            <xs:enumeration value="AUDIO_CHANNEL_IN_3POINT0POINT2"/>
+            <xs:enumeration value="AUDIO_CHANNEL_IN_3POINT1POINT2"/>
+            <xs:enumeration value="AUDIO_CHANNEL_IN_5POINT1"/>
+            <xs:enumeration value="AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO"/>
+            <xs:enumeration value="AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO"/>
+            <xs:enumeration value="AUDIO_CHANNEL_IN_VOICE_CALL_MONO"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_1"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_2"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_3"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_4"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_5"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_6"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_7"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_8"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_9"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_10"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_11"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_12"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_13"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_14"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_15"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_16"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_17"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_18"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_19"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_20"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_21"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_22"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_23"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_24"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="channelMasks">
+        <xs:list itemType="audioChannelMask" />
+    </xs:simpleType>
+    <xs:simpleType name="audioEncapsulationType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_ENCAPSULATION_TYPE_NONE"/>
+            <xs:enumeration value="AUDIO_ENCAPSULATION_TYPE_IEC61937"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="profile">
+        <xs:attribute name="name" type="xs:token" use="optional"/>
+        <xs:attribute name="format" type="extendableAudioFormat" use="optional"/>
+        <xs:attribute name="samplingRates" type="samplingRates" use="optional"/>
+        <xs:attribute name="channelMasks" type="channelMasks" use="optional"/>
+        <xs:attribute name="encapsulationType" type="audioEncapsulationType" use="optional"/>
+    </xs:complexType>
+    <xs:simpleType name="audioGainMode">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_GAIN_MODE_JOINT"/>
+            <xs:enumeration value="AUDIO_GAIN_MODE_CHANNELS"/>
+            <xs:enumeration value="AUDIO_GAIN_MODE_RAMP"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="audioGainModeMaskUnrestricted">
+        <xs:list itemType="audioGainMode" />
+    </xs:simpleType>
+    <xs:simpleType name='audioGainModeMask'>
+        <xs:restriction base='audioGainModeMaskUnrestricted'>
+            <xs:minLength value='1' />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="gains">
+        <xs:sequence>
+            <xs:element name="gain" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:attribute name="name" type="xs:token" use="required"/>
+                    <xs:attribute name="mode" type="audioGainModeMask" use="required"/>
+                    <xs:attribute name="channel_mask" type="audioChannelMask" use="optional"/>
+                    <xs:attribute name="minValueMB" type="xs:int" use="optional"/>
+                    <xs:attribute name="maxValueMB" type="xs:int" use="optional"/>
+                    <xs:attribute name="defaultValueMB" type="xs:int" use="optional"/>
+                    <xs:attribute name="stepValueMB" type="xs:int" use="optional"/>
+                    <xs:attribute name="minRampMs" type="xs:int" use="optional"/>
+                    <xs:attribute name="maxRampMs" type="xs:int" use="optional"/>
+                    <xs:attribute name="useForVolume" type="xs:boolean" use="optional"/>
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="devicePorts">
+        <xs:sequence>
+            <xs:element name="devicePort" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:sequence>
+                        <xs:element name="profile" type="profile" minOccurs="0" maxOccurs="unbounded"/>
+                        <xs:element name="gains" type="gains" minOccurs="0"/>
+                    </xs:sequence>
+                    <xs:attribute name="tagName" type="xs:token" use="required"/>
+                    <xs:attribute name="type" type="extendableAudioDevice" use="required"/>
+                    <xs:attribute name="role" type="role" use="required"/>
+                    <xs:attribute name="address" type="xs:string" use="optional" default=""/>
+                    <!-- Note that XSD 1.0 can not check that a type only has one default. -->
+                    <xs:attribute name="default" type="xs:boolean" use="optional">
+                        <xs:annotation>
+                            <xs:documentation xml:lang="en">
+                                The default device will be used if multiple have the same type
+                                and no explicit route request exists for a specific device of
+                                that type.
+                            </xs:documentation>
+                        </xs:annotation>
+                    </xs:attribute>
+                    <xs:attribute name="encodedFormats" type="audioFormatsList" use="optional"
+                                  default="" />
+                </xs:complexType>
+                <xs:unique name="devicePortProfileUniqueness">
+                    <xs:selector xpath="profile"/>
+                    <xs:field xpath="format"/>
+                    <xs:field xpath="samplingRate"/>
+                    <xs:field xpath="channelMasks"/>
+                </xs:unique>
+                <xs:unique name="devicePortGainUniqueness">
+                    <xs:selector xpath="gains/gain"/>
+                    <xs:field xpath="@name"/>
+                </xs:unique>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:simpleType name="mixType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="mix"/>
+            <xs:enumeration value="mux"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="routes">
+        <xs:sequence>
+            <xs:element name="route" minOccurs="0" maxOccurs="unbounded">
+                <xs:annotation>
+                    <xs:documentation xml:lang="en">
+                        List all available sources for a given sink.
+                    </xs:documentation>
+                </xs:annotation>
+                <xs:complexType>
+                    <xs:attribute name="type" type="mixType" use="required"/>
+                    <xs:attribute name="sink" type="xs:string" use="required"/>
+                    <xs:attribute name="sources" type="xs:string" use="required"/>
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="volumes">
+        <xs:sequence>
+            <xs:element name="volume" type="volume" minOccurs="0" maxOccurs="unbounded"/>
+            <xs:element name="reference" type="reference" minOccurs="0" maxOccurs="unbounded">
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <!-- TODO: Always require a ref for better xsd validations.
+               Currently a volume could have no points nor ref
+               as it can not be forbidden by xsd 1.0.-->
+    <xs:simpleType name="volumePoint">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Comma separated pair of number.
+                The fist one is the framework level (between 0 and 100).
+                The second one is the volume to send to the HAL.
+                The framework will interpolate volumes not specified.
+                Their MUST be at least 2 points specified.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:pattern value="([0-9]{1,2}|100),-?[0-9]+"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="audioStreamType">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Audio stream type describing the intended use case of a stream.
+                Please consult frameworks/base/media/java/android/media/AudioSystem.java
+                for the description of each value.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_STREAM_VOICE_CALL"/>
+            <xs:enumeration value="AUDIO_STREAM_SYSTEM"/>
+            <xs:enumeration value="AUDIO_STREAM_RING"/>
+            <xs:enumeration value="AUDIO_STREAM_MUSIC"/>
+            <xs:enumeration value="AUDIO_STREAM_ALARM"/>
+            <xs:enumeration value="AUDIO_STREAM_NOTIFICATION"/>
+            <xs:enumeration value="AUDIO_STREAM_BLUETOOTH_SCO"/>
+            <xs:enumeration value="AUDIO_STREAM_ENFORCED_AUDIBLE"/>
+            <xs:enumeration value="AUDIO_STREAM_DTMF"/>
+            <xs:enumeration value="AUDIO_STREAM_TTS"/>
+            <xs:enumeration value="AUDIO_STREAM_ACCESSIBILITY"/>
+            <xs:enumeration value="AUDIO_STREAM_ASSISTANT"/>
+            <xs:enumeration value="AUDIO_STREAM_REROUTING"/>
+            <xs:enumeration value="AUDIO_STREAM_PATCH"/>
+            <xs:enumeration value="AUDIO_STREAM_CALL_ASSISTANT"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="audioSource">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                An audio source defines the intended use case for the sound being recorded.
+                Please consult frameworks/base/media/java/android/media/MediaRecorder.java
+                for the description of each value.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_SOURCE_DEFAULT"/>
+            <xs:enumeration value="AUDIO_SOURCE_MIC"/>
+            <xs:enumeration value="AUDIO_SOURCE_VOICE_UPLINK"/>
+            <xs:enumeration value="AUDIO_SOURCE_VOICE_DOWNLINK"/>
+            <xs:enumeration value="AUDIO_SOURCE_VOICE_CALL"/>
+            <xs:enumeration value="AUDIO_SOURCE_CAMCORDER"/>
+            <xs:enumeration value="AUDIO_SOURCE_VOICE_RECOGNITION"/>
+            <xs:enumeration value="AUDIO_SOURCE_VOICE_COMMUNICATION"/>
+            <xs:enumeration value="AUDIO_SOURCE_REMOTE_SUBMIX"/>
+            <xs:enumeration value="AUDIO_SOURCE_UNPROCESSED"/>
+            <xs:enumeration value="AUDIO_SOURCE_VOICE_PERFORMANCE"/>
+            <xs:enumeration value="AUDIO_SOURCE_ECHO_REFERENCE"/>
+            <xs:enumeration value="AUDIO_SOURCE_FM_TUNER"/>
+            <xs:enumeration value="AUDIO_SOURCE_HOTWORD"/>
+            <xs:enumeration value="AUDIO_SOURCE_ULTRASOUND"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <!-- Enum values of device_category from Volume.h. -->
+    <xs:simpleType name="deviceCategory">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="DEVICE_CATEGORY_HEADSET"/>
+            <xs:enumeration value="DEVICE_CATEGORY_SPEAKER"/>
+            <xs:enumeration value="DEVICE_CATEGORY_EARPIECE"/>
+            <xs:enumeration value="DEVICE_CATEGORY_EXT_MEDIA"/>
+            <xs:enumeration value="DEVICE_CATEGORY_HEARING_AID"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="volume">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Volume section defines a volume curve for a given use case and device category.
+                It contains a list of points of this curve expressing the attenuation in Millibels
+                for a given volume index from 0 to 100.
+                <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER">
+                    <point>0,-9600</point>
+                    <point>100,0</point>
+                </volume>
+
+                It may also reference a reference/@name to avoid duplicating curves.
+                <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+                        ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+                <reference name="DEFAULT_MEDIA_VOLUME_CURVE">
+                    <point>0,-9600</point>
+                    <point>100,0</point>
+                </reference>
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="point" type="volumePoint" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+        <xs:attribute name="stream" type="audioStreamType"/>
+        <xs:attribute name="deviceCategory" type="deviceCategory"/>
+        <xs:attribute name="ref" type="xs:token" use="optional"/>
+    </xs:complexType>
+    <xs:complexType name="reference">
+        <xs:sequence>
+            <xs:element name="point" type="volumePoint" minOccurs="2" maxOccurs="unbounded"/>
+        </xs:sequence>
+        <xs:attribute name="name" type="xs:token" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="surroundSound">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Surround Sound section provides configuration related to handling of
+                multi-channel formats.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="formats" type="surroundFormats"/>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:simpleType name="audioFormatsList">
+        <xs:list itemType="extendableAudioFormat" />
+    </xs:simpleType>
+    <xs:complexType name="surroundFormats">
+        <xs:sequence>
+            <xs:element name="format" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:attribute name="name" type="extendableAudioFormat" use="required"/>
+                    <xs:attribute name="subformats" type="audioFormatsList" />
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:simpleType name="engineSuffix">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="default"/>
+            <xs:enumeration value="configurable"/>
+        </xs:restriction>
+    </xs:simpleType>
+</xs:schema>
diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
index 52403e1..3920a58 100644
--- a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
+++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
@@ -26,14 +26,14 @@
 #include "DynamicsProcessingSw.h"
 
 using aidl::android::hardware::audio::effect::DynamicsProcessingSw;
-using aidl::android::hardware::audio::effect::DynamicsProcessingSwImplUUID;
 using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kDynamicsProcessingSwImplUUID;
 using aidl::android::hardware::audio::effect::State;
 using aidl::android::media::audio::common::AudioUuid;
 
 extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
                                            std::shared_ptr<IEffect>* instanceSpp) {
-    if (!in_impl_uuid || *in_impl_uuid != DynamicsProcessingSwImplUUID) {
+    if (!in_impl_uuid || *in_impl_uuid != kDynamicsProcessingSwImplUUID) {
         LOG(ERROR) << __func__ << "uuid not supported";
         return EX_ILLEGAL_ARGUMENT;
     }
diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
index fc26902..2bc2762 100644
--- a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
+++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
@@ -39,8 +39,8 @@
   public:
     DynamicsProcessingSw() { LOG(DEBUG) << __func__; }
     ~DynamicsProcessingSw() {
+        cleanUp();
         LOG(DEBUG) << __func__;
-        releaseContext();
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
@@ -57,13 +57,14 @@
     const DynamicsProcessing::Capability kCapability;
     /* Effect descriptor */
     const Descriptor kDescriptor = {
-            .common = {.id = {.type = DynamicsProcessingTypeUUID,
-                              .uuid = DynamicsProcessingSwImplUUID,
+            .common = {.id = {.type = kDynamicsProcessingTypeUUID,
+                              .uuid = kDynamicsProcessingSwImplUUID,
                               .proxy = std::nullopt},
                        .flags = {.type = Flags::Type::INSERT,
                                  .insert = Flags::Insert::FIRST,
                                  .volume = Flags::Volume::CTRL},
-                       .name = "DynamicsProcessingSw"},
+                       .name = "DynamicsProcessingSw",
+                       .implementor = "The Android Open Source Project"},
             .capability = Capability::make<Capability::dynamicsProcessing>(kCapability)};
 
     /* parameters */
diff --git a/audio/aidl/default/reverb/Android.bp b/audio/aidl/default/envReverb/Android.bp
similarity index 95%
copy from audio/aidl/default/reverb/Android.bp
copy to audio/aidl/default/envReverb/Android.bp
index 955038c..c239ee5 100644
--- a/audio/aidl/default/reverb/Android.bp
+++ b/audio/aidl/default/envReverb/Android.bp
@@ -24,14 +24,14 @@
 }
 
 cc_library_shared {
-    name: "libreverbsw",
+    name: "libenvreverbsw",
     defaults: [
         "aidlaudioeffectservice_defaults",
         "latest_android_media_audio_common_types_ndk_shared",
         "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
-        "ReverbSw.cpp",
+        "EnvReverbSw.cpp",
         ":effectCommonFile",
     ],
     visibility: [
diff --git a/audio/aidl/default/reverb/ReverbSw.cpp b/audio/aidl/default/envReverb/EnvReverbSw.cpp
similarity index 77%
copy from audio/aidl/default/reverb/ReverbSw.cpp
copy to audio/aidl/default/envReverb/EnvReverbSw.cpp
index 639f1a2..ad447ab 100644
--- a/audio/aidl/default/reverb/ReverbSw.cpp
+++ b/audio/aidl/default/envReverb/EnvReverbSw.cpp
@@ -15,7 +15,7 @@
  */
 
 #include <cstddef>
-#define LOG_TAG "AHAL_ReverbSw"
+#define LOG_TAG "AHAL_EnvReverbSw"
 #include <Utils.h>
 #include <algorithm>
 #include <unordered_set>
@@ -23,22 +23,22 @@
 #include <android-base/logging.h>
 #include <fmq/AidlMessageQueue.h>
 
-#include "ReverbSw.h"
+#include "EnvReverbSw.h"
 
+using aidl::android::hardware::audio::effect::EnvReverbSw;
 using aidl::android::hardware::audio::effect::IEffect;
-using aidl::android::hardware::audio::effect::ReverbSw;
-using aidl::android::hardware::audio::effect::ReverbSwImplUUID;
+using aidl::android::hardware::audio::effect::kEnvReverbSwImplUUID;
 using aidl::android::hardware::audio::effect::State;
 using aidl::android::media::audio::common::AudioUuid;
 
 extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
                                            std::shared_ptr<IEffect>* instanceSpp) {
-    if (!in_impl_uuid || *in_impl_uuid != ReverbSwImplUUID) {
+    if (!in_impl_uuid || *in_impl_uuid != kEnvReverbSwImplUUID) {
         LOG(ERROR) << __func__ << "uuid not supported";
         return EX_ILLEGAL_ARGUMENT;
     }
     if (instanceSpp) {
-        *instanceSpp = ndk::SharedRefBase::make<ReverbSw>();
+        *instanceSpp = ndk::SharedRefBase::make<EnvReverbSw>();
         LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
         return EX_NONE;
     } else {
@@ -64,13 +64,13 @@
 
 namespace aidl::android::hardware::audio::effect {
 
-ndk::ScopedAStatus ReverbSw::getDescriptor(Descriptor* _aidl_return) {
+ndk::ScopedAStatus EnvReverbSw::getDescriptor(Descriptor* _aidl_return) {
     LOG(DEBUG) << __func__ << kDescriptor.toString();
     *_aidl_return = kDescriptor;
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus ReverbSw::setParameterSpecific(const Parameter::Specific& specific) {
+ndk::ScopedAStatus EnvReverbSw::setParameterSpecific(const Parameter::Specific& specific) {
     RETURN_IF(Parameter::Specific::reverb != specific.getTag(), EX_ILLEGAL_ARGUMENT,
               "EffectNotSupported");
     std::lock_guard lg(mMutex);
@@ -81,24 +81,24 @@
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus ReverbSw::getParameterSpecific(const Parameter::Id& id,
-                                                  Parameter::Specific* specific) {
+ndk::ScopedAStatus EnvReverbSw::getParameterSpecific(const Parameter::Id& id,
+                                                     Parameter::Specific* specific) {
     auto tag = id.getTag();
     RETURN_IF(Parameter::Id::reverbTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
     specific->set<Parameter::Specific::reverb>(mSpecificParam);
     return ndk::ScopedAStatus::ok();
 }
 
-std::shared_ptr<EffectContext> ReverbSw::createContext(const Parameter::Common& common) {
+std::shared_ptr<EffectContext> EnvReverbSw::createContext(const Parameter::Common& common) {
     if (mContext) {
         LOG(DEBUG) << __func__ << " context already exist";
         return mContext;
     }
-    mContext = std::make_shared<ReverbSwContext>(1 /* statusFmqDepth */, common);
+    mContext = std::make_shared<EnvReverbSwContext>(1 /* statusFmqDepth */, common);
     return mContext;
 }
 
-RetCode ReverbSw::releaseContext() {
+RetCode EnvReverbSw::releaseContext() {
     if (mContext) {
         mContext.reset();
     }
@@ -106,7 +106,7 @@
 }
 
 // Processing method running in EffectWorker thread.
-IEffect::Status ReverbSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status EnvReverbSw::effectProcessImpl(float* in, float* out, int process) {
     // TODO: get data buffer and process.
     LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
     for (int i = 0; i < process; i++) {
diff --git a/audio/aidl/default/reverb/ReverbSw.h b/audio/aidl/default/envReverb/EnvReverbSw.h
similarity index 79%
rename from audio/aidl/default/reverb/ReverbSw.h
rename to audio/aidl/default/envReverb/EnvReverbSw.h
index e00956f..5a9ab27 100644
--- a/audio/aidl/default/reverb/ReverbSw.h
+++ b/audio/aidl/default/envReverb/EnvReverbSw.h
@@ -26,21 +26,21 @@
 
 namespace aidl::android::hardware::audio::effect {
 
-class ReverbSwContext final : public EffectContext {
+class EnvReverbSwContext final : public EffectContext {
   public:
-    ReverbSwContext(int statusDepth, const Parameter::Common& common)
+    EnvReverbSwContext(int statusDepth, const Parameter::Common& common)
         : EffectContext(statusDepth, common) {
         LOG(DEBUG) << __func__;
     }
     // TODO: add specific context here
 };
 
-class ReverbSw final : public EffectImpl {
+class EnvReverbSw final : public EffectImpl {
   public:
-    ReverbSw() { LOG(DEBUG) << __func__; }
-    ~ReverbSw() {
+    EnvReverbSw() { LOG(DEBUG) << __func__; }
+    ~EnvReverbSw() {
+        cleanUp();
         LOG(DEBUG) << __func__;
-        releaseContext();
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
@@ -52,18 +52,19 @@
     RetCode releaseContext() override;
 
   private:
-    std::shared_ptr<ReverbSwContext> mContext;
+    std::shared_ptr<EnvReverbSwContext> mContext;
     /* capabilities */
     const Reverb::Capability kCapability;
     /* Effect descriptor */
     const Descriptor kDescriptor = {
-            .common = {.id = {.type = ReverbTypeUUID,
-                              .uuid = ReverbSwImplUUID,
+            .common = {.id = {.type = kEnvReverbTypeUUID,
+                              .uuid = kEnvReverbSwImplUUID,
                               .proxy = std::nullopt},
                        .flags = {.type = Flags::Type::INSERT,
                                  .insert = Flags::Insert::FIRST,
                                  .volume = Flags::Volume::CTRL},
-                       .name = "ReverbSw"},
+                       .name = "EnvReverbSw",
+                       .implementor = "The Android Open Source Project"},
             .capability = Capability::make<Capability::reverb>(kCapability)};
 
     /* parameters */
diff --git a/audio/aidl/default/equalizer/Android.bp b/audio/aidl/default/equalizer/Android.bp
index 69d7450..8de6b1a 100644
--- a/audio/aidl/default/equalizer/Android.bp
+++ b/audio/aidl/default/equalizer/Android.bp
@@ -31,7 +31,7 @@
         "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
-        "Equalizer.cpp",
+        "EqualizerSw.cpp",
         ":effectCommonFile",
     ],
     visibility: [
diff --git a/audio/aidl/default/equalizer/Equalizer.cpp b/audio/aidl/default/equalizer/EqualizerSw.cpp
similarity index 97%
rename from audio/aidl/default/equalizer/Equalizer.cpp
rename to audio/aidl/default/equalizer/EqualizerSw.cpp
index 0e07d39..d61ef97 100644
--- a/audio/aidl/default/equalizer/Equalizer.cpp
+++ b/audio/aidl/default/equalizer/EqualizerSw.cpp
@@ -23,17 +23,17 @@
 #include <android-base/logging.h>
 #include <fmq/AidlMessageQueue.h>
 
-#include "equalizer-impl/EqualizerSw.h"
+#include "EqualizerSw.h"
 
 using aidl::android::hardware::audio::effect::EqualizerSw;
-using aidl::android::hardware::audio::effect::EqualizerSwImplUUID;
 using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kEqualizerSwImplUUID;
 using aidl::android::hardware::audio::effect::State;
 using aidl::android::media::audio::common::AudioUuid;
 
 extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
                                            std::shared_ptr<IEffect>* instanceSpp) {
-    if (!in_impl_uuid || *in_impl_uuid != EqualizerSwImplUUID) {
+    if (!in_impl_uuid || *in_impl_uuid != kEqualizerSwImplUUID) {
         LOG(ERROR) << __func__ << "uuid not supported";
         return EX_ILLEGAL_ARGUMENT;
     }
diff --git a/audio/aidl/default/include/equalizer-impl/EqualizerSw.h b/audio/aidl/default/equalizer/EqualizerSw.h
similarity index 89%
rename from audio/aidl/default/include/equalizer-impl/EqualizerSw.h
rename to audio/aidl/default/equalizer/EqualizerSw.h
index dad03e1..aa4587a 100644
--- a/audio/aidl/default/include/equalizer-impl/EqualizerSw.h
+++ b/audio/aidl/default/equalizer/EqualizerSw.h
@@ -26,7 +26,7 @@
 
 namespace aidl::android::hardware::audio::effect {
 
-class EqualizerSwContext : public EffectContext {
+class EqualizerSwContext final : public EffectContext {
   public:
     EqualizerSwContext(int statusDepth, const Parameter::Common& common)
         : EffectContext(statusDepth, common) {
@@ -78,12 +78,12 @@
     // Add equalizer specific context for processing here
 };
 
-class EqualizerSw : public EffectImpl {
+class EqualizerSw final : public EffectImpl {
   public:
     EqualizerSw() { LOG(DEBUG) << __func__; }
     ~EqualizerSw() {
+        cleanUp();
         LOG(DEBUG) << __func__;
-        releaseContext();
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
@@ -109,13 +109,14 @@
 
     const Equalizer::Capability kEqCap = {.bandFrequencies = mBandFrequency, .presets = mPresets};
     // Effect descriptor.
-    const Descriptor kDesc = {.common = {.id = {.type = EqualizerTypeUUID,
-                                                .uuid = EqualizerSwImplUUID,
-                                                .proxy = std::nullopt},
+    const Descriptor kDesc = {.common = {.id = {.type = kEqualizerTypeUUID,
+                                                .uuid = kEqualizerSwImplUUID,
+                                                .proxy = kEqualizerProxyUUID},
                                          .flags = {.type = Flags::Type::INSERT,
                                                    .insert = Flags::Insert::FIRST,
                                                    .volume = Flags::Volume::CTRL},
-                                         .name = "EqualizerSw"},
+                                         .name = "EqualizerSw",
+                                         .implementor = "The Android Open Source Project"},
                               .capability = Capability::make<Capability::equalizer>(kEqCap)};
 
     ndk::ScopedAStatus getParameterEqualizer(const Equalizer::Tag& tag,
diff --git a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
index 90675c2..fd5ea34 100644
--- a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
+++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
@@ -26,14 +26,14 @@
 #include "HapticGeneratorSw.h"
 
 using aidl::android::hardware::audio::effect::HapticGeneratorSw;
-using aidl::android::hardware::audio::effect::HapticGeneratorSwImplUUID;
 using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kHapticGeneratorSwImplUUID;
 using aidl::android::hardware::audio::effect::State;
 using aidl::android::media::audio::common::AudioUuid;
 
 extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
                                            std::shared_ptr<IEffect>* instanceSpp) {
-    if (!in_impl_uuid || *in_impl_uuid != HapticGeneratorSwImplUUID) {
+    if (!in_impl_uuid || *in_impl_uuid != kHapticGeneratorSwImplUUID) {
         LOG(ERROR) << __func__ << "uuid not supported";
         return EX_ILLEGAL_ARGUMENT;
     }
diff --git a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
index b5a5036..518aa87 100644
--- a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
+++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
@@ -39,8 +39,8 @@
   public:
     HapticGeneratorSw() { LOG(DEBUG) << __func__; }
     ~HapticGeneratorSw() {
+        cleanUp();
         LOG(DEBUG) << __func__;
-        releaseContext();
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
@@ -57,13 +57,14 @@
     const HapticGenerator::Capability kCapability;
     /* Effect descriptor */
     const Descriptor kDescriptor = {
-            .common = {.id = {.type = HapticGeneratorTypeUUID,
-                              .uuid = HapticGeneratorSwImplUUID,
+            .common = {.id = {.type = kHapticGeneratorTypeUUID,
+                              .uuid = kHapticGeneratorSwImplUUID,
                               .proxy = std::nullopt},
                        .flags = {.type = Flags::Type::INSERT,
                                  .insert = Flags::Insert::FIRST,
                                  .volume = Flags::Volume::CTRL},
-                       .name = "HapticGeneratorSw"},
+                       .name = "HapticGeneratorSw",
+                       .implementor = "The Android Open Source Project"},
             .capability = Capability::make<Capability::hapticGenerator>(kCapability)};
 
     /* parameters */
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index 61516b2..0086743 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -35,6 +35,7 @@
   private:
     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 connectExternalDevice(
             const ::aidl::android::media::audio::common::AudioPort& in_templateIdAndAdditionalData,
             ::aidl::android::media::audio::common::AudioPort* _aidl_return) override;
@@ -70,6 +71,17 @@
             bool* _aidl_return) override;
     ndk::ScopedAStatus resetAudioPatch(int32_t in_patchId) override;
     ndk::ScopedAStatus resetAudioPortConfig(int32_t in_portConfigId) override;
+    ndk::ScopedAStatus getMasterMute(bool* _aidl_return) override;
+    ndk::ScopedAStatus setMasterMute(bool in_mute) override;
+    ndk::ScopedAStatus getMasterVolume(float* _aidl_return) override;
+    ndk::ScopedAStatus setMasterVolume(float in_volume) override;
+    ndk::ScopedAStatus getMicMute(bool* _aidl_return) override;
+    ndk::ScopedAStatus setMicMute(bool in_mute) override;
+    ndk::ScopedAStatus updateAudioMode(
+            ::aidl::android::hardware::audio::core::AudioMode in_mode) override;
+    ndk::ScopedAStatus updateScreenRotation(
+            ::aidl::android::hardware::audio::core::IModule::ScreenRotation in_rotation) override;
+    ndk::ScopedAStatus updateScreenState(bool in_isTurnedOn) override;
 
     void cleanUpPatch(int32_t patchId);
     ndk::ScopedAStatus createStreamContext(
@@ -88,12 +100,18 @@
 
     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.
+    std::shared_ptr<ITelephony> mTelephony;
     // ids of ports created at runtime via 'connectExternalDevice'.
     std::set<int32_t> mConnectedDevicePorts;
     Streams mStreams;
     // Maps port ids and port config ids to patch ids.
     // Multimap because both ports and configs can be used by multiple patches.
     std::multimap<int32_t, int32_t> mPatches;
+    bool mMasterMute = false;
+    float mMasterVolume = 1.0f;
+    bool mMicMute = false;
 };
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index 488edf1..5ee0f82 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -54,8 +54,8 @@
             int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
             DataMQ;
 
-    // Ensure that this value is not used by any of StreamDescriptor.COMMAND_*
-    static constexpr int COMMAND_EXIT = -1;
+    // Ensure that this value is not used by any of StreamDescriptor.State enums
+    static constexpr int32_t STATE_CLOSED = -1;
 
     StreamContext() = default;
     StreamContext(std::unique_ptr<CommandMQ> commandMQ, std::unique_ptr<ReplyMQ> replyMQ,
@@ -99,6 +99,10 @@
 
 class StreamWorkerCommonLogic : public ::android::hardware::audio::common::StreamLogic {
   public:
+    bool isClosed() const {
+        return static_cast<int32_t>(mState.load()) == StreamContext::STATE_CLOSED;
+    }
+    void setClosed() { mState = static_cast<StreamDescriptor::State>(StreamContext::STATE_CLOSED); }
     void setIsConnected(bool connected) { mIsConnected = connected; }
 
   protected:
@@ -109,9 +113,12 @@
           mReplyMQ(context.getReplyMQ()),
           mDataMQ(context.getDataMQ()) {}
     std::string init() override;
+    void populateReply(StreamDescriptor::Reply* reply, bool isConnected) const;
 
-    // Used both by the main and worker threads.
+    // Atomic fields are used both by the main and worker threads.
     std::atomic<bool> mIsConnected = false;
+    static_assert(std::atomic<StreamDescriptor::State>::is_always_lock_free);
+    std::atomic<StreamDescriptor::State> mState = StreamDescriptor::State::STANDBY;
     // All fields are used on the worker thread only.
     const int mInternalCommandCookie;
     const size_t mFrameSize;
@@ -132,6 +139,9 @@
 
   protected:
     Status cycle() override;
+
+  private:
+    bool read(size_t clientSize, StreamDescriptor::Reply* reply);
 };
 using StreamInWorker = ::android::hardware::audio::common::StreamWorker<StreamInWorkerLogic>;
 
@@ -143,6 +153,9 @@
 
   protected:
     Status cycle() override;
+
+  private:
+    bool write(size_t clientSize, StreamDescriptor::Reply* reply);
 };
 using StreamOutWorker = ::android::hardware::audio::common::StreamWorker<StreamOutWorkerLogic>;
 
@@ -155,7 +168,7 @@
                        ? ndk::ScopedAStatus::ok()
                        : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     }
-    bool isClosed() const { return mIsClosed; }
+    bool isClosed() const { return mWorker.isClosed(); }
     void setIsConnected(bool connected) { mWorker.setIsConnected(connected); }
     ndk::ScopedAStatus updateMetadata(const Metadata& metadata);
 
@@ -168,9 +181,6 @@
     Metadata mMetadata;
     StreamContext mContext;
     StreamWorker mWorker;
-    // This variable is checked in the destructor which can be called on an arbitrary Binder thread,
-    // thus we need to ensure that any changes made by other threads are sequentially consistent.
-    std::atomic<bool> mIsClosed = false;
 };
 
 class StreamIn
diff --git a/audio/aidl/default/include/core-impl/Telephony.h b/audio/aidl/default/include/core-impl/Telephony.h
new file mode 100644
index 0000000..597f3d6
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/Telephony.h
@@ -0,0 +1,34 @@
+/*
+ * 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 <android/binder_enums.h>
+
+#include <aidl/android/hardware/audio/core/BnTelephony.h>
+
+namespace aidl::android::hardware::audio::core {
+
+class Telephony : public BnTelephony {
+  private:
+    ndk::ScopedAStatus getSupportedAudioModes(std::vector<AudioMode>* _aidl_return) override;
+    ndk::ScopedAStatus switchAudioMode(AudioMode in_mode) override;
+
+    const std::vector<AudioMode> mSupportedAudioModes = {::ndk::enum_range<AudioMode>().begin(),
+                                                         ::ndk::enum_range<AudioMode>().end()};
+};
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/effect-impl/EffectImpl.h b/audio/aidl/default/include/effect-impl/EffectImpl.h
index cb395b7..d9825da 100644
--- a/audio/aidl/default/include/effect-impl/EffectImpl.h
+++ b/audio/aidl/default/include/effect-impl/EffectImpl.h
@@ -30,11 +30,8 @@
 
 class EffectImpl : public BnEffect, public EffectWorker {
   public:
-    EffectImpl() { LOG(DEBUG) << __func__; }
-    ~EffectImpl() {
-        cleanUp();
-        LOG(DEBUG) << __func__;
-    }
+    EffectImpl() = default;
+    virtual ~EffectImpl() = default;
 
     /**
      * Each effect implementation CAN override these methods if necessary
@@ -78,9 +75,9 @@
     State mState GUARDED_BY(mMutex) = State::INIT;
 
     IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
+    void cleanUp();
 
   private:
-    void cleanUp();
     std::shared_ptr<EffectContext> mContext GUARDED_BY(mMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectTypes.h b/audio/aidl/default/include/effect-impl/EffectTypes.h
index edce26b..fc6a01d 100644
--- a/audio/aidl/default/include/effect-impl/EffectTypes.h
+++ b/audio/aidl/default/include/effect-impl/EffectTypes.h
@@ -19,6 +19,7 @@
 #include <string>
 
 #include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <android-base/logging.h>
 
 typedef binder_exception_t (*EffectCreateFunctor)(
         const ::aidl::android::media::audio::common::AudioUuid*,
@@ -101,4 +102,23 @@
         }                                                                                        \
     } while (0)
 
+static inline bool stringToUuid(const char* str,
+                                ::aidl::android::media::audio::common::AudioUuid* uuid) {
+    RETURN_VALUE_IF(!uuid || !str, false, "nullPtr");
+
+    uint32_t tmp[10];
+    if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", tmp, tmp + 1, tmp + 2, tmp + 3,
+               tmp + 4, tmp + 5, tmp + 6, tmp + 7, tmp + 8, tmp + 9) < 10) {
+        return false;
+    }
+
+    uuid->timeLow = (uint32_t)tmp[0];
+    uuid->timeMid = (uint16_t)tmp[1];
+    uuid->timeHiAndVersion = (uint16_t)tmp[2];
+    uuid->clockSeq = (uint16_t)tmp[3];
+    uuid->node.insert(uuid->node.end(), {(uint8_t)tmp[4], (uint8_t)tmp[5], (uint8_t)tmp[6],
+                                         (uint8_t)tmp[7], (uint8_t)tmp[8], (uint8_t)tmp[9]});
+    return true;
+}
+
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectUUID.h b/audio/aidl/default/include/effect-impl/EffectUUID.h
index 767cf6c..7709eab 100644
--- a/audio/aidl/default/include/effect-impl/EffectUUID.h
+++ b/audio/aidl/default/include/effect-impl/EffectUUID.h
@@ -15,155 +15,190 @@
  */
 
 #pragma once
+#include <map>
+
 #include <aidl/android/media/audio/common/AudioUuid.h>
 
 namespace aidl::android::hardware::audio::effect {
 
 using ::aidl::android::media::audio::common::AudioUuid;
 
-// Null UUID
-static const AudioUuid EffectNullUuid = {static_cast<int32_t>(0xec7178ec),
-                                         0xe5e1,
-                                         0x4432,
-                                         0xa3f4,
-                                         {0x46, 0x57, 0xe6, 0x79, 0x52, 0x10}};
-
+// ec7178ec-e5e1-4432-a3f4-4657e6795210
+static const AudioUuid kEffectNullUuid = {static_cast<int32_t>(0xec7178ec),
+                                          0xe5e1,
+                                          0x4432,
+                                          0xa3f4,
+                                          {0x46, 0x57, 0xe6, 0x79, 0x52, 0x10}};
 // Zero UUID
-static const AudioUuid EffectZeroUuid = {
+static const AudioUuid kEffectZeroUuid = {
         static_cast<int32_t>(0x0), 0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
 
-// Equalizer type UUID.
-static const AudioUuid EqualizerTypeUUID = {static_cast<int32_t>(0x0bed4300),
-                                            0xddd6,
-                                            0x11db,
-                                            0x8f34,
-                                            {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
-
-// Equalizer implementation UUID.
-static const AudioUuid EqualizerSwImplUUID = {static_cast<int32_t>(0x0bed4300),
-                                              0x847d,
-                                              0x11df,
-                                              0xbb17,
-                                              {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
-
-// Equalizer bundle implementation UUID.
-static const AudioUuid EqualizerBundleImplUUID = {static_cast<int32_t>(0xce772f20),
-                                                  0x847d,
-                                                  0x11df,
-                                                  0xbb17,
-                                                  {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
-
-// fa8184a4-588b-11ed-9b6a-0242ac120002
-static const AudioUuid BassBoostTypeUUID = {static_cast<int32_t>(0xfa8184a4),
-                                            0x588b,
-                                            0x11ed,
-                                            0x9b6a,
-                                            {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 0634f220-ddd4-11db-a0fc-0002a5d5c51b
+static const AudioUuid kBassBoostTypeUUID = {static_cast<int32_t>(0x0634f220),
+                                             0xddd4,
+                                             0x11db,
+                                             0xa0fc,
+                                             {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
 // fa8181f2-588b-11ed-9b6a-0242ac120002
-static const AudioUuid BassBoostSwImplUUID = {static_cast<int32_t>(0xfa8181f2),
-                                              0x588b,
-                                              0x11ed,
-                                              0x9b6a,
-                                              {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
-// fa81862a-588b-11ed-9b6a-0242ac120002
-static const AudioUuid DownmixTypeUUID = {static_cast<int32_t>(0xfa81862a),
-                                          0x588b,
-                                          0x11ed,
-                                          0x9b6a,
-                                          {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
-// fa8187ba-588b-11ed-9b6a-0242ac120002
-static const AudioUuid DownmixSwImplUUID = {static_cast<int32_t>(0xfa8187ba),
-                                            0x588b,
-                                            0x11ed,
-                                            0x9b6a,
-                                            {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
-// fa818954-588b-11ed-9b6a-0242ac120002
-static const AudioUuid DynamicsProcessingTypeUUID = {static_cast<int32_t>(0xfa818954),
-                                                     0x588b,
-                                                     0x11ed,
-                                                     0x9b6a,
-                                                     {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
-// fa818d78-588b-11ed-9b6a-0242ac120002
-static const AudioUuid DynamicsProcessingSwImplUUID = {static_cast<int32_t>(0xfa818d78),
-                                                       0x588b,
-                                                       0x11ed,
-                                                       0x9b6a,
-                                                       {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
-// fa818f62-588b-11ed-9b6a-0242ac120002
-static const AudioUuid HapticGeneratorTypeUUID = {static_cast<int32_t>(0xfa818f62),
-                                                  0x588b,
-                                                  0x11ed,
-                                                  0x9b6a,
-                                                  {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
-// fa819110-588b-11ed-9b6a-0242ac120002
-static const AudioUuid HapticGeneratorSwImplUUID = {static_cast<int32_t>(0xfa819110),
-                                                    0x588b,
-                                                    0x11ed,
-                                                    0x9b6a,
-                                                    {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
-
-// fa8194a8-588b-11ed-9b6a-0242ac120002
-static const AudioUuid LoudnessEnhancerTypeUUID = {static_cast<int32_t>(0xfa8194a8),
-                                                   0x588b,
-                                                   0x11ed,
-                                                   0x9b6a,
-                                                   {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
-// fa819610-588b-11ed-9b6a-0242ac120002
-static const AudioUuid LoudnessEnhancerSwImplUUID = {static_cast<int32_t>(0xfa819610),
-                                                     0x588b,
-                                                     0x11ed,
-                                                     0x9b6a,
-                                                     {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
-// fa819886-588b-11ed-9b6a-0242ac120002
-static const AudioUuid ReverbTypeUUID = {static_cast<int32_t>(0xfa819886),
-                                         0x588b,
-                                         0x11ed,
-                                         0x9b6a,
-                                         {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
-// fa8199c6-588b-11ed-9b6a-0242ac120002
-static const AudioUuid ReverbSwImplUUID = {static_cast<int32_t>(0xfa8199c6),
-                                           0x588b,
-                                           0x11ed,
-                                           0x9b6a,
-                                           {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
-
-// fa819af2-588b-11ed-9b6a-0242ac120002
-static const AudioUuid VirtualizerTypeUUID = {static_cast<int32_t>(0xfa819af2),
-                                              0x588b,
-                                              0x11ed,
-                                              0x9b6a,
-                                              {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
-// fa819d86-588b-11ed-9b6a-0242ac120002
-static const AudioUuid VirtualizerSwImplUUID = {static_cast<int32_t>(0xfa819d86),
-                                                0x588b,
-                                                0x11ed,
-                                                0x9b6a,
-                                                {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
-
-// fa819f3e-588b-11ed-9b6a-0242ac120002
-static const AudioUuid VisualizerTypeUUID = {static_cast<int32_t>(0xfa819f3e),
-                                             0x588b,
-                                             0x11ed,
-                                             0x9b6a,
-                                             {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
-// fa81a0f6-588b-11ed-9b6a-0242ac120002
-static const AudioUuid VisualizerSwImplUUID = {static_cast<int32_t>(0xfa81a0f6),
+static const AudioUuid kBassBoostSwImplUUID = {static_cast<int32_t>(0xfa8181f2),
                                                0x588b,
                                                0x11ed,
                                                0x9b6a,
                                                {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
-
-// fa81a2b8-588b-11ed-9b6a-0242ac120002
-static const AudioUuid VolumeTypeUUID = {static_cast<int32_t>(0xfa81a2b8),
-                                         0x588b,
-                                         0x11ed,
-                                         0x9b6a,
-                                         {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
-// fa81a718-588b-11ed-9b6a-0242ac120002
-static const AudioUuid VolumeSwImplUUID = {static_cast<int32_t>(0xfa81a718),
+// fa81862a-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kDownmixTypeUUID = {static_cast<int32_t>(0xfa81862a),
                                            0x588b,
                                            0x11ed,
                                            0x9b6a,
                                            {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// fa8187ba-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kDownmixSwImplUUID = {static_cast<int32_t>(0xfa8187ba),
+                                             0x588b,
+                                             0x11ed,
+                                             0x9b6a,
+                                             {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 0bed4300-ddd6-11db-8f34-0002a5d5c51b.
+static const AudioUuid kEqualizerTypeUUID = {static_cast<int32_t>(0x0bed4300),
+                                             0xddd6,
+                                             0x11db,
+                                             0x8f34,
+                                             {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// 0bed4300-847d-11df-bb17-0002a5d5c51b
+static const AudioUuid kEqualizerSwImplUUID = {static_cast<int32_t>(0x0bed4300),
+                                               0x847d,
+                                               0x11df,
+                                               0xbb17,
+                                               {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// ce772f20-847d-11df-bb17-0002a5d5c51b
+static const AudioUuid kEqualizerBundleImplUUID = {static_cast<int32_t>(0xce772f20),
+                                                   0x847d,
+                                                   0x11df,
+                                                   0xbb17,
+                                                   {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// c8e70ecd-48ca-456e-8a4f-0002a5d5c51b
+static const AudioUuid kEqualizerProxyUUID = {static_cast<int32_t>(0xc8e70ecd),
+                                              0x48ca,
+                                              0x456e,
+                                              0x8a4f,
+                                              {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// 7261676f-6d75-7369-6364-28e2fd3ac39e
+static const AudioUuid kDynamicsProcessingTypeUUID = {static_cast<int32_t>(0x7261676f),
+                                                      0x6d75,
+                                                      0x7369,
+                                                      0x6364,
+                                                      {0x28, 0xe2, 0xfd, 0x3a, 0xc3, 0x9e}};
+// fa818d78-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kDynamicsProcessingSwImplUUID = {static_cast<int32_t>(0xfa818d78),
+                                                        0x588b,
+                                                        0x11ed,
+                                                        0x9b6a,
+                                                        {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 1411e6d6-aecd-4021-a1cf-a6aceb0d71e5
+static const AudioUuid kHapticGeneratorTypeUUID = {static_cast<int32_t>(0x1411e6d6),
+                                                   0xaecd,
+                                                   0x4021,
+                                                   0xa1cf,
+                                                   {0xa6, 0xac, 0xeb, 0x0d, 0x71, 0xe5}};
+// fa819110-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kHapticGeneratorSwImplUUID = {static_cast<int32_t>(0xfa819110),
+                                                     0x588b,
+                                                     0x11ed,
+                                                     0x9b6a,
+                                                     {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// fe3199be-aed0-413f-87bb-11260eb63cf1
+static const AudioUuid kLoudnessEnhancerTypeUUID = {static_cast<int32_t>(0xfe3199be),
+                                                    0xaed0,
+                                                    0x413f,
+                                                    0x87bb,
+                                                    {0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}};
+// fa819610-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kLoudnessEnhancerSwImplUUID = {static_cast<int32_t>(0xfa819610),
+                                                      0x588b,
+                                                      0x11ed,
+                                                      0x9b6a,
+                                                      {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// c2e5d5f0-94bd-4763-9cac-4e234d06839e
+static const AudioUuid kEnvReverbTypeUUID = {static_cast<int32_t>(0xc2e5d5f0),
+                                             0x94bd,
+                                             0x4763,
+                                             0x9cac,
+                                             {0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e}};
+// fa819886-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kEnvReverbSwImplUUID = {static_cast<int32_t>(0xfa819886),
+                                               0x588b,
+                                               0x11ed,
+                                               0x9b6a,
+                                               {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 47382d60-ddd8-11db-bf3a-0002a5d5c51b
+static const AudioUuid kPresetReverbTypeUUID = {static_cast<int32_t>(0x47382d60),
+                                                0xddd8,
+                                                0x11db,
+                                                0xbf3a,
+                                                {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// fa8199c6-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kPresetReverbSwImplUUID = {static_cast<int32_t>(0xfa8199c6),
+                                                  0x588b,
+                                                  0x11ed,
+                                                  0x9b6a,
+                                                  {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 37cc2c00-dddd-11db-8577-0002a5d5c51b
+static const AudioUuid kVirtualizerTypeUUID = {static_cast<int32_t>(0x37cc2c00),
+                                               0xdddd,
+                                               0x11db,
+                                               0x8577,
+                                               {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// fa819d86-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kVirtualizerSwImplUUID = {static_cast<int32_t>(0xfa819d86),
+                                                 0x588b,
+                                                 0x11ed,
+                                                 0x9b6a,
+                                                 {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// fa819f3e-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kVisualizerTypeUUID = {static_cast<int32_t>(0xfa819f3e),
+                                              0x588b,
+                                              0x11ed,
+                                              0x9b6a,
+                                              {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// fa81a0f6-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kVisualizerSwImplUUID = {static_cast<int32_t>(0xfa81a0f6),
+                                                0x588b,
+                                                0x11ed,
+                                                0x9b6a,
+                                                {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// fa81a2b8-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kVolumeTypeUUID = {static_cast<int32_t>(0xfa81a2b8),
+                                          0x588b,
+                                          0x11ed,
+                                          0x9b6a,
+                                          {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// fa81a718-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kVolumeSwImplUUID = {static_cast<int32_t>(0xfa81a718),
+                                            0x588b,
+                                            0x11ed,
+                                            0x9b6a,
+                                            {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+
+/**
+ * @brief A map between effect name and effect type UUID.
+ * All <name> attribution in effect/effectProxy of audio_effects.xml should be listed in this map.
+ * We need this map is because existing audio_effects.xml don't have a type UUID defined.
+ */
+static const std::map<const std::string /* effect type */, const AudioUuid&> kUuidNameTypeMap = {
+        {"bassboost", kBassBoostTypeUUID},
+        {"downmix", kDownmixTypeUUID},
+        {"dynamics_processing", kDynamicsProcessingTypeUUID},
+        {"equalizer", kEqualizerTypeUUID},
+        {"haptic_generator", kHapticGeneratorTypeUUID},
+        {"loudness_enhancer", kLoudnessEnhancerTypeUUID},
+        {"env_reverb", kEnvReverbTypeUUID},
+        {"preset_reverb", kPresetReverbTypeUUID},
+        {"reverb_env_aux", kEnvReverbTypeUUID},
+        {"reverb_env_ins", kEnvReverbTypeUUID},
+        {"reverb_pre_aux", kPresetReverbTypeUUID},
+        {"reverb_pre_ins", kPresetReverbTypeUUID},
+        {"virtualizer", kVirtualizerTypeUUID},
+        {"visualizer", kVisualizerTypeUUID},
+        {"volume", kVolumeTypeUUID},
+};
 
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectWorker.h b/audio/aidl/default/include/effect-impl/EffectWorker.h
index a297937..6a78eab 100644
--- a/audio/aidl/default/include/effect-impl/EffectWorker.h
+++ b/audio/aidl/default/include/effect-impl/EffectWorker.h
@@ -62,6 +62,7 @@
     }
 
     // must implement by each effect implementation
+    // TODO: consider if this interface need adjustment to handle in-place processing
     virtual IEffect::Status effectProcessImpl(float* in, float* out, int processSamples) = 0;
 
   private:
diff --git a/audio/aidl/default/include/effectFactory-impl/EffectConfig.h b/audio/aidl/default/include/effectFactory-impl/EffectConfig.h
new file mode 100644
index 0000000..2b904f5
--- /dev/null
+++ b/audio/aidl/default/include/effectFactory-impl/EffectConfig.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <functional>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <cutils/properties.h>
+#include <tinyxml2.h>
+
+#include "effect-impl/EffectTypes.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+/**
+ *  Library contains a mapping from library name to path.
+ *  Effect contains a mapping from effect name to Libraries and implementation UUID.
+ *  Pre/post processor contains a mapping from processing name to effect names.
+ */
+class EffectConfig {
+  public:
+    explicit EffectConfig(const std::string& file);
+
+    // <library>
+    struct Library {
+        std::string name;
+        std::string path;
+    };
+    struct LibraryUuid {
+        std::string name;  // library name
+        ::aidl::android::media::audio::common::AudioUuid uuid;
+    };
+    // <effects>
+    struct EffectLibraries {
+        std::optional<struct LibraryUuid> proxyLibrary;
+        std::vector<struct LibraryUuid> libraries;
+    };
+
+    int getSkippedElements() const { return mSkippedElements; }
+    const std::unordered_map<std::string, std::string> getLibraryMap() const { return mLibraryMap; }
+    const std::unordered_map<std::string, struct EffectLibraries> getEffectsMap() const {
+        return mEffectsMap;
+    }
+    const std::unordered_map<std::string, std::vector<std::string>> getProcessingMap() const {
+        return mProcessingMap;
+    }
+
+  private:
+    int mSkippedElements;
+    /* Parsed Libraries result */
+    std::unordered_map<std::string, std::string> mLibraryMap;
+    /* Parsed Effects result */
+    std::unordered_map<std::string, struct EffectLibraries> mEffectsMap;
+    /* Parsed pre/post processing result */
+    std::unordered_map<std::string, std::vector<std::string>> mProcessingMap;
+
+    /** @return all `node`s children that are elements and match the tag if provided. */
+    std::vector<std::reference_wrapper<const tinyxml2::XMLElement>> getChildren(
+            const tinyxml2::XMLNode& node, const char* childTag = nullptr);
+
+    /** Parse a library xml note and push the result in mLibraryMap or return false on failure. */
+    bool parseLibrary(const tinyxml2::XMLElement& xml);
+
+    /** Parse an effect from an xml element describing it.
+     * @return true and pushes the effect in mEffectsMap on success, false on failure.
+     */
+    bool parseEffect(const tinyxml2::XMLElement& xml);
+
+    bool parseStream(const tinyxml2::XMLElement& xml);
+
+    // Function to parse effect.library name and effect.uuid from xml
+    bool parseLibraryUuid(const tinyxml2::XMLElement& xml, struct LibraryUuid& libraryUuid,
+                          bool isProxy = false);
+
+    const char* dump(const tinyxml2::XMLElement& element,
+                     tinyxml2::XMLPrinter&& printer = {}) const;
+};
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
index d50bd63..7edace0 100644
--- a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
+++ b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
@@ -19,15 +19,17 @@
 #include <any>
 #include <map>
 #include <optional>
+#include <set>
 #include <vector>
 
 #include <aidl/android/hardware/audio/effect/BnFactory.h>
+#include "EffectConfig.h"
 
 namespace aidl::android::hardware::audio::effect {
 
 class Factory : public BnFactory {
   public:
-    Factory();
+    explicit Factory(const std::string& file);
     /**
      * @brief Get identity of all effects supported by the device, with the optional filter by type
      * and/or by instance UUID.
@@ -77,9 +79,10 @@
             override;
 
   private:
+    const EffectConfig mConfig;
     ~Factory();
-    // List of effect descriptors supported by the devices.
-    std::vector<Descriptor::Identity> mIdentityList;
+    // Set of effect descriptors supported by the devices.
+    std::set<Descriptor::Identity> mIdentitySet;
 
     std::map<aidl::android::media::audio::common::AudioUuid /* implementationUUID */,
              std::pair<std::unique_ptr<void, std::function<void(void*)>> /* dlHandle */,
@@ -91,10 +94,13 @@
 
     ndk::ScopedAStatus destroyEffectImpl(const std::shared_ptr<IEffect>& in_handle);
     void cleanupEffectMap();
-    void openEffectLibrary(
-            const ::aidl::android::media::audio::common::AudioUuid& type,
-            const ::aidl::android::media::audio::common::AudioUuid& impl,
-            const std::optional<::aidl::android::media::audio::common::AudioUuid>& proxy,
-            const std::string& libName);
+    void openEffectLibrary(const ::aidl::android::media::audio::common::AudioUuid& impl,
+                           const std::string& libName);
+    void createIdentityWithConfig(
+            const EffectConfig::LibraryUuid& configLib,
+            const ::aidl::android::media::audio::common::AudioUuid& typeUuid,
+            const std::optional<::aidl::android::media::audio::common::AudioUuid> proxyUuid);
+    void loadEffectLibs();
 };
+
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp
index 51645c7..9d2b978 100644
--- a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp
+++ b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp
@@ -26,14 +26,14 @@
 #include "LoudnessEnhancerSw.h"
 
 using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kLoudnessEnhancerSwImplUUID;
 using aidl::android::hardware::audio::effect::LoudnessEnhancerSw;
-using aidl::android::hardware::audio::effect::LoudnessEnhancerSwImplUUID;
 using aidl::android::hardware::audio::effect::State;
 using aidl::android::media::audio::common::AudioUuid;
 
 extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
                                            std::shared_ptr<IEffect>* instanceSpp) {
-    if (!in_impl_uuid || *in_impl_uuid != LoudnessEnhancerSwImplUUID) {
+    if (!in_impl_uuid || *in_impl_uuid != kLoudnessEnhancerSwImplUUID) {
         LOG(ERROR) << __func__ << "uuid not supported";
         return EX_ILLEGAL_ARGUMENT;
     }
@@ -76,16 +76,60 @@
     std::lock_guard lg(mMutex);
     RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
 
-    mSpecificParam = specific.get<Parameter::Specific::loudnessEnhancer>();
-    LOG(DEBUG) << __func__ << " success with: " << specific.toString();
-    return ndk::ScopedAStatus::ok();
+    auto& leParam = specific.get<Parameter::Specific::loudnessEnhancer>();
+    auto tag = leParam.getTag();
+
+    switch (tag) {
+        case LoudnessEnhancer::gainMb: {
+            RETURN_IF(mContext->setLeGainMb(leParam.get<LoudnessEnhancer::gainMb>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setGainMbFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "LoudnessEnhancerTagNotSupported");
+        }
+    }
 }
 
 ndk::ScopedAStatus LoudnessEnhancerSw::getParameterSpecific(const Parameter::Id& id,
                                                             Parameter::Specific* specific) {
     auto tag = id.getTag();
     RETURN_IF(Parameter::Id::loudnessEnhancerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
-    specific->set<Parameter::Specific::loudnessEnhancer>(mSpecificParam);
+    auto leId = id.get<Parameter::Id::loudnessEnhancerTag>();
+    auto leIdTag = leId.getTag();
+    switch (leIdTag) {
+        case LoudnessEnhancer::Id::commonTag:
+            return getParameterLoudnessEnhancer(leId.get<LoudnessEnhancer::Id::commonTag>(),
+                                                specific);
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(leIdTag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "LoudnessEnhancerTagNotSupported");
+    }
+}
+
+ndk::ScopedAStatus LoudnessEnhancerSw::getParameterLoudnessEnhancer(
+        const LoudnessEnhancer::Tag& tag, Parameter::Specific* specific) {
+    std::lock_guard lg(mMutex);
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    LoudnessEnhancer leParam;
+    switch (tag) {
+        case LoudnessEnhancer::gainMb: {
+            leParam.set<LoudnessEnhancer::gainMb>(mContext->getLeGainMb());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "LoudnessEnhancerTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::loudnessEnhancer>(leParam);
     return ndk::ScopedAStatus::ok();
 }
 
diff --git a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h
index c0de9c1..856bf0b 100644
--- a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h
+++ b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h
@@ -32,15 +32,24 @@
         : EffectContext(statusDepth, common) {
         LOG(DEBUG) << __func__;
     }
-    // TODO: add specific context here
+
+    RetCode setLeGainMb(int gainMb) {
+        // TODO : Add implementation to apply new gain
+        mGainMb = gainMb;
+        return RetCode::SUCCESS;
+    }
+    int getLeGainMb() const { return mGainMb; }
+
+  private:
+    int mGainMb = 0;  // Default Gain
 };
 
 class LoudnessEnhancerSw final : public EffectImpl {
   public:
     LoudnessEnhancerSw() { LOG(DEBUG) << __func__; }
     ~LoudnessEnhancerSw() {
+        cleanUp();
         LOG(DEBUG) << __func__;
-        releaseContext();
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
@@ -57,16 +66,17 @@
     const LoudnessEnhancer::Capability kCapability;
     /* Effect descriptor */
     const Descriptor kDescriptor = {
-            .common = {.id = {.type = LoudnessEnhancerTypeUUID,
-                              .uuid = LoudnessEnhancerSwImplUUID,
+            .common = {.id = {.type = kLoudnessEnhancerTypeUUID,
+                              .uuid = kLoudnessEnhancerSwImplUUID,
                               .proxy = std::nullopt},
                        .flags = {.type = Flags::Type::INSERT,
                                  .insert = Flags::Insert::FIRST,
                                  .volume = Flags::Volume::CTRL},
-                       .name = "LoudnessEnhancerSw"},
+                       .name = "LoudnessEnhancerSw",
+                       .implementor = "The Android Open Source Project"},
             .capability = Capability::make<Capability::loudnessEnhancer>(kCapability)};
 
-    /* parameters */
-    LoudnessEnhancer mSpecificParam;
+    ndk::ScopedAStatus getParameterLoudnessEnhancer(const LoudnessEnhancer::Tag& tag,
+                                                    Parameter::Specific* specific);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/reverb/Android.bp b/audio/aidl/default/presetReverb/Android.bp
similarity index 95%
rename from audio/aidl/default/reverb/Android.bp
rename to audio/aidl/default/presetReverb/Android.bp
index 955038c..4148511 100644
--- a/audio/aidl/default/reverb/Android.bp
+++ b/audio/aidl/default/presetReverb/Android.bp
@@ -24,14 +24,14 @@
 }
 
 cc_library_shared {
-    name: "libreverbsw",
+    name: "libpresetreverbsw",
     defaults: [
         "aidlaudioeffectservice_defaults",
         "latest_android_media_audio_common_types_ndk_shared",
         "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
-        "ReverbSw.cpp",
+        "PresetReverbSw.cpp",
         ":effectCommonFile",
     ],
     visibility: [
diff --git a/audio/aidl/default/reverb/ReverbSw.cpp b/audio/aidl/default/presetReverb/PresetReverbSw.cpp
similarity index 77%
rename from audio/aidl/default/reverb/ReverbSw.cpp
rename to audio/aidl/default/presetReverb/PresetReverbSw.cpp
index 639f1a2..069d0ff 100644
--- a/audio/aidl/default/reverb/ReverbSw.cpp
+++ b/audio/aidl/default/presetReverb/PresetReverbSw.cpp
@@ -15,7 +15,7 @@
  */
 
 #include <cstddef>
-#define LOG_TAG "AHAL_ReverbSw"
+#define LOG_TAG "AHAL_PresetReverbSw"
 #include <Utils.h>
 #include <algorithm>
 #include <unordered_set>
@@ -23,22 +23,22 @@
 #include <android-base/logging.h>
 #include <fmq/AidlMessageQueue.h>
 
-#include "ReverbSw.h"
+#include "PresetReverbSw.h"
 
 using aidl::android::hardware::audio::effect::IEffect;
-using aidl::android::hardware::audio::effect::ReverbSw;
-using aidl::android::hardware::audio::effect::ReverbSwImplUUID;
+using aidl::android::hardware::audio::effect::kPresetReverbSwImplUUID;
+using aidl::android::hardware::audio::effect::PresetReverbSw;
 using aidl::android::hardware::audio::effect::State;
 using aidl::android::media::audio::common::AudioUuid;
 
 extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
                                            std::shared_ptr<IEffect>* instanceSpp) {
-    if (!in_impl_uuid || *in_impl_uuid != ReverbSwImplUUID) {
+    if (!in_impl_uuid || *in_impl_uuid != kPresetReverbSwImplUUID) {
         LOG(ERROR) << __func__ << "uuid not supported";
         return EX_ILLEGAL_ARGUMENT;
     }
     if (instanceSpp) {
-        *instanceSpp = ndk::SharedRefBase::make<ReverbSw>();
+        *instanceSpp = ndk::SharedRefBase::make<PresetReverbSw>();
         LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
         return EX_NONE;
     } else {
@@ -64,13 +64,13 @@
 
 namespace aidl::android::hardware::audio::effect {
 
-ndk::ScopedAStatus ReverbSw::getDescriptor(Descriptor* _aidl_return) {
+ndk::ScopedAStatus PresetReverbSw::getDescriptor(Descriptor* _aidl_return) {
     LOG(DEBUG) << __func__ << kDescriptor.toString();
     *_aidl_return = kDescriptor;
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus ReverbSw::setParameterSpecific(const Parameter::Specific& specific) {
+ndk::ScopedAStatus PresetReverbSw::setParameterSpecific(const Parameter::Specific& specific) {
     RETURN_IF(Parameter::Specific::reverb != specific.getTag(), EX_ILLEGAL_ARGUMENT,
               "EffectNotSupported");
     std::lock_guard lg(mMutex);
@@ -81,24 +81,24 @@
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus ReverbSw::getParameterSpecific(const Parameter::Id& id,
-                                                  Parameter::Specific* specific) {
+ndk::ScopedAStatus PresetReverbSw::getParameterSpecific(const Parameter::Id& id,
+                                                        Parameter::Specific* specific) {
     auto tag = id.getTag();
     RETURN_IF(Parameter::Id::reverbTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
     specific->set<Parameter::Specific::reverb>(mSpecificParam);
     return ndk::ScopedAStatus::ok();
 }
 
-std::shared_ptr<EffectContext> ReverbSw::createContext(const Parameter::Common& common) {
+std::shared_ptr<EffectContext> PresetReverbSw::createContext(const Parameter::Common& common) {
     if (mContext) {
         LOG(DEBUG) << __func__ << " context already exist";
         return mContext;
     }
-    mContext = std::make_shared<ReverbSwContext>(1 /* statusFmqDepth */, common);
+    mContext = std::make_shared<PresetReverbSwContext>(1 /* statusFmqDepth */, common);
     return mContext;
 }
 
-RetCode ReverbSw::releaseContext() {
+RetCode PresetReverbSw::releaseContext() {
     if (mContext) {
         mContext.reset();
     }
@@ -106,7 +106,7 @@
 }
 
 // Processing method running in EffectWorker thread.
-IEffect::Status ReverbSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status PresetReverbSw::effectProcessImpl(float* in, float* out, int process) {
     // TODO: get data buffer and process.
     LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
     for (int i = 0; i < process; i++) {
diff --git a/audio/aidl/default/reverb/ReverbSw.h b/audio/aidl/default/presetReverb/PresetReverbSw.h
similarity index 78%
copy from audio/aidl/default/reverb/ReverbSw.h
copy to audio/aidl/default/presetReverb/PresetReverbSw.h
index e00956f..75a5a94 100644
--- a/audio/aidl/default/reverb/ReverbSw.h
+++ b/audio/aidl/default/presetReverb/PresetReverbSw.h
@@ -26,21 +26,21 @@
 
 namespace aidl::android::hardware::audio::effect {
 
-class ReverbSwContext final : public EffectContext {
+class PresetReverbSwContext final : public EffectContext {
   public:
-    ReverbSwContext(int statusDepth, const Parameter::Common& common)
+    PresetReverbSwContext(int statusDepth, const Parameter::Common& common)
         : EffectContext(statusDepth, common) {
         LOG(DEBUG) << __func__;
     }
     // TODO: add specific context here
 };
 
-class ReverbSw final : public EffectImpl {
+class PresetReverbSw final : public EffectImpl {
   public:
-    ReverbSw() { LOG(DEBUG) << __func__; }
-    ~ReverbSw() {
+    PresetReverbSw() { LOG(DEBUG) << __func__; }
+    ~PresetReverbSw() {
+        cleanUp();
         LOG(DEBUG) << __func__;
-        releaseContext();
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
@@ -52,18 +52,19 @@
     RetCode releaseContext() override;
 
   private:
-    std::shared_ptr<ReverbSwContext> mContext;
+    std::shared_ptr<PresetReverbSwContext> mContext;
     /* capabilities */
     const Reverb::Capability kCapability;
     /* Effect descriptor */
     const Descriptor kDescriptor = {
-            .common = {.id = {.type = ReverbTypeUUID,
-                              .uuid = ReverbSwImplUUID,
+            .common = {.id = {.type = kPresetReverbTypeUUID,
+                              .uuid = kPresetReverbSwImplUUID,
                               .proxy = std::nullopt},
                        .flags = {.type = Flags::Type::INSERT,
                                  .insert = Flags::Insert::FIRST,
                                  .volume = Flags::Volume::CTRL},
-                       .name = "ReverbSw"},
+                       .name = "PresetReverbSw",
+                       .implementor = "The Android Open Source Project"},
             .capability = Capability::make<Capability::reverb>(kCapability)};
 
     /* parameters */
diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.cpp b/audio/aidl/default/virtualizer/VirtualizerSw.cpp
index ccb7b4b..9688fc8 100644
--- a/audio/aidl/default/virtualizer/VirtualizerSw.cpp
+++ b/audio/aidl/default/virtualizer/VirtualizerSw.cpp
@@ -26,14 +26,14 @@
 #include "VirtualizerSw.h"
 
 using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kVirtualizerSwImplUUID;
 using aidl::android::hardware::audio::effect::State;
 using aidl::android::hardware::audio::effect::VirtualizerSw;
-using aidl::android::hardware::audio::effect::VirtualizerSwImplUUID;
 using aidl::android::media::audio::common::AudioUuid;
 
 extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
                                            std::shared_ptr<IEffect>* instanceSpp) {
-    if (!in_impl_uuid || *in_impl_uuid != VirtualizerSwImplUUID) {
+    if (!in_impl_uuid || *in_impl_uuid != kVirtualizerSwImplUUID) {
         LOG(ERROR) << __func__ << "uuid not supported";
         return EX_ILLEGAL_ARGUMENT;
     }
diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.h b/audio/aidl/default/virtualizer/VirtualizerSw.h
index da1998b..e4de8b3 100644
--- a/audio/aidl/default/virtualizer/VirtualizerSw.h
+++ b/audio/aidl/default/virtualizer/VirtualizerSw.h
@@ -39,8 +39,8 @@
   public:
     VirtualizerSw() { LOG(DEBUG) << __func__; }
     ~VirtualizerSw() {
+        cleanUp();
         LOG(DEBUG) << __func__;
-        releaseContext();
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
@@ -57,13 +57,14 @@
     const Virtualizer::Capability kCapability;
     /* Effect descriptor */
     const Descriptor kDescriptor = {
-            .common = {.id = {.type = VirtualizerTypeUUID,
-                              .uuid = VirtualizerSwImplUUID,
+            .common = {.id = {.type = kVirtualizerTypeUUID,
+                              .uuid = kVirtualizerSwImplUUID,
                               .proxy = std::nullopt},
                        .flags = {.type = Flags::Type::INSERT,
                                  .insert = Flags::Insert::FIRST,
                                  .volume = Flags::Volume::CTRL},
-                       .name = "VirtualizerSw"},
+                       .name = "VirtualizerSw",
+                       .implementor = "The Android Open Source Project"},
             .capability = Capability::make<Capability::virtualizer>(kCapability)};
 
     /* parameters */
diff --git a/audio/aidl/default/visualizer/VisualizerSw.cpp b/audio/aidl/default/visualizer/VisualizerSw.cpp
index 5a24f18..24a7bef 100644
--- a/audio/aidl/default/visualizer/VisualizerSw.cpp
+++ b/audio/aidl/default/visualizer/VisualizerSw.cpp
@@ -26,14 +26,14 @@
 #include "VisualizerSw.h"
 
 using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kVisualizerSwImplUUID;
 using aidl::android::hardware::audio::effect::State;
 using aidl::android::hardware::audio::effect::VisualizerSw;
-using aidl::android::hardware::audio::effect::VisualizerSwImplUUID;
 using aidl::android::media::audio::common::AudioUuid;
 
 extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
                                            std::shared_ptr<IEffect>* instanceSpp) {
-    if (!in_impl_uuid || *in_impl_uuid != VisualizerSwImplUUID) {
+    if (!in_impl_uuid || *in_impl_uuid != kVisualizerSwImplUUID) {
         LOG(ERROR) << __func__ << "uuid not supported";
         return EX_ILLEGAL_ARGUMENT;
     }
diff --git a/audio/aidl/default/visualizer/VisualizerSw.h b/audio/aidl/default/visualizer/VisualizerSw.h
index 21101dd..bccd6e9 100644
--- a/audio/aidl/default/visualizer/VisualizerSw.h
+++ b/audio/aidl/default/visualizer/VisualizerSw.h
@@ -39,8 +39,8 @@
   public:
     VisualizerSw() { LOG(DEBUG) << __func__; }
     ~VisualizerSw() {
+        cleanUp();
         LOG(DEBUG) << __func__;
-        releaseContext();
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
@@ -57,13 +57,14 @@
     const Visualizer::Capability kCapability;
     /* Effect descriptor */
     const Descriptor kDescriptor = {
-            .common = {.id = {.type = VisualizerTypeUUID,
-                              .uuid = VisualizerSwImplUUID,
+            .common = {.id = {.type = kVisualizerTypeUUID,
+                              .uuid = kVisualizerSwImplUUID,
                               .proxy = std::nullopt},
                        .flags = {.type = Flags::Type::INSERT,
                                  .insert = Flags::Insert::FIRST,
                                  .volume = Flags::Volume::CTRL},
-                       .name = "VisualizerSw"},
+                       .name = "VisualizerSw",
+                       .implementor = "The Android Open Source Project"},
             .capability = Capability::make<Capability::visualizer>(kCapability)};
 
     /* parameters */
diff --git a/audio/aidl/default/volume/VolumeSw.cpp b/audio/aidl/default/volume/VolumeSw.cpp
index e2f42d7..b8af921 100644
--- a/audio/aidl/default/volume/VolumeSw.cpp
+++ b/audio/aidl/default/volume/VolumeSw.cpp
@@ -26,14 +26,14 @@
 #include "VolumeSw.h"
 
 using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kVolumeSwImplUUID;
 using aidl::android::hardware::audio::effect::State;
 using aidl::android::hardware::audio::effect::VolumeSw;
-using aidl::android::hardware::audio::effect::VolumeSwImplUUID;
 using aidl::android::media::audio::common::AudioUuid;
 
 extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
                                            std::shared_ptr<IEffect>* instanceSpp) {
-    if (!in_impl_uuid || *in_impl_uuid != VolumeSwImplUUID) {
+    if (!in_impl_uuid || *in_impl_uuid != kVolumeSwImplUUID) {
         LOG(ERROR) << __func__ << "uuid not supported";
         return EX_ILLEGAL_ARGUMENT;
     }
diff --git a/audio/aidl/default/volume/VolumeSw.h b/audio/aidl/default/volume/VolumeSw.h
index e46c864..86e01c1 100644
--- a/audio/aidl/default/volume/VolumeSw.h
+++ b/audio/aidl/default/volume/VolumeSw.h
@@ -39,8 +39,8 @@
   public:
     VolumeSw() { LOG(DEBUG) << __func__; }
     ~VolumeSw() {
+        cleanUp();
         LOG(DEBUG) << __func__;
-        releaseContext();
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
@@ -57,13 +57,14 @@
     const Volume::Capability kCapability;
     /* Effect descriptor */
     const Descriptor kDescriptor = {
-            .common = {.id = {.type = VolumeTypeUUID,
-                              .uuid = VolumeSwImplUUID,
+            .common = {.id = {.type = kVolumeTypeUUID,
+                              .uuid = kVolumeSwImplUUID,
                               .proxy = std::nullopt},
                        .flags = {.type = Flags::Type::INSERT,
                                  .insert = Flags::Insert::FIRST,
                                  .volume = Flags::Volume::CTRL},
-                       .name = "VolumeSw"},
+                       .name = "VolumeSw",
+                       .implementor = "The Android Open Source Project"},
             .capability = Capability::make<Capability::volume>(kCapability)};
 
     /* parameters */
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index 8de1d79..03e9fca 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -7,136 +7,72 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
-cc_test {
-    name: "VtsHalAudioCoreTargetTest",
+cc_defaults {
+    name: "VtsHalAudioTargetTestDefaults",
     defaults: [
-        "VtsHalTargetTestDefaults",
-        "use_libaidlvintf_gtest_helper_static",
         "latest_android_hardware_audio_common_ndk_static",
-        "latest_android_hardware_audio_core_ndk_static",
         "latest_android_media_audio_common_types_ndk_static",
+        "use_libaidlvintf_gtest_helper_static",
+        "VtsHalTargetTestDefaults",
     ],
     shared_libs: [
         "libbinder_ndk",
-        "libcutils",
         "libfmq",
     ],
     static_libs: [
+        "android.hardware.audio.effect-V1-ndk",
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
         "libaudioaidlcommon",
     ],
+    header_libs: ["libaudioaidl_headers"],
     cflags: [
         "-Wall",
         "-Wextra",
         "-Werror",
         "-Wthread-safety",
     ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
+
+cc_test {
+    name: "VtsHalAudioCoreTargetTest",
+    defaults: [
+        "VtsHalAudioTargetTestDefaults",
+        "latest_android_hardware_audio_core_ndk_static",
+    ],
+    shared_libs: [
+        "libcutils",
+    ],
     srcs: [
         "ModuleConfig.cpp",
         "VtsHalAudioCoreTargetTest.cpp",
     ],
-    test_suites: [
-        "general-tests",
-        "vts",
-    ],
 }
 
 cc_test {
     name: "VtsHalAudioEffectFactoryTargetTest",
-    defaults: [
-        "latest_android_media_audio_common_types_ndk_static",
-        "VtsHalTargetTestDefaults",
-        "use_libaidlvintf_gtest_helper_static",
-    ],
-    srcs: [
-        "VtsHalAudioEffectFactoryTargetTest.cpp",
-    ],
-    shared_libs: [
-        "libbinder_ndk",
-    ],
-    static_libs: [
-        "android.hardware.audio.effect-V1-ndk",
-        "android.hardware.common-V2-ndk",
-        "android.hardware.common.fmq-V1-ndk",
-    ],
-    header_libs: ["libaudioaidl_headers"],
-    cflags: [
-        "-Wall",
-        "-Wextra",
-        "-Werror",
-        "-Wthread-safety",
-    ],
-    test_suites: [
-        "general-tests",
-        "vts",
-    ],
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalAudioEffectFactoryTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalAudioEffectTargetTest",
-    defaults: [
-        "latest_android_hardware_audio_common_ndk_static",
-        "latest_android_media_audio_common_types_ndk_static",
-        "VtsHalTargetTestDefaults",
-        "use_libaidlvintf_gtest_helper_static",
-    ],
-    srcs: [
-        "VtsHalAudioEffectTargetTest.cpp",
-    ],
-    shared_libs: [
-        "libbinder_ndk",
-        "libfmq",
-    ],
-    static_libs: [
-        "android.hardware.audio.effect-V1-ndk",
-        "android.hardware.common-V2-ndk",
-        "android.hardware.common.fmq-V1-ndk",
-        "libaudioaidlcommon",
-    ],
-    header_libs: ["libaudioaidl_headers"],
-    cflags: [
-        "-Wall",
-        "-Wextra",
-        "-Werror",
-        "-Wthread-safety",
-    ],
-    test_suites: [
-        "general-tests",
-        "vts",
-    ],
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalAudioEffectTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalEqualizerTargetTest",
-    defaults: [
-        "latest_android_hardware_audio_common_ndk_static",
-        "latest_android_media_audio_common_types_ndk_static",
-        "VtsHalTargetTestDefaults",
-        "use_libaidlvintf_gtest_helper_static",
-    ],
-    srcs: [
-        "VtsHalEqualizerTargetTest.cpp",
-    ],
-    shared_libs: [
-        "libbinder_ndk",
-        "libfmq",
-    ],
-    static_libs: [
-        "android.hardware.audio.effect-V1-ndk",
-        "android.hardware.common-V2-ndk",
-        "android.hardware.common.fmq-V1-ndk",
-        "libaudioaidlcommon",
-    ],
-    header_libs: ["libaudioaidl_headers"],
-    cflags: [
-        "-Wall",
-        "-Wextra",
-        "-Werror",
-        "-Wthread-safety",
-    ],
-    test_suites: [
-        "general-tests",
-        "vts",
-    ],
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalEqualizerTargetTest.cpp"],
+}
+
+cc_test {
+    name: "VtsHalLoudnessEnhancerTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalLoudnessEnhancerTargetTest.cpp"],
 }
diff --git a/audio/aidl/vts/AudioHalBinderServiceUtil.h b/audio/aidl/vts/AudioHalBinderServiceUtil.h
index e928286..c8d81b1 100644
--- a/audio/aidl/vts/AudioHalBinderServiceUtil.h
+++ b/audio/aidl/vts/AudioHalBinderServiceUtil.h
@@ -21,6 +21,7 @@
 #include <mutex>
 
 #include <android-base/properties.h>
+#include <android/binder_auto_utils.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
 
@@ -34,7 +35,7 @@
         if (mBinder == nullptr) {
             LOG(ERROR) << "Failed to get service " << serviceName;
         } else {
-            LOG(DEBUG) << "succeed to get service " << serviceName;
+            LOG(DEBUG) << "Succeeded to get service " << serviceName;
         }
         return mBinder;
     }
diff --git a/audio/aidl/vts/EffectFactoryHelper.h b/audio/aidl/vts/EffectFactoryHelper.h
index d58fcf2..dc766dd 100644
--- a/audio/aidl/vts/EffectFactoryHelper.h
+++ b/audio/aidl/vts/EffectFactoryHelper.h
@@ -29,10 +29,7 @@
 using namespace android;
 
 using aidl::android::hardware::audio::effect::Descriptor;
-using aidl::android::hardware::audio::effect::EffectNullUuid;
-using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::IFactory;
-using aidl::android::hardware::audio::effect::Processing;
 using aidl::android::media::audio::common::AudioUuid;
 
 class EffectFactoryHelper {
@@ -48,122 +45,36 @@
         ASSERT_NE(mEffectFactory, nullptr);
         mEffectFactory = IFactory::fromBinder(binderUtil.restartService());
         ASSERT_NE(mEffectFactory, nullptr);
-        ClearEffectMap();
     }
 
-    void QueryEffects(const std::optional<AudioUuid>& in_type,
-                      const std::optional<AudioUuid>& in_instance,
-                      const std::optional<AudioUuid>& in_proxy,
-                      std::vector<Descriptor::Identity>* _aidl_return) {
-        ASSERT_NE(mEffectFactory, nullptr);
-        EXPECT_IS_OK(mEffectFactory->queryEffects(in_type, in_instance, in_proxy, _aidl_return));
-        mIds = *_aidl_return;
-    }
+    std::shared_ptr<IFactory> GetFactory() const { return mEffectFactory; }
 
-    void QueryProcessing(const std::optional<Processing::Type>& in_type,
-                         std::vector<Processing>* _aidl_return) {
-        ASSERT_NE(mEffectFactory, nullptr);
-        EXPECT_IS_OK(mEffectFactory->queryProcessing(in_type, _aidl_return));
-        // only update the whole list if no filter applied
-        if (!in_type.has_value()) {
-            mProcesses = *_aidl_return;
-        }
-    }
+    static std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>>
+    getAllEffectDescriptors(std::string serviceName, std::optional<AudioUuid> type = std::nullopt) {
+        AudioHalBinderServiceUtil util;
+        auto names = android::getAidlHalInstanceNames(serviceName);
+        std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>> result;
 
-    void CreateEffects() {
-        for (const auto& id : mIds) {
-            std::shared_ptr<IEffect> effect;
-            EXPECT_IS_OK(mEffectFactory->createEffect(id.uuid, &effect));
-            EXPECT_NE(effect, nullptr) << id.toString();
-            if (effect) {
-                mEffectIdMap[effect] = id;
+        for (const auto& name : names) {
+            auto factory = IFactory::fromBinder(util.connectToService(name));
+            if (factory) {
+                if (std::vector<Descriptor::Identity> ids;
+                    factory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids).isOk()) {
+                    for (const auto& id : ids) {
+                        if (type.has_value() && id.type != type.value()) {
+                            continue;
+                        }
+                        result.emplace_back(factory, id);
+                    }
+                }
             }
         }
-    }
 
-    void QueryAndCreateEffects(const AudioUuid& type = EffectNullUuid) {
-        std::vector<Descriptor::Identity> ids;
-        ASSERT_NE(mEffectFactory, nullptr);
-
-        if (type == EffectNullUuid) {
-            EXPECT_IS_OK(
-                    mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
-        } else {
-            EXPECT_IS_OK(mEffectFactory->queryEffects(type, std::nullopt, std::nullopt, &ids));
-        }
-        for (const auto& id : ids) {
-            ASSERT_EQ(id.type, type);
-            std::shared_ptr<IEffect> effect;
-            EXPECT_IS_OK(mEffectFactory->createEffect(id.uuid, &effect));
-            EXPECT_NE(effect, nullptr) << id.toString();
-            if (effect) {
-                mEffectIdMap[effect] = id;
-            }
-        }
+        return result;
     }
 
-    void CreateEffectsAndExpect(
-            const std::vector<std::pair<Descriptor::Identity, binder_exception_t>>& uuid_status) {
-        ASSERT_NE(mEffectFactory, nullptr);
-        for (const auto& it : uuid_status) {
-            std::shared_ptr<IEffect> effect;
-            auto status = mEffectFactory->createEffect(it.first.uuid, &effect);
-            EXPECT_STATUS(it.second, status);
-            if (effect) {
-                mEffectIdMap[effect] = it.first;
-            }
-        }
-    }
-
-    void DestroyEffectAndExpect(std::shared_ptr<IEffect>& instance, binder_exception_t exception) {
-        ASSERT_NE(mEffectFactory, nullptr);
-        auto status = mEffectFactory->destroyEffect(instance);
-        EXPECT_STATUS(exception, status);
-    }
-
-    void QueryAndCreateAllEffects() {
-        ASSERT_NE(mEffectFactory, nullptr);
-        EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt,
-                                                  &mCompleteIds));
-        for (const auto& id : mCompleteIds) {
-            std::shared_ptr<IEffect> effect;
-            EXPECT_IS_OK(mEffectFactory->createEffect(id.uuid, &effect));
-            EXPECT_NE(effect, nullptr) << id.toString();
-            mEffectIdMap[effect] = id;
-        }
-    }
-
-    void DestroyEffects(const binder_exception_t expected = EX_NONE, const int remaining = 0) {
-        ASSERT_NE(mEffectFactory, nullptr);
-
-        for (auto it = mEffectIdMap.begin(); it != mEffectIdMap.end();) {
-            auto erased = it++;
-            auto status = mEffectFactory->destroyEffect(erased->first);
-            EXPECT_STATUS(expected, status);
-            if (status.isOk()) {
-                mEffectIdMap.erase(erased);
-            }
-        }
-        EXPECT_EQ((unsigned int)remaining, mEffectIdMap.size());
-    }
-
-    std::shared_ptr<IFactory> GetFactory() { return mEffectFactory; }
-    const std::vector<Descriptor::Identity>& GetEffectIds() { return mIds; }
-    const std::vector<Descriptor::Identity>& GetCompleteEffectIdList() const {
-        return mCompleteIds;
-    }
-    const std::map<std::shared_ptr<IEffect>, Descriptor::Identity>& GetEffectMap() const {
-        return mEffectIdMap;
-    }
-    void ClearEffectMap() { mEffectIdMap.clear(); }
-
   private:
     std::shared_ptr<IFactory> mEffectFactory;
     std::string mServiceName;
     AudioHalBinderServiceUtil binderUtil;
-    std::vector<Descriptor::Identity> mIds;
-    std::vector<Descriptor::Identity> mCompleteIds;
-    std::vector<Processing> mProcesses;
-
-    std::map<std::shared_ptr<IEffect>, Descriptor::Identity> mEffectIdMap;
 };
diff --git a/audio/aidl/vts/EffectHelper.h b/audio/aidl/vts/EffectHelper.h
index 623ac37..73a1f49 100644
--- a/audio/aidl/vts/EffectHelper.h
+++ b/audio/aidl/vts/EffectHelper.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <algorithm>
 #include <memory>
 #include <string>
 #include <unordered_map>
@@ -24,7 +25,6 @@
 #include <aidl/android/hardware/audio/effect/IEffect.h>
 #include <aidl/android/hardware/audio/effect/IFactory.h>
 #include <aidl/android/media/audio/common/AudioChannelLayout.h>
-#include <aidl/android/media/audio/common/AudioDeviceType.h>
 #include <android/binder_auto_utils.h>
 #include <fmq/AidlMessageQueue.h>
 
@@ -35,275 +35,139 @@
 using namespace android;
 using aidl::android::hardware::audio::effect::CommandId;
 using aidl::android::hardware::audio::effect::Descriptor;
-using aidl::android::hardware::audio::effect::EffectNullUuid;
-using aidl::android::hardware::audio::effect::EffectZeroUuid;
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::Parameter;
 using aidl::android::hardware::audio::effect::State;
 using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
 using aidl::android::media::audio::common::AudioChannelLayout;
-using aidl::android::media::audio::common::AudioDeviceType;
 using aidl::android::media::audio::common::AudioFormatDescription;
 using aidl::android::media::audio::common::AudioFormatType;
 using aidl::android::media::audio::common::AudioUuid;
 using aidl::android::media::audio::common::PcmType;
 
-const AudioFormatDescription DefaultFormat = {
+const AudioFormatDescription kDefaultFormatDescription = {
         .type = AudioFormatType::PCM, .pcm = PcmType::FLOAT_32_BIT, .encoding = ""};
 
+typedef ::android::AidlMessageQueue<IEffect::Status,
+                                    ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+        StatusMQ;
+typedef ::android::AidlMessageQueue<float,
+                                    ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+        DataMQ;
+
 class EffectHelper {
   public:
-    explicit EffectHelper(const std::string& name) : mFactoryHelper(EffectFactoryHelper(name)) {
-        mFactoryHelper.ConnectToFactoryService();
+    static void create(std::shared_ptr<IFactory> factory, std::shared_ptr<IEffect>& effect,
+                       Descriptor::Identity id, binder_status_t status = EX_NONE) {
+        ASSERT_NE(factory, nullptr);
+        EXPECT_STATUS(status, factory->createEffect(id.uuid, &effect));
+        if (status == EX_NONE) {
+            ASSERT_NE(effect, nullptr) << id.uuid.toString();
+        }
     }
 
-    void OpenEffects(const AudioUuid& type = EffectNullUuid) {
-        auto open = [&](const std::shared_ptr<IEffect>& effect) {
-            ASSERT_NE(effect, nullptr);
-            IEffect::OpenEffectReturn ret;
-            EXPECT_IS_OK(effect->open(mCommon, mSpecific, &ret));
-            EffectParam params;
-            params.statusMQ = std::make_unique<StatusMQ>(ret.statusMQ);
-            params.inputMQ = std::make_unique<DataMQ>(ret.inputDataMQ);
-            params.outputMQ = std::make_unique<DataMQ>(ret.outputDataMQ);
-            mEffectParams.push_back(std::move(params));
-        };
-        EXPECT_NO_FATAL_FAILURE(ForEachEffect(open, type));
+    static void destroy(std::shared_ptr<IFactory> factory, std::shared_ptr<IEffect> effect,
+                        binder_status_t status = EX_NONE) {
+        ASSERT_NE(factory, nullptr);
+        ASSERT_NE(effect, nullptr);
+        EXPECT_STATUS(status, factory->destroyEffect(effect));
     }
 
-    void CloseEffects(const binder_status_t status = EX_NONE) {
-        auto close = [&](const std::shared_ptr<IEffect>& effect) {
-            ASSERT_NE(effect, nullptr);
+    static void open(std::shared_ptr<IEffect> effect, const Parameter::Common& common,
+                     const std::optional<Parameter::Specific>& specific,
+                     IEffect::OpenEffectReturn* ret, binder_status_t status = EX_NONE) {
+        ASSERT_NE(effect, nullptr);
+        EXPECT_STATUS(status, effect->open(common, specific, ret));
+    }
+
+    static void open(std::shared_ptr<IEffect> effect, int session = 0,
+                     binder_status_t status = EX_NONE) {
+        ASSERT_NE(effect, nullptr);
+        Parameter::Common common = EffectHelper::createParamCommon(session);
+        IEffect::OpenEffectReturn ret;
+        open(effect, common, std::nullopt /* specific */, &ret, status);
+    }
+
+    static void close(std::shared_ptr<IEffect> effect, binder_status_t status = EX_NONE) {
+        if (effect) {
             EXPECT_STATUS(status, effect->close());
-        };
-
-        EXPECT_NO_FATAL_FAILURE(ForEachEffect(close));
-    }
-
-    void CreateEffects(const int n = 1) {
-        for (int i = 0; i < n; i++) {
-            ASSERT_NO_FATAL_FAILURE(mFactoryHelper.QueryAndCreateAllEffects());
         }
     }
-
-    void CreateEffectsWithUUID(const AudioUuid& type = EffectNullUuid) {
-        ASSERT_NO_FATAL_FAILURE(mFactoryHelper.QueryAndCreateEffects(type));
+    static void getDescriptor(std::shared_ptr<IEffect> effect, Descriptor& desc,
+                              binder_status_t status = EX_NONE) {
+        ASSERT_NE(effect, nullptr);
+        EXPECT_STATUS(status, effect->getDescriptor(&desc));
     }
-
-    void QueryEffects() { ASSERT_NO_FATAL_FAILURE(mFactoryHelper.QueryAndCreateAllEffects()); }
-
-    void DestroyEffects(const binder_status_t status = EX_NONE, const int remaining = 0) {
-        ASSERT_NO_FATAL_FAILURE(mFactoryHelper.DestroyEffects(status, remaining));
-        mEffectDescriptors.clear();
+    static void expectState(std::shared_ptr<IEffect> effect, State expectState,
+                            binder_status_t status = EX_NONE) {
+        ASSERT_NE(effect, nullptr);
+        State state;
+        EXPECT_STATUS(status, effect->getState(&state));
+        EXPECT_EQ(expectState, state);
     }
-
-    void GetEffectDescriptors() {
-        auto get = [&](const std::shared_ptr<IEffect>& effect) {
-            ASSERT_NE(effect, nullptr);
-            Descriptor desc;
-            EXPECT_IS_OK(effect->getDescriptor(&desc));
-            mEffectDescriptors.push_back(std::move(desc));
-        };
-        EXPECT_NO_FATAL_FAILURE(ForEachEffect(get));
+    static void command(std::shared_ptr<IEffect> effect, CommandId command,
+                        binder_status_t status = EX_NONE) {
+        ASSERT_NE(effect, nullptr);
+        EXPECT_STATUS(status, effect->command(command));
     }
-
-    void CommandEffects(CommandId command) {
-        auto close = [&](const std::shared_ptr<IEffect>& effect) {
-            ASSERT_NE(effect, nullptr);
-            EXPECT_IS_OK(effect->command(command));
-        };
-        EXPECT_NO_FATAL_FAILURE(ForEachEffect(close));
+    static void allocateInputData(const Parameter::Common common, std::unique_ptr<DataMQ>& mq,
+                                  std::vector<float>& buffer) {
+        ASSERT_NE(mq, nullptr);
+        auto frameSize = android::hardware::audio::common::getFrameSizeInBytes(
+                common.input.base.format, common.input.base.channelMask);
+        const size_t floatsToWrite = mq->availableToWrite();
+        EXPECT_NE(0UL, floatsToWrite);
+        EXPECT_EQ(frameSize * common.input.frameCount, floatsToWrite * sizeof(float));
+        buffer.resize(floatsToWrite);
+        std::fill(buffer.begin(), buffer.end(), 0x5a);
     }
-
-    void CommandEffectsExpectStatus(CommandId command, const binder_status_t status) {
-        auto func = [&](const std::shared_ptr<IEffect>& effect) {
-            ASSERT_NE(effect, nullptr);
-            EXPECT_STATUS(status, effect->command(command));
-        };
-        EXPECT_NO_FATAL_FAILURE(ForEachEffect(func));
+    static void writeToFmq(std::unique_ptr<DataMQ>& mq, const std::vector<float>& buffer) {
+        const size_t available = mq->availableToWrite();
+        EXPECT_NE(0Ul, available);
+        auto bufferFloats = buffer.size();
+        auto floatsToWrite = std::min(available, bufferFloats);
+        EXPECT_TRUE(mq->write(buffer.data(), floatsToWrite));
     }
-
-    void ExpectState(State expected) {
-        auto get = [&](const std::shared_ptr<IEffect>& effect) {
-            ASSERT_NE(effect, nullptr);
-            State state = State::INIT;
-            EXPECT_IS_OK(effect->getState(&state));
-            EXPECT_EQ(expected, state);
-        };
-        EXPECT_NO_FATAL_FAILURE(ForEachEffect(get));
-    }
-
-    void SetParameter() {
-        auto func = [&](const std::shared_ptr<IEffect>& effect) {
-            ASSERT_NE(effect, nullptr);
-            Parameter param;
-            param.set<Parameter::common>(mCommon);
-            EXPECT_IS_OK(effect->setParameter(param));
-        };
-        EXPECT_NO_FATAL_FAILURE(ForEachEffect(func));
-    }
-
-    void VerifyParameters() {
-        auto func = [&](const std::shared_ptr<IEffect>& effect) {
-            ASSERT_NE(effect, nullptr);
-            Parameter paramCommonGet = Parameter(), paramCommonExpect = Parameter();
-            Parameter::Id id;
-            id.set<Parameter::Id::commonTag>(Parameter::common);
-            paramCommonExpect.set<Parameter::common>(mCommon);
-            EXPECT_IS_OK(effect->getParameter(id, &paramCommonGet));
-            EXPECT_EQ(paramCommonExpect, paramCommonGet)
-                    << paramCommonExpect.toString() << " vs " << paramCommonGet.toString();
-        };
-        EXPECT_NO_FATAL_FAILURE(ForEachEffect(func));
-    }
-
-    void QueryEffects(const std::optional<AudioUuid>& in_type,
-                      const std::optional<AudioUuid>& in_instance,
-                      const std::optional<AudioUuid>& in_proxy,
-                      std::vector<Descriptor::Identity>* _aidl_return) {
-        mFactoryHelper.QueryEffects(in_type, in_instance, in_proxy, _aidl_return);
-    }
-
-    template <typename Functor>
-    void ForEachEffect(Functor functor, const std::optional<AudioUuid>& type = EffectNullUuid) {
-        auto effectMap = mFactoryHelper.GetEffectMap();
-        for (const auto& it : effectMap) {
-            SCOPED_TRACE(it.second.toString());
-            if (type != EffectNullUuid && it.second.type != type) continue;
-            functor(it.first);
+    static void readFromFmq(std::unique_ptr<StatusMQ>& statusMq, size_t statusNum,
+                            std::unique_ptr<DataMQ>& dataMq, size_t expectFloats,
+                            std::vector<float>& buffer) {
+        IEffect::Status status{};
+        EXPECT_TRUE(statusMq->readBlocking(&status, statusNum));
+        EXPECT_EQ(STATUS_OK, status.status);
+        if (statusNum != 0) {
+            EXPECT_EQ(expectFloats, (unsigned)status.fmqProduced);
+            EXPECT_EQ(expectFloats, dataMq->availableToRead());
+            if (expectFloats != 0) {
+                EXPECT_TRUE(dataMq->read(buffer.data(), expectFloats));
+            }
         }
     }
+    static Parameter::Common createParamCommon(
+            int session = 0, int ioHandle = -1, int iSampleRate = 48000, int oSampleRate = 48000,
+            long iFrameCount = 0x100, long oFrameCount = 0x100,
+            AudioChannelLayout inputChannelLayout =
+                    AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+                            AudioChannelLayout::LAYOUT_STEREO),
+            AudioChannelLayout outputChannelLayout =
+                    AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+                            AudioChannelLayout::LAYOUT_STEREO)) {
+        Parameter::Common common;
+        common.session = session;
+        common.ioHandle = ioHandle;
 
-    template <typename Functor>
-    void ForEachDescriptor(Functor functor) {
-        for (size_t i = 0; i < mEffectDescriptors.size(); i++) {
-            SCOPED_TRACE(mEffectDescriptors[i].toString());
-            functor(i, mEffectDescriptors[i]);
-        }
-    }
-
-    static const size_t mWriteMQBytes = 0x400;
-
-    enum class IO : char { INPUT = 0, OUTPUT = 1, INOUT = 2 };
-
-    void initParamCommonFormat(IO io = IO::INOUT,
-                               const AudioFormatDescription& format = DefaultFormat) {
-        if (io == IO::INPUT || io == IO::INOUT) {
-            mCommon.input.base.format = format;
-        }
-        if (io == IO::OUTPUT || io == IO::INOUT) {
-            mCommon.output.base.format = format;
-        }
-    }
-
-    void initParamCommonSampleRate(IO io = IO::INOUT, const int& sampleRate = 48000) {
-        if (io == IO::INPUT || io == IO::INOUT) {
-            mCommon.input.base.sampleRate = sampleRate;
-        }
-        if (io == IO::OUTPUT || io == IO::INOUT) {
-            mCommon.output.base.sampleRate = sampleRate;
-        }
-    }
-
-    void initParamCommonFrameCount(IO io = IO::INOUT, const long& frameCount = 48000) {
-        if (io == IO::INPUT || io == IO::INOUT) {
-            mCommon.input.frameCount = frameCount;
-        }
-        if (io == IO::OUTPUT || io == IO::INOUT) {
-            mCommon.output.frameCount = frameCount;
-        }
-    }
-    void initParamCommon(int session = 0, int ioHandle = -1, int iSampleRate = 48000,
-                         int oSampleRate = 48000, long iFrameCount = 0x100,
-                         long oFrameCount = 0x100) {
-        mCommon.session = session;
-        mCommon.ioHandle = ioHandle;
-
-        auto& input = mCommon.input;
-        auto& output = mCommon.output;
+        auto& input = common.input;
+        auto& output = common.output;
         input.base.sampleRate = iSampleRate;
-        input.base.channelMask = mInputChannelLayout;
+        input.base.channelMask = inputChannelLayout;
+        input.base.format = kDefaultFormatDescription;
         input.frameCount = iFrameCount;
-        input.base.format = DefaultFormat;
         output.base.sampleRate = oSampleRate;
-        output.base.channelMask = mOutputChannelLayout;
-        output.base.format = DefaultFormat;
+        output.base.channelMask = outputChannelLayout;
+        output.base.format = kDefaultFormatDescription;
         output.frameCount = oFrameCount;
-        output.base.format = DefaultFormat;
-        inputFrameSize = android::hardware::audio::common::getFrameSizeInBytes(
-                input.base.format, input.base.channelMask);
-        outputFrameSize = android::hardware::audio::common::getFrameSizeInBytes(
-                output.base.format, output.base.channelMask);
+        return common;
     }
 
-    void setSpecific(Parameter::Specific& specific) { mSpecific = specific; }
-
-    // usually this function only call once.
-    void PrepareInputData(size_t bytes = mWriteMQBytes) {
-        size_t maxInputBytes = mWriteMQBytes;
-        for (auto& it : mEffectParams) {
-            auto& mq = it.inputMQ;
-            EXPECT_NE(nullptr, mq);
-            EXPECT_TRUE(mq->isValid());
-            const size_t bytesToWrite = mq->availableToWrite() * sizeof(float);
-            EXPECT_EQ(inputFrameSize * mCommon.input.frameCount, bytesToWrite);
-            EXPECT_NE(0UL, bytesToWrite);
-            EXPECT_TRUE(bytes <= bytesToWrite);
-            maxInputBytes = std::max(maxInputBytes, bytesToWrite);
-        }
-        mInputBuffer.resize(maxInputBytes / sizeof(float));
-        std::fill(mInputBuffer.begin(), mInputBuffer.end(), 0x5a);
-    }
-
-    void writeToFmq(size_t bytes = mWriteMQBytes) {
-        for (auto& it : mEffectParams) {
-            auto& mq = it.inputMQ;
-            EXPECT_NE(nullptr, mq);
-            const size_t bytesToWrite = mq->availableToWrite() * sizeof(float);
-            EXPECT_NE(0Ul, bytesToWrite);
-            EXPECT_TRUE(bytes <= bytesToWrite);
-            EXPECT_TRUE(mq->write(mInputBuffer.data(), bytes / sizeof(float)));
-        }
-    }
-
-    void readFromFmq(size_t expectBytes = mWriteMQBytes) {
-        for (auto& it : mEffectParams) {
-            IEffect::Status status{};
-            auto& statusMq = it.statusMQ;
-            EXPECT_NE(nullptr, statusMq);
-            EXPECT_TRUE(statusMq->readBlocking(&status, 1));
-            EXPECT_EQ(STATUS_OK, status.status);
-            EXPECT_EQ(expectBytes, (unsigned)status.fmqProduced * sizeof(float));
-
-            auto& outputMq = it.outputMQ;
-            EXPECT_NE(nullptr, outputMq);
-            EXPECT_EQ(expectBytes, outputMq->availableToRead() * sizeof(float));
-        }
-    }
-
-    void setInputChannelLayout(AudioChannelLayout input) { mInputChannelLayout = input; }
-    void setOutputChannelLayout(AudioChannelLayout output) { mOutputChannelLayout = output; }
-    const std::vector<Descriptor::Identity>& GetCompleteEffectIdList() const {
-        return mFactoryHelper.GetCompleteEffectIdList();
-    }
-    const std::vector<Descriptor>& getDescriptorVec() const { return mEffectDescriptors; }
-
-  private:
-    EffectFactoryHelper mFactoryHelper;
-
-    AudioChannelLayout mInputChannelLayout =
-            AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
-                    AudioChannelLayout::LAYOUT_STEREO);
-    AudioChannelLayout mOutputChannelLayout =
-            AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
-                    AudioChannelLayout::LAYOUT_STEREO);
-
-    Parameter::Common mCommon;
-    std::optional<Parameter::Specific> mSpecific = std::nullopt;
-
-    size_t inputFrameSize, outputFrameSize;
-    std::vector<float> mInputBuffer;  // reuse same buffer for all effects testing
-
     typedef ::android::AidlMessageQueue<
             IEffect::Status, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
             StatusMQ;
@@ -317,6 +181,4 @@
         std::unique_ptr<DataMQ> inputMQ;
         std::unique_ptr<DataMQ> outputMQ;
     };
-    std::vector<EffectParam> mEffectParams;
-    std::vector<Descriptor> mEffectDescriptors;
 };
diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
index 2381200..5e9aa7f 100644
--- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <algorithm>
+#include <cmath>
 #include <limits>
 #include <memory>
 #include <optional>
@@ -29,11 +30,12 @@
 #include <Utils.h>
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
-#include <aidl/android/hardware/audio/core/IConfig.h>
 #include <aidl/android/hardware/audio/core/IModule.h>
+#include <aidl/android/hardware/audio/core/ITelephony.h>
 #include <aidl/android/media/audio/common/AudioIoFlags.h>
 #include <aidl/android/media/audio/common/AudioOutputFlags.h>
 #include <android-base/chrono_utils.h>
+#include <android/binder_enums.h>
 #include <fmq/AidlMessageQueue.h>
 
 #include "AudioHalBinderServiceUtil.h"
@@ -45,11 +47,13 @@
 using aidl::android::hardware::audio::common::RecordTrackMetadata;
 using aidl::android::hardware::audio::common::SinkMetadata;
 using aidl::android::hardware::audio::common::SourceMetadata;
+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::IModule;
 using aidl::android::hardware::audio::core::IStreamIn;
 using aidl::android::hardware::audio::core::IStreamOut;
+using aidl::android::hardware::audio::core::ITelephony;
 using aidl::android::hardware::audio::core::ModuleDebug;
 using aidl::android::hardware::audio::core::StreamDescriptor;
 using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
@@ -66,9 +70,11 @@
 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::Void;
 using android::hardware::audio::common::isBitPositionFlagSet;
 using android::hardware::audio::common::StreamLogic;
 using android::hardware::audio::common::StreamWorker;
+using ndk::enum_range;
 using ndk::ScopedAStatus;
 
 template <typename T>
@@ -171,25 +177,49 @@
     AudioPortConfig mConfig;
 };
 
-class AudioCoreModule : public testing::TestWithParam<std::string> {
+template <typename PropType, class Instance, typename Getter, typename Setter>
+void TestAccessors(Instance* inst, Getter getter, Setter setter,
+                   const std::vector<PropType>& validValues,
+                   const std::vector<PropType>& invalidValues, bool* isSupported) {
+    PropType initialValue{};
+    ScopedAStatus status = (inst->*getter)(&initialValue);
+    if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+        *isSupported = false;
+        return;
+    }
+    *isSupported = true;
+    for (const auto v : validValues) {
+        EXPECT_IS_OK((inst->*setter)(v)) << "for valid value: " << v;
+        PropType currentValue{};
+        EXPECT_IS_OK((inst->*getter)(&currentValue));
+        EXPECT_EQ(v, currentValue);
+    }
+    for (const auto v : invalidValues) {
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, (inst->*setter)(v)) << "for invalid value: " << v;
+    }
+    EXPECT_IS_OK((inst->*setter)(initialValue)) << "Failed to restore the initial value";
+}
+
+// Can be used as a base for any test here, does not depend on the fixture GTest parameters.
+class AudioCoreModuleBase {
   public:
     // The default buffer size is used mostly for negative tests.
     static constexpr int kDefaultBufferSizeFrames = 256;
 
-    void SetUp() override {
-        ASSERT_NO_FATAL_FAILURE(ConnectToService());
+    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 TearDown() override {
+    void TearDownImpl() {
         if (module != nullptr) {
             EXPECT_IS_OK(module->setModuleDebug(ModuleDebug{}));
         }
     }
 
-    void ConnectToService() {
-        module = IModule::fromBinder(binderUtil.connectToService(GetParam()));
+    void ConnectToService(const std::string& moduleName) {
+        module = IModule::fromBinder(binderUtil.connectToService(moduleName));
         ASSERT_NE(module, nullptr);
     }
 
@@ -269,6 +299,13 @@
     WithDebugFlags debug;
 };
 
+class AudioCoreModule : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam())); }
+
+    void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
+};
+
 class WithDevicePortConnectedState {
   public:
     explicit WithDevicePortConnectedState(const AudioPort& idAndData) : mIdAndData(idAndData) {}
@@ -352,21 +389,36 @@
     std::unique_ptr<DataMQ> mDataMQ;
 };
 
-class StreamCommonLogic : public StreamLogic {
+class StreamLogicDriver {
   public:
-    StreamDescriptor::Position getLastObservablePosition() {
-        std::lock_guard<std::mutex> lock(mLock);
-        return mLastReply.observable;
-    }
+    virtual ~StreamLogicDriver() = default;
+    // Return 'true' to stop the worker.
+    virtual bool done() = 0;
+    // For 'Writer' logic, if the 'actualSize' is 0, write is skipped.
+    // The 'fmqByteCount' from the returned command is passed as is to the HAL.
+    virtual StreamDescriptor::Command getNextCommand(int maxDataSize,
+                                                     int* actualSize = nullptr) = 0;
+    // Return 'true' to indicate that no further processing is needed,
+    // for example, the driver is expecting a bad status to be returned.
+    // The logic cycle will return with 'CONTINUE' status. Otherwise,
+    // the reply will be validated and then passed to 'processValidReply'.
+    virtual bool interceptRawReply(const StreamDescriptor::Reply& reply) = 0;
+    // Return 'false' to indicate that the contents of the reply are unexpected.
+    // Will abort the logic cycle.
+    virtual bool processValidReply(const StreamDescriptor::Reply& reply) = 0;
+};
 
+class StreamCommonLogic : public StreamLogic {
   protected:
-    explicit StreamCommonLogic(const StreamContext& context)
+    StreamCommonLogic(const StreamContext& context, StreamLogicDriver* driver)
         : mCommandMQ(context.getCommandMQ()),
           mReplyMQ(context.getReplyMQ()),
           mDataMQ(context.getDataMQ()),
-          mData(context.getBufferSizeBytes()) {}
+          mData(context.getBufferSizeBytes()),
+          mDriver(driver) {}
     StreamContext::CommandMQ* getCommandMQ() const { return mCommandMQ; }
     StreamContext::ReplyMQ* getReplyMQ() const { return mReplyMQ; }
+    StreamLogicDriver* getDriver() const { return mDriver; }
 
     std::string init() override { return ""; }
 
@@ -374,19 +426,20 @@
     StreamContext::ReplyMQ* mReplyMQ;
     StreamContext::DataMQ* mDataMQ;
     std::vector<int8_t> mData;
-    std::mutex mLock;
-    StreamDescriptor::Reply mLastReply GUARDED_BY(mLock);
+    StreamLogicDriver* const mDriver;
 };
 
 class StreamReaderLogic : public StreamCommonLogic {
   public:
-    explicit StreamReaderLogic(const StreamContext& context) : StreamCommonLogic(context) {}
+    StreamReaderLogic(const StreamContext& context, StreamLogicDriver* driver)
+        : StreamCommonLogic(context, driver) {}
 
   protected:
     Status cycle() override {
-        StreamDescriptor::Command command{};
-        command.code = StreamDescriptor::COMMAND_BURST;
-        command.fmqByteCount = mData.size();
+        if (getDriver()->done()) {
+            return Status::EXIT;
+        }
+        StreamDescriptor::Command command = getDriver()->getNextCommand(mData.size());
         if (!mCommandMQ->writeBlocking(&command, 1)) {
             LOG(ERROR) << __func__ << ": writing of command into MQ failed";
             return Status::ABORT;
@@ -396,25 +449,55 @@
             LOG(ERROR) << __func__ << ": reading of reply from MQ failed";
             return Status::ABORT;
         }
+        if (getDriver()->interceptRawReply(reply)) {
+            return Status::CONTINUE;
+        }
         if (reply.status != STATUS_OK) {
             LOG(ERROR) << __func__ << ": received error status: " << statusToString(reply.status);
             return Status::ABORT;
         }
-        if (reply.fmqByteCount < 0 || reply.fmqByteCount > command.fmqByteCount) {
+        if (reply.fmqByteCount < 0 ||
+            (command.getTag() == StreamDescriptor::Command::Tag::burst &&
+             reply.fmqByteCount > command.get<StreamDescriptor::Command::Tag::burst>())) {
             LOG(ERROR) << __func__
                        << ": received invalid byte count in the reply: " << reply.fmqByteCount;
             return Status::ABORT;
         }
-        {
-            std::lock_guard<std::mutex> lock(mLock);
-            mLastReply = reply;
+        if (static_cast<size_t>(reply.fmqByteCount) != mDataMQ->availableToRead()) {
+            LOG(ERROR) << __func__
+                       << ": the byte count in the reply is not the same as the amount of "
+                       << "data available in the MQ: " << reply.fmqByteCount
+                       << " != " << mDataMQ->availableToRead();
         }
-        const size_t readCount = std::min({mDataMQ->availableToRead(),
-                                           static_cast<size_t>(reply.fmqByteCount), mData.size()});
-        if (readCount == 0 || mDataMQ->read(mData.data(), readCount)) {
+        if (reply.latencyMs < 0 && reply.latencyMs != StreamDescriptor::LATENCY_UNKNOWN) {
+            LOG(ERROR) << __func__ << ": received invalid latency value: " << reply.latencyMs;
+            return Status::ABORT;
+        }
+        if (reply.xrunFrames < 0) {
+            LOG(ERROR) << __func__ << ": received invalid xrunFrames value: " << reply.xrunFrames;
+            return Status::ABORT;
+        }
+        if (std::find(enum_range<StreamDescriptor::State>().begin(),
+                      enum_range<StreamDescriptor::State>().end(),
+                      reply.state) == enum_range<StreamDescriptor::State>().end()) {
+            LOG(ERROR) << __func__ << ": received invalid stream state: " << toString(reply.state);
+            return Status::ABORT;
+        }
+        const bool acceptedReply = getDriver()->processValidReply(reply);
+        if (const size_t readCount = mDataMQ->availableToRead(); readCount > 0) {
+            std::vector<int8_t> data(readCount);
+            if (mDataMQ->read(data.data(), readCount)) {
+                memcpy(mData.data(), data.data(), std::min(mData.size(), data.size()));
+                goto checkAcceptedReply;
+            }
+            LOG(ERROR) << __func__ << ": reading of " << readCount << " data bytes from MQ failed";
+            return Status::ABORT;
+        }  // readCount == 0
+    checkAcceptedReply:
+        if (acceptedReply) {
             return Status::CONTINUE;
         }
-        LOG(ERROR) << __func__ << ": reading of " << readCount << " data bytes from MQ failed";
+        LOG(ERROR) << __func__ << ": unacceptable reply: " << reply.toString();
         return Status::ABORT;
     }
 };
@@ -422,17 +505,20 @@
 
 class StreamWriterLogic : public StreamCommonLogic {
   public:
-    explicit StreamWriterLogic(const StreamContext& context) : StreamCommonLogic(context) {}
+    StreamWriterLogic(const StreamContext& context, StreamLogicDriver* driver)
+        : StreamCommonLogic(context, driver) {}
 
   protected:
     Status cycle() override {
-        if (!mDataMQ->write(mData.data(), mData.size())) {
+        if (getDriver()->done()) {
+            return Status::EXIT;
+        }
+        int actualSize = 0;
+        StreamDescriptor::Command command = getDriver()->getNextCommand(mData.size(), &actualSize);
+        if (actualSize != 0 && !mDataMQ->write(mData.data(), mData.size())) {
             LOG(ERROR) << __func__ << ": writing of " << mData.size() << " bytes to MQ failed";
             return Status::ABORT;
         }
-        StreamDescriptor::Command command{};
-        command.code = StreamDescriptor::COMMAND_BURST;
-        command.fmqByteCount = mData.size();
         if (!mCommandMQ->writeBlocking(&command, 1)) {
             LOG(ERROR) << __func__ << ": writing of command into MQ failed";
             return Status::ABORT;
@@ -442,20 +528,45 @@
             LOG(ERROR) << __func__ << ": reading of reply from MQ failed";
             return Status::ABORT;
         }
+        if (getDriver()->interceptRawReply(reply)) {
+            return Status::CONTINUE;
+        }
         if (reply.status != STATUS_OK) {
             LOG(ERROR) << __func__ << ": received error status: " << statusToString(reply.status);
             return Status::ABORT;
         }
-        if (reply.fmqByteCount < 0 || reply.fmqByteCount > command.fmqByteCount) {
+        if (reply.fmqByteCount < 0 ||
+            (command.getTag() == StreamDescriptor::Command::Tag::burst &&
+             reply.fmqByteCount > command.get<StreamDescriptor::Command::Tag::burst>())) {
             LOG(ERROR) << __func__
                        << ": received invalid byte count in the reply: " << reply.fmqByteCount;
             return Status::ABORT;
         }
-        {
-            std::lock_guard<std::mutex> lock(mLock);
-            mLastReply = reply;
+        if (mDataMQ->availableToWrite() != mDataMQ->getQuantumCount()) {
+            LOG(ERROR) << __func__ << ": the HAL module did not consume all data from the data MQ: "
+                       << "available to write " << mDataMQ->availableToWrite()
+                       << ", total size: " << mDataMQ->getQuantumCount();
+            return Status::ABORT;
         }
-        return Status::CONTINUE;
+        if (reply.latencyMs < 0 && reply.latencyMs != StreamDescriptor::LATENCY_UNKNOWN) {
+            LOG(ERROR) << __func__ << ": received invalid latency value: " << reply.latencyMs;
+            return Status::ABORT;
+        }
+        if (reply.xrunFrames < 0) {
+            LOG(ERROR) << __func__ << ": received invalid xrunFrames value: " << reply.xrunFrames;
+            return Status::ABORT;
+        }
+        if (std::find(enum_range<StreamDescriptor::State>().begin(),
+                      enum_range<StreamDescriptor::State>().end(),
+                      reply.state) == enum_range<StreamDescriptor::State>().end()) {
+            LOG(ERROR) << __func__ << ": received invalid stream state: " << toString(reply.state);
+            return Status::ABORT;
+        }
+        if (getDriver()->processValidReply(reply)) {
+            return Status::CONTINUE;
+        }
+        LOG(ERROR) << __func__ << ": unacceptable reply: " << reply.toString();
+        return Status::ABORT;
     }
 };
 using StreamWriter = StreamWorker<StreamWriterLogic>;
@@ -466,52 +577,6 @@
     using Worker = std::conditional_t<is_input, StreamReader, StreamWriter>;
 };
 
-// A dedicated version to test replies to invalid commands.
-class StreamInvalidCommandLogic : public StreamCommonLogic {
-  public:
-    StreamInvalidCommandLogic(const StreamContext& context,
-                              const std::vector<StreamDescriptor::Command>& commands)
-        : StreamCommonLogic(context), mCommands(commands) {}
-
-    std::vector<std::string> getUnexpectedStatuses() {
-        std::lock_guard<std::mutex> lock(mLock);
-        return mUnexpectedStatuses;
-    }
-
-  protected:
-    Status cycle() override {
-        // Send all commands in one cycle to simplify testing.
-        // Extra logging helps to sort out issues with unexpected HAL behavior.
-        for (const auto& command : mCommands) {
-            LOG(INFO) << __func__ << ": writing command " << command.toString() << " into MQ...";
-            if (!getCommandMQ()->writeBlocking(&command, 1)) {
-                LOG(ERROR) << __func__ << ": writing of command into MQ failed";
-                return Status::ABORT;
-            }
-            StreamDescriptor::Reply reply{};
-            LOG(INFO) << __func__ << ": reading reply for command " << command.toString() << "...";
-            if (!getReplyMQ()->readBlocking(&reply, 1)) {
-                LOG(ERROR) << __func__ << ": reading of reply from MQ failed";
-                return Status::ABORT;
-            }
-            LOG(INFO) << __func__ << ": received status " << statusToString(reply.status)
-                      << " for command " << command.toString();
-            if (reply.status != STATUS_BAD_VALUE) {
-                std::string s = command.toString();
-                s.append(", ").append(statusToString(reply.status));
-                std::lock_guard<std::mutex> lock(mLock);
-                mUnexpectedStatuses.push_back(std::move(s));
-            }
-        };
-        return Status::EXIT;
-    }
-
-  private:
-    const std::vector<StreamDescriptor::Command> mCommands;
-    std::mutex mLock;
-    std::vector<std::string> mUnexpectedStatuses GUARDED_BY(mLock);
-};
-
 template <typename Stream>
 class WithStream {
   public:
@@ -1208,6 +1273,152 @@
     }
 }
 
+TEST_P(AudioCoreModule, MasterMute) {
+    bool isSupported = false;
+    EXPECT_NO_FATAL_FAILURE(TestAccessors<bool>(module.get(), &IModule::getMasterMute,
+                                                &IModule::setMasterMute, {false, true}, {},
+                                                &isSupported));
+    if (!isSupported) {
+        GTEST_SKIP() << "Master mute is not supported";
+    }
+    // TODO: Test that master mute actually mutes output.
+}
+
+TEST_P(AudioCoreModule, MasterVolume) {
+    bool isSupported = false;
+    EXPECT_NO_FATAL_FAILURE(TestAccessors<float>(
+            module.get(), &IModule::getMasterVolume, &IModule::setMasterVolume, {0.0f, 0.5f, 1.0f},
+            {-0.1, 1.1, NAN, INFINITY, -INFINITY, 1 + std::numeric_limits<float>::epsilon()},
+            &isSupported));
+    if (!isSupported) {
+        GTEST_SKIP() << "Master volume is not supported";
+    }
+    // TODO: Test that master volume actually attenuates output.
+}
+
+TEST_P(AudioCoreModule, MicMute) {
+    bool isSupported = false;
+    EXPECT_NO_FATAL_FAILURE(TestAccessors<bool>(module.get(), &IModule::getMicMute,
+                                                &IModule::setMicMute, {false, true}, {},
+                                                &isSupported));
+    if (!isSupported) {
+        GTEST_SKIP() << "Mic mute is not supported";
+    }
+    // TODO: Test that mic mute actually mutes input.
+}
+
+TEST_P(AudioCoreModule, UpdateAudioMode) {
+    for (const auto mode : ::ndk::enum_range<AudioMode>()) {
+        EXPECT_IS_OK(module->updateAudioMode(mode)) << toString(mode);
+    }
+    EXPECT_IS_OK(module->updateAudioMode(AudioMode::NORMAL));
+}
+
+TEST_P(AudioCoreModule, UpdateScreenRotation) {
+    for (const auto rotation : ::ndk::enum_range<IModule::ScreenRotation>()) {
+        EXPECT_IS_OK(module->updateScreenRotation(rotation)) << toString(rotation);
+    }
+    EXPECT_IS_OK(module->updateScreenRotation(IModule::ScreenRotation::DEG_0));
+}
+
+TEST_P(AudioCoreModule, UpdateScreenState) {
+    EXPECT_IS_OK(module->updateScreenState(false));
+    EXPECT_IS_OK(module->updateScreenState(true));
+}
+
+class AudioCoreTelephony : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam()));
+        ASSERT_IS_OK(module->getTelephony(&telephony));
+    }
+
+    void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
+
+    std::shared_ptr<ITelephony> telephony;
+};
+
+TEST_P(AudioCoreTelephony, GetSupportedAudioModes) {
+    if (telephony == nullptr) {
+        GTEST_SKIP() << "Telephony is not supported";
+    }
+    std::vector<AudioMode> modes1;
+    ASSERT_IS_OK(telephony->getSupportedAudioModes(&modes1));
+    const std::vector<AudioMode> kMandatoryModes = {AudioMode::NORMAL, AudioMode::RINGTONE,
+                                                    AudioMode::IN_CALL,
+                                                    AudioMode::IN_COMMUNICATION};
+    for (const auto mode : kMandatoryModes) {
+        EXPECT_NE(modes1.end(), std::find(modes1.begin(), modes1.end(), mode))
+                << "Mandatory mode not supported: " << toString(mode);
+    }
+    std::vector<AudioMode> modes2;
+    ASSERT_IS_OK(telephony->getSupportedAudioModes(&modes2));
+    ASSERT_EQ(modes1.size(), modes2.size())
+            << "Sizes of audio mode arrays do not match across consequent calls to "
+            << "getSupportedAudioModes";
+    std::sort(modes1.begin(), modes1.end());
+    std::sort(modes2.begin(), modes2.end());
+    EXPECT_EQ(modes1, modes2);
+};
+
+TEST_P(AudioCoreTelephony, SwitchAudioMode) {
+    if (telephony == nullptr) {
+        GTEST_SKIP() << "Telephony is not supported";
+    }
+    std::vector<AudioMode> supportedModes;
+    ASSERT_IS_OK(telephony->getSupportedAudioModes(&supportedModes));
+    std::set<AudioMode> unsupportedModes = {
+            // Start with all, remove supported ones
+            ::ndk::enum_range<AudioMode>().begin(), ::ndk::enum_range<AudioMode>().end()};
+    for (const auto mode : supportedModes) {
+        EXPECT_IS_OK(telephony->switchAudioMode(mode)) << toString(mode);
+        unsupportedModes.erase(mode);
+    }
+    for (const auto mode : unsupportedModes) {
+        EXPECT_STATUS(EX_UNSUPPORTED_OPERATION, telephony->switchAudioMode(mode)) << toString(mode);
+    }
+}
+
+class StreamLogicDriverInvalidCommand : public StreamLogicDriver {
+  public:
+    StreamLogicDriverInvalidCommand(const std::vector<StreamDescriptor::Command>& commands)
+        : mCommands(commands) {}
+
+    std::string getUnexpectedStatuses() {
+        // This method is intended to be called after the worker thread has joined,
+        // thus no extra synchronization is needed.
+        std::string s;
+        if (!mStatuses.empty()) {
+            s = std::string("Pairs of (command, actual status): ")
+                        .append((android::internal::ToString(mStatuses)));
+        }
+        return s;
+    }
+
+    bool done() override { return mNextCommand >= mCommands.size(); }
+    StreamDescriptor::Command getNextCommand(int, int* actualSize) override {
+        if (actualSize != nullptr) *actualSize = 0;
+        return mCommands[mNextCommand++];
+    }
+    bool interceptRawReply(const StreamDescriptor::Reply& reply) override {
+        if (reply.status != STATUS_BAD_VALUE) {
+            std::string s = mCommands[mNextCommand - 1].toString();
+            s.append(", ").append(statusToString(reply.status));
+            mStatuses.push_back(std::move(s));
+            // If the HAL does not recognize the command as invalid,
+            // retrieve the data etc.
+            return reply.status != STATUS_OK;
+        }
+        return true;
+    }
+    bool processValidReply(const StreamDescriptor::Reply&) override { return true; }
+
+  private:
+    const std::vector<StreamDescriptor::Command> mCommands;
+    size_t mNextCommand = 0;
+    std::vector<std::string> mStatuses;
+};
+
 template <typename Stream>
 class AudioStream : public AudioCoreModule {
   public:
@@ -1315,19 +1526,6 @@
         EXPECT_NO_FATAL_FAILURE(OpenTwiceSamePortConfigImpl(portConfig.value()));
     }
 
-    void ReadOrWrite(bool useSetupSequence2, bool validateObservablePosition) {
-        const auto allPortConfigs =
-                moduleConfig->getPortConfigsForMixPorts(IOTraits<Stream>::is_input);
-        if (allPortConfigs.empty()) {
-            GTEST_SKIP() << "No mix ports have attached devices";
-        }
-        for (const auto& portConfig : allPortConfigs) {
-            EXPECT_NO_FATAL_FAILURE(
-                    ReadOrWriteImpl(portConfig, useSetupSequence2, validateObservablePosition))
-                    << portConfig.toString();
-        }
-    }
-
     void ResetPortConfigWithOpenStream() {
         const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
         if (!portConfig.has_value()) {
@@ -1357,131 +1555,40 @@
                 << stream1.getPortId();
     }
 
-    template <class Worker>
-    void WaitForObservablePositionAdvance(Worker& worker) {
-        static constexpr int kWriteDurationUs = 50 * 1000;
-        static constexpr std::chrono::milliseconds kPositionChangeTimeout{10000};
-        int64_t framesInitial;
-        framesInitial = worker.getLastObservablePosition().frames;
-        ASSERT_FALSE(worker.hasError());
-        bool timedOut = false;
-        int64_t frames = framesInitial;
-        for (android::base::Timer elapsed;
-             frames <= framesInitial && !worker.hasError() &&
-             !(timedOut = (elapsed.duration() >= kPositionChangeTimeout));) {
-            usleep(kWriteDurationUs);
-            frames = worker.getLastObservablePosition().frames;
-        }
-        EXPECT_FALSE(timedOut);
-        EXPECT_FALSE(worker.hasError()) << worker.getError();
-        EXPECT_GT(frames, framesInitial);
-    }
-
-    void ReadOrWriteImpl(const AudioPortConfig& portConfig, bool useSetupSequence2,
-                         bool validateObservablePosition) {
-        if (!useSetupSequence2) {
-            ASSERT_NO_FATAL_FAILURE(
-                    ReadOrWriteSetupSequence1(portConfig, validateObservablePosition));
-        } else {
-            ASSERT_NO_FATAL_FAILURE(
-                    ReadOrWriteSetupSequence2(portConfig, validateObservablePosition));
-        }
-    }
-
-    // Set up a patch first, then open a stream.
-    void ReadOrWriteSetupSequence1(const AudioPortConfig& portConfig,
-                                   bool validateObservablePosition) {
-        auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
-                IOTraits<Stream>::is_input, portConfig);
-        ASSERT_FALSE(devicePorts.empty());
-        auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
-        WithAudioPatch patch(IOTraits<Stream>::is_input, portConfig, devicePortConfig);
-        ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
-
-        WithStream<Stream> stream(patch.getPortConfig(IOTraits<Stream>::is_input));
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
-        typename IOTraits<Stream>::Worker worker(*stream.getContext());
-
-        ASSERT_TRUE(worker.start());
-        ASSERT_TRUE(worker.waitForAtLeastOneCycle());
-        if (validateObservablePosition) {
-            ASSERT_NO_FATAL_FAILURE(WaitForObservablePositionAdvance(worker));
-        }
-    }
-
-    // Open a stream, then set up a patch for it.
-    void ReadOrWriteSetupSequence2(const AudioPortConfig& portConfig,
-                                   bool validateObservablePosition) {
-        WithStream<Stream> stream(portConfig);
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
-        typename IOTraits<Stream>::Worker worker(*stream.getContext());
-
-        auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
-                IOTraits<Stream>::is_input, portConfig);
-        ASSERT_FALSE(devicePorts.empty());
-        auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
-        WithAudioPatch patch(IOTraits<Stream>::is_input, stream.getPortConfig(), devicePortConfig);
-        ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
-
-        ASSERT_TRUE(worker.start());
-        ASSERT_TRUE(worker.waitForAtLeastOneCycle());
-        if (validateObservablePosition) {
-            ASSERT_NO_FATAL_FAILURE(WaitForObservablePositionAdvance(worker));
-        }
-    }
-
     void SendInvalidCommandImpl(const AudioPortConfig& portConfig) {
-        std::vector<StreamDescriptor::Command> commands(6);
-        commands[0].code = -1;
-        commands[1].code = StreamDescriptor::COMMAND_BURST - 1;
-        commands[2].code = std::numeric_limits<int32_t>::min();
-        commands[3].code = std::numeric_limits<int32_t>::max();
-        commands[4].code = StreamDescriptor::COMMAND_BURST;
-        commands[4].fmqByteCount = -1;
-        commands[5].code = StreamDescriptor::COMMAND_BURST;
-        commands[5].fmqByteCount = std::numeric_limits<int32_t>::min();
+        std::vector<StreamDescriptor::Command> commands = {
+                StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::hal_reserved_exit>(
+                        0),
+                // TODO: For proper testing of input streams, need to put the stream into
+                // a state which accepts BURST commands.
+                StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(-1),
+                StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(
+                        std::numeric_limits<int32_t>::min()),
+        };
         WithStream<Stream> stream(portConfig);
         ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
-        StreamWorker<StreamInvalidCommandLogic> writer(*stream.getContext(), commands);
-        ASSERT_TRUE(writer.start());
-        writer.waitForAtLeastOneCycle();
-        auto unexpectedStatuses = writer.getUnexpectedStatuses();
-        EXPECT_EQ(0UL, unexpectedStatuses.size())
-                << "Pairs of (command, actual status): "
-                << android::internal::ToString(unexpectedStatuses);
+        StreamLogicDriverInvalidCommand driver(commands);
+        typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver);
+        ASSERT_TRUE(worker.start());
+        worker.join();
+        EXPECT_EQ("", driver.getUnexpectedStatuses());
     }
 };
 using AudioStreamIn = AudioStream<IStreamIn>;
 using AudioStreamOut = AudioStream<IStreamOut>;
 
-#define TEST_IO_STREAM(method_name)                                                \
+#define TEST_IN_AND_OUT_STREAM(method_name)                                        \
     TEST_P(AudioStreamIn, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); } \
     TEST_P(AudioStreamOut, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); }
-#define TEST_IO_STREAM_2(method_name, arg1, arg2)           \
-    TEST_P(AudioStreamIn, method_name##_##arg1##_##arg2) {  \
-        ASSERT_NO_FATAL_FAILURE(method_name(arg1, arg2));   \
-    }                                                       \
-    TEST_P(AudioStreamOut, method_name##_##arg1##_##arg2) { \
-        ASSERT_NO_FATAL_FAILURE(method_name(arg1, arg2));   \
-    }
 
-TEST_IO_STREAM(CloseTwice);
-TEST_IO_STREAM(OpenAllConfigs);
-TEST_IO_STREAM(OpenInvalidBufferSize);
-TEST_IO_STREAM(OpenInvalidDirection);
-TEST_IO_STREAM(OpenOverMaxCount);
-TEST_IO_STREAM(OpenTwiceSamePortConfig);
-// Use of constants makes comprehensible test names.
-constexpr bool SetupSequence1 = false;
-constexpr bool SetupSequence2 = true;
-constexpr bool SetupOnly = false;
-constexpr bool ValidateObservablePosition = true;
-TEST_IO_STREAM_2(ReadOrWrite, SetupSequence1, SetupOnly);
-TEST_IO_STREAM_2(ReadOrWrite, SetupSequence2, SetupOnly);
-TEST_IO_STREAM_2(ReadOrWrite, SetupSequence1, ValidateObservablePosition);
-TEST_IO_STREAM_2(ReadOrWrite, SetupSequence2, ValidateObservablePosition);
-TEST_IO_STREAM(ResetPortConfigWithOpenStream);
-TEST_IO_STREAM(SendInvalidCommand);
+TEST_IN_AND_OUT_STREAM(CloseTwice);
+TEST_IN_AND_OUT_STREAM(OpenAllConfigs);
+TEST_IN_AND_OUT_STREAM(OpenInvalidBufferSize);
+TEST_IN_AND_OUT_STREAM(OpenInvalidDirection);
+TEST_IN_AND_OUT_STREAM(OpenOverMaxCount);
+TEST_IN_AND_OUT_STREAM(OpenTwiceSamePortConfig);
+TEST_IN_AND_OUT_STREAM(ResetPortConfigWithOpenStream);
+TEST_IN_AND_OUT_STREAM(SendInvalidCommand);
 
 TEST_P(AudioStreamOut, OpenTwicePrimary) {
     const auto mixPorts = moduleConfig->getMixPorts(false);
@@ -1523,6 +1630,165 @@
             << "when no offload info is provided for a compressed offload mix port";
 }
 
+using CommandAndState = std::pair<StreamDescriptor::Command, StreamDescriptor::State>;
+
+class StreamLogicDefaultDriver : public StreamLogicDriver {
+  public:
+    explicit StreamLogicDefaultDriver(const std::vector<CommandAndState>& commands)
+        : mCommands(commands) {}
+
+    // The three methods below is intended to be called after the worker
+    // thread has joined, thus no extra synchronization is needed.
+    bool hasObservablePositionIncrease() const { return mObservablePositionIncrease; }
+    bool hasRetrogradeObservablePosition() const { return mRetrogradeObservablePosition; }
+    std::string getUnexpectedStateTransition() const { return mUnexpectedTransition; }
+
+    bool done() override { return mNextCommand >= mCommands.size(); }
+    StreamDescriptor::Command getNextCommand(int maxDataSize, int* actualSize) override {
+        auto command = mCommands[mNextCommand++].first;
+        if (command.getTag() == StreamDescriptor::Command::Tag::burst) {
+            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--;
+                *actualSize = maxDataSize;
+            }
+            command.set<StreamDescriptor::Command::Tag::burst>(maxDataSize);
+        } else {
+            if (actualSize != nullptr) *actualSize = 0;
+        }
+        return command;
+    }
+    bool interceptRawReply(const StreamDescriptor::Reply&) override { return false; }
+    bool processValidReply(const StreamDescriptor::Reply& reply) override {
+        if (mPreviousFrames.has_value()) {
+            if (reply.observable.frames > mPreviousFrames.value()) {
+                mObservablePositionIncrease = true;
+            } else if (reply.observable.frames < mPreviousFrames.value()) {
+                mRetrogradeObservablePosition = true;
+            }
+        }
+        mPreviousFrames = reply.observable.frames;
+
+        const auto& lastCommandState = mCommands[mNextCommand - 1];
+        if (lastCommandState.second != reply.state) {
+            std::string s = std::string("Unexpected transition from the state ")
+                                    .append(mPreviousState)
+                                    .append(" to ")
+                                    .append(toString(reply.state))
+                                    .append(" caused by the command ")
+                                    .append(lastCommandState.first.toString());
+            LOG(ERROR) << __func__ << ": " << s;
+            mUnexpectedTransition = std::move(s);
+            return false;
+        }
+        return true;
+    }
+
+  protected:
+    const std::vector<CommandAndState>& mCommands;
+    size_t mNextCommand = 0;
+    std::optional<int64_t> mPreviousFrames;
+    std::string mPreviousState = "<initial state>";
+    bool mObservablePositionIncrease = false;
+    bool mRetrogradeObservablePosition = false;
+    std::string mUnexpectedTransition;
+};
+
+using NamedCommandSequence = std::pair<std::string, std::vector<CommandAndState>>;
+enum { PARAM_MODULE_NAME, PARAM_CMD_SEQ, PARAM_SETUP_SEQ };
+using StreamIoTestParameters =
+        std::tuple<std::string /*moduleName*/, NamedCommandSequence, bool /*useSetupSequence2*/>;
+template <typename Stream>
+class AudioStreamIo : public AudioCoreModuleBase,
+                      public testing::TestWithParam<StreamIoTestParameters> {
+  public:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(SetUpImpl(std::get<PARAM_MODULE_NAME>(GetParam())));
+        ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    }
+
+    void Run() {
+        const auto allPortConfigs =
+                moduleConfig->getPortConfigsForMixPorts(IOTraits<Stream>::is_input);
+        if (allPortConfigs.empty()) {
+            GTEST_SKIP() << "No mix ports have attached devices";
+        }
+        for (const auto& portConfig : allPortConfigs) {
+            SCOPED_TRACE(portConfig.toString());
+            const auto& commandsAndStates = std::get<PARAM_CMD_SEQ>(GetParam()).second;
+            if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
+                ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates));
+            } else {
+                ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates));
+            }
+        }
+    }
+
+    bool ValidateObservablePosition(const AudioPortConfig& /*portConfig*/) {
+        // May return false based on the portConfig, e.g. for telephony ports.
+        return true;
+    }
+
+    // Set up a patch first, then open a stream.
+    void RunStreamIoCommandsImplSeq1(const AudioPortConfig& portConfig,
+                                     const std::vector<CommandAndState>& commandsAndStates) {
+        auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
+                IOTraits<Stream>::is_input, portConfig);
+        ASSERT_FALSE(devicePorts.empty());
+        auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
+        WithAudioPatch patch(IOTraits<Stream>::is_input, portConfig, devicePortConfig);
+        ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+
+        WithStream<Stream> stream(patch.getPortConfig(IOTraits<Stream>::is_input));
+        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        StreamLogicDefaultDriver driver(commandsAndStates);
+        typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver);
+
+        ASSERT_TRUE(worker.start());
+        worker.join();
+        EXPECT_FALSE(worker.hasError()) << worker.getError();
+        EXPECT_EQ("", driver.getUnexpectedStateTransition());
+        if (ValidateObservablePosition(portConfig)) {
+            EXPECT_TRUE(driver.hasObservablePositionIncrease());
+            EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
+        }
+    }
+
+    // Open a stream, then set up a patch for it.
+    void RunStreamIoCommandsImplSeq2(const AudioPortConfig& portConfig,
+                                     const std::vector<CommandAndState>& commandsAndStates) {
+        WithStream<Stream> stream(portConfig);
+        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        StreamLogicDefaultDriver driver(commandsAndStates);
+        typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver);
+
+        auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
+                IOTraits<Stream>::is_input, portConfig);
+        ASSERT_FALSE(devicePorts.empty());
+        auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
+        WithAudioPatch patch(IOTraits<Stream>::is_input, stream.getPortConfig(), devicePortConfig);
+        ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+
+        ASSERT_TRUE(worker.start());
+        worker.join();
+        EXPECT_FALSE(worker.hasError()) << worker.getError();
+        EXPECT_EQ("", driver.getUnexpectedStateTransition());
+        if (ValidateObservablePosition(portConfig)) {
+            EXPECT_TRUE(driver.hasObservablePositionIncrease());
+            EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
+        }
+    }
+};
+using AudioStreamIoIn = AudioStreamIo<IStreamIn>;
+using AudioStreamIoOut = AudioStreamIo<IStreamOut>;
+
+#define TEST_IN_AND_OUT_STREAM_IO(method_name)                                       \
+    TEST_P(AudioStreamIoIn, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); } \
+    TEST_P(AudioStreamIoOut, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); }
+
+TEST_IN_AND_OUT_STREAM_IO(Run);
+
 // Tests specific to audio patches. The fixure class is named 'AudioModulePatch'
 // to avoid clashing with 'AudioPatch' class.
 class AudioModulePatch : public AudioCoreModule {
@@ -1696,6 +1962,10 @@
                          testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
                          android::PrintInstanceNameToString);
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreModule);
+INSTANTIATE_TEST_SUITE_P(AudioCoreTelephonyTest, AudioCoreTelephony,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+                         android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreTelephony);
 INSTANTIATE_TEST_SUITE_P(AudioStreamInTest, AudioStreamIn,
                          testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
                          android::PrintInstanceNameToString);
@@ -1704,6 +1974,117 @@
                          testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
                          android::PrintInstanceNameToString);
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamOut);
+
+static const StreamDescriptor::Command kStartCommand =
+        StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::start>(Void{});
+static const StreamDescriptor::Command kBurstCommand =
+        StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(0);
+static const StreamDescriptor::Command kDrainCommand =
+        StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::drain>(Void{});
+static const StreamDescriptor::Command kStandbyCommand =
+        StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::standby>(Void{});
+static const StreamDescriptor::Command kPauseCommand =
+        StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::pause>(Void{});
+static const StreamDescriptor::Command kFlushCommand =
+        StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::flush>(Void{});
+static const NamedCommandSequence kReadOrWriteSeq =
+        std::make_pair(std::string("ReadOrWrite"),
+                       std::vector<CommandAndState>{
+                               std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+                               std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+                               std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+                               std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE)});
+static const NamedCommandSequence kDrainInSeq =
+        std::make_pair(std::string("Drain"),
+                       std::vector<CommandAndState>{
+                               std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+                               std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+                               std::make_pair(kDrainCommand, StreamDescriptor::State::DRAINING),
+                               std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
+                               std::make_pair(kDrainCommand, StreamDescriptor::State::DRAINING),
+                               // TODO: This will need to be changed once DRAIN starts taking time.
+                               std::make_pair(kBurstCommand, StreamDescriptor::State::STANDBY)});
+static const NamedCommandSequence kDrainOutSeq =
+        std::make_pair(std::string("Drain"),
+                       std::vector<CommandAndState>{
+                               std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+                               std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+                               // TODO: This will need to be changed once DRAIN starts taking time.
+                               std::make_pair(kDrainCommand, StreamDescriptor::State::IDLE)});
+// TODO: This will need to be changed once DRAIN starts taking time so we can pause it.
+static const NamedCommandSequence kDrainPauseOutSeq = std::make_pair(
+        std::string("DrainPause"),
+        std::vector<CommandAndState>{std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+                                     std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+                                     std::make_pair(kDrainCommand, StreamDescriptor::State::IDLE)});
+static const NamedCommandSequence kStandbySeq =
+        std::make_pair(std::string("Standby"),
+                       std::vector<CommandAndState>{
+                               std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+                               std::make_pair(kStandbyCommand, StreamDescriptor::State::STANDBY),
+                               // Perform a read or write in order to advance observable position
+                               // (this is verified by tests).
+                               std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+                               std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE)});
+static const NamedCommandSequence kPauseInSeq =
+        std::make_pair(std::string("Pause"),
+                       std::vector<CommandAndState>{
+                               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 kPauseOutSeq =
+        std::make_pair(std::string("Pause"),
+                       std::vector<CommandAndState>{
+                               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)});
+static const NamedCommandSequence kFlushInSeq =
+        std::make_pair(std::string("Flush"),
+                       std::vector<CommandAndState>{
+                               std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+                               std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+                               std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
+                               std::make_pair(kFlushCommand, StreamDescriptor::State::STANDBY)});
+static const NamedCommandSequence kFlushOutSeq = std::make_pair(
+        std::string("Flush"),
+        std::vector<CommandAndState>{std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+                                     std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+                                     std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
+                                     std::make_pair(kFlushCommand, StreamDescriptor::State::IDLE)});
+std::string GetStreamIoTestName(const testing::TestParamInfo<StreamIoTestParameters>& info) {
+    return android::PrintInstanceNameToString(
+                   testing::TestParamInfo<std::string>{std::get<PARAM_MODULE_NAME>(info.param),
+                                                       info.index})
+            .append("_")
+            .append(std::get<PARAM_CMD_SEQ>(info.param).first)
+            .append("_SetupSeq")
+            .append(std::get<PARAM_SETUP_SEQ>(info.param) ? "2" : "1");
+}
+INSTANTIATE_TEST_SUITE_P(
+        AudioStreamIoInTest, AudioStreamIoIn,
+        testing::Combine(testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+                         testing::Values(kReadOrWriteSeq, kDrainInSeq, kStandbySeq, kPauseInSeq,
+                                         kFlushInSeq),
+                         testing::Values(false, true)),
+        GetStreamIoTestName);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamIoIn);
+INSTANTIATE_TEST_SUITE_P(
+        AudioStreamIoOutTest, AudioStreamIoOut,
+        testing::Combine(testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+                         testing::Values(kReadOrWriteSeq, kDrainOutSeq, kDrainPauseOutSeq,
+                                         kStandbySeq, kPauseOutSeq, kFlushOutSeq),
+                         testing::Values(false, true)),
+        GetStreamIoTestName);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamIoOut);
+
 INSTANTIATE_TEST_SUITE_P(AudioPatchTest, AudioModulePatch,
                          testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
                          android::PrintInstanceNameToString);
diff --git a/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
index d30dff4..8ae963e 100644
--- a/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <memory>
+#include <set>
 #include <string>
 #include <vector>
 
@@ -37,23 +38,81 @@
 using namespace android;
 
 using aidl::android::hardware::audio::effect::Descriptor;
-using aidl::android::hardware::audio::effect::EffectNullUuid;
-using aidl::android::hardware::audio::effect::EffectZeroUuid;
+using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kEffectNullUuid;
+using aidl::android::hardware::audio::effect::kEffectZeroUuid;
 using aidl::android::hardware::audio::effect::Processing;
+using aidl::android::media::audio::common::AudioSource;
+using aidl::android::media::audio::common::AudioStreamType;
 using aidl::android::media::audio::common::AudioUuid;
 
 /// Effect factory testing.
 class EffectFactoryTest : public testing::TestWithParam<std::string> {
   public:
-    void SetUp() override { ASSERT_NO_FATAL_FAILURE(mFactory.ConnectToFactoryService()); }
+    void SetUp() override {
+        mFactoryHelper = std::make_unique<EffectFactoryHelper>(GetParam());
+        connectAndGetFactory();
+    }
 
-    void TearDown() override { mFactory.DestroyEffects(); }
+    void TearDown() override {
+        for (auto& effect : mEffects) {
+            const auto status = mEffectFactory->destroyEffect(effect);
+            EXPECT_STATUS(EX_NONE, status);
+        }
+    }
 
-    EffectFactoryHelper mFactory = EffectFactoryHelper(GetParam());
+    std::unique_ptr<EffectFactoryHelper> mFactoryHelper;
+    std::shared_ptr<IFactory> mEffectFactory;
+    std::vector<std::shared_ptr<IEffect>> mEffects;
+    const Descriptor::Identity kNullDesc = {.uuid = kEffectNullUuid};
+    const Descriptor::Identity kZeroDesc = {.uuid = kEffectZeroUuid};
 
-    const Descriptor::Identity nullDesc = {.uuid = EffectNullUuid};
-    const Descriptor::Identity zeroDesc = {.uuid = EffectZeroUuid};
+    template <typename Functor>
+    void ForEachId(const std::vector<Descriptor::Identity> ids, Functor functor) {
+        for (const auto& id : ids) {
+            SCOPED_TRACE(id.toString());
+            functor(id);
+        }
+    }
+    template <typename Functor>
+    void ForEachEffect(std::vector<std::shared_ptr<IEffect>> effects, Functor functor) {
+        for (auto& effect : effects) {
+            functor(effect);
+        }
+    }
+
+    std::vector<std::shared_ptr<IEffect>> createWithIds(
+            const std::vector<Descriptor::Identity> ids,
+            const binder_status_t expectStatus = EX_NONE) {
+        std::vector<std::shared_ptr<IEffect>> effects;
+        for (const auto& id : ids) {
+            std::shared_ptr<IEffect> effect;
+            EXPECT_STATUS(expectStatus, mEffectFactory->createEffect(id.uuid, &effect));
+            if (expectStatus == EX_NONE) {
+                EXPECT_NE(effect, nullptr) << " null effect with uuid: " << id.uuid.toString();
+                effects.push_back(std::move(effect));
+            }
+        }
+        return effects;
+    }
+    void destroyEffects(std::vector<std::shared_ptr<IEffect>> effects,
+                        const binder_status_t expectStatus = EX_NONE) {
+        for (const auto& effect : effects) {
+            EXPECT_STATUS(expectStatus, mEffectFactory->destroyEffect(effect));
+        }
+    }
+    void creatAndDestroyIds(const std::vector<Descriptor::Identity> ids) {
+        for (const auto& id : ids) {
+            auto effects = createWithIds({id});
+            ASSERT_NO_FATAL_FAILURE(destroyEffects(effects));
+        }
+    }
+    void connectAndGetFactory() {
+        ASSERT_NO_FATAL_FAILURE(mFactoryHelper->ConnectToFactoryService());
+        mEffectFactory = mFactoryHelper->GetFactory();
+        ASSERT_NE(mEffectFactory, nullptr);
+    }
 };
 
 TEST_P(EffectFactoryTest, SetupAndTearDown) {
@@ -61,165 +120,160 @@
 }
 
 TEST_P(EffectFactoryTest, CanBeRestarted) {
-    ASSERT_NO_FATAL_FAILURE(mFactory.RestartFactoryService());
+    ASSERT_NO_FATAL_FAILURE(mFactoryHelper->RestartFactoryService());
 }
 
-TEST_P(EffectFactoryTest, QueriedDescriptorList) {
-    std::vector<Descriptor::Identity> descriptors;
-    mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors);
-    EXPECT_NE(descriptors.size(), 0UL);
-}
+/**
+ * @brief Check at least support list of effect must be supported by aosp:
+ * https://developer.android.com/reference/android/media/audiofx/AudioEffect
+ */
+TEST_P(EffectFactoryTest, ExpectAllAospEffectTypes) {
+    std::vector<Descriptor::Identity> ids;
+    std::set<AudioUuid> typeUuidSet(
+            {aidl::android::hardware::audio::effect::kBassBoostTypeUUID,
+             aidl::android::hardware::audio::effect::kEqualizerTypeUUID,
+             aidl::android::hardware::audio::effect::kEnvReverbTypeUUID,
+             aidl::android::hardware::audio::effect::kPresetReverbTypeUUID,
+             aidl::android::hardware::audio::effect::kDynamicsProcessingTypeUUID,
+             aidl::android::hardware::audio::effect::kHapticGeneratorTypeUUID,
+             aidl::android::hardware::audio::effect::kVirtualizerTypeUUID});
 
-TEST_P(EffectFactoryTest, DescriptorUUIDNotNull) {
-    std::vector<Descriptor::Identity> descriptors;
-    mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors);
-    // TODO: Factory eventually need to return the full list of MUST supported AOSP effects.
-    for (auto& desc : descriptors) {
-        EXPECT_NE(desc.type, EffectNullUuid);
-        EXPECT_NE(desc.uuid, EffectNullUuid);
+    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
+    EXPECT_TRUE(ids.size() >= typeUuidSet.size());
+    for (const auto& id : ids) {
+        typeUuidSet.erase(id.type);
     }
+    std::string msg = " missing type UUID:\n";
+    for (const auto& uuid : typeUuidSet) {
+        msg += (uuid.toString() + "\n");
+    }
+    SCOPED_TRACE(msg);
+    EXPECT_EQ(0UL, typeUuidSet.size());
 }
 
-TEST_P(EffectFactoryTest, QueriedDescriptorNotExistType) {
-    std::vector<Descriptor::Identity> descriptors;
-    mFactory.QueryEffects(EffectNullUuid, std::nullopt, std::nullopt, &descriptors);
-    EXPECT_EQ(descriptors.size(), 0UL);
+TEST_P(EffectFactoryTest, QueryNullTypeUuid) {
+    std::vector<Descriptor::Identity> ids;
+    EXPECT_IS_OK(mEffectFactory->queryEffects(kEffectNullUuid, std::nullopt, std::nullopt, &ids));
+    EXPECT_EQ(ids.size(), 0UL);
 }
 
-TEST_P(EffectFactoryTest, QueriedDescriptorNotExistInstance) {
-    std::vector<Descriptor::Identity> descriptors;
-    mFactory.QueryEffects(std::nullopt, EffectNullUuid, std::nullopt, &descriptors);
-    EXPECT_EQ(descriptors.size(), 0UL);
+TEST_P(EffectFactoryTest, QueriedNullImplUuid) {
+    std::vector<Descriptor::Identity> ids;
+    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, kEffectNullUuid, std::nullopt, &ids));
+    EXPECT_EQ(ids.size(), 0UL);
 }
 
-TEST_P(EffectFactoryTest, CreateAndDestroyOnce) {
-    std::vector<Descriptor::Identity> descriptors;
-    mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors);
-    auto numIds = mFactory.GetEffectIds().size();
-    EXPECT_NE(numIds, 0UL);
-
-    auto& effectMap = mFactory.GetEffectMap();
-    EXPECT_EQ(effectMap.size(), 0UL);
-    mFactory.CreateEffects();
-    EXPECT_EQ(effectMap.size(), numIds);
-    mFactory.DestroyEffects();
-    EXPECT_EQ(effectMap.size(), 0UL);
+TEST_P(EffectFactoryTest, QueriedNullProxyUuid) {
+    std::vector<Descriptor::Identity> ids;
+    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, kEffectNullUuid, &ids));
+    EXPECT_EQ(ids.size(), 0UL);
 }
 
-TEST_P(EffectFactoryTest, CreateAndDestroyRepeat) {
-    std::vector<Descriptor::Identity> descriptors;
-    mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors);
-    auto numIds = mFactory.GetEffectIds().size();
-    EXPECT_NE(numIds, 0UL);
+// create all effects, and then destroy them all together
+TEST_P(EffectFactoryTest, CreateAndDestroyEffects) {
+    std::vector<Descriptor::Identity> ids;
+    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
+    EXPECT_NE(ids.size(), 0UL);
 
-    auto& effectMap = mFactory.GetEffectMap();
-    EXPECT_EQ(effectMap.size(), 0UL);
-    mFactory.CreateEffects();
-    EXPECT_EQ(effectMap.size(), numIds);
-    mFactory.DestroyEffects();
-    EXPECT_EQ(effectMap.size(), 0UL);
-
-    // Create and destroy again
-    mFactory.CreateEffects();
-    EXPECT_EQ(effectMap.size(), numIds);
-    mFactory.DestroyEffects();
-    EXPECT_EQ(effectMap.size(), 0UL);
+    std::vector<std::shared_ptr<IEffect>> effects;
+    effects = createWithIds(ids);
+    EXPECT_EQ(ids.size(), effects.size());
+    destroyEffects(effects);
 }
 
 TEST_P(EffectFactoryTest, CreateMultipleInstanceOfSameEffect) {
-    std::vector<Descriptor::Identity> descriptors;
-    mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors);
-    auto numIds = mFactory.GetEffectIds().size();
-    EXPECT_NE(numIds, 0UL);
+    std::vector<Descriptor::Identity> ids;
+    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
+    EXPECT_NE(ids.size(), 0UL);
 
-    auto& effectMap = mFactory.GetEffectMap();
-    EXPECT_EQ(effectMap.size(), 0UL);
-    mFactory.CreateEffects();
-    EXPECT_EQ(effectMap.size(), numIds);
-    // Create effect instances of same implementation
-    mFactory.CreateEffects();
-    EXPECT_EQ(effectMap.size(), 2 * numIds);
+    std::vector<std::shared_ptr<IEffect>> effects = createWithIds(ids);
+    EXPECT_EQ(ids.size(), effects.size());
+    std::vector<std::shared_ptr<IEffect>> effects2 = createWithIds(ids);
+    EXPECT_EQ(ids.size(), effects2.size());
+    std::vector<std::shared_ptr<IEffect>> effects3 = createWithIds(ids);
+    EXPECT_EQ(ids.size(), effects3.size());
 
-    mFactory.CreateEffects();
-    EXPECT_EQ(effectMap.size(), 3 * numIds);
+    destroyEffects(effects);
+    destroyEffects(effects2);
+    destroyEffects(effects3);
+}
 
-    mFactory.DestroyEffects();
-    EXPECT_EQ(effectMap.size(), 0UL);
+// create and destroy each effect one by one
+TEST_P(EffectFactoryTest, CreateAndDestroyEffectsOneByOne) {
+    std::vector<Descriptor::Identity> ids;
+    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
+    EXPECT_NE(ids.size(), 0UL);
+
+    creatAndDestroyIds(ids);
+}
+
+// for each effect: repeat 3 times create and destroy
+TEST_P(EffectFactoryTest, CreateAndDestroyRepeat) {
+    std::vector<Descriptor::Identity> ids;
+    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
+    EXPECT_NE(ids.size(), 0UL);
+
+    creatAndDestroyIds(ids);
+    creatAndDestroyIds(ids);
+    creatAndDestroyIds(ids);
 }
 
 // Expect EX_ILLEGAL_ARGUMENT when create with invalid UUID.
 TEST_P(EffectFactoryTest, CreateWithInvalidUuid) {
-    std::vector<std::pair<Descriptor::Identity, binder_status_t>> descriptors;
-    descriptors.push_back(std::make_pair(nullDesc, EX_ILLEGAL_ARGUMENT));
-    descriptors.push_back(std::make_pair(zeroDesc, EX_ILLEGAL_ARGUMENT));
-
-    auto& effectMap = mFactory.GetEffectMap();
-    mFactory.CreateEffectsAndExpect(descriptors);
-    EXPECT_EQ(effectMap.size(), 0UL);
+    std::vector<Descriptor::Identity> ids = {kNullDesc, kZeroDesc};
+    auto effects = createWithIds(ids, EX_ILLEGAL_ARGUMENT);
+    EXPECT_EQ(effects.size(), 0UL);
 }
 
 // Expect EX_ILLEGAL_ARGUMENT when destroy null interface.
 TEST_P(EffectFactoryTest, DestroyWithInvalidInterface) {
     std::shared_ptr<IEffect> spDummyEffect(nullptr);
-
-    mFactory.DestroyEffectAndExpect(spDummyEffect, EX_ILLEGAL_ARGUMENT);
+    destroyEffects({spDummyEffect}, EX_ILLEGAL_ARGUMENT);
 }
 
-TEST_P(EffectFactoryTest, CreateAndRemoveReference) {
-    std::vector<Descriptor::Identity> descriptors;
-    mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors);
-    auto numIds = mFactory.GetEffectIds().size();
-    EXPECT_NE(numIds, 0UL);
+// Same descriptor ID should work after service restart.
+TEST_P(EffectFactoryTest, CreateDestroyWithRestart) {
+    std::vector<Descriptor::Identity> ids;
+    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
+    EXPECT_NE(ids.size(), 0UL);
+    creatAndDestroyIds(ids);
 
-    auto& effectMap = mFactory.GetEffectMap();
-    EXPECT_EQ(effectMap.size(), 0UL);
-    mFactory.CreateEffects();
-    EXPECT_EQ(effectMap.size(), numIds);
-    // remove all reference
-    mFactory.ClearEffectMap();
-    EXPECT_EQ(effectMap.size(), 0UL);
+    mFactoryHelper->RestartFactoryService();
+
+    connectAndGetFactory();
+    creatAndDestroyIds(ids);
 }
 
-TEST_P(EffectFactoryTest, CreateRemoveReferenceAndCreateDestroy) {
-    std::vector<Descriptor::Identity> descriptors;
-    mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors);
-    auto numIds = mFactory.GetEffectIds().size();
-    EXPECT_NE(numIds, 0UL);
+// Effect handle invalid after restart.
+TEST_P(EffectFactoryTest, EffectInvalidAfterRestart) {
+    std::vector<Descriptor::Identity> ids;
+    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
+    EXPECT_NE(ids.size(), 0UL);
+    std::vector<std::shared_ptr<IEffect>> effects = createWithIds(ids);
 
-    auto& effectMap = mFactory.GetEffectMap();
-    EXPECT_EQ(effectMap.size(), 0UL);
-    mFactory.CreateEffects();
-    EXPECT_EQ(effectMap.size(), numIds);
-    // remove all reference
-    mFactory.ClearEffectMap();
-    EXPECT_EQ(effectMap.size(), 0UL);
+    ASSERT_NO_FATAL_FAILURE(mFactoryHelper->RestartFactoryService());
 
-    // Create and destroy again
-    mFactory.CreateEffects();
-    EXPECT_EQ(effectMap.size(), numIds);
-    mFactory.DestroyEffects();
-    EXPECT_EQ(effectMap.size(), 0UL);
+    connectAndGetFactory();
+    destroyEffects(effects, EX_ILLEGAL_ARGUMENT);
 }
 
-TEST_P(EffectFactoryTest, CreateRestartAndCreateDestroy) {
-    std::vector<Descriptor::Identity> descriptors;
-    mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors);
-    auto numIds = mFactory.GetEffectIds().size();
-    auto& effectMap = mFactory.GetEffectMap();
-    mFactory.CreateEffects();
-    EXPECT_EQ(effectMap.size(), numIds);
-    ASSERT_NO_FATAL_FAILURE(mFactory.RestartFactoryService());
-
-    mFactory.CreateEffects();
-    EXPECT_EQ(effectMap.size(), numIds);
-    mFactory.DestroyEffects();
-    EXPECT_EQ(effectMap.size(), 0UL);
-}
-
+// expect no error with the queryProcessing interface, but don't check number of processing
 TEST_P(EffectFactoryTest, QueryProcess) {
     std::vector<Processing> processing;
-    mFactory.QueryProcessing(std::nullopt, &processing);
-    // TODO: verify the number of process in example implementation after audio_effects.xml migrated
+    EXPECT_IS_OK(mEffectFactory->queryProcessing(std::nullopt, &processing));
+
+    Processing::Type streamType =
+            Processing::Type::make<Processing::Type::streamType>(AudioStreamType::SYSTEM);
+    std::vector<Processing> processingFilteredByStream;
+    EXPECT_IS_OK(mEffectFactory->queryProcessing(streamType, &processingFilteredByStream));
+
+    Processing::Type source =
+            Processing::Type::make<Processing::Type::source>(AudioSource::DEFAULT);
+    std::vector<Processing> processingFilteredBySource;
+    EXPECT_IS_OK(mEffectFactory->queryProcessing(source, &processingFilteredBySource));
+
+    EXPECT_TRUE(processing.size() >= processingFilteredByStream.size());
+    EXPECT_TRUE(processing.size() >= processingFilteredBySource.size());
 }
 
 INSTANTIATE_TEST_SUITE_P(EffectFactoryTest, EffectFactoryTest,
diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
index 3ea67bc..8212149 100644
--- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -16,26 +16,24 @@
 
 #define LOG_TAG "VtsHalAudioEffectTargetTest"
 
+#include <chrono>
 #include <memory>
 #include <string>
-#include <unordered_map>
-#include <unordered_set>
 #include <vector>
 
+#include <Utils.h>
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
+#include <aidl/android/hardware/audio/effect/IEffect.h>
+#include <aidl/android/hardware/audio/effect/IFactory.h>
 #include <android-base/logging.h>
-#include <android-base/properties.h>
 #include <android/binder_interface_utils.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
-
-#include <Utils.h>
-#include <aidl/android/hardware/audio/effect/IEffect.h>
-#include <aidl/android/hardware/audio/effect/IFactory.h>
-#include <aidl/android/media/audio/common/AudioDeviceType.h>
+#include <fmq/AidlMessageQueue.h>
 
 #include "AudioHalBinderServiceUtil.h"
+#include "EffectFactoryHelper.h"
 #include "EffectHelper.h"
 #include "TestUtils.h"
 
@@ -49,309 +47,725 @@
 using aidl::android::hardware::audio::effect::IFactory;
 using aidl::android::hardware::audio::effect::Parameter;
 using aidl::android::hardware::audio::effect::State;
-using aidl::android::media::audio::common::AudioDeviceType;
 
-class AudioEffectTest : public testing::TestWithParam<std::string>, public EffectHelper {
+enum ParamName { PARAM_INSTANCE_NAME };
+using EffectTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>>;
+
+class AudioEffectTest : public testing::TestWithParam<EffectTestParam>, public EffectHelper {
   public:
-    AudioEffectTest() : EffectHelper(GetParam()) {}
+    AudioEffectTest() { std::tie(mFactory, mIdentity) = std::get<PARAM_INSTANCE_NAME>(GetParam()); }
 
-    void SetUp() override {
-        CreateEffects();
-        initParamCommonFormat();
-        initParamCommon();
-    }
+    void SetUp() override {}
+    void TearDown() override {}
 
-    void TearDown() override {
-        CloseEffects();
-        DestroyEffects();
-    }
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    Descriptor::Identity mIdentity;
 };
 
-TEST_P(AudioEffectTest, OpenEffectTest) {
-    OpenEffects();
+TEST_P(AudioEffectTest, SetupAndTearDown) {
+    // Intentionally empty test body.
 }
 
-TEST_P(AudioEffectTest, OpenAndCloseEffect) {
-    OpenEffects();
-    CloseEffects();
+TEST_P(AudioEffectTest, CreateAndDestroy) {
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
-TEST_P(AudioEffectTest, CloseUnopenedEffectTest) {
-    CloseEffects();
+TEST_P(AudioEffectTest, OpenAndClose) {
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(open(effect));
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
-TEST_P(AudioEffectTest, DoubleOpenCloseEffects) {
-    OpenEffects();
-    CloseEffects();
-    OpenEffects();
-    CloseEffects();
-
-    OpenEffects();
-    OpenEffects();
-    CloseEffects();
-
-    OpenEffects();
-    CloseEffects();
-    CloseEffects();
+TEST_P(AudioEffectTest, CloseUnopenedEffect) {
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
-TEST_P(AudioEffectTest, GetDescriptors) {
-    GetEffectDescriptors();
+TEST_P(AudioEffectTest, DoubleOpenAndClose) {
+    std::shared_ptr<IEffect> effect1, effect2;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(open(effect1));
+    ASSERT_NO_FATAL_FAILURE(open(effect2, 1 /* session */));
+    ASSERT_NO_FATAL_FAILURE(close(effect1));
+    ASSERT_NO_FATAL_FAILURE(close(effect2));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect1));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect2));
 }
 
-TEST_P(AudioEffectTest, DescriptorIdExistAndUnique) {
-    auto checker = [&](const std::shared_ptr<IEffect>& effect) {
-        Descriptor desc;
-        std::vector<Descriptor::Identity> idList;
-        EXPECT_IS_OK(effect->getDescriptor(&desc));
-        QueryEffects(desc.common.id.type, desc.common.id.uuid, desc.common.id.proxy, &idList);
-        // Must have at least one instance.
-        EXPECT_NE(idList.size(), 0UL);
-    };
-    ForEachEffect(checker);
+TEST_P(AudioEffectTest, TripleOpenAndClose) {
+    std::shared_ptr<IEffect> effect1, effect2, effect3;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect3, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(open(effect1));
+    ASSERT_NO_FATAL_FAILURE(open(effect2, 1 /* session */));
+    ASSERT_NO_FATAL_FAILURE(open(effect3, 2 /* session */));
+    ASSERT_NO_FATAL_FAILURE(close(effect1));
+    ASSERT_NO_FATAL_FAILURE(close(effect2));
+    ASSERT_NO_FATAL_FAILURE(close(effect3));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect1));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect2));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect3));
+}
 
-    // Check unique with a set
-    auto stringHash = [](const Descriptor::Identity& id) {
-        return std::hash<std::string>()(id.toString());
-    };
-    auto vec = GetCompleteEffectIdList();
-    std::unordered_set<Descriptor::Identity, decltype(stringHash)> idSet(0, stringHash);
-    for (auto it : vec) {
-        EXPECT_EQ(idSet.count(it), 0UL) << it.toString();
-        idSet.insert(it);
+TEST_P(AudioEffectTest, GetDescritorBeforeOpen) {
+    std::shared_ptr<IEffect> effect;
+    Descriptor desc;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, desc));
+    EXPECT_EQ(mIdentity.toString(), desc.common.id.toString());
+    EXPECT_NE("", desc.common.name);
+    EXPECT_NE("", desc.common.implementor);
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+TEST_P(AudioEffectTest, GetDescritorAfterOpen) {
+    std::shared_ptr<IEffect> effect;
+    Descriptor beforeOpen, afterOpen, afterClose;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, beforeOpen));
+    ASSERT_NO_FATAL_FAILURE(open(effect));
+    ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, afterOpen));
+    EXPECT_EQ(beforeOpen.toString(), afterOpen.toString()) << "\n"
+                                                           << beforeOpen.toString() << "\n"
+                                                           << afterOpen.toString();
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, afterClose));
+    EXPECT_EQ(beforeOpen.toString(), afterClose.toString()) << "\n"
+                                                            << beforeOpen.toString() << "\n"
+                                                            << afterClose.toString();
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+TEST_P(AudioEffectTest, DescriptorExistAndUnique) {
+    std::shared_ptr<IEffect> effect;
+    Descriptor desc;
+
+    auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor);
+    std::set<Descriptor::Identity> idSet;
+    for (const auto& it : descList) {
+        auto& id = it.second;
+        EXPECT_EQ(0ul, idSet.count(id));
+        idSet.insert(id);
     }
+
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, desc));
+    EXPECT_EQ(1ul, idSet.count(desc.common.id));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
 /// State testing.
 // An effect instance is in INIT state by default after it was created.
 TEST_P(AudioEffectTest, InitStateAfterCreation) {
-    ExpectState(State::INIT);
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
-// An effect instance transfer to INIT state after it was open successfully with IEffect.open().
+// An effect instance transfer to IDLE state after IEffect.ASSERT_NO_FATAL_FAILURE(open().
 TEST_P(AudioEffectTest, IdleStateAfterOpen) {
-    OpenEffects();
-    ExpectState(State::IDLE);
-    CloseEffects();
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(open(effect));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
 // An effect instance is in PROCESSING state after it receive an START command.
 TEST_P(AudioEffectTest, ProcessingStateAfterStart) {
-    OpenEffects();
-    CommandEffects(CommandId::START);
-    ExpectState(State::PROCESSING);
-    CommandEffects(CommandId::STOP);
-    CloseEffects();
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
+    ASSERT_NO_FATAL_FAILURE(open(effect));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
 // An effect instance transfer to IDLE state after Command.Id.STOP in PROCESSING state.
 TEST_P(AudioEffectTest, IdleStateAfterStop) {
-    OpenEffects();
-    CommandEffects(CommandId::START);
-    ExpectState(State::PROCESSING);
-    CommandEffects(CommandId::STOP);
-    ExpectState(State::IDLE);
-    CloseEffects();
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(open(effect));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
 // An effect instance transfer to IDLE state after Command.Id.RESET in PROCESSING state.
 TEST_P(AudioEffectTest, IdleStateAfterReset) {
-    OpenEffects();
-    CommandEffects(CommandId::START);
-    ExpectState(State::PROCESSING);
-    CommandEffects(CommandId::RESET);
-    ExpectState(State::IDLE);
-    CloseEffects();
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(open(effect));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
-// An effect instance transfer to INIT if instance receive a close() call.
+// An effect instance transfer to INIT after IEffect.ASSERT_NO_FATAL_FAILURE(close().
 TEST_P(AudioEffectTest, InitStateAfterClose) {
-    OpenEffects();
-    CommandEffects(CommandId::START);
-    ExpectState(State::PROCESSING);
-    CommandEffects(CommandId::STOP);
-    ExpectState(State::IDLE);
-    CloseEffects();
-    ExpectState(State::INIT);
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(open(effect));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
 // An effect instance shouldn't accept any command before open.
 TEST_P(AudioEffectTest, NoCommandAcceptedBeforeOpen) {
-    ExpectState(State::INIT);
-    CommandEffectsExpectStatus(CommandId::START, EX_ILLEGAL_STATE);
-    CommandEffectsExpectStatus(CommandId::STOP, EX_ILLEGAL_STATE);
-    CommandEffectsExpectStatus(CommandId::RESET, EX_ILLEGAL_STATE);
-    ExpectState(State::INIT);
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START, EX_ILLEGAL_STATE));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP, EX_ILLEGAL_STATE));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET, EX_ILLEGAL_STATE));
+    ASSERT_NO_FATAL_FAILURE(open(effect));
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
 // No-op when receive STOP command in IDLE state.
 TEST_P(AudioEffectTest, StopCommandInIdleStateNoOp) {
-    ExpectState(State::INIT);
-    OpenEffects();
-    ExpectState(State::IDLE);
-    CommandEffects(CommandId::STOP);
-    ExpectState(State::IDLE);
-    CloseEffects();
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(open(effect));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
-// No-op when receive STOP command in IDLE state.
+// No-op when receive RESET command in IDLE state.
 TEST_P(AudioEffectTest, ResetCommandInIdleStateNoOp) {
-    ExpectState(State::INIT);
-    OpenEffects();
-    ExpectState(State::IDLE);
-    CommandEffects(CommandId::RESET);
-    ExpectState(State::IDLE);
-    CloseEffects();
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(open(effect));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
 // Repeat START and STOP command.
 TEST_P(AudioEffectTest, RepeatStartAndStop) {
-    OpenEffects();
-    CommandEffects(CommandId::START);
-    ExpectState(State::PROCESSING);
-    CommandEffects(CommandId::STOP);
-    ExpectState(State::IDLE);
-    CommandEffects(CommandId::START);
-    ExpectState(State::PROCESSING);
-    CommandEffects(CommandId::STOP);
-    ExpectState(State::IDLE);
-    CloseEffects();
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(open(effect));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
 // Repeat START and RESET command.
 TEST_P(AudioEffectTest, RepeatStartAndReset) {
-    OpenEffects();
-    CommandEffects(CommandId::START);
-    ExpectState(State::PROCESSING);
-    CommandEffects(CommandId::RESET);
-    ExpectState(State::IDLE);
-    CommandEffects(CommandId::START);
-    ExpectState(State::PROCESSING);
-    CommandEffects(CommandId::RESET);
-    ExpectState(State::IDLE);
-    CloseEffects();
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(open(effect));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
-// Repeat START and STOP command, try to close at PROCESSING state.
+// Try to close an effect instance at PROCESSING state.
 TEST_P(AudioEffectTest, CloseProcessingStateEffects) {
-    OpenEffects();
-    CommandEffects(CommandId::START);
-    ExpectState(State::PROCESSING);
-    CommandEffects(CommandId::STOP);
-    ExpectState(State::IDLE);
-    CommandEffects(CommandId::START);
-    ExpectState(State::PROCESSING);
-    CloseEffects(EX_ILLEGAL_STATE);
-    // cleanup
-    CommandEffects(CommandId::STOP);
-    ExpectState(State::IDLE);
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(open(effect));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+
+    ASSERT_NO_FATAL_FAILURE(close(effect, EX_ILLEGAL_STATE));
+
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
 // Expect EX_ILLEGAL_STATE if the effect instance is not in a proper state to be destroyed.
 TEST_P(AudioEffectTest, DestroyOpenEffects) {
-    // cleanup all effects.
-    CloseEffects();
-    DestroyEffects();
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(open(effect));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
 
-    // open effects, destroy without close, expect to get EX_ILLEGAL_STATE status.
-    CreateEffects();
-    OpenEffects();
-    auto vec = GetCompleteEffectIdList();
-    DestroyEffects(EX_ILLEGAL_STATE, vec.size());
-    CloseEffects();
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect, EX_ILLEGAL_STATE));
+}
+
+// Expect EX_ILLEGAL_STATE if the effect instance is not in a proper state to be destroyed.
+TEST_P(AudioEffectTest, DestroyProcessingEffects) {
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(open(effect));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect, EX_ILLEGAL_STATE));
+}
+
+TEST_P(AudioEffectTest, NormalSequenceStates) {
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
+    ASSERT_NO_FATAL_FAILURE(open(effect));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
 /// Parameter testing.
 // Verify parameters pass in open can be successfully get.
-TEST_P(AudioEffectTest, VerifyParametersAfterOpen) {
-    OpenEffects();
-    VerifyParameters();
-    CloseEffects();
+TEST_P(AudioEffectTest, VerifyCommonParametersAfterOpen) {
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+
+    Parameter::Common common = EffectHelper::createParamCommon();
+    IEffect::OpenEffectReturn ret;
+    ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+
+    Parameter get = Parameter(), expect = Parameter();
+    expect.set<Parameter::common>(common);
+    Parameter::Id id;
+    id.set<Parameter::Id::commonTag>(Parameter::common);
+    EXPECT_IS_OK(effect->getParameter(id, &get));
+    EXPECT_EQ(expect, get) << expect.toString() << " vs " << get.toString();
+
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
 // Verify parameters pass in set can be successfully get.
-TEST_P(AudioEffectTest, SetAndGetParameter) {
-    OpenEffects();
-    VerifyParameters();
-    initParamCommon(1 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */,
-                    44100 /* oSampleRate */);
-    SetParameter();
-    VerifyParameters();
-    CloseEffects();
+TEST_P(AudioEffectTest, SetAndGetCommonParameter) {
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(open(effect));
+
+    Parameter::Common common = EffectHelper::createParamCommon(
+            0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
+    Parameter get = Parameter(), set = Parameter();
+    set.set<Parameter::common>(common);
+    EXPECT_IS_OK(effect->setParameter(set));
+
+    Parameter::Id id;
+    id.set<Parameter::Id::commonTag>(Parameter::common);
+    EXPECT_IS_OK(effect->getParameter(id, &get));
+    EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
+
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
-// Verify parameters pass in set can be successfully get.
+// Verify parameters set and get in PROCESSING state.
 TEST_P(AudioEffectTest, SetAndGetParameterInProcessing) {
-    OpenEffects();
-    VerifyParameters();
-    CommandEffects(CommandId::START);
-    ExpectState(State::PROCESSING);
-    initParamCommon(1 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */,
-                    44100 /* oSampleRate */);
-    SetParameter();
-    VerifyParameters();
-    CommandEffects(CommandId::STOP);
-    ExpectState(State::IDLE);
-    CloseEffects();
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(open(effect));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+
+    Parameter::Common common = EffectHelper::createParamCommon(
+            0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
+    Parameter get = Parameter(), set = Parameter();
+    set.set<Parameter::common>(common);
+    EXPECT_IS_OK(effect->setParameter(set));
+
+    Parameter::Id id;
+    id.set<Parameter::Id::commonTag>(Parameter::common);
+    EXPECT_IS_OK(effect->getParameter(id, &get));
+    EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
+
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
-// Parameters kept after reset.
-TEST_P(AudioEffectTest, ResetAndVerifyParameter) {
-    OpenEffects();
-    VerifyParameters();
-    CommandEffects(CommandId::START);
-    ExpectState(State::PROCESSING);
-    initParamCommon(1 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */,
-                    44100 /* oSampleRate */);
-    SetParameter();
-    VerifyParameters();
-    CommandEffects(CommandId::RESET);
-    ExpectState(State::IDLE);
-    VerifyParameters();
-    CloseEffects();
+// Verify parameters set and get in IDLE state.
+TEST_P(AudioEffectTest, SetAndGetParameterInIdle) {
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(open(effect));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+
+    Parameter::Common common = EffectHelper::createParamCommon(
+            0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
+    Parameter get = Parameter(), set = Parameter();
+    set.set<Parameter::common>(common);
+    EXPECT_IS_OK(effect->setParameter(set));
+
+    Parameter::Id id;
+    id.set<Parameter::Id::commonTag>(Parameter::common);
+    EXPECT_IS_OK(effect->getParameter(id, &get));
+    EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
+
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
-// TODO: need a way to support setting different sessionId to different effect instances
-#if 0
-// Multiple instances of same implementation running.
-TEST_P(AudioEffectTest, MultipleInstancesRunningWithDiffSessionId) {
-    CreateEffects();
-    ExpectState(State::INIT);
-    OpenEffects();
-    ExpectState(State::IDLE);
-    CommandEffects(CommandId::START);
-    ExpectState(State::PROCESSING);
-    initParamCommon(1 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */,
-                    44100 /* oSampleRate */);
-    SetParameter();
-    VerifyParameters();
-    CommandEffects(CommandId::STOP);
-    ExpectState(State::IDLE);
-    VerifyParameters();
-    CloseEffects();
-}
-#endif
+// Verify Parameters kept after stop.
+TEST_P(AudioEffectTest, SetAndGetParameterAfterStop) {
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(open(effect));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
 
-// Send data to effects and expect it to consume by check statusMQ.
-TEST_P(AudioEffectTest, ExpectEffectsToConsumeDataInMQ) {
-    OpenEffects();
-    PrepareInputData(mWriteMQBytes);
+    Parameter::Common common = EffectHelper::createParamCommon(
+            0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
+    Parameter get = Parameter(), set = Parameter();
+    set.set<Parameter::common>(common);
+    EXPECT_IS_OK(effect->setParameter(set));
 
-    CommandEffects(CommandId::START);
-    writeToFmq(mWriteMQBytes);
-    readFromFmq(mWriteMQBytes);
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
 
-    ExpectState(State::PROCESSING);
-    CommandEffects(CommandId::STOP);
-    // cleanup
-    CommandEffects(CommandId::STOP);
-    ExpectState(State::IDLE);
-    CloseEffects();
+    Parameter::Id id;
+    id.set<Parameter::Id::commonTag>(Parameter::common);
+    EXPECT_IS_OK(effect->getParameter(id, &get));
+    EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
+
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
-INSTANTIATE_TEST_SUITE_P(AudioEffectTestTest, AudioEffectTest,
-                         testing::ValuesIn(android::getAidlHalInstanceNames(IFactory::descriptor)),
-                         android::PrintInstanceNameToString);
+// Verify Parameters kept after reset.
+TEST_P(AudioEffectTest, SetAndGetParameterAfterReset) {
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(open(effect));
+
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+
+    Parameter::Common common = EffectHelper::createParamCommon(
+            0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
+    Parameter get = Parameter(), set = Parameter();
+    set.set<Parameter::common>(common);
+    EXPECT_IS_OK(effect->setParameter(set));
+
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+
+    Parameter::Id id;
+    id.set<Parameter::Id::commonTag>(Parameter::common);
+    EXPECT_IS_OK(effect->getParameter(id, &get));
+    EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
+
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+/// Data processing test
+// Send data to effects and expect it to be consumed by checking statusMQ.
+TEST_P(AudioEffectTest, ConsumeDataInProcessingState) {
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+
+    Parameter::Common common = EffectHelper::createParamCommon(
+            0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+            kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+    IEffect::OpenEffectReturn ret;
+    ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+    auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+
+    std::vector<float> buffer;
+    EffectHelper::allocateInputData(common, inputMQ, buffer);
+    EffectHelper::writeToFmq(inputMQ, buffer);
+    EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
+
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// Send data to effects and expect it to be consumed after effect restart.
+TEST_P(AudioEffectTest, ConsumeDataAfterRestart) {
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+
+    Parameter::Common common = EffectHelper::createParamCommon(
+            0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+            kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+    IEffect::OpenEffectReturn ret;
+    ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+    auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+
+    std::vector<float> buffer;
+    EffectHelper::allocateInputData(common, inputMQ, buffer);
+    EffectHelper::writeToFmq(inputMQ, buffer);
+    EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
+
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// Send data to IDLE effects and expect it to be consumed after effect start.
+TEST_P(AudioEffectTest, SendDataAtIdleAndConsumeDataInProcessing) {
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+
+    Parameter::Common common = EffectHelper::createParamCommon(
+            0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+            kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+    IEffect::OpenEffectReturn ret;
+    ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+    auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+
+    std::vector<float> buffer;
+    EffectHelper::allocateInputData(common, inputMQ, buffer);
+    EffectHelper::writeToFmq(inputMQ, buffer);
+    EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
+
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+
+    EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
+
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// Send data multiple times.
+TEST_P(AudioEffectTest, ProcessDataMultipleTimes) {
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+
+    Parameter::Common common = EffectHelper::createParamCommon(
+            0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+            kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+    IEffect::OpenEffectReturn ret;
+    ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+    auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+
+    std::vector<float> buffer;
+    EffectHelper::allocateInputData(common, inputMQ, buffer);
+    EffectHelper::writeToFmq(inputMQ, buffer);
+    EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
+
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+
+    EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
+    // expect no status and data after consume
+    EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
+
+    EffectHelper::writeToFmq(inputMQ, buffer);
+    EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
+    // expect no status and data after consume
+    EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
+
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// Send data to IDLE state effects and expect it not be consumed.
+TEST_P(AudioEffectTest, NotConsumeDataInIdleState) {
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+
+    Parameter::Common common = EffectHelper::createParamCommon(
+            0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+            kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+    IEffect::OpenEffectReturn ret;
+    ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+    auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+
+    std::vector<float> buffer;
+    EffectHelper::allocateInputData(common, inputMQ, buffer);
+    EffectHelper::writeToFmq(inputMQ, buffer);
+    EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
+
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
+
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// Send data to closed effects and expect it not be consumed.
+TEST_P(AudioEffectTest, NotConsumeDataByClosedEffect) {
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+
+    Parameter::Common common = EffectHelper::createParamCommon(
+            0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+            kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+    IEffect::OpenEffectReturn ret;
+    ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+
+    auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+
+    std::vector<float> buffer;
+    EffectHelper::allocateInputData(common, inputMQ, buffer);
+    EffectHelper::writeToFmq(inputMQ, buffer);
+    EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
+
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// Send data to multiple effects.
+TEST_P(AudioEffectTest, ConsumeDataMultipleEffects) {
+    std::shared_ptr<IEffect> effect1, effect2;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mIdentity));
+
+    Parameter::Common common1 = EffectHelper::createParamCommon(
+            0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+            kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+    Parameter::Common common2 = EffectHelper::createParamCommon(
+            1 /* session */, 1 /* ioHandle */, 48000 /* iSampleRate */, 48000 /* oSampleRate */,
+            2 * kInputFrameCount /* iFrameCount */, 2 * kOutputFrameCount /* oFrameCount */);
+    IEffect::OpenEffectReturn ret1, ret2;
+    ASSERT_NO_FATAL_FAILURE(open(effect1, common1, std::nullopt /* specific */, &ret1, EX_NONE));
+    ASSERT_NO_FATAL_FAILURE(open(effect2, common2, std::nullopt /* specific */, &ret2, EX_NONE));
+    ASSERT_NO_FATAL_FAILURE(command(effect1, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect1, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(effect2, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect2, State::PROCESSING));
+
+    auto statusMQ1 = std::make_unique<EffectHelper::StatusMQ>(ret1.statusMQ);
+    auto inputMQ1 = std::make_unique<EffectHelper::DataMQ>(ret1.inputDataMQ);
+    auto outputMQ1 = std::make_unique<EffectHelper::DataMQ>(ret1.outputDataMQ);
+
+    std::vector<float> buffer1, buffer2;
+    EffectHelper::allocateInputData(common1, inputMQ1, buffer1);
+    EffectHelper::writeToFmq(inputMQ1, buffer1);
+    EffectHelper::readFromFmq(statusMQ1, 1, outputMQ1, buffer1.size(), buffer1);
+
+    auto statusMQ2 = std::make_unique<EffectHelper::StatusMQ>(ret2.statusMQ);
+    auto inputMQ2 = std::make_unique<EffectHelper::DataMQ>(ret2.inputDataMQ);
+    auto outputMQ2 = std::make_unique<EffectHelper::DataMQ>(ret2.outputDataMQ);
+    EffectHelper::allocateInputData(common2, inputMQ2, buffer2);
+    EffectHelper::writeToFmq(inputMQ2, buffer2);
+    EffectHelper::readFromFmq(statusMQ2, 1, outputMQ2, buffer2.size(), buffer2);
+
+    ASSERT_NO_FATAL_FAILURE(command(effect1, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect1, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(effect1));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect1));
+
+    ASSERT_NO_FATAL_FAILURE(command(effect2, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect2, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(effect2));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect2));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        SingleEffectInstanceTest, AudioEffectTest,
+        ::testing::Combine(testing::ValuesIn(
+                EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor))),
+        [](const testing::TestParamInfo<AudioEffectTest::ParamType>& info) {
+            auto msSinceEpoch = std::chrono::duration_cast<std::chrono::nanoseconds>(
+                                        std::chrono::system_clock::now().time_since_epoch())
+                                        .count();
+            auto instance = std::get<PARAM_INSTANCE_NAME>(info.param);
+            std::ostringstream address;
+            address << msSinceEpoch << "_factory_" << instance.first.get();
+            std::string name = address.str() + "_UUID_timeLow_" +
+                               ::android::internal::ToString(instance.second.uuid.timeLow) +
+                               "_timeMid_" +
+                               ::android::internal::ToString(instance.second.uuid.timeMid);
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioEffectTest);
 
 int main(int argc, char** argv) {
diff --git a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
index 4162551..f19dff6 100644
--- a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
@@ -35,8 +35,6 @@
 #include <Utils.h>
 #include <aidl/android/hardware/audio/effect/IEffect.h>
 #include <aidl/android/hardware/audio/effect/IFactory.h>
-#include <aidl/android/media/audio/common/AudioChannelLayout.h>
-#include <aidl/android/media/audio/common/AudioDeviceType.h>
 
 #include "AudioHalBinderServiceUtil.h"
 #include "EffectHelper.h"
@@ -47,103 +45,126 @@
 
 using aidl::android::hardware::audio::effect::Capability;
 using aidl::android::hardware::audio::effect::Descriptor;
-using aidl::android::hardware::audio::effect::EffectNullUuid;
 using aidl::android::hardware::audio::effect::Equalizer;
-using aidl::android::hardware::audio::effect::EqualizerTypeUUID;
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kEqualizerTypeUUID;
 using aidl::android::hardware::audio::effect::Parameter;
 
 /**
- * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
- * VtsAudioEfectTargetTest.
+ * Here we focus on specific effect (equalizer) parameter checking, general IEffect interfaces
+ * testing performed in VtsAudioEfectTargetTest.
  */
-enum ParamName { PARAM_INSTANCE_NAME, PARAM_PRESET_INDEX, PARAM_BAND_INDEX, PARAM_BAND_LEVEL };
-using EqualizerParamTestParam = std::tuple<std::string, int, int, int>;
+
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_BAND_LEVEL };
+using EqualizerParamTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>, int>;
 
 /*
 Testing parameter range, assuming the parameter supported by effect is in this range.
 This range is verified with IEffect.getDescriptor(), for any index supported vts expect EX_NONE
 from IEffect.setParameter(), otherwise expect EX_ILLEGAL_ARGUMENT.
 */
-constexpr std::pair<int, int> kPresetIndexRange = {-1, 10};  // valid range [0, 9]
-constexpr std::pair<int, int> kBandIndexRange = {-1, 5};     // valid range [0, 4]
-constexpr std::pair<int, int> kBandLevelRange = {-5, 5};     // needs update with implementation
+const std::vector<int> kBandLevels = {0, -10, 10};  // needs update with implementation
 
-class EqualizerParamTest : public ::testing::TestWithParam<EqualizerParamTestParam>,
-                           public EffectHelper {
+class EqualizerTest : public ::testing::TestWithParam<EqualizerParamTestParam>,
+                      public EffectHelper {
   public:
-    EqualizerParamTest()
-        : EffectHelper(std::get<PARAM_INSTANCE_NAME>(GetParam())),
-          mParamPresetIndex(std::get<PARAM_PRESET_INDEX>(GetParam())),
-          mParamBandIndex(std::get<PARAM_BAND_INDEX>(GetParam())),
-          mParamBandLevel(std::get<PARAM_BAND_LEVEL>(GetParam())) {}
+    EqualizerTest() : mBandLevel(std::get<PARAM_BAND_LEVEL>(GetParam())) {
+        std::tie(mFactory, mIdentity) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    }
 
     void SetUp() override {
-        CreateEffectsWithUUID(EqualizerTypeUUID);
-        initParamCommonFormat();
-        initParamCommon();
-        initParamSpecific();
-        OpenEffects(EqualizerTypeUUID);
-        SCOPED_TRACE(testing::Message() << "preset: " << mParamPresetIndex << " bandIdx "
-                                        << mParamBandIndex << " level " << mParamBandLevel);
-    }
+        ASSERT_NE(nullptr, mFactory);
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mIdentity));
 
+        Parameter::Specific specific = getDefaultParamSpecific();
+        Parameter::Common common = EffectHelper::createParamCommon(
+                0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+        IEffect::OpenEffectReturn ret;
+        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+        ASSERT_NE(nullptr, mEffect);
+        ASSERT_NO_FATAL_FAILURE(setTagRange());
+    }
     void TearDown() override {
-        CloseEffects();
-        DestroyEffects();
-        CleanUp();
+        ASSERT_NO_FATAL_FAILURE(close(mEffect));
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
     }
 
-    int mParamPresetIndex = 0;
-    int mParamBandIndex = 0;
-    int mParamBandLevel = 0;
+    std::pair<int, int> setPresetIndexRange(const Equalizer::Capability& cap) const {
+        const auto [min, max] =
+                std::minmax_element(cap.presets.begin(), cap.presets.end(),
+                                    [](const auto& a, const auto& b) { return a.index < b.index; });
+        return {min->index, max->index};
+    }
+    std::pair<int, int> setBandIndexRange(const Equalizer::Capability& cap) const {
+        const auto [min, max] =
+                std::minmax_element(cap.bandFrequencies.begin(), cap.bandFrequencies.end(),
+                                    [](const auto& a, const auto& b) { return a.index < b.index; });
+        return {min->index, max->index};
+    }
+    void setTagRange() {
+        Descriptor desc;
+        ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+        Equalizer::Capability& eqCap = desc.capability.get<Capability::equalizer>();
+        mPresetIndex = setPresetIndexRange(eqCap);
+        mBandIndex = setBandIndexRange(eqCap);
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor::Identity mIdentity;
+    std::pair<int, int> mPresetIndex;
+    std::pair<int, int> mBandIndex;
+    const int mBandLevel;
+    Descriptor mDesc;
 
     void SetAndGetEqualizerParameters() {
-        auto functor = [&](const std::shared_ptr<IEffect>& effect) {
-            for (auto& it : mTags) {
-                auto& tag = it.first;
-                auto& eq = it.second;
+        ASSERT_NE(nullptr, mEffect);
+        for (auto& it : mTags) {
+            auto& tag = it.first;
+            auto& eq = it.second;
 
-                // validate parameter
-                Descriptor desc;
-                ASSERT_STATUS(EX_NONE, effect->getDescriptor(&desc));
-                const bool valid = isTagInRange(it.first, it.second, desc);
-                const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+            // validate parameter
+            const bool valid = isTagInRange(it.first, it.second);
+            const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
 
-                // set
-                Parameter expectParam;
-                Parameter::Specific specific;
-                specific.set<Parameter::Specific::equalizer>(*eq.get());
-                expectParam.set<Parameter::specific>(specific);
-                EXPECT_STATUS(expected, effect->setParameter(expectParam))
-                        << expectParam.toString();
+            // set
+            Parameter expectParam;
+            Parameter::Specific specific;
+            specific.set<Parameter::Specific::equalizer>(eq);
+            expectParam.set<Parameter::specific>(specific);
+            EXPECT_STATUS(expected, mEffect->setParameter(expectParam))
+                    << expectParam.toString() << "\n"
+                    << mDesc.toString();
 
-                // only get if parameter in range and set success
-                if (expected == EX_NONE) {
-                    Parameter getParam;
-                    Parameter::Id id;
-                    Equalizer::Id eqId;
-                    eqId.set<Equalizer::Id::commonTag>(tag);
-                    id.set<Parameter::Id::equalizerTag>(eqId);
-                    // if set success, then get should match
-                    EXPECT_STATUS(expected, effect->getParameter(id, &getParam));
-                    EXPECT_TRUE(isEqParameterExpected(expectParam, getParam));
-                }
+            // only get if parameter in range and set success
+            if (expected == EX_NONE) {
+                Parameter getParam;
+                Parameter::Id id;
+                Equalizer::Id eqId;
+                eqId.set<Equalizer::Id::commonTag>(tag);
+                id.set<Parameter::Id::equalizerTag>(eqId);
+                // if set success, then get should match
+                EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
+                EXPECT_TRUE(isEqParameterExpected(expectParam, getParam))
+                        << "\nexpect:" << expectParam.toString()
+                        << "\ngetParam:" << getParam.toString();
             }
-        };
-        EXPECT_NO_FATAL_FAILURE(ForEachEffect(functor));
+        }
     }
 
     bool isEqParameterExpected(const Parameter& expect, const Parameter& target) {
-        // if parameter same, then for sure matched
+        // if parameter same, then for sure they are matched
         if (expect == target) return true;
 
         // if not, see if target include the expect parameter, and others all default (0).
         /*
-            This is verify the case of client setParameter to a single bandLevel ({3, -1} for
-           example), and return of getParameter must be [{0, 0}, {1, 0}, {2, 0}, {3, -1}, {4, 0}]
-        */
+         * This is to verify the case of client setParameter to a single bandLevel ({3, -1} for
+         * example), and return of getParameter must be [{0, 0}, {1, 0}, {2, 0}, {3, -1}, {4, 0}]
+         */
         EXPECT_EQ(expect.getTag(), Parameter::specific);
         EXPECT_EQ(target.getTag(), Parameter::specific);
 
@@ -160,10 +181,16 @@
         switch (eqTag) {
             case Equalizer::bandLevels: {
                 auto expectBl = expectEq.get<Equalizer::bandLevels>();
+                std::sort(expectBl.begin(), expectBl.end(),
+                          [](const auto& a, const auto& b) { return a.index < b.index; });
+                expectBl.erase(std::unique(expectBl.begin(), expectBl.end()), expectBl.end());
                 auto targetBl = targetEq.get<Equalizer::bandLevels>();
                 return std::includes(targetBl.begin(), targetBl.end(), expectBl.begin(),
                                      expectBl.end());
             }
+            case Equalizer::preset: {
+                return expectEq.get<Equalizer::preset>() == targetEq.get<Equalizer::preset>();
+            }
             default:
                 return false;
         }
@@ -173,27 +200,24 @@
     void addPresetParam(int preset) {
         Equalizer eq;
         eq.set<Equalizer::preset>(preset);
-        mTags.push_back({Equalizer::preset, std::make_unique<Equalizer>(std::move(eq))});
+        mTags.push_back({Equalizer::preset, eq});
     }
 
     void addBandLevelsParam(std::vector<Equalizer::BandLevel>& bandLevels) {
         Equalizer eq;
         eq.set<Equalizer::bandLevels>(bandLevels);
-        mTags.push_back({Equalizer::bandLevels, std::make_unique<Equalizer>(std::move(eq))});
+        mTags.push_back({Equalizer::bandLevels, eq});
     }
 
-    bool isTagInRange(const Equalizer::Tag& tag, const std::unique_ptr<Equalizer>& eq,
-                      const Descriptor& desc) const {
-        std::cout << "xxx" << toString(tag) << " " << desc.toString();
-        const Equalizer::Capability& eqCap = desc.capability.get<Capability::equalizer>();
+    bool isTagInRange(const Equalizer::Tag& tag, const Equalizer& eq) const {
         switch (tag) {
             case Equalizer::preset: {
-                int index = eq->get<Equalizer::preset>();
-                return isPresetIndexInRange(eqCap, index);
+                int index = eq.get<Equalizer::preset>();
+                return index >= mPresetIndex.first && index <= mPresetIndex.second;
             }
             case Equalizer::bandLevels: {
-                auto& bandLevel = eq->get<Equalizer::bandLevels>();
-                return isBandIndexInRange(eqCap, bandLevel);
+                auto& bandLevel = eq.get<Equalizer::bandLevels>();
+                return isBandInRange(bandLevel);
             }
             default:
                 return false;
@@ -201,78 +225,125 @@
         return false;
     }
 
-    bool isPresetIndexInRange(const Equalizer::Capability& cap, int idx) const {
-        const auto [min, max] =
-                std::minmax_element(cap.presets.begin(), cap.presets.end(),
-                                    [](const auto& a, const auto& b) { return a.index < b.index; });
-        return idx >= min->index && idx <= max->index;
-    }
-
-    bool isBandIndexInRange(const Equalizer::Capability& cap,
-                            const std::vector<Equalizer::BandLevel>& bandLevel) const {
+    bool isBandInRange(const std::vector<Equalizer::BandLevel>& bandLevel) const {
         for (auto& it : bandLevel) {
-            if (!isBandIndexInRange(cap, it.index)) return false;
+            if (it.index < mBandIndex.first || it.index > mBandIndex.second) return false;
         }
         return true;
     }
 
-    bool isBandIndexInRange(const Equalizer::Capability& cap, int idx) const {
-        const auto [min, max] =
-                std::minmax_element(cap.bandFrequencies.begin(), cap.bandFrequencies.end(),
-                                    [](const auto& a, const auto& b) { return a.index < b.index; });
-        return idx >= min->index && idx <= max->index;
+    Parameter::Specific getDefaultParamSpecific() {
+        Equalizer eq = Equalizer::make<Equalizer::preset>(0);
+        Parameter::Specific specific =
+                Parameter::Specific::make<Parameter::Specific::equalizer>(eq);
+        return specific;
     }
 
   private:
-    std::vector<std::pair<Equalizer::Tag, std::unique_ptr<Equalizer>>> mTags;
+    std::vector<std::pair<Equalizer::Tag, Equalizer>> mTags;
 
     bool validCapabilityTag(Capability& cap) { return cap.getTag() == Capability::equalizer; }
 
-    void initParamSpecific() {
-        Equalizer eq;
-        eq.set<Equalizer::preset>(0);
-        Parameter::Specific specific;
-        specific.set<Parameter::Specific::equalizer>(eq);
-        setSpecific(specific);
-    }
-
     void CleanUp() { mTags.clear(); }
 };
 
-TEST_P(EqualizerParamTest, SetAndGetPreset) {
-    EXPECT_NO_FATAL_FAILURE(addPresetParam(mParamPresetIndex));
-    SetAndGetEqualizerParameters();
+TEST_P(EqualizerTest, SetAndGetPresetOutOfLowerBound) {
+    addPresetParam(mPresetIndex.second - 1);
+    ASSERT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
 }
 
-TEST_P(EqualizerParamTest, SetAndGetSingleBand) {
-    std::vector<Equalizer::BandLevel> bandLevels;
-    Equalizer::BandLevel bandLevel = {mParamBandIndex, mParamBandLevel};
-    bandLevels.push_back(bandLevel);
-    EXPECT_NO_FATAL_FAILURE(addBandLevelsParam(bandLevels));
-    SetAndGetEqualizerParameters();
+TEST_P(EqualizerTest, SetAndGetPresetOutOfUpperBound) {
+    addPresetParam(mPresetIndex.second + 1);
+    EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetPresetAtLowerBound) {
+    addPresetParam(mPresetIndex.first);
+    EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetPresetAtHigherBound) {
+    addPresetParam(mPresetIndex.second);
+    EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetPresetInBound) {
+    addPresetParam((mPresetIndex.first + mPresetIndex.second) >> 1);
+    EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetBandOutOfLowerBound) {
+    std::vector<Equalizer::BandLevel> bandLevels{{mBandIndex.first - 1, mBandLevel}};
+    addBandLevelsParam(bandLevels);
+    EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetBandOutOfUpperBound) {
+    std::vector<Equalizer::BandLevel> bandLevels{{mBandIndex.second + 1, mBandLevel}};
+    addBandLevelsParam(bandLevels);
+    EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetBandAtLowerBound) {
+    std::vector<Equalizer::BandLevel> bandLevels{{mBandIndex.first, mBandLevel}};
+    addBandLevelsParam(bandLevels);
+    EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetBandAtHigherBound) {
+    std::vector<Equalizer::BandLevel> bandLevels{{mBandIndex.second, mBandLevel}};
+    addBandLevelsParam(bandLevels);
+    EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetBandInBound) {
+    std::vector<Equalizer::BandLevel> bandLevels{
+            {(mBandIndex.first + mBandIndex.second) >> 1, mBandLevel}};
+    addBandLevelsParam(bandLevels);
+    EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetMultiBands) {
+    addPresetParam(mPresetIndex.first);
+    std::vector<Equalizer::BandLevel> bandLevels{
+            {mBandIndex.first, mBandLevel},
+            {mBandIndex.second, mBandLevel},
+            {(mBandIndex.first + mBandIndex.second) >> 1, mBandLevel}};
+    addBandLevelsParam(bandLevels);
+    EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetMultipleParams) {
+    std::vector<Equalizer::BandLevel> bandLevels{
+            {(mBandIndex.first + mBandIndex.second) >> 1, mBandLevel}};
+    addBandLevelsParam(bandLevels);
+    addPresetParam((mPresetIndex.first + mPresetIndex.second) >> 1);
+    EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
 }
 
 INSTANTIATE_TEST_SUITE_P(
-        EqualizerTest, EqualizerParamTest,
-        ::testing::Combine(
-                testing::ValuesIn(android::getAidlHalInstanceNames(IFactory::descriptor)),
-                testing::Range(kPresetIndexRange.first, kPresetIndexRange.second),
-                testing::Range(kBandIndexRange.first, kBandIndexRange.second),
-                testing::Range(kBandLevelRange.first, kBandLevelRange.second)),
-        [](const testing::TestParamInfo<EqualizerParamTest::ParamType>& info) {
-            std::string instance = std::get<PARAM_INSTANCE_NAME>(info.param);
-            std::string presetIdx = std::to_string(std::get<PARAM_PRESET_INDEX>(info.param));
-            std::string bandIdx = std::to_string(std::get<PARAM_BAND_INDEX>(info.param));
+        EqualizerTest, EqualizerTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kEqualizerTypeUUID)),
+                           testing::ValuesIn(kBandLevels)),
+        [](const testing::TestParamInfo<EqualizerTest::ParamType>& info) {
+            auto msSinceEpoch = std::chrono::duration_cast<std::chrono::nanoseconds>(
+                                        std::chrono::system_clock::now().time_since_epoch())
+                                        .count();
+            auto instance = std::get<PARAM_INSTANCE_NAME>(info.param);
             std::string bandLevel = std::to_string(std::get<PARAM_BAND_LEVEL>(info.param));
-
-            std::string name = instance + "_presetIndex" + presetIdx + "_bandIndex" + bandIdx +
-                               "_bandLevel" + bandLevel;
+            std::ostringstream address;
+            address << msSinceEpoch << "_factory_" << instance.first.get();
+            std::string name = address.str() + "_UUID_timeLow_" +
+                               ::android::internal::ToString(instance.second.uuid.timeLow) +
+                               "_timeMid_" +
+                               ::android::internal::ToString(instance.second.uuid.timeMid) +
+                               "_bandLevel_" + bandLevel;
             std::replace_if(
                     name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
             return name;
         });
-
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EqualizerParamTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EqualizerTest);
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
diff --git a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
new file mode 100644
index 0000000..1485657
--- /dev/null
+++ b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/Vintf.h>
+
+#define LOG_TAG "VtsHalLoudnessEnhancerTest"
+
+#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::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kLoudnessEnhancerTypeUUID;
+using aidl::android::hardware::audio::effect::LoudnessEnhancer;
+using aidl::android::hardware::audio::effect::Parameter;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_GAIN_MB };
+using LoudnessEnhancerParamTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>, int>;
+
+// Every int 32 bit value is a valid gain, so testing the corner cases and one regular value.
+// TODO : Update the test values once range/capability is updated by implementation.
+const std::vector<int> kGainMbValues = {std::numeric_limits<int>::min(), 100,
+                                        std::numeric_limits<int>::max()};
+
+class LoudnessEnhancerParamTest : public ::testing::TestWithParam<LoudnessEnhancerParamTestParam>,
+                                  public EffectHelper {
+  public:
+    LoudnessEnhancerParamTest() : mParamGainMb(std::get<PARAM_GAIN_MB>(GetParam())) {
+        std::tie(mFactory, mIdentity) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    }
+
+    void SetUp() override {
+        ASSERT_NE(nullptr, mFactory);
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mIdentity));
+
+        Parameter::Specific specific = getDefaultParamSpecific();
+        Parameter::Common common = EffectHelper::createParamCommon(
+                0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+        IEffect::OpenEffectReturn ret;
+        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+        ASSERT_NE(nullptr, mEffect);
+    }
+    void TearDown() override {
+        ASSERT_NO_FATAL_FAILURE(close(mEffect));
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+    }
+
+    Parameter::Specific getDefaultParamSpecific() {
+        LoudnessEnhancer le = LoudnessEnhancer::make<LoudnessEnhancer::gainMb>(0);
+        Parameter::Specific specific =
+                Parameter::Specific::make<Parameter::Specific::loudnessEnhancer>(le);
+        return specific;
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor::Identity mIdentity;
+    int mParamGainMb = 0;
+
+    void SetAndGetParameters() {
+        for (auto& it : mTags) {
+            auto& tag = it.first;
+            auto& le = it.second;
+
+            // set parameter
+            Parameter expectParam;
+            Parameter::Specific specific;
+            specific.set<Parameter::Specific::loudnessEnhancer>(le);
+            expectParam.set<Parameter::specific>(specific);
+            // All values are valid, set parameter should succeed
+            EXPECT_STATUS(EX_NONE, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+            // get parameter
+            Parameter getParam;
+            Parameter::Id id;
+            LoudnessEnhancer::Id leId;
+            leId.set<LoudnessEnhancer::Id::commonTag>(tag);
+            id.set<Parameter::Id::loudnessEnhancerTag>(leId);
+            EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+
+            EXPECT_EQ(expectParam, getParam) << "\nexpect:" << expectParam.toString()
+                                             << "\ngetParam:" << getParam.toString();
+        }
+    }
+
+    void addGainMbParam(int gainMb) {
+        LoudnessEnhancer le;
+        le.set<LoudnessEnhancer::gainMb>(gainMb);
+        mTags.push_back({LoudnessEnhancer::gainMb, le});
+    }
+
+  private:
+    std::vector<std::pair<LoudnessEnhancer::Tag, LoudnessEnhancer>> mTags;
+    void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(LoudnessEnhancerParamTest, SetAndGetGainMb) {
+    EXPECT_NO_FATAL_FAILURE(addGainMbParam(mParamGainMb));
+    SetAndGetParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        LoudnessEnhancerTest, LoudnessEnhancerParamTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kLoudnessEnhancerTypeUUID)),
+                           testing::ValuesIn(kGainMbValues)),
+        [](const testing::TestParamInfo<LoudnessEnhancerParamTest::ParamType>& info) {
+            auto msSinceEpoch = std::chrono::duration_cast<std::chrono::nanoseconds>(
+                                        std::chrono::system_clock::now().time_since_epoch())
+                                        .count();
+            auto instance = std::get<PARAM_INSTANCE_NAME>(info.param);
+            std::string gainMb = std::to_string(std::get<PARAM_GAIN_MB>(info.param));
+
+            std::ostringstream address;
+            address << msSinceEpoch << "_factory_" << instance.first.get();
+            std::string name = address.str() + "_UUID_timeLow_" +
+                               ::android::internal::ToString(instance.second.uuid.timeLow) +
+                               "_timeMid_" +
+                               ::android::internal::ToString(instance.second.uuid.timeMid) +
+                               "_gainMb" + gainMb;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(LoudnessEnhancerParamTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index e46e5b4..0ca6a58 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -1014,9 +1014,8 @@
         if (mDataPosition == 0) mOnDataStart();
         const size_t dataSize = std::min(mData.size() - mDataPosition, mDataMQ->availableToWrite());
         bool success = mDataMQ->write(mData.data() + mDataPosition, dataSize);
+        bool wrapped = false;
         ALOGE_IF(!success, "data message queue write failed");
-        mDataPosition += dataSize;
-        if (mDataPosition >= mData.size()) mDataPosition = 0;
         mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
 
         uint32_t efState = 0;
@@ -1034,6 +1033,11 @@
                 ALOGE("bad write status: %d", writeStatus.retval);
                 success = false;
             }
+            mDataPosition += writeStatus.reply.written;
+            if (mDataPosition >= mData.size()) {
+                mDataPosition = 0;
+                wrapped = true;
+            }
         }
         if (ret == -EAGAIN || ret == -EINTR) {
             // Spurious wakeup. This normally retries no more than once.
@@ -1042,7 +1046,7 @@
             ALOGE("bad wait status: %d", ret);
             success = false;
         }
-        if (success && mDataPosition == 0) {
+        if (wrapped) {
             success = mOnDataWrap();
         }
         return success;
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index 674dd11..70797a7 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -63,6 +63,31 @@
     generated_headers: ["le_audio_codec_capabilities"],
 }
 
+cc_test {
+    name: "BluetoothLeAudioCodecsProviderTest",
+    srcs: [
+        "aidl_session/BluetoothLeAudioCodecsProvider.cpp",
+        "aidl_session/BluetoothLeAudioCodecsProviderTest.cpp",
+    ],
+    header_libs: [
+        "libxsdc-utils",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "android.hardware.bluetooth.audio-V2-ndk",
+        "libxml2",
+    ],
+    test_suites: [
+        "general-tests",
+    ],
+    test_options: {
+        unit_test: false,
+    },
+    generated_sources: ["le_audio_codec_capabilities"],
+    generated_headers: ["le_audio_codec_capabilities"],
+}
+
 xsd_config {
     name: "le_audio_codec_capabilities",
     srcs: ["le_audio_codec_capabilities/le_audio_codec_capabilities.xsd"],
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
index 855dd28..faebbbf 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
@@ -398,8 +398,11 @@
   }
 
   if (kDefaultOffloadLeAudioCapabilities.empty()) {
+    auto le_audio_offload_setting =
+        BluetoothLeAudioCodecsProvider::ParseFromLeAudioOffloadSettingFile();
     kDefaultOffloadLeAudioCapabilities =
-        BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities();
+        BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities(
+            le_audio_offload_setting);
   }
 
   return kDefaultOffloadLeAudioCapabilities;
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
index bf49270..1dec900 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
@@ -34,20 +34,40 @@
 
 static std::vector<LeAudioCodecCapabilitiesSetting> leAudioCodecCapabilities;
 
-std::vector<LeAudioCodecCapabilitiesSetting>
-BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities() {
-  if (!leAudioCodecCapabilities.empty()) {
-    return leAudioCodecCapabilities;
-  }
+static bool isInvalidFileContent = false;
 
-  const auto le_audio_offload_setting =
+std::optional<setting::LeAudioOffloadSetting>
+BluetoothLeAudioCodecsProvider::ParseFromLeAudioOffloadSettingFile() {
+  if (!leAudioCodecCapabilities.empty() || isInvalidFileContent) {
+    return std::nullopt;
+  }
+  auto le_audio_offload_setting =
       setting::readLeAudioOffloadSetting(kLeAudioCodecCapabilitiesFile);
   if (!le_audio_offload_setting.has_value()) {
     LOG(ERROR) << __func__ << ": Failed to read "
                << kLeAudioCodecCapabilitiesFile;
+  }
+  return le_audio_offload_setting;
+}
+
+std::vector<LeAudioCodecCapabilitiesSetting>
+BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities(
+    const std::optional<setting::LeAudioOffloadSetting>&
+        le_audio_offload_setting) {
+  if (!leAudioCodecCapabilities.empty()) {
+    return leAudioCodecCapabilities;
+  }
+
+  if (!le_audio_offload_setting.has_value()) {
+    LOG(ERROR)
+        << __func__
+        << ": input le_audio_offload_setting content need to be non empty";
     return {};
   }
 
+  ClearLeAudioCodecCapabilities();
+  isInvalidFileContent = true;
+
   std::vector<setting::Scenario> supported_scenarios =
       GetScenarios(le_audio_offload_setting);
   if (supported_scenarios.empty()) {
@@ -79,9 +99,18 @@
 
   leAudioCodecCapabilities =
       ComposeLeAudioCodecCapabilities(supported_scenarios);
+  isInvalidFileContent = leAudioCodecCapabilities.empty();
+
   return leAudioCodecCapabilities;
 }
 
+void BluetoothLeAudioCodecsProvider::ClearLeAudioCodecCapabilities() {
+  leAudioCodecCapabilities.clear();
+  configuration_map_.clear();
+  codec_configuration_map_.clear();
+  strategy_configuration_map_.clear();
+}
+
 std::vector<setting::Scenario> BluetoothLeAudioCodecsProvider::GetScenarios(
     const std::optional<setting::LeAudioOffloadSetting>&
         le_audio_offload_setting) {
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
index 402235f..e879984 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
@@ -31,8 +31,13 @@
 
 class BluetoothLeAudioCodecsProvider {
  public:
+  static std::optional<setting::LeAudioOffloadSetting>
+  ParseFromLeAudioOffloadSettingFile();
   static std::vector<LeAudioCodecCapabilitiesSetting>
-  GetLeAudioCodecCapabilities();
+  GetLeAudioCodecCapabilities(
+      const std::optional<setting::LeAudioOffloadSetting>&
+          le_audio_offload_setting);
+  static void ClearLeAudioCodecCapabilities();
 
  private:
   static inline std::unordered_map<std::string, setting::Configuration>
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp
new file mode 100644
index 0000000..5393cd7
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp
@@ -0,0 +1,373 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include <optional>
+#include <tuple>
+
+#include "BluetoothLeAudioCodecsProvider.h"
+
+using aidl::android::hardware::bluetooth::audio::BluetoothLeAudioCodecsProvider;
+using aidl::android::hardware::bluetooth::audio::
+    LeAudioCodecCapabilitiesSetting;
+using aidl::android::hardware::bluetooth::audio::setting::AudioLocation;
+using aidl::android::hardware::bluetooth::audio::setting::CodecConfiguration;
+using aidl::android::hardware::bluetooth::audio::setting::
+    CodecConfigurationList;
+using aidl::android::hardware::bluetooth::audio::setting::CodecType;
+using aidl::android::hardware::bluetooth::audio::setting::Configuration;
+using aidl::android::hardware::bluetooth::audio::setting::ConfigurationList;
+using aidl::android::hardware::bluetooth::audio::setting::LeAudioOffloadSetting;
+using aidl::android::hardware::bluetooth::audio::setting::Scenario;
+using aidl::android::hardware::bluetooth::audio::setting::ScenarioList;
+using aidl::android::hardware::bluetooth::audio::setting::StrategyConfiguration;
+using aidl::android::hardware::bluetooth::audio::setting::
+    StrategyConfigurationList;
+
+typedef std::tuple<std::vector<ScenarioList>, std::vector<ConfigurationList>,
+                   std::vector<CodecConfigurationList>,
+                   std::vector<StrategyConfigurationList>>
+    OffloadSetting;
+
+// Define valid components for each list
+// Scenario
+static const Scenario kValidScenario(std::make_optional("OneChanStereo_16_1"),
+                                     std::make_optional("OneChanStereo_16_1"));
+// Configuration
+static const Configuration kValidConfigOneChanStereo_16_1(
+    std::make_optional("OneChanStereo_16_1"), std::make_optional("LC3_16k_1"),
+    std::make_optional("STEREO_ONE_CIS_PER_DEVICE"));
+// CodecConfiguration
+static const CodecConfiguration kValidCodecLC3_16k_1(
+    std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3),
+    std::nullopt, std::make_optional(16000), std::make_optional(7500),
+    std::make_optional(30), std::nullopt);
+// StrategyConfiguration
+static const StrategyConfiguration kValidStrategyStereoOneCis(
+    std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
+    std::make_optional(AudioLocation::STEREO), std::make_optional(2),
+    std::make_optional(1));
+static const StrategyConfiguration kValidStrategyStereoTwoCis(
+    std::make_optional("STEREO_TWO_CISES_PER_DEVICE"),
+    std::make_optional(AudioLocation::STEREO), std::make_optional(1),
+    std::make_optional(2));
+static const StrategyConfiguration kValidStrategyMonoOneCis(
+    std::make_optional("MONO_ONE_CIS_PER_DEVICE"),
+    std::make_optional(AudioLocation::MONO), std::make_optional(1),
+    std::make_optional(1));
+
+// Define valid test list built from above valid components
+// Scenario, Configuration, CodecConfiguration, StrategyConfiguration
+static const std::vector<ScenarioList> kValidScenarioList = {
+    ScenarioList(std::vector<Scenario>{kValidScenario})};
+static const std::vector<ConfigurationList> kValidConfigurationList = {
+    ConfigurationList(
+        std::vector<Configuration>{kValidConfigOneChanStereo_16_1})};
+static const std::vector<CodecConfigurationList> kValidCodecConfigurationList =
+    {CodecConfigurationList(
+        std::vector<CodecConfiguration>{kValidCodecLC3_16k_1})};
+static const std::vector<StrategyConfigurationList>
+    kValidStrategyConfigurationList = {
+        StrategyConfigurationList(std::vector<StrategyConfiguration>{
+            kValidStrategyStereoOneCis, kValidStrategyStereoTwoCis,
+            kValidStrategyMonoOneCis})};
+
+class BluetoothLeAudioCodecsProviderTest
+    : public ::testing::TestWithParam<OffloadSetting> {
+ public:
+  static std::vector<OffloadSetting> CreateTestCases(
+      const std::vector<ScenarioList>& scenario_lists,
+      const std::vector<ConfigurationList>& configuration_lists,
+      const std::vector<CodecConfigurationList>& codec_configuration_lists,
+      const std::vector<StrategyConfigurationList>&
+          strategy_configuration_lists) {
+    // make each vector in output test_cases has only one element
+    // to match the input of test params
+    // normally only one vector in input has multiple elements
+    // we just split elements in this vector to several vector
+    std::vector<OffloadSetting> test_cases;
+    for (const auto& scenario_list : scenario_lists) {
+      for (const auto& configuration_list : configuration_lists) {
+        for (const auto& codec_configuration_list : codec_configuration_lists) {
+          for (const auto& strategy_configuration_list :
+               strategy_configuration_lists) {
+            test_cases.push_back(CreateTestCase(
+                scenario_list, configuration_list, codec_configuration_list,
+                strategy_configuration_list));
+          }
+        }
+      }
+    }
+    return test_cases;
+  }
+
+ protected:
+  void Initialize() {
+    BluetoothLeAudioCodecsProvider::ClearLeAudioCodecCapabilities();
+  }
+
+  std::vector<LeAudioCodecCapabilitiesSetting> RunTestCase() {
+    auto& [scenario_lists, configuration_lists, codec_configuration_lists,
+           strategy_configuration_lists] = GetParam();
+    LeAudioOffloadSetting le_audio_offload_setting(
+        scenario_lists, configuration_lists, codec_configuration_lists,
+        strategy_configuration_lists);
+    auto le_audio_codec_capabilities =
+        BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities(
+            std::make_optional(le_audio_offload_setting));
+    return le_audio_codec_capabilities;
+  }
+
+ private:
+  static inline OffloadSetting CreateTestCase(
+      const ScenarioList& scenario_list,
+      const ConfigurationList& configuration_list,
+      const CodecConfigurationList& codec_configuration_list,
+      const StrategyConfigurationList& strategy_configuration_list) {
+    return std::make_tuple(
+        std::vector<ScenarioList>{scenario_list},
+        std::vector<ConfigurationList>{configuration_list},
+        std::vector<CodecConfigurationList>{codec_configuration_list},
+        std::vector<StrategyConfigurationList>{strategy_configuration_list});
+  }
+};
+
+class GetScenariosTest : public BluetoothLeAudioCodecsProviderTest {
+ public:
+  static std::vector<ScenarioList> CreateInvalidScenarios() {
+    std::vector<ScenarioList> invalid_scenario_test_cases;
+    invalid_scenario_test_cases.push_back(ScenarioList(std::vector<Scenario>{
+        Scenario(std::nullopt, std::make_optional("OneChanStereo_16_1"))}));
+
+    invalid_scenario_test_cases.push_back(ScenarioList(std::vector<Scenario>{
+        Scenario(std::make_optional("OneChanStereo_16_1"), std::nullopt)}));
+
+    invalid_scenario_test_cases.push_back(ScenarioList(
+        std::vector<Scenario>{Scenario(std::nullopt, std::nullopt)}));
+
+    invalid_scenario_test_cases.push_back(
+        ScenarioList(std::vector<Scenario>{}));
+
+    return invalid_scenario_test_cases;
+  }
+};
+
+TEST_P(GetScenariosTest, InvalidScenarios) {
+  Initialize();
+  auto le_audio_codec_capabilities = RunTestCase();
+  ASSERT_TRUE(le_audio_codec_capabilities.empty());
+}
+
+class UpdateConfigurationsToMapTest
+    : public BluetoothLeAudioCodecsProviderTest {
+ public:
+  static std::vector<ConfigurationList> CreateInvalidConfigurations() {
+    std::vector<ConfigurationList> invalid_configuration_test_cases;
+    invalid_configuration_test_cases.push_back(
+        ConfigurationList(std::vector<Configuration>{
+            Configuration(std::nullopt, std::make_optional("LC3_16k_1"),
+                          std::make_optional("STEREO_ONE_CIS_PER_DEVICE"))}));
+
+    invalid_configuration_test_cases.push_back(
+        ConfigurationList(std::vector<Configuration>{Configuration(
+            std::make_optional("OneChanStereo_16_1"), std::nullopt,
+            std::make_optional("STEREO_ONE_CIS_PER_DEVICE"))}));
+
+    invalid_configuration_test_cases.push_back(
+        ConfigurationList(std::vector<Configuration>{
+            Configuration(std::make_optional("OneChanStereo_16_1"),
+                          std::make_optional("LC3_16k_1"), std::nullopt)}));
+
+    invalid_configuration_test_cases.push_back(
+        ConfigurationList(std::vector<Configuration>{}));
+
+    return invalid_configuration_test_cases;
+  }
+};
+
+TEST_P(UpdateConfigurationsToMapTest, InvalidConfigurations) {
+  Initialize();
+  auto le_audio_codec_capabilities = RunTestCase();
+  ASSERT_TRUE(le_audio_codec_capabilities.empty());
+}
+
+class UpdateCodecConfigurationsToMapTest
+    : public BluetoothLeAudioCodecsProviderTest {
+ public:
+  static std::vector<CodecConfigurationList>
+  CreateInvalidCodecConfigurations() {
+    std::vector<CodecConfigurationList> invalid_codec_configuration_test_cases;
+    invalid_codec_configuration_test_cases.push_back(CodecConfigurationList(
+        std::vector<CodecConfiguration>{CodecConfiguration(
+            std::nullopt, std::make_optional(CodecType::LC3), std::nullopt,
+            std::make_optional(16000), std::make_optional(7500),
+            std::make_optional(30), std::nullopt)}));
+
+    invalid_codec_configuration_test_cases.push_back(CodecConfigurationList(
+        std::vector<CodecConfiguration>{CodecConfiguration(
+            std::make_optional("LC3_16k_1"), std::nullopt, std::nullopt,
+            std::make_optional(16000), std::make_optional(7500),
+            std::make_optional(30), std::nullopt)}));
+
+    invalid_codec_configuration_test_cases.push_back(CodecConfigurationList(
+        std::vector<CodecConfiguration>{CodecConfiguration(
+            std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3),
+            std::nullopt, std::nullopt, std::make_optional(7500),
+            std::make_optional(30), std::nullopt)}));
+
+    invalid_codec_configuration_test_cases.push_back(CodecConfigurationList(
+        std::vector<CodecConfiguration>{CodecConfiguration(
+            std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3),
+            std::nullopt, std::make_optional(16000), std::nullopt,
+            std::make_optional(30), std::nullopt)}));
+
+    invalid_codec_configuration_test_cases.push_back(CodecConfigurationList(
+        std::vector<CodecConfiguration>{CodecConfiguration(
+            std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3),
+            std::nullopt, std::make_optional(16000), std::make_optional(7500),
+            std::nullopt, std::nullopt)}));
+
+    invalid_codec_configuration_test_cases.push_back(
+        CodecConfigurationList(std::vector<CodecConfiguration>{}));
+
+    return invalid_codec_configuration_test_cases;
+  }
+};
+
+TEST_P(UpdateCodecConfigurationsToMapTest, InvalidCodecConfigurations) {
+  Initialize();
+  auto le_audio_codec_capabilities = RunTestCase();
+  ASSERT_TRUE(le_audio_codec_capabilities.empty());
+}
+
+class UpdateStrategyConfigurationsToMapTest
+    : public BluetoothLeAudioCodecsProviderTest {
+ public:
+  static std::vector<StrategyConfigurationList>
+  CreateInvalidStrategyConfigurations() {
+    std::vector<StrategyConfigurationList>
+        invalid_strategy_configuration_test_cases;
+    invalid_strategy_configuration_test_cases.push_back(
+        StrategyConfigurationList(
+            std::vector<StrategyConfiguration>{StrategyConfiguration(
+                std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
+                std::make_optional(AudioLocation::STEREO),
+                std::make_optional(2), std::make_optional(2))}));
+
+    invalid_strategy_configuration_test_cases.push_back(
+        StrategyConfigurationList(
+            std::vector<StrategyConfiguration>{StrategyConfiguration(
+                std::make_optional("MONO_ONE_CIS_PER_DEVICE"),
+                std::make_optional(AudioLocation::STEREO),
+                std::make_optional(2), std::make_optional(2))}));
+
+    invalid_strategy_configuration_test_cases.push_back(
+        StrategyConfigurationList(
+            std::vector<StrategyConfiguration>{StrategyConfiguration(
+                std::nullopt, std::make_optional(AudioLocation::STEREO),
+                std::make_optional(2), std::make_optional(1))}));
+
+    invalid_strategy_configuration_test_cases.push_back(
+        StrategyConfigurationList(
+            std::vector<StrategyConfiguration>{StrategyConfiguration(
+                std::make_optional("STEREO_ONE_CIS_PER_DEVICE"), std::nullopt,
+                std::make_optional(2), std::make_optional(1))}));
+
+    invalid_strategy_configuration_test_cases.push_back(
+        StrategyConfigurationList(
+            std::vector<StrategyConfiguration>{StrategyConfiguration(
+                std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
+                std::make_optional(AudioLocation::STEREO), std::nullopt,
+                std::make_optional(1))}));
+
+    invalid_strategy_configuration_test_cases.push_back(
+        StrategyConfigurationList(
+            std::vector<StrategyConfiguration>{StrategyConfiguration(
+                std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
+                std::make_optional(AudioLocation::STEREO),
+                std::make_optional(2), std::nullopt)}));
+
+    invalid_strategy_configuration_test_cases.push_back(
+        StrategyConfigurationList(std::vector<StrategyConfiguration>{}));
+
+    return invalid_strategy_configuration_test_cases;
+  }
+};
+
+TEST_P(UpdateStrategyConfigurationsToMapTest, InvalidStrategyConfigurations) {
+  Initialize();
+  auto le_audio_codec_capabilities = RunTestCase();
+  ASSERT_TRUE(le_audio_codec_capabilities.empty());
+}
+
+class ComposeLeAudioCodecCapabilitiesTest
+    : public BluetoothLeAudioCodecsProviderTest {
+ public:
+};
+
+TEST_P(ComposeLeAudioCodecCapabilitiesTest, CodecCapabilitiesNotEmpty) {
+  Initialize();
+  auto le_audio_codec_capabilities = RunTestCase();
+  ASSERT_TRUE(!le_audio_codec_capabilities.empty());
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GetScenariosTest);
+INSTANTIATE_TEST_SUITE_P(
+    BluetoothLeAudioCodecsProviderTest, GetScenariosTest,
+    ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
+        GetScenariosTest::CreateInvalidScenarios(), kValidConfigurationList,
+        kValidCodecConfigurationList, kValidStrategyConfigurationList)));
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UpdateConfigurationsToMapTest);
+INSTANTIATE_TEST_SUITE_P(
+    BluetoothLeAudioCodecsProviderTest, UpdateConfigurationsToMapTest,
+    ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
+        kValidScenarioList,
+        UpdateConfigurationsToMapTest::CreateInvalidConfigurations(),
+        kValidCodecConfigurationList, kValidStrategyConfigurationList)));
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    UpdateCodecConfigurationsToMapTest);
+INSTANTIATE_TEST_SUITE_P(
+    BluetoothLeAudioCodecsProviderTest, UpdateCodecConfigurationsToMapTest,
+    ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
+        kValidScenarioList, kValidConfigurationList,
+        UpdateCodecConfigurationsToMapTest::CreateInvalidCodecConfigurations(),
+        kValidStrategyConfigurationList)));
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    UpdateStrategyConfigurationsToMapTest);
+INSTANTIATE_TEST_SUITE_P(
+    BluetoothLeAudioCodecsProviderTest, UpdateStrategyConfigurationsToMapTest,
+    ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
+        kValidScenarioList, kValidConfigurationList,
+        kValidCodecConfigurationList,
+        UpdateStrategyConfigurationsToMapTest::
+            CreateInvalidStrategyConfigurations())));
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    ComposeLeAudioCodecCapabilitiesTest);
+INSTANTIATE_TEST_SUITE_P(
+    BluetoothLeAudioCodecsProviderTest, ComposeLeAudioCodecCapabilitiesTest,
+    ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
+        kValidScenarioList, kValidConfigurationList,
+        kValidCodecConfigurationList, kValidStrategyConfigurationList)));
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/camera/README.md b/camera/README.md
index 8ce3352..25badfd 100644
--- a/camera/README.md
+++ b/camera/README.md
@@ -10,3 +10,8 @@
 
 More complete information about the Android camera HAL and subsystem can be found at
 [source.android.com](http://source.android.com/devices/camera/index.html).
+
+### AIDL Camera HAL Interfaces
+
+The AIDL Camera HAL interfaces can be found in the respective <interface>/aidl
+directories.
diff --git a/camera/provider/README.md b/camera/provider/README.md
index 0718fb1..7666a58 100644
--- a/camera/provider/README.md
+++ b/camera/provider/README.md
@@ -35,3 +35,9 @@
 First HIDL version of the camara provider HAL callback interface, closely
 matching the feature set and operation of the pre-HIDL camera HAL module
 callbacks v2.4.
+
+### AIDL Camera HAL Default Implementation ###
+
+The default implementation can be found at
+$ANDROID_BUILD_TOP/hardware/google/camera/common/hal/aidl_service and
+$ANDROID_BUILD_TOP/hardware/google/camera/devices/EmulatedCamera
diff --git a/common/aidl/Android.bp b/common/aidl/Android.bp
index 43f8c4d..7f6890c 100644
--- a/common/aidl/Android.bp
+++ b/common/aidl/Android.bp
@@ -37,6 +37,7 @@
             min_sdk_version: "29",
         },
     },
+    frozen: true,
     versions: [
         "1",
         "2",
diff --git a/common/fmq/aidl/Android.bp b/common/fmq/aidl/Android.bp
index a85597c..95fcc41 100644
--- a/common/fmq/aidl/Android.bp
+++ b/common/fmq/aidl/Android.bp
@@ -37,5 +37,6 @@
             min_sdk_version: "29",
         },
     },
+    frozen: true,
     versions: ["1"],
 }
diff --git a/compatibility_matrices/Android.bp b/compatibility_matrices/Android.bp
index 4dc3f6c..37c2820 100644
--- a/compatibility_matrices/Android.bp
+++ b/compatibility_matrices/Android.bp
@@ -28,7 +28,6 @@
         "compatibility_matrix.3.xml",
     ],
     kernel_configs: [
-        "kernel_config_p_4.9",
         "kernel_config_p_4.14",
     ],
 }
@@ -40,7 +39,6 @@
         "compatibility_matrix.4.xml",
     ],
     kernel_configs: [
-        "kernel_config_q_4.9",
         "kernel_config_q_4.14",
         "kernel_config_q_4.19",
     ],
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index bbf05cc..7110ac0 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -197,7 +197,7 @@
             <regex-instance>[^/]+/[0-9]+</regex-instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" optional="true" updatable-via-apex="true">
         <name>android.hardware.camera.provider</name>
         <version>1</version>
         <interface>
diff --git a/fastboot/aidl/default/Android.bp b/fastboot/aidl/default/Android.bp
index 5cd4542..0c96b33 100644
--- a/fastboot/aidl/default/Android.bp
+++ b/fastboot/aidl/default/Android.bp
@@ -22,16 +22,20 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
-cc_library {
-    name: "android.hardware.fastboot-impl-mock",
-    recovery: true,
+cc_binary {
+    name: "android.hardware.fastboot-service.example_recovery",
+    init_rc: ["android.hardware.fastboot-service.example_recovery.rc"],
+    vintf_fragments: ["android.hardware.fastboot-service.example.xml"],
+    recovery_available: true,
     srcs: [
         "Fastboot.cpp",
+        "main.cpp",
     ],
     relative_install_path: "hw",
     shared_libs: [
         "libbase",
         "libbinder_ndk",
+        "liblog",
         "libutils",
         "libcutils",
         "android.hardware.fastboot-V1-ndk",
diff --git a/fastboot/aidl/default/android.hardware.fastboot-service.example.xml b/fastboot/aidl/default/android.hardware.fastboot-service.example.xml
new file mode 100644
index 0000000..9490f98
--- /dev/null
+++ b/fastboot/aidl/default/android.hardware.fastboot-service.example.xml
@@ -0,0 +1,8 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.fastboot</name>
+        <version>1</version>
+        <fqname>IFastboot/default</fqname>
+    </hal>
+</manifest>
+
diff --git a/fastboot/aidl/default/android.hardware.fastboot-service.example_recovery.rc b/fastboot/aidl/default/android.hardware.fastboot-service.example_recovery.rc
new file mode 100644
index 0000000..5d4ee13
--- /dev/null
+++ b/fastboot/aidl/default/android.hardware.fastboot-service.example_recovery.rc
@@ -0,0 +1,6 @@
+service vendor.fastboot-default /system/bin/hw/android.hardware.fastboot-service.example_recovery
+    class hal
+    seclabel u:r:hal_fastboot_default:s0
+    user system
+    group system
+    interface aidl android.hardware.fastboot.IFastboot/default
diff --git a/fastboot/aidl/default/main.cpp b/fastboot/aidl/default/main.cpp
new file mode 100644
index 0000000..1b1b41d
--- /dev/null
+++ b/fastboot/aidl/default/main.cpp
@@ -0,0 +1,38 @@
+
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include "Fastboot.h"
+
+using aidl::android::hardware::fastboot::Fastboot;
+using aidl::android::hardware::fastboot::IFastboot;
+
+int main(int, char* argv[]) {
+    android::base::InitLogging(argv, android::base::KernelLogger);
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+    std::shared_ptr<IFastboot> service = ndk::SharedRefBase::make<Fastboot>();
+
+    const std::string instance = std::string(IFastboot::descriptor) + "/default";
+    auto status = AServiceManager_addService(service->asBinder().get(), instance.c_str());
+    CHECK_EQ(status, STATUS_OK) << "Failed to add service " << instance << " " << status;
+    LOG(INFO) << "IFastboot AIDL service running...";
+
+    ABinderProcess_joinThreadPool();
+    return EXIT_FAILURE;  // should not reach
+}
diff --git a/fastboot/aidl/fastbootshim/Android.bp b/fastboot/aidl/fastbootshim/Android.bp
new file mode 100644
index 0000000..c843c12
--- /dev/null
+++ b/fastboot/aidl/fastbootshim/Android.bp
@@ -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.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_defaults {
+    name: "libfastbootshim_defaults",
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    static_libs: [
+        "android.hardware.fastboot-V1-ndk",
+        "android.hardware.fastboot@1.0",
+        "android.hardware.fastboot@1.1",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libcutils",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+    ],
+}
+
+// Shim library that wraps a HIDL Fastboot object into an AIDL Fastboot object.
+cc_library_static {
+    name: "libfastbootshim",
+    defaults: ["libfastbootshim_defaults"],
+    recovery_available: true,
+    srcs: [
+        "fastbootshim.cpp",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+}
diff --git a/fastboot/aidl/fastbootshim/fastbootshim.cpp b/fastboot/aidl/fastbootshim/fastbootshim.cpp
new file mode 100644
index 0000000..4ab67f3
--- /dev/null
+++ b/fastboot/aidl/fastbootshim/fastbootshim.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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 <fastbootshim.h>
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::Void;
+using ::android::hardware::fastboot::V1_0::FileSystemType;
+using ::android::hardware::fastboot::V1_0::Result;
+using ::android::hardware::fastboot::V1_0::Status;
+
+using ndk::ScopedAStatus;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace fastboot {
+ScopedAStatus ResultToAStatus(Result result) {
+    switch (result.status) {
+        case Status::SUCCESS:
+            return ScopedAStatus::ok();
+        case Status::NOT_SUPPORTED:
+            return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+        case Status::INVALID_ARGUMENT:
+            return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        case Status::FAILURE_UNKNOWN:
+            return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                    BnFastboot::FAILURE_UNKNOWN, ("Error " + std::string(result.message)).c_str());
+    }
+    return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+            BnFastboot::FAILURE_UNKNOWN,
+            ("Unrecognized status value " + toString(result.status)).c_str());
+}
+FastbootShim::FastbootShim(const sp<HidlFastboot>& service) : service_(service) {}
+
+ScopedAStatus FastbootShim::getPartitionType(const std::string& in_partitionName,
+                                             FileSystemType* _aidl_return) {
+    Result out_result = {Status::FAILURE_UNKNOWN, ""};
+    if (in_partitionName.empty()) {
+        return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                           "Invalid partition name");
+    }
+    const hidl_string partition = in_partitionName;
+    auto ret = service_->getPartitionType(partition, [&](auto type, auto& result) {
+        out_result = result;
+        if (out_result.status != Status::SUCCESS) return;
+        *_aidl_return = static_cast<aidl::android::hardware::fastboot::FileSystemType>(type);
+    });
+    return ResultToAStatus(out_result);
+}
+
+ScopedAStatus FastbootShim::doOemCommand(const std::string& in_oemCmd, std::string* _aidl_return) {
+    Result out_result = {Status::FAILURE_UNKNOWN, ""};
+    *_aidl_return = "";
+    if (in_oemCmd.empty()) {
+        return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, "Invalid command");
+    }
+    const hidl_string oemCmdArgs = in_oemCmd;
+    auto ret = service_->doOemCommand(oemCmdArgs, [&](auto& result) {
+        out_result = result;
+        if (out_result.status != Status::SUCCESS) return;
+        *_aidl_return = std::string(result.message.c_str());
+    });
+    return ResultToAStatus(out_result);
+}
+
+ScopedAStatus FastbootShim::getVariant(std::string* _aidl_return) {
+    Result out_result = {Status::FAILURE_UNKNOWN, ""};
+    *_aidl_return = "";
+    auto ret = service_->getVariant([&](auto& variant, auto& result) {
+        out_result = result;
+        if (out_result.status != Status::SUCCESS) return;
+        *_aidl_return = std::string(variant.c_str());
+    });
+    return ResultToAStatus(out_result);
+}
+
+ScopedAStatus FastbootShim::getOffModeChargeState(bool* _aidl_return) {
+    Result out_result = {Status::FAILURE_UNKNOWN, ""};
+    *_aidl_return = false;
+    auto ret = service_->getOffModeChargeState([&](auto state, auto& result) {
+        out_result = result;
+        if (out_result.status != Status::SUCCESS) return;
+        *_aidl_return = state;
+    });
+    return ResultToAStatus(out_result);
+}
+
+ScopedAStatus FastbootShim::getBatteryVoltageFlashingThreshold(int32_t* _aidl_return) {
+    Result out_result = {Status::FAILURE_UNKNOWN, ""};
+    *_aidl_return = 0;
+    auto ret = service_->getBatteryVoltageFlashingThreshold([&](auto batteryVoltage, auto& result) {
+        out_result = result;
+        if (out_result.status != Status::SUCCESS) return;
+        *_aidl_return = batteryVoltage;
+    });
+    return ResultToAStatus(out_result);
+}
+
+ScopedAStatus FastbootShim::doOemSpecificErase() {
+    Result out_result = {Status::FAILURE_UNKNOWN, ""};
+    auto ret = service_->doOemSpecificErase([&](auto& result) { out_result = result; });
+    return ResultToAStatus(out_result);
+}
+
+}  // namespace fastboot
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/fastboot/aidl/fastbootshim/include/fastbootshim.h b/fastboot/aidl/fastbootshim/include/fastbootshim.h
new file mode 100644
index 0000000..410a03e
--- /dev/null
+++ b/fastboot/aidl/fastbootshim/include/fastbootshim.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/fastboot/BnFastboot.h>
+#include <android/hardware/fastboot/1.1/IFastboot.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace fastboot {
+// Shim that wraps HIDL IFastboot with AIDL BnFastboot
+class FastbootShim : public BnFastboot {
+    using HidlFastboot = ::android::hardware::fastboot::V1_1::IFastboot;
+
+  public:
+    explicit FastbootShim(const ::android::sp<HidlFastboot>& service);
+    ::ndk::ScopedAStatus doOemCommand(const std::string& in_oemCmd,
+                                      std::string* _aidl_return) override;
+    ::ndk::ScopedAStatus doOemSpecificErase() override;
+    ::ndk::ScopedAStatus getBatteryVoltageFlashingThreshold(int32_t* _aidl_return) override;
+    ::ndk::ScopedAStatus getOffModeChargeState(bool* _aidl_return) override;
+    ::ndk::ScopedAStatus getPartitionType(
+            const std::string& in_partitionName,
+            ::aidl::android::hardware::fastboot::FileSystemType* _aidl_return) override;
+    ::ndk::ScopedAStatus getVariant(std::string* _aidl_return) override;
+
+  private:
+    ::android::sp<HidlFastboot> service_;
+};
+
+}  // namespace fastboot
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/graphics/allocator/aidl/Android.bp b/graphics/allocator/aidl/Android.bp
index 272ab48..6dc983c 100644
--- a/graphics/allocator/aidl/Android.bp
+++ b/graphics/allocator/aidl/Android.bp
@@ -14,9 +14,11 @@
         enabled: true,
         support_system_process: true,
     },
+    vndk_use_version: "1",
     srcs: ["android/hardware/graphics/allocator/*.aidl"],
     imports: [
         "android.hardware.common-V2",
+        "android.hardware.graphics.common-V3",
     ],
     stability: "vintf",
     backend: {
diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp
index 40a575d..3fddc9f 100644
--- a/graphics/common/aidl/Android.bp
+++ b/graphics/common/aidl/Android.bp
@@ -40,6 +40,7 @@
             min_sdk_version: "29",
         },
     },
+    frozen: true,
     versions_with_info: [
         {
             version: "1",
diff --git a/graphics/composer/aidl/Android.bp b/graphics/composer/aidl/Android.bp
index 9b88d98..56e6ed2 100644
--- a/graphics/composer/aidl/Android.bp
+++ b/graphics/composer/aidl/Android.bp
@@ -31,6 +31,7 @@
         enabled: true,
         support_system_process: true,
     },
+    frozen: true,
     srcs: [
         "android/hardware/graphics/composer3/*.aidl",
     ],
diff --git a/identity/aidl/Android.bp b/identity/aidl/Android.bp
index f568f7a..2090473 100644
--- a/identity/aidl/Android.bp
+++ b/identity/aidl/Android.bp
@@ -15,10 +15,10 @@
     ],
     imports: [
         "android.hardware.keymaster-V3",
-        "android.hardware.security.keymint-V3",
+        "android.hardware.security.rkp-V3",
     ],
     stability: "vintf",
-    frozen: false,
+    frozen: true,
     backend: {
         java: {
             platform_apis: true,
@@ -32,28 +32,28 @@
             version: "1",
             imports: [
                 "android.hardware.keymaster-V3",
-                "android.hardware.security.keymint-V1",
+                "android.hardware.security.rkp-V1",
             ],
         },
         {
             version: "2",
             imports: [
                 "android.hardware.keymaster-V3",
-                "android.hardware.security.keymint-V1",
+                "android.hardware.security.rkp-V1",
             ],
         },
         {
             version: "3",
             imports: [
                 "android.hardware.keymaster-V3",
-                "android.hardware.security.keymint-V1",
+                "android.hardware.security.rkp-V1",
             ],
         },
         {
             version: "4",
             imports: [
                 "android.hardware.keymaster-V3",
-                "android.hardware.security.keymint-V2",
+                "android.hardware.security.rkp-V3",
             ],
         },
 
@@ -67,20 +67,20 @@
 cc_defaults {
     name: "identity_use_latest_hal_aidl_ndk_static",
     static_libs: [
-        "android.hardware.identity-V5-ndk",
+        "android.hardware.identity-V4-ndk",
     ],
 }
 
 cc_defaults {
     name: "identity_use_latest_hal_aidl_ndk_shared",
     shared_libs: [
-        "android.hardware.identity-V5-ndk",
+        "android.hardware.identity-V4-ndk",
     ],
 }
 
 cc_defaults {
     name: "identity_use_latest_hal_aidl_cpp_static",
     static_libs: [
-        "android.hardware.identity-V5-cpp",
+        "android.hardware.identity-V4-cpp",
     ],
 }
diff --git a/identity/aidl/default/Android.bp b/identity/aidl/default/Android.bp
index a57875a..7bc3c8d 100644
--- a/identity/aidl/default/Android.bp
+++ b/identity/aidl/default/Android.bp
@@ -45,6 +45,7 @@
         "libpuresoftkeymasterdevice",
         "android.hardware.identity-support-lib",
         "android.hardware.keymaster-V3-ndk",
+        "android.hardware.security.rkp-V3-ndk",
     ],
 }
 
@@ -112,6 +113,7 @@
         "android.hardware.keymaster-V3-ndk",
         "android.hardware.identity-libeic-hal-common",
         "android.hardware.identity-libeic-library",
+        "android.hardware.security.rkp-V3-ndk",
     ],
     srcs: [
         "service.cpp",
diff --git a/identity/aidl/default/EicOpsImpl.cc b/identity/aidl/default/EicOpsImpl.cc
index b6d324f..803df64 100644
--- a/identity/aidl/default/EicOpsImpl.cc
+++ b/identity/aidl/default/EicOpsImpl.cc
@@ -489,7 +489,7 @@
 }
 
 bool eicOpsEcdh(const uint8_t publicKey[EIC_P256_PUB_KEY_SIZE],
-                const uint8_t privateKey[EIC_P256_PUB_KEY_SIZE],
+                const uint8_t privateKey[EIC_P256_PRIV_KEY_SIZE],
                 uint8_t sharedSecret[EIC_P256_COORDINATE_SIZE]) {
     vector<uint8_t> pubKeyVec(EIC_P256_PUB_KEY_SIZE + 1);
     pubKeyVec[0] = 0x04;
diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp
index 54bf887..5e303bb 100644
--- a/identity/aidl/vts/Android.bp
+++ b/identity/aidl/vts/Android.bp
@@ -39,6 +39,8 @@
         "libcrypto",
     ],
     static_libs: [
+        "android.hardware.security.rkp-V3-cpp",
+        "android.hardware.security.rkp-V3-ndk",
         "android.hardware.security.secureclock-V1-ndk",
         "libcppbor_external",
         "libcppcose_rkp",
diff --git a/memtrack/aidl/Android.bp b/memtrack/aidl/Android.bp
index 79effcb..0d1c241 100644
--- a/memtrack/aidl/Android.bp
+++ b/memtrack/aidl/Android.bp
@@ -39,5 +39,6 @@
             },
         },
     },
+    frozen: true,
     versions: ["1"],
 }
diff --git a/oemlock/aidl/default/OemLock.cpp b/oemlock/aidl/default/OemLock.cpp
index 646b532..234a8a9 100644
--- a/oemlock/aidl/default/OemLock.cpp
+++ b/oemlock/aidl/default/OemLock.cpp
@@ -24,29 +24,31 @@
 // Methods from ::android::hardware::oemlock::IOemLock follow.
 
 ::ndk::ScopedAStatus OemLock::getName(std::string *out_name) {
-    (void)out_name;
+    *out_name = "SomeCoolName";
     return ::ndk::ScopedAStatus::ok();
 }
 
 ::ndk::ScopedAStatus OemLock::setOemUnlockAllowedByCarrier(bool in_allowed, const std::vector<uint8_t> &in_signature, OemLockSecureStatus *_aidl_return) {
-    (void)in_allowed;
+    // Default impl doesn't care about a valid vendor signature
     (void)in_signature;
-    (void)_aidl_return;
+
+    mAllowedByCarrier = in_allowed;
+    *_aidl_return = OemLockSecureStatus::OK;
     return ::ndk::ScopedAStatus::ok();
 }
 
 ::ndk::ScopedAStatus OemLock::isOemUnlockAllowedByCarrier(bool *out_allowed) {
-    (void)out_allowed;
+    *out_allowed = mAllowedByCarrier;
     return ::ndk::ScopedAStatus::ok();
 }
 
 ::ndk::ScopedAStatus OemLock::setOemUnlockAllowedByDevice(bool in_allowed) {
-    (void)in_allowed;
+    mAllowedByDevice = in_allowed;
     return ::ndk::ScopedAStatus::ok();
 }
 
 ::ndk::ScopedAStatus OemLock::isOemUnlockAllowedByDevice(bool *out_allowed) {
-    (void)out_allowed;
+    *out_allowed = mAllowedByDevice;
     return ::ndk::ScopedAStatus::ok();
 }
 
diff --git a/oemlock/aidl/default/OemLock.h b/oemlock/aidl/default/OemLock.h
index b0df414..9dff21a 100644
--- a/oemlock/aidl/default/OemLock.h
+++ b/oemlock/aidl/default/OemLock.h
@@ -36,6 +36,10 @@
     ::ndk::ScopedAStatus isOemUnlockAllowedByDevice(bool* out_allowed) override;
     ::ndk::ScopedAStatus setOemUnlockAllowedByCarrier(bool in_allowed, const std::vector<uint8_t>& in_signature, OemLockSecureStatus* _aidl_return) override;
     ::ndk::ScopedAStatus setOemUnlockAllowedByDevice(bool in_allowed) override;
+
+  private:
+    bool mAllowedByCarrier = false;
+    bool mAllowedByDevice = false;
 };
 
 } // namespace oemlock
diff --git a/power/stats/aidl/OWNERS b/power/stats/aidl/OWNERS
index b290b49..e0d66d7 100644
--- a/power/stats/aidl/OWNERS
+++ b/power/stats/aidl/OWNERS
@@ -1,3 +1,4 @@
-bsschwar@google.com
+darrenhsu@google.com
+joaodias@google.com
 krossmo@google.com
-tstrudel@google.com
+vincentwang@google.com
diff --git a/radio/aidl/vts/radio_aidl_hal_utils.cpp b/radio/aidl/vts/radio_aidl_hal_utils.cpp
index efc4f26..6ed8e7d 100644
--- a/radio/aidl/vts/radio_aidl_hal_utils.cpp
+++ b/radio/aidl/vts/radio_aidl_hal_utils.cpp
@@ -92,6 +92,10 @@
     return testing::checkSubstringInCommandOutput("getprop persist.radio.multisim.config", "dsds");
 }
 
+bool isDsDaEnabled() {
+    return testing::checkSubstringInCommandOutput("getprop persist.radio.multisim.config", "dsda");
+}
+
 bool isTsTsEnabled() {
     return testing::checkSubstringInCommandOutput("getprop persist.radio.multisim.config", "tsts");
 }
diff --git a/radio/aidl/vts/radio_aidl_hal_utils.h b/radio/aidl/vts/radio_aidl_hal_utils.h
index 47976b9..8170a01 100644
--- a/radio/aidl/vts/radio_aidl_hal_utils.h
+++ b/radio/aidl/vts/radio_aidl_hal_utils.h
@@ -104,6 +104,11 @@
 bool isDsDsEnabled();
 
 /*
+ * Check if device is in DSDA (Dual SIM Dual Active).
+ */
+bool isDsDaEnabled();
+
+/*
  * Check if device is in TSTS (Triple SIM Triple Standby).
  */
 bool isTsTsEnabled();
diff --git a/radio/aidl/vts/radio_config_test.cpp b/radio/aidl/vts/radio_config_test.cpp
index 258b172..c979d28 100644
--- a/radio/aidl/vts/radio_config_test.cpp
+++ b/radio/aidl/vts/radio_config_test.cpp
@@ -176,7 +176,7 @@
         slotPortMapping.physicalSlotId = -1;
         slotPortMapping.portId = -1;
         std::vector<SlotPortMapping> slotPortMappingList = {slotPortMapping};
-        if (isDsDsEnabled()) {
+        if (isDsDsEnabled() || isDsDaEnabled()) {
             slotPortMappingList.push_back(slotPortMapping);
         } else if (isTsTsEnabled()) {
             slotPortMappingList.push_back(slotPortMapping);
@@ -252,7 +252,7 @@
         }
         if (isSsSsEnabled()) {
             EXPECT_EQ(1, simCount);
-        } else if (isDsDsEnabled()) {
+        } else if (isDsDsEnabled() || isDsDaEnabled()) {
             EXPECT_EQ(2, simCount);
         } else if (isTsTsEnabled()) {
             EXPECT_EQ(3, simCount);
diff --git a/security/keymint/README.md b/security/keymint/README.md
new file mode 100644
index 0000000..54647af
--- /dev/null
+++ b/security/keymint/README.md
@@ -0,0 +1,10 @@
+# KeyMint HAL
+
+This directory contains the HAL definition for KeyMint. KeyMint provides
+cryptographic services in a hardware-isolated environment.
+
+Note that the `IRemotelyProvisionedComponent` HAL, and it's associated types,
+used to also be defined in this directory. As of Android U, this HAL has been
+moved to a different directory (../rkp). This move is ABI compatible, as the
+interfaces have been maintained. The build is split so that the generated
+code may be built with different options.
diff --git a/security/keymint/TEST_MAPPING b/security/keymint/TEST_MAPPING
index 9ce5e9b..4ab60b6 100644
--- a/security/keymint/TEST_MAPPING
+++ b/security/keymint/TEST_MAPPING
@@ -1,6 +1,9 @@
 {
   "presubmit": [
     {
+      "name": "VtsAidlKeyMintTargetTest"
+    },
+    {
       "name": "VtsHalRemotelyProvisionedComponentTargetTest"
     }
   ]
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/.hash b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/.hash
index b712a52..3a6d415 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/.hash
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/.hash
@@ -1 +1,2 @@
 976674616001f714f4a4df49ee45f548de828524
+cd862ae2e49b54fc965dc1b99c218eb729c93bb1
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/.hash b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/.hash
index 69ba9a6..b4c2b78 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/.hash
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/.hash
@@ -1 +1,2 @@
 207c9f218b9b9e4e74ff5232eb16511eca9d7d2e
+70c734fbd5cac5b36676d66d8d9aa941967e1e7b
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl
index e310b44..6ae2369 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl
@@ -90,6 +90,7 @@
   DEVICE_UNIQUE_ATTESTATION = 1879048912,
   IDENTITY_CREDENTIAL_KEY = 1879048913,
   STORAGE_KEY = 1879048914,
+  ATTESTATION_ID_SECOND_IMEI = -1879047469,
   ASSOCIATED_DATA = -1879047192,
   NONCE = -1879047191,
   MAC_LENGTH = 805307371,
diff --git a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
index 47361d5..837fc81 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
@@ -726,9 +726,10 @@
     ATTESTATION_ID_SERIAL = TagType.BYTES | 713,
 
     /**
-     * Tag::ATTESTATION_ID_IMEI provides the IMEIs for all radios on the device to attested key
+     * Tag::ATTESTATION_ID_IMEI provides the IMEI one of the radios on the device to attested key
      * generation/import operations.  This field must be set only when requesting attestation of the
-     * device's identifiers.
+     * device's identifiers. If the device has more than one IMEI, a second IMEI may be included
+     * by using the Tag::ATTESTATION_ID_SECOND_IMEI tag.
      *
      * If the device does not support ID attestation (or destroyAttestationIds() was previously
      * called and the device can no longer attest its IDs), any key attestation request that
@@ -883,6 +884,20 @@
     STORAGE_KEY = TagType.BOOL | 722,
 
     /**
+     * Tag::ATTESTATION_ID_SECOND_IMEI provides an additional IMEI of one of the radios on the
+     * device to attested key generation/import operations. This field MUST be accompanied by
+     * the Tag::ATTESTATION_ID_IMEI tag. It would only be used to convery a second IMEI the device
+     * has, after Tag::ATTESTATION_ID_SECOND_IMEI has been used to convery the first IMEI.
+     *
+     * If the device does not support ID attestation (or destroyAttestationIds() was previously
+     * called and the device can no longer attest its IDs), any key attestation request that
+     * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS.
+     *
+     * Must never appear in KeyCharacteristics.
+     */
+    ATTESTATION_ID_SECOND_IMEI = TagType.BYTES | 723,
+
+    /**
      * OBSOLETE: Do not use.
      *
      * This tag value is included for historical reasons -- in Keymaster it was used to hold
diff --git a/security/keymint/aidl/default/Android.bp b/security/keymint/aidl/default/Android.bp
index 1a17fd4..17520b7 100644
--- a/security/keymint/aidl/default/Android.bp
+++ b/security/keymint/aidl/default/Android.bp
@@ -25,6 +25,7 @@
         "keymint_use_latest_hal_aidl_ndk_shared",
     ],
     shared_libs: [
+        "android.hardware.security.rkp-V3-ndk",
         "android.hardware.security.sharedsecret-V1-ndk",
         "android.hardware.security.secureclock-V1-ndk",
         "libbase",
diff --git a/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp
index ef5b0bd..13143bf 100644
--- a/security/keymint/aidl/vts/functional/Android.bp
+++ b/security/keymint/aidl/vts/functional/Android.bp
@@ -35,6 +35,7 @@
         "libcrypto",
     ],
     static_libs: [
+        "android.hardware.security.rkp-V3-ndk",
         "android.hardware.security.secureclock-V1-ndk",
         "libcppbor_external",
         "libcppcose_rkp",
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
index ca517ac..f4c0095 100644
--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -798,7 +798,7 @@
     add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
     add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
     add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
-    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serial");
+    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serialno");
     add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MANUFACTURER,
                       "ro.product.manufacturer");
     add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model");
diff --git a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
index 1dc5df3..cd140c8 100644
--- a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
+++ b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
@@ -252,7 +252,7 @@
     add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
     add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
     add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
-    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serial");
+    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serialno");
     add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MANUFACTURER,
                       "ro.product.manufacturer");
     add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model");
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 5473062..80abd92 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -1919,30 +1919,32 @@
 
     // The following check assumes that canonical CBOR encoding is used for the COSE_Key.
     if (testMode) {
-        EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
-                    MatchesRegex("{\n"
-                                 "  1 : 2,\n"   // kty: EC2
-                                 "  3 : -7,\n"  // alg: ES256
-                                 "  -1 : 1,\n"  // EC id: P256
-                                 // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
-                                 // sequence of 32 hexadecimal bytes, enclosed in braces and
-                                 // separated by commas. In this case, some Ed25519 public key.
-                                 "  -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"  // pub_x: data
-                                 "  -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"  // pub_y: data
-                                 "  -70000 : null,\n"                              // test marker
-                                 "}"));
+        EXPECT_THAT(
+                cppbor::prettyPrint(parsedPayload.get()),
+                MatchesRegex("\\{\n"
+                             "  1 : 2,\n"   // kty: EC2
+                             "  3 : -7,\n"  // alg: ES256
+                             "  -1 : 1,\n"  // EC id: P256
+                             // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
+                             // sequence of 32 hexadecimal bytes, enclosed in braces and
+                             // separated by commas. In this case, some Ed25519 public key.
+                             "  -2 : \\{(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}\\},\n"  // pub_x: data
+                             "  -3 : \\{(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}\\},\n"  // pub_y: data
+                             "  -70000 : null,\n"                                  // test marker
+                             "\\}"));
     } else {
-        EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
-                    MatchesRegex("{\n"
-                                 "  1 : 2,\n"   // kty: EC2
-                                 "  3 : -7,\n"  // alg: ES256
-                                 "  -1 : 1,\n"  // EC id: P256
-                                 // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
-                                 // sequence of 32 hexadecimal bytes, enclosed in braces and
-                                 // separated by commas. In this case, some Ed25519 public key.
-                                 "  -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"  // pub_x: data
-                                 "  -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"  // pub_y: data
-                                 "}"));
+        EXPECT_THAT(
+                cppbor::prettyPrint(parsedPayload.get()),
+                MatchesRegex("\\{\n"
+                             "  1 : 2,\n"   // kty: EC2
+                             "  3 : -7,\n"  // alg: ES256
+                             "  -1 : 1,\n"  // EC id: P256
+                             // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
+                             // sequence of 32 hexadecimal bytes, enclosed in braces and
+                             // separated by commas. In this case, some Ed25519 public key.
+                             "  -2 : \\{(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}\\},\n"  // pub_x: data
+                             "  -3 : \\{(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}\\},\n"  // pub_y: data
+                             "\\}"));
     }
 }
 
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 2194529..b8d0c20 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -1027,6 +1027,15 @@
  * without providing NOT_BEFORE and NOT_AFTER parameters.
  */
 TEST_P(NewKeyGenerationTest, RsaWithMissingValidity) {
+    if (AidlVersion() < 2) {
+        /*
+         * The KeyMint V1 spec required that CERTIFICATE_NOT_{BEFORE,AFTER} be
+         * specified for asymmetric key generation. However, this was not
+         * checked at the time so we can only be strict about checking this for
+         * implementations of KeyMint version 2 and above.
+         */
+        GTEST_SKIP() << "Validity strict since KeyMint v2";
+    }
     // Per RFC 5280 4.1.2.5, an undefined expiration (not-after) field should be set to
     // GeneralizedTime 999912312359559, which is 253402300799000 ms from Jan 1, 1970.
     constexpr uint64_t kUndefinedExpirationDateTime = 253402300799000;
@@ -1680,6 +1689,15 @@
  * without providing NOT_BEFORE and NOT_AFTER parameters.
  */
 TEST_P(NewKeyGenerationTest, EcdsaWithMissingValidity) {
+    if (AidlVersion() < 2) {
+        /*
+         * The KeyMint V1 spec required that CERTIFICATE_NOT_{BEFORE,AFTER} be
+         * specified for asymmetric key generation. However, this was not
+         * checked at the time so we can only be strict about checking this for
+         * implementations of KeyMint version 2 and above.
+         */
+        GTEST_SKIP() << "Validity strict since KeyMint v2";
+    }
     // Per RFC 5280 4.1.2.5, an undefined expiration (not-after) field should be set to
     // GeneralizedTime 999912312359559, which is 253402300799000 ms from Jan 1, 1970.
     constexpr uint64_t kUndefinedExpirationDateTime = 253402300799000;
@@ -1990,7 +2008,7 @@
     add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
     add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
     add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
-    add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serial");
+    add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serialno");
     add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_MANUFACTURER, "ro.product.manufacturer");
     add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model");
 
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index 4f361bb..97fe08a 100644
--- a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -251,6 +251,19 @@
     EXPECT_LE(hwInfo.uniqueId->size(), 32);
 }
 
+/**
+ * Verify implementation supports at least MIN_SUPPORTED_NUM_KEYS_IN_CSR keys in a CSR.
+ */
+TEST_P(GetHardwareInfoTests, supportedNumKeysInCsr) {
+    if (rpcHardwareInfo.versionNumber < VERSION_WITHOUT_TEST_MODE) {
+        return;
+    }
+
+    RpcHardwareInfo hwInfo;
+    ASSERT_TRUE(provisionable_->getHardwareInfo(&hwInfo).isOk());
+    ASSERT_GE(hwInfo.supportedNumKeysInCsr, RpcHardwareInfo::MIN_SUPPORTED_NUM_KEYS_IN_CSR);
+}
+
 using GenerateKeyTests = VtsRemotelyProvisionedComponentTests;
 
 INSTANTIATE_REM_PROV_AIDL_TEST(GenerateKeyTests);
@@ -701,7 +714,8 @@
 }
 
 /**
- * Generate a non-empty certificate request.  Make sure contents are reproducible.
+ * Generate a non-empty certificate request.  Make sure contents are reproducible but allow for the
+ * signature to be different since algorithms including ECDSA P-256 can include a random value.
  */
 TEST_P(CertificateRequestV2Test, NonEmptyRequestReproducible) {
     generateKeys(false /* testMode */, 1 /* numKeys */);
@@ -711,27 +725,23 @@
     auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
     ASSERT_TRUE(status.isOk()) << status.getMessage();
 
-    auto firstBcc = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
-    ASSERT_TRUE(firstBcc) << firstBcc.message();
+    auto firstCsr = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
+    ASSERT_TRUE(firstCsr) << firstCsr.message();
 
     status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
     ASSERT_TRUE(status.isOk()) << status.getMessage();
 
-    auto secondBcc = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
-    ASSERT_TRUE(secondBcc) << secondBcc.message();
+    auto secondCsr = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
+    ASSERT_TRUE(secondCsr) << secondCsr.message();
 
-    ASSERT_EQ(firstBcc->size(), secondBcc->size());
-    for (auto i = 0; i < firstBcc->size(); i++) {
-        ASSERT_EQ(firstBcc->at(i).pubKey, secondBcc->at(i).pubKey);
-    }
+    ASSERT_EQ(**firstCsr, **secondCsr);
 }
 
 /**
  * Generate a non-empty certificate request with multiple keys.
  */
 TEST_P(CertificateRequestV2Test, NonEmptyRequestMultipleKeys) {
-    // TODO(b/254137722): define a minimum number of keys that must be supported.
-    generateKeys(false /* testMode */, 5 /* numKeys */);
+    generateKeys(false /* testMode */, rpcHardwareInfo.supportedNumKeysInCsr /* numKeys */);
 
     bytevec csr;
 
diff --git a/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp b/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp
index 5bbae4c..0c61c25 100644
--- a/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp
+++ b/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp
@@ -16,16 +16,21 @@
 
 #define LOG_TAG "keymint_benchmark"
 
+#include <iostream>
+
 #include <base/command_line.h>
 #include <benchmark/benchmark.h>
-#include <iostream>
 
 #include <aidl/Vintf.h>
 #include <aidl/android/hardware/security/keymint/ErrorCode.h>
 #include <aidl/android/hardware/security/keymint/IKeyMintDevice.h>
 #include <android/binder_manager.h>
 #include <binder/IServiceManager.h>
+
 #include <keymint_support/authorization_set.h>
+#include <keymint_support/openssl_utils.h>
+#include <openssl/curve25519.h>
+#include <openssl/x509.h>
 
 #define SMALL_MESSAGE_SIZE 64
 #define MEDIUM_MESSAGE_SIZE 1024
@@ -119,6 +124,22 @@
         return {};
     }
 
+    string getAlgorithmString(string transform) {
+        if (transform.find("AES") != string::npos) {
+            return "AES";
+        } else if (transform.find("Hmac") != string::npos) {
+            return "HMAC";
+        } else if (transform.find("DESede") != string::npos) {
+            return "TRIPLE_DES";
+        } else if (transform.find("RSA") != string::npos) {
+            return "RSA";
+        } else if (transform.find("EC") != string::npos) {
+            return "EC";
+        }
+        std::cerr << "Can't find algorithm for " << transform << std::endl;
+        return "";
+    }
+
     Digest getDigest(string transform) {
         if (transform.find("MD5") != string::npos) {
             return Digest::MD5;
@@ -135,29 +156,56 @@
             return Digest::SHA_2_512;
         } else if (transform.find("RSA") != string::npos &&
                    transform.find("OAEP") != string::npos) {
-            return Digest::SHA1;
+            if (securityLevel_ == SecurityLevel::STRONGBOX) {
+                return Digest::SHA_2_256;
+            } else {
+                return Digest::SHA1;
+            }
         } else if (transform.find("Hmac") != string::npos) {
             return Digest::SHA_2_256;
         }
         return Digest::NONE;
     }
 
+    string getDigestString(string transform) {
+        if (transform.find("MD5") != string::npos) {
+            return "MD5";
+        } else if (transform.find("SHA1") != string::npos ||
+                   transform.find("SHA-1") != string::npos) {
+            return "SHA1";
+        } else if (transform.find("SHA224") != string::npos) {
+            return "SHA_2_224";
+        } else if (transform.find("SHA256") != string::npos) {
+            return "SHA_2_256";
+        } else if (transform.find("SHA384") != string::npos) {
+            return "SHA_2_384";
+        } else if (transform.find("SHA512") != string::npos) {
+            return "SHA_2_512";
+        } else if (transform.find("RSA") != string::npos &&
+                   transform.find("OAEP") != string::npos) {
+            if (securityLevel_ == SecurityLevel::STRONGBOX) {
+                return "SHA_2_256";
+            } else {
+                return "SHA1";
+            }
+        } else if (transform.find("Hmac") != string::npos) {
+            return "SHA_2_256";
+        }
+        return "";
+    }
+
     optional<EcCurve> getCurveFromLength(int keySize) {
         switch (keySize) {
             case 224:
                 return EcCurve::P_224;
-                break;
             case 256:
                 return EcCurve::P_256;
-                break;
             case 384:
                 return EcCurve::P_384;
-                break;
             case 521:
                 return EcCurve::P_521;
-                break;
             default:
-                return {};
+                return std::nullopt;
         }
     }
 
@@ -261,6 +309,109 @@
         return GetReturnErrorCode(result);
     }
 
+    /* Copied the function LocalRsaEncryptMessage from
+     * hardware/interfaces/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp in VTS.
+     * Replaced asserts with the condition check and return false in case of failure condition.
+     * Require return value to skip the benchmark test case from further execution in case
+     * LocalRsaEncryptMessage fails.
+     */
+    optional<string> LocalRsaEncryptMessage(const string& message, const AuthorizationSet& params) {
+        // Retrieve the public key from the leaf certificate.
+        if (cert_chain_.empty()) {
+            std::cerr << "Local RSA encrypt Error: invalid cert_chain_" << std::endl;
+            return "Failure";
+        }
+        X509_Ptr key_cert(parse_cert_blob(cert_chain_[0].encodedCertificate));
+        EVP_PKEY_Ptr pub_key(X509_get_pubkey(key_cert.get()));
+        RSA_Ptr rsa(EVP_PKEY_get1_RSA(const_cast<EVP_PKEY*>(pub_key.get())));
+
+        // Retrieve relevant tags.
+        Digest digest = Digest::NONE;
+        Digest mgf_digest = Digest::SHA1;
+        PaddingMode padding = PaddingMode::NONE;
+
+        auto digest_tag = params.GetTagValue(TAG_DIGEST);
+        if (digest_tag.has_value()) digest = digest_tag.value();
+        auto pad_tag = params.GetTagValue(TAG_PADDING);
+        if (pad_tag.has_value()) padding = pad_tag.value();
+        auto mgf_tag = params.GetTagValue(TAG_RSA_OAEP_MGF_DIGEST);
+        if (mgf_tag.has_value()) mgf_digest = mgf_tag.value();
+
+        const EVP_MD* md = openssl_digest(digest);
+        const EVP_MD* mgf_md = openssl_digest(mgf_digest);
+
+        // Set up encryption context.
+        EVP_PKEY_CTX_Ptr ctx(EVP_PKEY_CTX_new(pub_key.get(), /* engine= */ nullptr));
+        if (EVP_PKEY_encrypt_init(ctx.get()) <= 0) {
+            std::cerr << "Local RSA encrypt Error: Encryption init failed" << std::endl;
+            return "Failure";
+        }
+
+        int rc = -1;
+        switch (padding) {
+            case PaddingMode::NONE:
+                rc = EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_NO_PADDING);
+                break;
+            case PaddingMode::RSA_PKCS1_1_5_ENCRYPT:
+                rc = EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_PADDING);
+                break;
+            case PaddingMode::RSA_OAEP:
+                rc = EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING);
+                break;
+            default:
+                break;
+        }
+        if (rc <= 0) {
+            std::cerr << "Local RSA encrypt Error: Set padding failed" << std::endl;
+            return "Failure";
+        }
+        if (padding == PaddingMode::RSA_OAEP) {
+            if (!EVP_PKEY_CTX_set_rsa_oaep_md(ctx.get(), md)) {
+                std::cerr << "Local RSA encrypt Error: Set digest failed: " << ERR_peek_last_error()
+                          << std::endl;
+                return "Failure";
+            }
+            if (!EVP_PKEY_CTX_set_rsa_mgf1_md(ctx.get(), mgf_md)) {
+                std::cerr << "Local RSA encrypt Error: Set digest failed: " << ERR_peek_last_error()
+                          << std::endl;
+                return "Failure";
+            }
+        }
+
+        // Determine output size.
+        size_t outlen;
+        if (EVP_PKEY_encrypt(ctx.get(), nullptr /* out */, &outlen,
+                             reinterpret_cast<const uint8_t*>(message.data()),
+                             message.size()) <= 0) {
+            std::cerr << "Local RSA encrypt Error: Determine output size failed: "
+                      << ERR_peek_last_error() << std::endl;
+            return "Failure";
+        }
+
+        // Left-zero-pad the input if necessary.
+        const uint8_t* to_encrypt = reinterpret_cast<const uint8_t*>(message.data());
+        size_t to_encrypt_len = message.size();
+
+        std::unique_ptr<string> zero_padded_message;
+        if (padding == PaddingMode::NONE && to_encrypt_len < outlen) {
+            zero_padded_message.reset(new string(outlen, '\0'));
+            memcpy(zero_padded_message->data() + (outlen - to_encrypt_len), message.data(),
+                   message.size());
+            to_encrypt = reinterpret_cast<const uint8_t*>(zero_padded_message->data());
+            to_encrypt_len = outlen;
+        }
+
+        // Do the encryption.
+        string output(outlen, '\0');
+        if (EVP_PKEY_encrypt(ctx.get(), reinterpret_cast<uint8_t*>(output.data()), &outlen,
+                             to_encrypt, to_encrypt_len) <= 0) {
+            std::cerr << "Local RSA encrypt Error: Encryption failed: " << ERR_peek_last_error()
+                      << std::endl;
+            return "Failure";
+        }
+        return output;
+    }
+
     SecurityLevel securityLevel_;
     string name_;
 
@@ -268,12 +419,13 @@
     ErrorCode GenerateKey(const AuthorizationSet& key_desc,
                           const optional<AttestationKey>& attest_key = std::nullopt) {
         key_blob_.clear();
+        cert_chain_.clear();
         KeyCreationResult creationResult;
         Status result = keymint_->generateKey(key_desc.vector_data(), attest_key, &creationResult);
         if (result.isOk()) {
             key_blob_ = std::move(creationResult.keyBlob);
+            cert_chain_ = std::move(creationResult.certificateChain);
             creationResult.keyCharacteristics.clear();
-            creationResult.certificateChain.clear();
         }
         return GetReturnErrorCode(result);
     }
@@ -338,6 +490,11 @@
         return ErrorCode::UNKNOWN_ERROR;
     }
 
+    X509_Ptr parse_cert_blob(const vector<uint8_t>& blob) {
+        const uint8_t* p = blob.data();
+        return X509_Ptr(d2i_X509(nullptr /* allocate new */, &p, blob.size()));
+    }
+
     std::shared_ptr<IKeyMintOperation> op_;
     vector<Certificate> cert_chain_;
     vector<uint8_t> key_blob_;
@@ -390,6 +547,10 @@
     BENCHMARK_KM_MSG(encrypt, transform, keySize, msgSize) \
     BENCHMARK_KM_MSG(decrypt, transform, keySize, msgSize)
 
+// Skip public key operations as they are not supported in KeyMint.
+#define BENCHMARK_KM_ASYM_CIPHER(transform, keySize, msgSize)   \
+    BENCHMARK_KM_MSG(decrypt, transform, keySize, msgSize)
+
 #define BENCHMARK_KM_CIPHER_ALL_MSGS(transform, keySize) \
     BENCHMARK_KM_ALL_MSGS(encrypt, transform, keySize)   \
     BENCHMARK_KM_ALL_MSGS(decrypt, transform, keySize)
@@ -397,12 +558,43 @@
 #define BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, keySize) \
     BENCHMARK_KM_ALL_MSGS(sign, transform, keySize)         \
     BENCHMARK_KM_ALL_MSGS(verify, transform, keySize)
-// clang-format on
+
+// Skip public key operations as they are not supported in KeyMint.
+#define BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, keySize) \
+    BENCHMARK_KM_ALL_MSGS(sign, transform, keySize) \
+    // clang-format on
 
 /*
  * ============= KeyGen TESTS ==================
  */
+
+static bool isValidSBKeySize(string transform, int keySize) {
+    std::optional<Algorithm> algorithm = keymintTest->getAlgorithm(transform);
+    switch (algorithm.value()) {
+        case Algorithm::AES:
+            return (keySize == 128 || keySize == 256);
+        case Algorithm::HMAC:
+            return (keySize % 8 == 0 && keySize >= 64 && keySize <= 512);
+        case Algorithm::TRIPLE_DES:
+            return (keySize == 168);
+        case Algorithm::RSA:
+            return (keySize == 2048);
+        case Algorithm::EC:
+            return (keySize == 256);
+    }
+    return false;
+}
+
 static void keygen(benchmark::State& state, string transform, int keySize) {
+    // Skip the test for unsupported key size in StrongBox
+    if (keymintTest->securityLevel_ == SecurityLevel::STRONGBOX &&
+        !isValidSBKeySize(transform, keySize)) {
+        state.SkipWithError(("Skipped for STRONGBOX: Keysize: " + std::to_string(keySize) +
+                             " is not supported in StrongBox for algorithm: " +
+                             keymintTest->getAlgorithmString(transform))
+                                    .c_str());
+        return;
+    }
     addDefaultLabel(state);
     for (auto _ : state) {
         if (!keymintTest->GenerateKey(transform, keySize)) {
@@ -438,8 +630,24 @@
 /*
  * ============= SIGNATURE TESTS ==================
  */
-
 static void sign(benchmark::State& state, string transform, int keySize, int msgSize) {
+    // Skip the test for unsupported key size or unsupported digest in StrongBox
+    if (keymintTest->securityLevel_ == SecurityLevel::STRONGBOX) {
+        if (!isValidSBKeySize(transform, keySize)) {
+            state.SkipWithError(("Skipped for STRONGBOX: Keysize: " + std::to_string(keySize) +
+                                 " is not supported in StrongBox for algorithm: " +
+                                 keymintTest->getAlgorithmString(transform))
+                                        .c_str());
+            return;
+        }
+        if (keymintTest->getDigest(transform) != Digest::SHA_2_256) {
+            state.SkipWithError(
+                    ("Skipped for STRONGBOX: Digest: " + keymintTest->getDigestString(transform) +
+                     " is not supported in StrongBox")
+                            .c_str());
+            return;
+        }
+    }
     addDefaultLabel(state);
     if (!keymintTest->GenerateKey(transform, keySize, true)) {
         state.SkipWithError(
@@ -469,6 +677,23 @@
 }
 
 static void verify(benchmark::State& state, string transform, int keySize, int msgSize) {
+    // Skip the test for unsupported key size or unsupported digest in StrongBox
+    if (keymintTest->securityLevel_ == SecurityLevel::STRONGBOX) {
+        if (!isValidSBKeySize(transform, keySize)) {
+            state.SkipWithError(("Skipped for STRONGBOX: Keysize: " + std::to_string(keySize) +
+                                 " is not supported in StrongBox for algorithm: " +
+                                 keymintTest->getAlgorithmString(transform))
+                                        .c_str());
+            return;
+        }
+        if (keymintTest->getDigest(transform) != Digest::SHA_2_256) {
+            state.SkipWithError(
+                    ("Skipped for STRONGBOX: Digest: " + keymintTest->getDigestString(transform) +
+                     " is not supported in StrongBox")
+                            .c_str());
+            return;
+        }
+    }
     addDefaultLabel(state);
     if (!keymintTest->GenerateKey(transform, keySize, true)) {
         state.SkipWithError(
@@ -525,10 +750,10 @@
 BENCHMARK_KM_SIGNATURE_ALL_HMAC_KEYS(HmacSHA512)
 
 #define BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(transform) \
-    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 224)      \
-    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 256)      \
-    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 384)      \
-    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 521)
+    BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 224)      \
+    BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 256)      \
+    BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 384)      \
+    BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 521)
 
 BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(NONEwithECDSA);
 BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(SHA1withECDSA);
@@ -538,13 +763,14 @@
 BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(SHA512withECDSA);
 
 #define BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(transform) \
-    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 2048)   \
-    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 3072)   \
-    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 4096)
+    BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 2048)   \
+    BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 3072)   \
+    BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 4096)
 
 BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(MD5withRSA);
 BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA1withRSA);
 BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA224withRSA);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA256withRSA);
 BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA384withRSA);
 BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA512withRSA);
 
@@ -553,6 +779,7 @@
 BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA224withRSA/PSS);
 BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA384withRSA/PSS);
 BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA512withRSA/PSS);
+
 // clang-format on
 
 /*
@@ -560,6 +787,15 @@
  */
 
 static void encrypt(benchmark::State& state, string transform, int keySize, int msgSize) {
+    // Skip the test for unsupported key size in StrongBox
+    if (keymintTest->securityLevel_ == SecurityLevel::STRONGBOX &&
+        (!isValidSBKeySize(transform, keySize))) {
+        state.SkipWithError(("Skipped for STRONGBOX: Keysize: " + std::to_string(keySize) +
+                             " is not supported in StrongBox for algorithm: " +
+                             keymintTest->getAlgorithmString(transform))
+                                    .c_str());
+        return;
+    }
     addDefaultLabel(state);
     if (!keymintTest->GenerateKey(transform, keySize)) {
         state.SkipWithError(
@@ -589,6 +825,15 @@
 }
 
 static void decrypt(benchmark::State& state, string transform, int keySize, int msgSize) {
+    // Skip the test for unsupported key size in StrongBox
+    if (keymintTest->securityLevel_ == SecurityLevel::STRONGBOX &&
+        (!isValidSBKeySize(transform, keySize))) {
+        state.SkipWithError(("Skipped for STRONGBOX: Keysize: " + std::to_string(keySize) +
+                             " is not supported in StrongBox for algorithm: " +
+                             keymintTest->getAlgorithmString(transform))
+                                    .c_str());
+        return;
+    }
     addDefaultLabel(state);
     if (!keymintTest->GenerateKey(transform, keySize)) {
         state.SkipWithError(
@@ -598,23 +843,34 @@
     AuthorizationSet out_params;
     AuthorizationSet in_params = keymintTest->getOperationParams(transform);
     string message = keymintTest->GenerateMessage(msgSize);
-    auto error = keymintTest->Begin(KeyPurpose::ENCRYPT, in_params, &out_params);
-    if (error != ErrorCode::OK) {
-        state.SkipWithError(
-                ("Encryption begin error, " + std::to_string(keymintTest->getError())).c_str());
-        return;
+    optional<string> encryptedMessage;
+
+    if (keymintTest->getAlgorithm(transform).value() == Algorithm::RSA) {
+        // Public key operation not supported, doing local Encryption
+        encryptedMessage = keymintTest->LocalRsaEncryptMessage(message, in_params);
+        if ((keySize / 8) != (*encryptedMessage).size()) {
+            state.SkipWithError("Local Encryption falied");
+            return;
+        }
+    } else {
+        auto error = keymintTest->Begin(KeyPurpose::ENCRYPT, in_params, &out_params);
+        if (error != ErrorCode::OK) {
+            state.SkipWithError(
+                    ("Encryption begin error, " + std::to_string(keymintTest->getError())).c_str());
+            return;
+        }
+        encryptedMessage = keymintTest->Process(message);
+        if (!encryptedMessage) {
+            state.SkipWithError(
+                    ("Encryption error, " + std::to_string(keymintTest->getError())).c_str());
+            return;
+        }
+        in_params.push_back(out_params);
+        out_params.Clear();
     }
-    auto encryptedMessage = keymintTest->Process(message);
-    if (!encryptedMessage) {
-        state.SkipWithError(
-                ("Encryption error, " + std::to_string(keymintTest->getError())).c_str());
-        return;
-    }
-    in_params.push_back(out_params);
-    out_params.Clear();
     for (auto _ : state) {
         state.PauseTiming();
-        error = keymintTest->Begin(KeyPurpose::DECRYPT, in_params, &out_params);
+        auto error = keymintTest->Begin(KeyPurpose::DECRYPT, in_params, &out_params);
         if (error != ErrorCode::OK) {
             state.SkipWithError(
                     ("Decryption begin error, " + std::to_string(keymintTest->getError())).c_str());
@@ -649,9 +905,9 @@
 BENCHMARK_KM_CIPHER_ALL_MSGS(DESede/ECB/PKCS7Padding, 168);
 
 #define BENCHMARK_KM_CIPHER_ALL_RSA_KEYS(transform, msgSize) \
-    BENCHMARK_KM_CIPHER(transform, 2048, msgSize)            \
-    BENCHMARK_KM_CIPHER(transform, 3072, msgSize)            \
-    BENCHMARK_KM_CIPHER(transform, 4096, msgSize)
+    BENCHMARK_KM_ASYM_CIPHER(transform, 2048, msgSize)            \
+    BENCHMARK_KM_ASYM_CIPHER(transform, 3072, msgSize)            \
+    BENCHMARK_KM_ASYM_CIPHER(transform, 4096, msgSize)
 
 BENCHMARK_KM_CIPHER_ALL_RSA_KEYS(RSA/ECB/NoPadding, SMALL_MESSAGE_SIZE);
 BENCHMARK_KM_CIPHER_ALL_RSA_KEYS(RSA/ECB/PKCS1Padding, SMALL_MESSAGE_SIZE);
diff --git a/security/keymint/support/Android.bp b/security/keymint/support/Android.bp
index 3f48320..efd6fc7 100644
--- a/security/keymint/support/Android.bp
+++ b/security/keymint/support/Android.bp
@@ -63,6 +63,9 @@
     defaults: [
         "keymint_use_latest_hal_aidl_ndk_shared",
     ],
+    static_libs: [
+        "android.hardware.security.rkp-V3-ndk",
+    ],
     shared_libs: [
         "libbase",
         "libbinder_ndk",
@@ -78,6 +81,7 @@
     name: "libkeymint_remote_prov_support_test",
     srcs: ["remote_prov_utils_test.cpp"],
     static_libs: [
+        "android.hardware.security.rkp-V3-ndk",
         "libgmock",
         "libgtest_main",
     ],
diff --git a/security/keymint/support/include/remote_prov/remote_prov_utils.h b/security/keymint/support/include/remote_prov/remote_prov_utils.h
index 6871e1b..1b94c62 100644
--- a/security/keymint/support/include/remote_prov/remote_prov_utils.h
+++ b/security/keymint/support/include/remote_prov/remote_prov_utils.h
@@ -181,14 +181,13 @@
  * Verify the CSR as if the device is still early in the factory process and may not
  * have all device identifiers provisioned yet.
  */
-ErrMsgOr<std::vector<BccEntryData>> verifyFactoryCsr(const cppbor::Array& keysToSign,
-                                                     const std::vector<uint8_t>& csr,
-                                                     IRemotelyProvisionedComponent* provisionable,
-                                                     const std::vector<uint8_t>& challenge);
+ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyFactoryCsr(
+        const cppbor::Array& keysToSign, const std::vector<uint8_t>& csr,
+        IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge);
 /**
  * Verify the CSR as if the device is a final production sample.
  */
-ErrMsgOr<std::vector<BccEntryData>> verifyProductionCsr(
+ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyProductionCsr(
         const cppbor::Array& keysToSign, const std::vector<uint8_t>& csr,
         IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge);
 
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
index f7ab3ac..7e164fd 100644
--- a/security/keymint/support/remote_prov_utils.cpp
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -521,11 +521,10 @@
         return errMsg;
     }
 
-    std::unique_ptr<cppbor::Map> parsed(parsedVerifiedDeviceInfo->asMap());
+    std::unique_ptr<cppbor::Map> parsed(parsedVerifiedDeviceInfo.release()->asMap());
     if (!parsed) {
         return "DeviceInfo must be a CBOR map.";
     }
-    parsedVerifiedDeviceInfo.release();
 
     if (parsed->clone()->asMap()->canonicalize().encode() != deviceInfoBytes) {
         return "DeviceInfo ordering is non-canonical.";
@@ -846,54 +845,79 @@
     return "";
 }
 
-ErrMsgOr<cppbor::Array> parseAndValidateCsrPayload(const cppbor::Array& keysToSign,
-                                                   const std::vector<uint8_t>& csrPayload,
-                                                   IRemotelyProvisionedComponent* provisionable,
-                                                   const std::vector<uint8_t>& challenge,
-                                                   bool isFactory) {
+ErrMsgOr<std::unique_ptr<cppbor::Array>> parseAndValidateCsrPayload(
+        const cppbor::Array& keysToSign, const std::vector<uint8_t>& csrPayload,
+        IRemotelyProvisionedComponent* provisionable, bool isFactory) {
     auto [parsedCsrPayload, _, errMsg] = cppbor::parse(csrPayload);
     if (!parsedCsrPayload) {
         return errMsg;
     }
-    if (!parsedCsrPayload->asArray()) {
+
+    std::unique_ptr<cppbor::Array> parsed(parsedCsrPayload.release()->asArray());
+    if (!parsed) {
         return "CSR payload is not a CBOR array.";
     }
-    if (parsedCsrPayload->asArray()->size() != 5U) {
-        return "CSR payload must contain version, certificate type, device info, challenge, keys. "
+
+    if (parsed->size() != 4U) {
+        return "CSR payload must contain version, certificate type, device info, keys. "
                "However, the parsed CSR payload has " +
-               std::to_string(parsedCsrPayload->asArray()->size()) + " entries.";
+               std::to_string(parsed->size()) + " entries.";
     }
 
-    auto& signedVersion = parsedCsrPayload->asArray()->get(0);
-    auto& signedCertificateType = parsedCsrPayload->asArray()->get(1);
-    auto& signedDeviceInfo = parsedCsrPayload->asArray()->get(2);
-    auto& signedChallenge = parsedCsrPayload->asArray()->get(3);
-    auto& signedKeys = parsedCsrPayload->asArray()->get(4);
+    auto signedVersion = parsed->get(0)->asUint();
+    auto signedCertificateType = parsed->get(1)->asTstr();
+    auto signedDeviceInfo = parsed->get(2)->asMap();
+    auto signedKeys = parsed->get(3)->asArray();
 
-    if (!signedVersion || !signedVersion->asUint() || signedVersion->asUint()->value() != 1U) {
-        return "CSR payload version must be an unsigned integer and must be equal to 1.";
+    if (!signedVersion || signedVersion->value() != 3U) {
+        return "CSR payload version must be an unsigned integer and must be equal to 3.";
     }
-    if (!signedCertificateType || !signedCertificateType->asTstr()) {
+    if (!signedCertificateType) {
         // Certificate type is allowed to be extendend by vendor, i.e. we can't
         // enforce its value.
         return "Certificate type must be a Tstr.";
     }
-    if (!signedDeviceInfo || !signedDeviceInfo->asMap()) {
+    if (!signedDeviceInfo) {
         return "Device info must be an Map.";
     }
-    if (!signedChallenge || !signedChallenge->asBstr()) {
-        return "Challenge must be a Bstr.";
-    }
-    if (!signedKeys || !signedKeys->asArray()) {
+    if (!signedKeys) {
         return "Keys must be an Array.";
     }
 
-    auto result = parseAndValidateDeviceInfo(signedDeviceInfo->asMap()->encode(), provisionable,
-                                             isFactory);
+    auto result = parseAndValidateDeviceInfo(signedDeviceInfo->encode(), provisionable, isFactory);
     if (!result) {
         return result.message();
     }
 
+    if (signedKeys->encode() != keysToSign.encode()) {
+        return "Signed keys do not match.";
+    }
+
+    return std::move(parsed);
+}
+
+ErrMsgOr<bytevec> parseAndValidateAuthenticatedRequestSignedPayload(
+        const std::vector<uint8_t>& signedPayload, const std::vector<uint8_t>& challenge) {
+    auto [parsedSignedPayload, _, errMsg] = cppbor::parse(signedPayload);
+    if (!parsedSignedPayload) {
+        return errMsg;
+    }
+    if (!parsedSignedPayload->asArray()) {
+        return "SignedData payload is not a CBOR array.";
+    }
+    if (parsedSignedPayload->asArray()->size() != 2U) {
+        return "SignedData payload must contain the challenge and request. However, the parsed "
+               "SignedData payload has " +
+               std::to_string(parsedSignedPayload->asArray()->size()) + " entries.";
+    }
+
+    auto signedChallenge = parsedSignedPayload->asArray()->get(0)->asBstr();
+    auto signedRequest = parsedSignedPayload->asArray()->get(1)->asBstr();
+
+    if (!signedChallenge) {
+        return "Challenge must be a Bstr.";
+    }
+
     if (challenge.size() < 32 || challenge.size() > 64) {
         return "Challenge size must be between 32 and 64 bytes inclusive. "
                "However, challenge is " +
@@ -901,68 +925,57 @@
     }
 
     auto challengeBstr = cppbor::Bstr(challenge);
-    if (*signedChallenge->asBstr() != challengeBstr) {
+    if (*signedChallenge != challengeBstr) {
         return "Signed challenge does not match."
                "\n  Actual: " +
                cppbor::prettyPrint(signedChallenge->asBstr(), 64 /* maxBStrSize */) +
                "\nExpected: " + cppbor::prettyPrint(&challengeBstr, 64 /* maxBStrSize */);
     }
 
-    if (signedKeys->asArray()->encode() != keysToSign.encode()) {
-        return "Signed keys do not match.";
+    if (!signedRequest) {
+        return "Request must be a Bstr.";
     }
 
-    return std::move(*parsedCsrPayload->asArray());
+    return signedRequest->value();
 }
 
-ErrMsgOr<std::vector<BccEntryData>> verifyCsr(const cppbor::Array& keysToSign,
-                                              const std::vector<uint8_t>& csr,
-                                              IRemotelyProvisionedComponent* provisionable,
-                                              const std::vector<uint8_t>& challenge,
-                                              bool isFactory) {
-    auto [parsedCsr, _, csrErrMsg] = cppbor::parse(csr);
-    if (!parsedCsr) {
+ErrMsgOr<bytevec> parseAndValidateAuthenticatedRequest(const std::vector<uint8_t>& request,
+                                                       const std::vector<uint8_t>& challenge) {
+    auto [parsedRequest, _, csrErrMsg] = cppbor::parse(request);
+    if (!parsedRequest) {
         return csrErrMsg;
     }
-    if (!parsedCsr->asArray()) {
-        return "CSR is not a CBOR array.";
+    if (!parsedRequest->asArray()) {
+        return "AuthenticatedRequest is not a CBOR array.";
     }
-    if (parsedCsr->asArray()->size() != 4U) {
-        return "CSR must contain version, UDS certificates, DICE chain, and signed data. "
-               "However, the parsed CSR has " +
-               std::to_string(parsedCsr->asArray()->size()) + " entries.";
+    if (parsedRequest->asArray()->size() != 4U) {
+        return "AuthenticatedRequest must contain version, UDS certificates, DICE chain, and "
+               "signed data. However, the parsed AuthenticatedRequest has " +
+               std::to_string(parsedRequest->asArray()->size()) + " entries.";
     }
 
-    auto& version = parsedCsr->asArray()->get(0);
-    auto& udsCerts = parsedCsr->asArray()->get(1);
-    auto& diceCertChain = parsedCsr->asArray()->get(2);
-    auto& signedData = parsedCsr->asArray()->get(3);
+    auto version = parsedRequest->asArray()->get(0)->asUint();
+    auto udsCerts = parsedRequest->asArray()->get(1)->asMap();
+    auto diceCertChain = parsedRequest->asArray()->get(2)->asArray();
+    auto signedData = parsedRequest->asArray()->get(3)->asArray();
 
-    if (!version || !version->asUint() || version->asUint()->value() != 3U) {
-        return "Version must be an unsigned integer and must be equal to 3.";
+    if (!version || version->value() != 1U) {
+        return "AuthenticatedRequest version must be an unsigned integer and must be equal to 1.";
     }
-    if (!udsCerts || !udsCerts->asMap()) {
-        return "UdsCerts must be an Map.";
+    if (!udsCerts) {
+        return "AuthenticatedRequest UdsCerts must be an Map.";
     }
-    if (!diceCertChain || !diceCertChain->asArray()) {
-        return "DiceCertChain must be an Array.";
+    if (!diceCertChain) {
+        return "AuthenticatedRequest DiceCertChain must be an Array.";
     }
-    if (!signedData || !signedData->asArray()) {
-        return "SignedData must be an Array.";
-    }
-
-    RpcHardwareInfo info;
-    provisionable->getHardwareInfo(&info);
-    if (version->asUint()->value() != info.versionNumber) {
-        return "CSR version (" + std::to_string(version->asUint()->value()) +
-               ") does not match the remotely provisioned component version (" +
-               std::to_string(info.versionNumber) + ").";
+    if (!signedData) {
+        return "AuthenticatedRequest SignedData must be an Array.";
     }
 
     // DICE chain is [ pubkey, + DiceChainEntry ]. Its format is the same as BCC from RKP v1-2.
-    auto diceContents = validateBcc(diceCertChain->asArray());
+    auto diceContents = validateBcc(diceCertChain);
     if (!diceContents) {
-        return diceContents.message() + "\n" + prettyPrint(diceCertChain.get());
+        return diceContents.message() + "\n" + prettyPrint(diceCertChain);
     }
     if (diceContents->size() == 0U) {
         return "The DICE chain is empty. It must contain at least one entry.";
@@ -970,33 +983,51 @@
 
     auto& udsPub = diceContents->back().pubKey;
 
-    auto error = validateUdsCerts(*udsCerts->asMap(), udsPub);
+    auto error = validateUdsCerts(*udsCerts, udsPub);
     if (!error.empty()) {
         return error;
     }
 
-    auto csrPayload = verifyAndParseCoseSign1(signedData->asArray(), udsPub, {} /* aad */);
+    auto signedPayload = verifyAndParseCoseSign1(signedData, udsPub, {} /* aad */);
+    if (!signedPayload) {
+        return signedPayload.message();
+    }
+
+    auto payload = parseAndValidateAuthenticatedRequestSignedPayload(*signedPayload, challenge);
+    if (!payload) {
+        return payload.message();
+    }
+
+    return payload;
+}
+
+ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyCsr(const cppbor::Array& keysToSign,
+                                                   const std::vector<uint8_t>& csr,
+                                                   IRemotelyProvisionedComponent* provisionable,
+                                                   const std::vector<uint8_t>& challenge,
+                                                   bool isFactory) {
+    RpcHardwareInfo info;
+    provisionable->getHardwareInfo(&info);
+    if (info.versionNumber != 3) {
+        return "Remotely provisioned component version (" + std::to_string(info.versionNumber) +
+               ") does not match expected version (3).";
+    }
+
+    auto csrPayload = parseAndValidateAuthenticatedRequest(csr, challenge);
     if (!csrPayload) {
         return csrPayload.message();
     }
 
-    auto parsedCsrPayload = parseAndValidateCsrPayload(keysToSign, *csrPayload, provisionable,
-                                                       challenge, isFactory);
-    if (!parsedCsrPayload) {
-        return parsedCsrPayload.message();
-    }
-
-    return *diceContents;
+    return parseAndValidateCsrPayload(keysToSign, *csrPayload, provisionable, isFactory);
 }
 
-ErrMsgOr<std::vector<BccEntryData>> verifyFactoryCsr(const cppbor::Array& keysToSign,
-                                                     const std::vector<uint8_t>& csr,
-                                                     IRemotelyProvisionedComponent* provisionable,
-                                                     const std::vector<uint8_t>& challenge) {
+ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyFactoryCsr(
+        const cppbor::Array& keysToSign, const std::vector<uint8_t>& csr,
+        IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge) {
     return verifyCsr(keysToSign, csr, provisionable, challenge, /*isFactory=*/true);
 }
 
-ErrMsgOr<std::vector<BccEntryData>> verifyProductionCsr(
+ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyProductionCsr(
         const cppbor::Array& keysToSign, const std::vector<uint8_t>& csr,
         IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge) {
     return verifyCsr(keysToSign, csr, provisionable, challenge, /*isFactory=*/false);
diff --git a/security/keymint/RKP_CHANGELOG.md b/security/rkp/CHANGELOG.md
similarity index 74%
rename from security/keymint/RKP_CHANGELOG.md
rename to security/rkp/CHANGELOG.md
index 243fc26..29b1a1c 100644
--- a/security/keymint/RKP_CHANGELOG.md
+++ b/security/rkp/CHANGELOG.md
@@ -19,6 +19,12 @@
   * `uniqueId` String added as a field in order to differentiate IRPC instances on device.
 
 ## IRemotelyProvisionedComponent 2 -> 3
+* The RKP HAL now builds separately from KeyMint.
+  * The HAL remains under the `android.hardware.security.keymint` package for
+    compatibility with previous releases. ABI compatibility requires this.
+  * Dependencies on the RKP HAL must add a dependency on
+    `"android.hardware.security.rkp"` generated code (instead of
+    `"android.hardward.security.keymint"`).
 * ProtectedData has been removed.
 * DeviceInfo
   * `version` has moved to a top-level field within the CSR generated by the HAL
@@ -30,4 +36,5 @@
     * the chain of signing, MACing, and encryption operations has been replaced with a single
       COSE_Sign1 object.
     * CertificateType has been added to identify the type of certificate being requested.
-
+* RpcHardwareInfo
+  * `supportedNumKeysInCsr` added to report the maximum number of keys supported in a CSR.
diff --git a/security/keymint/RKP_README.md b/security/rkp/README.md
similarity index 95%
rename from security/keymint/RKP_README.md
rename to security/rkp/README.md
index 89a2598..5fb4948 100644
--- a/security/keymint/RKP_README.md
+++ b/security/rkp/README.md
@@ -6,8 +6,8 @@
 keys. The HAL must interact effectively with Keystore (and other daemons) and
 protect device privacy and security.
 
-Note that this API is designed for KeyMint, but with the intention that it
-should be usable for other HALs that require certificate provisioning.
+Note that this API was originally designed for KeyMint, with the intention that
+it should be usable for other HALs that require certificate provisioning.
 Throughout this document we'll refer to the Keystore and KeyMint (formerly
 called Keymaster) components, but only for concreteness and convenience; those
 labels could be replaced with the names of any system and secure area
@@ -312,7 +312,7 @@
 ```
 
 Please see
-[ProtectedData.aidl](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl)
+[ProtectedData.aidl](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl)
 for a full CDDL definition of the BCC.
 
 ### `CertificateRequest`
@@ -366,9 +366,9 @@
 following links:
 
 *   [IRemotelyProvisionedComponent
-    HAL](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl)
-*   [ProtectedData](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl)
-*   [MacedPublicKey](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl)
-*   [RpcHardwareInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl)
-*   [DeviceInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl)
+    HAL](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl)
+*   [ProtectedData](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl)
+*   [MacedPublicKey](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl)
+*   [RpcHardwareInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl)
+*   [DeviceInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl)
 
diff --git a/security/rkp/aidl/Android.bp b/security/rkp/aidl/Android.bp
new file mode 100644
index 0000000..4c479f4
--- /dev/null
+++ b/security/rkp/aidl/Android.bp
@@ -0,0 +1,37 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.security.rkp",
+    vendor_available: true,
+    srcs: [
+        // This HAL was originally part of keymint.
+        "android/hardware/security/keymint/*.aidl",
+
+        // in the future
+        // "android/hardware/security/rkp/*.aidl",
+    ],
+    stability: "vintf",
+    backend: {
+        java: {
+            min_sdk_version: "33",
+        },
+        rust: {
+            enabled: true,
+        },
+    },
+    versions_with_info: [
+        {
+            version: "1",
+        },
+        {
+            version: "2",
+        },
+    ],
+}
diff --git a/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/.hash b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/.hash
new file mode 100644
index 0000000..404553b
--- /dev/null
+++ b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/.hash
@@ -0,0 +1 @@
+d285480d2e0002adc0ace80edf34aa725679512e
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/DeviceInfo.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/DeviceInfo.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/DeviceInfo.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/DeviceInfo.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/MacedPublicKey.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/MacedPublicKey.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/MacedPublicKey.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/MacedPublicKey.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/ProtectedData.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/ProtectedData.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/ProtectedData.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/ProtectedData.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/RpcHardwareInfo.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/RpcHardwareInfo.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/RpcHardwareInfo.aidl
diff --git a/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/.hash b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/.hash
new file mode 100644
index 0000000..8700d33
--- /dev/null
+++ b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/.hash
@@ -0,0 +1 @@
+c8d34e56ae0807b61f028019622d8b60a37e0a8b
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/DeviceInfo.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/DeviceInfo.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/DeviceInfo.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/DeviceInfo.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/MacedPublicKey.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/MacedPublicKey.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/MacedPublicKey.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/MacedPublicKey.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/ProtectedData.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/ProtectedData.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/ProtectedData.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/ProtectedData.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/RpcHardwareInfo.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/RpcHardwareInfo.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/RpcHardwareInfo.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/DeviceInfo.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/DeviceInfo.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/DeviceInfo.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/DeviceInfo.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/MacedPublicKey.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/MacedPublicKey.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/MacedPublicKey.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/MacedPublicKey.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ProtectedData.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/ProtectedData.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ProtectedData.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/ProtectedData.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
similarity index 95%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
index 5ff45f8..b1f99e1 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
+++ b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
@@ -39,7 +39,9 @@
   @utf8InCpp String rpcAuthorName;
   int supportedEekCurve = 0;
   @nullable @utf8InCpp String uniqueId;
+  int supportedNumKeysInCsr = 4;
   const int CURVE_NONE = 0;
   const int CURVE_P256 = 1;
   const int CURVE_25519 = 2;
+  const int MIN_SUPPORTED_NUM_KEYS_IN_CSR = 20;
 }
diff --git a/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl b/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl
similarity index 100%
rename from security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl
rename to security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
similarity index 98%
rename from security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
rename to security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
index 86c1717..78969d1 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
+++ b/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
@@ -315,13 +315,12 @@
      *
      * @return the following CBOR Certificate Signing Request (Csr) serialized into a byte array:
      *
-     * Csr = AuthenticatedMessage<CsrPayload>
+     * Csr = AuthenticatedRequest<CsrPayload>
      *
      * CsrPayload = [                      ; CBOR Array defining the payload for Csr
-     *     version: 1,                     ; The CsrPayload CDDL Schema version.
+     *     version: 3,                     ; The CsrPayload CDDL Schema version.
      *     CertificateType,                ; The type of certificate being requested.
      *     DeviceInfo,                     ; Defined in DeviceInfo.aidl
-     *     challenge: bstr .size (32..64), ; Provided by the method parameters
      *     KeysToSign,                     ; Provided by the method parameters
      * ]
      *
@@ -335,11 +334,14 @@
      *
      * KeysToSign = [ * PublicKey ]   ; Please see MacedPublicKey.aidl for the PublicKey definition.
      *
-     * AuthenticatedMessage<T> = [
-     *    version: 3,              ; The AuthenticatedMessage CDDL Schema version.
-     *    UdsCerts,
-     *    DiceCertChain,
-     *    SignedData<T>,
+     * AuthenticatedRequest<T> = [
+     *     version: 1,              ; The AuthenticatedRequest CDDL Schema version.
+     *     UdsCerts,
+     *     DiceCertChain,
+     *     SignedData<[
+     *         challenge: bstr .size (32..64), ; Provided by the method parameters
+     *         bstr .cbor T,
+     *     ]>,
      * ]
      *
      * ; COSE_Sign1 (untagged)
diff --git a/security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl b/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
similarity index 100%
rename from security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
rename to security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
diff --git a/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl b/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl
similarity index 100%
rename from security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
rename to security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl
diff --git a/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/rkp/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
similarity index 87%
rename from security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
rename to security/rkp/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
index 0cb33ce..5fe5b00 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
+++ b/security/rkp/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
@@ -74,4 +74,17 @@
      *
      */
     @nullable @utf8InCpp String uniqueId;
+
+    /**
+     * supportedNumKeysInCsr is the maximum number of keys in a CSR that this implementation can
+     * support. This value is implementation defined.
+     *
+     * From version 3 onwards, supportedNumKeysInCsr must be larger or equal to
+     * MIN_SUPPORTED_NUM_KEYS_IN_CSR.
+     *
+     * The default value was chosen as the value enforced by the VTS test in versions 1 and 2 of
+     * this interface.
+     */
+    const int MIN_SUPPORTED_NUM_KEYS_IN_CSR = 20;
+    int supportedNumKeysInCsr = 4;
 }
diff --git a/sensors/aidl/Android.bp b/sensors/aidl/Android.bp
index d04017c..9673190 100644
--- a/sensors/aidl/Android.bp
+++ b/sensors/aidl/Android.bp
@@ -11,6 +11,7 @@
     name: "android.hardware.sensors",
     vendor_available: true,
     srcs: ["android/hardware/sensors/*.aidl"],
+    host_supported: true,
     imports: [
         "android.hardware.common-V2",
         "android.hardware.common.fmq-V1",
diff --git a/audio/aidl/default/reverb/Android.bp b/sensors/aidl/convert/Android.bp
similarity index 69%
copy from audio/aidl/default/reverb/Android.bp
copy to sensors/aidl/convert/Android.bp
index 955038c..8e2146d 100644
--- a/audio/aidl/default/reverb/Android.bp
+++ b/sensors/aidl/convert/Android.bp
@@ -23,18 +23,21 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
-cc_library_shared {
-    name: "libreverbsw",
-    defaults: [
-        "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
+cc_library_static {
+    name: "android.hardware.sensors-V1-convert",
+    vendor_available: true,
+    srcs: ["convert.cpp"],
+    export_include_dirs: ["include"],
+    shared_libs: [
+        "liblog",
+        "libcutils",
+        "libhardware",
+        "libbase",
+        "libutils",
+        "android.hardware.sensors-V1-ndk",
     ],
-    srcs: [
-        "ReverbSw.cpp",
-        ":effectCommonFile",
-    ],
-    visibility: [
-        "//hardware/interfaces/audio/aidl/default",
+    local_include_dirs: ["include/aidl/sensors"],
+    export_shared_lib_headers: [
+        "libhardware",
     ],
 }
diff --git a/sensors/aidl/convert/convert.cpp b/sensors/aidl/convert/convert.cpp
new file mode 100644
index 0000000..415f435
--- /dev/null
+++ b/sensors/aidl/convert/convert.cpp
@@ -0,0 +1,496 @@
+/*
+ * 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/sensors/convert.h"
+#include "android-base/logging.h"
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace implementation {
+
+using aidl::android::hardware::sensors::AdditionalInfo;
+using aidl::android::hardware::sensors::DynamicSensorInfo;
+using aidl::android::hardware::sensors::Event;
+using aidl::android::hardware::sensors::ISensors;
+using aidl::android::hardware::sensors::SensorInfo;
+using aidl::android::hardware::sensors::SensorStatus;
+using aidl::android::hardware::sensors::SensorType;
+
+status_t convertToStatus(ndk::ScopedAStatus status) {
+    if (status.isOk()) {
+        return OK;
+    } else {
+        switch (status.getExceptionCode()) {
+            case EX_ILLEGAL_ARGUMENT: {
+                return BAD_VALUE;
+            }
+            case EX_SECURITY: {
+                return PERMISSION_DENIED;
+            }
+            case EX_UNSUPPORTED_OPERATION: {
+                return INVALID_OPERATION;
+            }
+            case EX_SERVICE_SPECIFIC: {
+                switch (status.getServiceSpecificError()) {
+                    case ISensors::ERROR_BAD_VALUE: {
+                        return BAD_VALUE;
+                    }
+                    case ISensors::ERROR_NO_MEMORY: {
+                        return NO_MEMORY;
+                    }
+                    default: {
+                        return UNKNOWN_ERROR;
+                    }
+                }
+            }
+            default: {
+                return UNKNOWN_ERROR;
+            }
+        }
+    }
+}
+
+void convertToSensor(const SensorInfo& src, sensor_t* dst) {
+    dst->name = strdup(src.name.c_str());
+    dst->vendor = strdup(src.vendor.c_str());
+    dst->version = src.version;
+    dst->handle = src.sensorHandle;
+    dst->type = (int)src.type;
+    dst->maxRange = src.maxRange;
+    dst->resolution = src.resolution;
+    dst->power = src.power;
+    dst->minDelay = src.minDelayUs;
+    dst->fifoReservedEventCount = src.fifoReservedEventCount;
+    dst->fifoMaxEventCount = src.fifoMaxEventCount;
+    dst->stringType = strdup(src.typeAsString.c_str());
+    dst->requiredPermission = strdup(src.requiredPermission.c_str());
+    dst->maxDelay = src.maxDelayUs;
+    dst->flags = src.flags;
+    dst->reserved[0] = dst->reserved[1] = 0;
+}
+
+void convertToSensorEvent(const Event& src, sensors_event_t* dst) {
+    *dst = {.version = sizeof(sensors_event_t),
+            .sensor = src.sensorHandle,
+            .type = (int32_t)src.sensorType,
+            .reserved0 = 0,
+            .timestamp = src.timestamp};
+
+    switch (src.sensorType) {
+        case SensorType::META_DATA: {
+            // Legacy HALs expect the handle reference in the meta data field.
+            // Copy it over from the handle of the event.
+            dst->meta_data.what = (int32_t)src.payload.get<Event::EventPayload::meta>().what;
+            dst->meta_data.sensor = src.sensorHandle;
+            // Set the sensor handle to 0 to maintain compatibility.
+            dst->sensor = 0;
+            break;
+        }
+
+        case SensorType::ACCELEROMETER:
+        case SensorType::MAGNETIC_FIELD:
+        case SensorType::ORIENTATION:
+        case SensorType::GYROSCOPE:
+        case SensorType::GRAVITY:
+        case SensorType::LINEAR_ACCELERATION: {
+            dst->acceleration.x = src.payload.get<Event::EventPayload::vec3>().x;
+            dst->acceleration.y = src.payload.get<Event::EventPayload::vec3>().y;
+            dst->acceleration.z = src.payload.get<Event::EventPayload::vec3>().z;
+            dst->acceleration.status = (int32_t)src.payload.get<Event::EventPayload::vec3>().status;
+            break;
+        }
+
+        case SensorType::GAME_ROTATION_VECTOR: {
+            dst->data[0] = src.payload.get<Event::EventPayload::vec4>().x;
+            dst->data[1] = src.payload.get<Event::EventPayload::vec4>().y;
+            dst->data[2] = src.payload.get<Event::EventPayload::vec4>().z;
+            dst->data[3] = src.payload.get<Event::EventPayload::vec4>().w;
+            break;
+        }
+
+        case SensorType::ROTATION_VECTOR:
+        case SensorType::GEOMAGNETIC_ROTATION_VECTOR: {
+            dst->data[0] = src.payload.get<Event::EventPayload::data>().values[0];
+            dst->data[1] = src.payload.get<Event::EventPayload::data>().values[1];
+            dst->data[2] = src.payload.get<Event::EventPayload::data>().values[2];
+            dst->data[3] = src.payload.get<Event::EventPayload::data>().values[3];
+            dst->data[4] = src.payload.get<Event::EventPayload::data>().values[4];
+            break;
+        }
+
+        case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
+        case SensorType::GYROSCOPE_UNCALIBRATED:
+        case SensorType::ACCELEROMETER_UNCALIBRATED: {
+            dst->uncalibrated_gyro.x_uncalib = src.payload.get<Event::EventPayload::uncal>().x;
+            dst->uncalibrated_gyro.y_uncalib = src.payload.get<Event::EventPayload::uncal>().y;
+            dst->uncalibrated_gyro.z_uncalib = src.payload.get<Event::EventPayload::uncal>().z;
+            dst->uncalibrated_gyro.x_bias = src.payload.get<Event::EventPayload::uncal>().xBias;
+            dst->uncalibrated_gyro.y_bias = src.payload.get<Event::EventPayload::uncal>().yBias;
+            dst->uncalibrated_gyro.z_bias = src.payload.get<Event::EventPayload::uncal>().zBias;
+            break;
+        }
+
+        case SensorType::HINGE_ANGLE:
+        case SensorType::DEVICE_ORIENTATION:
+        case SensorType::LIGHT:
+        case SensorType::PRESSURE:
+        case SensorType::PROXIMITY:
+        case SensorType::RELATIVE_HUMIDITY:
+        case SensorType::AMBIENT_TEMPERATURE:
+        case SensorType::SIGNIFICANT_MOTION:
+        case SensorType::STEP_DETECTOR:
+        case SensorType::TILT_DETECTOR:
+        case SensorType::WAKE_GESTURE:
+        case SensorType::GLANCE_GESTURE:
+        case SensorType::PICK_UP_GESTURE:
+        case SensorType::WRIST_TILT_GESTURE:
+        case SensorType::STATIONARY_DETECT:
+        case SensorType::MOTION_DETECT:
+        case SensorType::HEART_BEAT:
+        case SensorType::LOW_LATENCY_OFFBODY_DETECT: {
+            dst->data[0] = src.payload.get<Event::EventPayload::scalar>();
+            break;
+        }
+
+        case SensorType::STEP_COUNTER: {
+            dst->u64.step_counter = src.payload.get<Event::EventPayload::stepCount>();
+            break;
+        }
+
+        case SensorType::HEART_RATE: {
+            dst->heart_rate.bpm = src.payload.get<Event::EventPayload::heartRate>().bpm;
+            dst->heart_rate.status =
+                    (int8_t)src.payload.get<Event::EventPayload::heartRate>().status;
+            break;
+        }
+
+        case SensorType::POSE_6DOF: {  // 15 floats
+            for (size_t i = 0; i < 15; ++i) {
+                dst->data[i] = src.payload.get<Event::EventPayload::pose6DOF>().values[i];
+            }
+            break;
+        }
+
+        case SensorType::DYNAMIC_SENSOR_META: {
+            dst->dynamic_sensor_meta.connected =
+                    src.payload.get<Event::EventPayload::dynamic>().connected;
+            dst->dynamic_sensor_meta.handle =
+                    src.payload.get<Event::EventPayload::dynamic>().sensorHandle;
+            dst->dynamic_sensor_meta.sensor = NULL;  // to be filled in later
+
+            memcpy(dst->dynamic_sensor_meta.uuid,
+                   src.payload.get<Event::EventPayload::dynamic>().uuid.values.data(), 16);
+
+            break;
+        }
+
+        case SensorType::ADDITIONAL_INFO: {
+            const AdditionalInfo& srcInfo = src.payload.get<Event::EventPayload::additional>();
+
+            additional_info_event_t* dstInfo = &dst->additional_info;
+            dstInfo->type = (int32_t)srcInfo.type;
+            dstInfo->serial = srcInfo.serial;
+
+            switch (srcInfo.payload.getTag()) {
+                case AdditionalInfo::AdditionalInfoPayload::Tag::dataInt32: {
+                    const auto& values =
+                            srcInfo.payload.get<AdditionalInfo::AdditionalInfoPayload::dataInt32>()
+                                    .values;
+                    CHECK_EQ(values.size() * sizeof(int32_t), sizeof(dstInfo->data_int32));
+                    memcpy(dstInfo->data_int32, values.data(), sizeof(dstInfo->data_int32));
+                    break;
+                }
+                case AdditionalInfo::AdditionalInfoPayload::Tag::dataFloat: {
+                    const auto& values =
+                            srcInfo.payload.get<AdditionalInfo::AdditionalInfoPayload::dataFloat>()
+                                    .values;
+                    CHECK_EQ(values.size() * sizeof(float), sizeof(dstInfo->data_float));
+                    memcpy(dstInfo->data_float, values.data(), sizeof(dstInfo->data_float));
+                    break;
+                }
+                default: {
+                    LOG(ERROR) << "Invalid sensor additional info tag: ",
+                            (int)srcInfo.payload.getTag();
+                }
+            }
+            break;
+        }
+
+        case SensorType::HEAD_TRACKER: {
+            const auto& ht = src.payload.get<Event::EventPayload::headTracker>();
+            dst->head_tracker.rx = ht.rx;
+            dst->head_tracker.ry = ht.ry;
+            dst->head_tracker.rz = ht.rz;
+            dst->head_tracker.vx = ht.vx;
+            dst->head_tracker.vy = ht.vy;
+            dst->head_tracker.vz = ht.vz;
+            dst->head_tracker.discontinuity_count = ht.discontinuityCount;
+            break;
+        }
+
+        case SensorType::ACCELEROMETER_LIMITED_AXES:
+        case SensorType::GYROSCOPE_LIMITED_AXES:
+            dst->limited_axes_imu.x = src.payload.get<Event::EventPayload::limitedAxesImu>().x;
+            dst->limited_axes_imu.y = src.payload.get<Event::EventPayload::limitedAxesImu>().y;
+            dst->limited_axes_imu.z = src.payload.get<Event::EventPayload::limitedAxesImu>().z;
+            dst->limited_axes_imu.x_supported =
+                    src.payload.get<Event::EventPayload::limitedAxesImu>().xSupported;
+            dst->limited_axes_imu.y_supported =
+                    src.payload.get<Event::EventPayload::limitedAxesImu>().ySupported;
+            dst->limited_axes_imu.z_supported =
+                    src.payload.get<Event::EventPayload::limitedAxesImu>().zSupported;
+            break;
+
+        case SensorType::ACCELEROMETER_LIMITED_AXES_UNCALIBRATED:
+        case SensorType::GYROSCOPE_LIMITED_AXES_UNCALIBRATED:
+            dst->limited_axes_imu_uncalibrated.x_uncalib =
+                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().x;
+            dst->limited_axes_imu_uncalibrated.y_uncalib =
+                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().y;
+            dst->limited_axes_imu_uncalibrated.z_uncalib =
+                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().z;
+            dst->limited_axes_imu_uncalibrated.x_bias =
+                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().xBias;
+            dst->limited_axes_imu_uncalibrated.y_bias =
+                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().yBias;
+            dst->limited_axes_imu_uncalibrated.z_bias =
+                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().zBias;
+            dst->limited_axes_imu_uncalibrated.x_supported =
+                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().xSupported;
+            dst->limited_axes_imu_uncalibrated.y_supported =
+                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().ySupported;
+            dst->limited_axes_imu_uncalibrated.z_supported =
+                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().zSupported;
+            break;
+
+        case SensorType::HEADING:
+            dst->heading.heading = src.payload.get<Event::EventPayload::heading>().heading;
+            dst->heading.accuracy = src.payload.get<Event::EventPayload::heading>().accuracy;
+            break;
+
+        default: {
+            CHECK_GE((int32_t)src.sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE);
+
+            memcpy(dst->data, src.payload.get<Event::EventPayload::data>().values.data(),
+                   16 * sizeof(float));
+            break;
+        }
+    }
+}
+
+void convertFromSensorEvent(const sensors_event_t& src, Event* dst) {
+    *dst = {
+            .timestamp = src.timestamp,
+            .sensorHandle = src.sensor,
+            .sensorType = (SensorType)src.type,
+    };
+
+    switch (dst->sensorType) {
+        case SensorType::META_DATA: {
+            Event::EventPayload::MetaData meta;
+            meta.what = (Event::EventPayload::MetaData::MetaDataEventType)src.meta_data.what;
+            // Legacy HALs contain the handle reference in the meta data field.
+            // Copy that over to the handle of the event. In legacy HALs this
+            // field was expected to be 0.
+            dst->sensorHandle = src.meta_data.sensor;
+            dst->payload.set<Event::EventPayload::Tag::meta>(meta);
+            break;
+        }
+
+        case SensorType::ACCELEROMETER:
+        case SensorType::MAGNETIC_FIELD:
+        case SensorType::ORIENTATION:
+        case SensorType::GYROSCOPE:
+        case SensorType::GRAVITY:
+        case SensorType::LINEAR_ACCELERATION: {
+            Event::EventPayload::Vec3 vec3;
+            vec3.x = src.acceleration.x;
+            vec3.y = src.acceleration.y;
+            vec3.z = src.acceleration.z;
+            vec3.status = (SensorStatus)src.acceleration.status;
+            dst->payload.set<Event::EventPayload::Tag::vec3>(vec3);
+            break;
+        }
+
+        case SensorType::GAME_ROTATION_VECTOR: {
+            Event::EventPayload::Vec4 vec4;
+            vec4.x = src.data[0];
+            vec4.y = src.data[1];
+            vec4.z = src.data[2];
+            vec4.w = src.data[3];
+            dst->payload.set<Event::EventPayload::Tag::vec4>(vec4);
+            break;
+        }
+
+        case SensorType::ROTATION_VECTOR:
+        case SensorType::GEOMAGNETIC_ROTATION_VECTOR: {
+            Event::EventPayload::Data data;
+            memcpy(data.values.data(), src.data, 5 * sizeof(float));
+            dst->payload.set<Event::EventPayload::Tag::data>(data);
+            break;
+        }
+
+        case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
+        case SensorType::GYROSCOPE_UNCALIBRATED:
+        case SensorType::ACCELEROMETER_UNCALIBRATED: {
+            Event::EventPayload::Uncal uncal;
+            uncal.x = src.uncalibrated_gyro.x_uncalib;
+            uncal.y = src.uncalibrated_gyro.y_uncalib;
+            uncal.z = src.uncalibrated_gyro.z_uncalib;
+            uncal.xBias = src.uncalibrated_gyro.x_bias;
+            uncal.yBias = src.uncalibrated_gyro.y_bias;
+            uncal.zBias = src.uncalibrated_gyro.z_bias;
+            dst->payload.set<Event::EventPayload::Tag::uncal>(uncal);
+            break;
+        }
+
+        case SensorType::DEVICE_ORIENTATION:
+        case SensorType::LIGHT:
+        case SensorType::PRESSURE:
+        case SensorType::PROXIMITY:
+        case SensorType::RELATIVE_HUMIDITY:
+        case SensorType::AMBIENT_TEMPERATURE:
+        case SensorType::SIGNIFICANT_MOTION:
+        case SensorType::STEP_DETECTOR:
+        case SensorType::TILT_DETECTOR:
+        case SensorType::WAKE_GESTURE:
+        case SensorType::GLANCE_GESTURE:
+        case SensorType::PICK_UP_GESTURE:
+        case SensorType::WRIST_TILT_GESTURE:
+        case SensorType::STATIONARY_DETECT:
+        case SensorType::MOTION_DETECT:
+        case SensorType::HEART_BEAT:
+        case SensorType::LOW_LATENCY_OFFBODY_DETECT:
+        case SensorType::HINGE_ANGLE: {
+            dst->payload.set<Event::EventPayload::Tag::scalar>((float)src.data[0]);
+            break;
+        }
+
+        case SensorType::STEP_COUNTER: {
+            dst->payload.set<Event::EventPayload::Tag::stepCount>(src.u64.step_counter);
+            break;
+        }
+
+        case SensorType::HEART_RATE: {
+            Event::EventPayload::HeartRate heartRate;
+            heartRate.bpm = src.heart_rate.bpm;
+            heartRate.status = (SensorStatus)src.heart_rate.status;
+            dst->payload.set<Event::EventPayload::Tag::heartRate>(heartRate);
+            break;
+        }
+
+        case SensorType::POSE_6DOF: {  // 15 floats
+            Event::EventPayload::Pose6Dof pose6DOF;
+            for (size_t i = 0; i < 15; ++i) {
+                pose6DOF.values[i] = src.data[i];
+            }
+            dst->payload.set<Event::EventPayload::Tag::pose6DOF>(pose6DOF);
+            break;
+        }
+
+        case SensorType::DYNAMIC_SENSOR_META: {
+            DynamicSensorInfo dynamic;
+            dynamic.connected = src.dynamic_sensor_meta.connected;
+            dynamic.sensorHandle = src.dynamic_sensor_meta.handle;
+
+            memcpy(dynamic.uuid.values.data(), src.dynamic_sensor_meta.uuid, 16);
+            dst->payload.set<Event::EventPayload::Tag::dynamic>(dynamic);
+            break;
+        }
+
+        case SensorType::ADDITIONAL_INFO: {
+            AdditionalInfo info;
+            const additional_info_event_t& srcInfo = src.additional_info;
+            info.type = (AdditionalInfo::AdditionalInfoType)srcInfo.type;
+            info.serial = srcInfo.serial;
+
+            AdditionalInfo::AdditionalInfoPayload::Int32Values data;
+            CHECK_EQ(data.values.size() * sizeof(int32_t), sizeof(srcInfo.data_int32));
+            memcpy(data.values.data(), srcInfo.data_int32, sizeof(srcInfo.data_int32));
+            info.payload.set<AdditionalInfo::AdditionalInfoPayload::Tag::dataInt32>(data);
+
+            dst->payload.set<Event::EventPayload::Tag::additional>(info);
+            break;
+        }
+
+        case SensorType::HEAD_TRACKER: {
+            Event::EventPayload::HeadTracker headTracker;
+            headTracker.rx = src.head_tracker.rx;
+            headTracker.ry = src.head_tracker.ry;
+            headTracker.rz = src.head_tracker.rz;
+            headTracker.vx = src.head_tracker.vx;
+            headTracker.vy = src.head_tracker.vy;
+            headTracker.vz = src.head_tracker.vz;
+            headTracker.discontinuityCount = src.head_tracker.discontinuity_count;
+
+            dst->payload.set<Event::EventPayload::Tag::headTracker>(headTracker);
+            break;
+        }
+
+        case SensorType::ACCELEROMETER_LIMITED_AXES:
+        case SensorType::GYROSCOPE_LIMITED_AXES: {
+            Event::EventPayload::LimitedAxesImu limitedAxesImu;
+            limitedAxesImu.x = src.limited_axes_imu.x;
+            limitedAxesImu.y = src.limited_axes_imu.y;
+            limitedAxesImu.z = src.limited_axes_imu.z;
+            limitedAxesImu.xSupported = src.limited_axes_imu.x_supported;
+            limitedAxesImu.ySupported = src.limited_axes_imu.y_supported;
+            limitedAxesImu.zSupported = src.limited_axes_imu.z_supported;
+            dst->payload.set<Event::EventPayload::Tag::limitedAxesImu>(limitedAxesImu);
+            break;
+        }
+
+        case SensorType::ACCELEROMETER_LIMITED_AXES_UNCALIBRATED:
+        case SensorType::GYROSCOPE_LIMITED_AXES_UNCALIBRATED: {
+            Event::EventPayload::LimitedAxesImuUncal limitedAxesImuUncal;
+            limitedAxesImuUncal.x = src.limited_axes_imu_uncalibrated.x_uncalib;
+            limitedAxesImuUncal.y = src.limited_axes_imu_uncalibrated.y_uncalib;
+            limitedAxesImuUncal.z = src.limited_axes_imu_uncalibrated.z_uncalib;
+            limitedAxesImuUncal.xBias = src.limited_axes_imu_uncalibrated.x_bias;
+            limitedAxesImuUncal.yBias = src.limited_axes_imu_uncalibrated.y_bias;
+            limitedAxesImuUncal.yBias = src.limited_axes_imu_uncalibrated.y_bias;
+            limitedAxesImuUncal.zBias = src.limited_axes_imu_uncalibrated.z_bias;
+            limitedAxesImuUncal.xSupported = src.limited_axes_imu_uncalibrated.x_supported;
+            limitedAxesImuUncal.ySupported = src.limited_axes_imu_uncalibrated.y_supported;
+            limitedAxesImuUncal.zSupported = src.limited_axes_imu_uncalibrated.z_supported;
+            dst->payload.set<Event::EventPayload::Tag::limitedAxesImuUncal>(limitedAxesImuUncal);
+            break;
+        }
+
+        case SensorType::HEADING: {
+            Event::EventPayload::Heading heading;
+            heading.heading = src.heading.heading;
+            heading.accuracy = src.heading.accuracy;
+            dst->payload.set<Event::EventPayload::heading>(heading);
+            break;
+        }
+
+        default: {
+            CHECK_GE((int32_t)dst->sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE);
+
+            Event::EventPayload::Data data;
+            memcpy(data.values.data(), src.data, 16 * sizeof(float));
+            dst->payload.set<Event::EventPayload::Tag::data>(data);
+            break;
+        }
+    }
+}
+
+}  // namespace implementation
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/sensors/aidl/convert/include/aidl/sensors/convert.h b/sensors/aidl/convert/include/aidl/sensors/convert.h
new file mode 100644
index 0000000..702b226
--- /dev/null
+++ b/sensors/aidl/convert/include/aidl/sensors/convert.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/sensors/ISensors.h>
+#include <hardware/sensors.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace implementation {
+
+status_t convertToStatus(ndk::ScopedAStatus status);
+void convertToSensor(const aidl::android::hardware::sensors::SensorInfo& src, sensor_t* dst);
+void convertToSensorEvent(const aidl::android::hardware::sensors::Event& src, sensors_event_t* dst);
+void convertFromSensorEvent(const sensors_event_t& src,
+                            aidl::android::hardware::sensors::Event* dst);
+
+}  // namespace implementation
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/usb/1.0/default/Android.bp b/usb/1.0/default/Android.bp
index 4bed2c7..5f56fe0 100644
--- a/usb/1.0/default/Android.bp
+++ b/usb/1.0/default/Android.bp
@@ -21,21 +21,11 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
-filegroup {
-    name: "android.hardware.usb@1.0-service.xml",
-    srcs: ["android.hardware.usb@1.0-service.xml"],
-}
-
-filegroup {
-    name: "android.hardware.usb@1.0-service.rc",
-    srcs: ["android.hardware.usb@1.0-service.rc"],
-}
-
 cc_binary {
     name: "android.hardware.usb@1.0-service",
     defaults: ["hidl_defaults"],
-    init_rc: [":android.hardware.usb@1.0-service.rc"],
-    vintf_fragments: [":android.hardware.usb@1.0-service.xml"],
+    init_rc: ["android.hardware.usb@1.0-service.rc"],
+    vintf_fragments: ["android.hardware.usb@1.0-service.xml"],
     relative_install_path: "hw",
     vendor: true,
     srcs: [
diff --git a/usb/1.0/default/apex/manifest.json b/usb/1.0/default/apex/manifest.json
deleted file mode 100644
index 6a1095f..0000000
--- a/usb/1.0/default/apex/manifest.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-  "name": "com.android.hardware.usb",
-  "version": 1
-}
diff --git a/usb/aidl/default/Android.bp b/usb/aidl/default/Android.bp
index 7cb2822..ad331f9 100644
--- a/usb/aidl/default/Android.bp
+++ b/usb/aidl/default/Android.bp
@@ -37,8 +37,18 @@
         "android.hardware.usb-V1-ndk",
         "libbase",
         "libbinder_ndk",
-	"libcutils",
+        "libcutils",
         "liblog",
         "libutils",
     ],
 }
+
+filegroup {
+    name: "android.hardware.usb-service.example.xml",
+    srcs: ["android.hardware.usb-service.example.xml"],
+}
+
+filegroup {
+    name: "android.hardware.usb-service.example.rc",
+    srcs: ["android.hardware.usb-service.example.rc"],
+}
diff --git a/usb/1.0/default/apex/Android.bp b/usb/apex/Android.bp
similarity index 84%
rename from usb/1.0/default/apex/Android.bp
rename to usb/apex/Android.bp
index ee50fdf..765aa21 100644
--- a/usb/1.0/default/apex/Android.bp
+++ b/usb/apex/Android.bp
@@ -27,19 +27,6 @@
     certificate: "com.android.hardware.usb",
 }
 
-genrule {
-    name: "com.android.hardware.usb.rc-gen",
-    srcs: [":android.hardware.usb@1.0-service.rc"],
-    out: ["com.android.hardware.usb.rc"],
-    cmd: "sed -E 's/\\/vendor/\\/apex\\/com.android.hardware.usb/' $(in) > $(out)",
-}
-
-prebuilt_etc {
-    name: "com.android.hardware.usb.rc",
-    src: ":com.android.hardware.usb.rc-gen",
-    installable: false,
-}
-
 apex {
     name: "com.android.hardware.usb",
     manifest: "manifest.json",
@@ -49,11 +36,25 @@
     updatable: false,
     soc_specific: true,
     use_vndk_as_stable: true,
-    binaries: ["android.hardware.usb@1.0-service"],
+    binaries: ["android.hardware.usb-service.example"],
     prebuilts: [
-        "com.android.hardware.usb.rc",
+        "com.android.hardware.usb.rc", // init .rc
         "android.hardware.usb.accessory.prebuilt.xml",
         "android.hardware.usb.host.prebuilt.xml",
     ],
-    vintf_fragments: [":android.hardware.usb@1.0-service.xml"],
+    vintf_fragments: [":android.hardware.usb-service.example.xml"],
+}
+
+// Replace the binary path from /vendor/bin to /apex/{name}/bin in the init .rc file
+genrule {
+    name: "com.android.hardware.usb.rc-gen",
+    srcs: [":android.hardware.usb-service.example.rc"],
+    out: ["com.android.hardware.usb.rc"],
+    cmd: "sed -E 's/\\/vendor/\\/apex\\/com.android.hardware.usb/' $(in) > $(out)",
+}
+
+prebuilt_etc {
+    name: "com.android.hardware.usb.rc",
+    src: ":com.android.hardware.usb.rc-gen",
+    installable: false,
 }
diff --git a/usb/1.0/default/apex/com.android.hardware.usb.avbpubkey b/usb/apex/com.android.hardware.usb.avbpubkey
similarity index 100%
rename from usb/1.0/default/apex/com.android.hardware.usb.avbpubkey
rename to usb/apex/com.android.hardware.usb.avbpubkey
Binary files differ
diff --git a/usb/1.0/default/apex/com.android.hardware.usb.pem b/usb/apex/com.android.hardware.usb.pem
similarity index 100%
rename from usb/1.0/default/apex/com.android.hardware.usb.pem
rename to usb/apex/com.android.hardware.usb.pem
diff --git a/usb/1.0/default/apex/com.android.hardware.usb.pk8 b/usb/apex/com.android.hardware.usb.pk8
similarity index 100%
rename from usb/1.0/default/apex/com.android.hardware.usb.pk8
rename to usb/apex/com.android.hardware.usb.pk8
Binary files differ
diff --git a/usb/1.0/default/apex/com.android.hardware.usb.x509.pem b/usb/apex/com.android.hardware.usb.x509.pem
similarity index 100%
rename from usb/1.0/default/apex/com.android.hardware.usb.x509.pem
rename to usb/apex/com.android.hardware.usb.x509.pem
diff --git a/usb/1.0/default/apex/file_contexts b/usb/apex/file_contexts
similarity index 66%
rename from usb/1.0/default/apex/file_contexts
rename to usb/apex/file_contexts
index bc84ac4..f223a56 100644
--- a/usb/1.0/default/apex/file_contexts
+++ b/usb/apex/file_contexts
@@ -2,4 +2,4 @@
 # Permission XMLs
 /etc/permissions(/.*)?                         u:object_r:vendor_configs_file:s0
 # binary
-/bin/hw/android\.hardware\.usb@1\.0-service    u:object_r:hal_usb_default_exec:s0
\ No newline at end of file
+/bin/hw/android\.hardware\.usb-service\.example        u:object_r:hal_usb_default_exec:s0
\ No newline at end of file
diff --git a/usb/apex/manifest.json b/usb/apex/manifest.json
new file mode 100644
index 0000000..1a41b90
--- /dev/null
+++ b/usb/apex/manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.usb",
+    "version": 1
+}
diff --git a/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp b/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp
index fa50821..0924da7 100644
--- a/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp
+++ b/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp
@@ -170,7 +170,6 @@
 
     if ((functions & GadgetFunction::RNDIS) != 0) {
         ALOGI("setCurrentUsbFunctions rndis");
-        if (linkFunction("gsi.rndis", (*functionCount)++)) return Status::ERROR;
         std::string rndisFunction = GetProperty(kVendorRndisConfig, "");
         if (rndisFunction != "") {
             if (linkFunction(rndisFunction.c_str(), (*functionCount)++)) return Status::ERROR;
diff --git a/uwb/aidl/Android.bp b/uwb/aidl/Android.bp
index 52f0605..7dc2b7f 100755
--- a/uwb/aidl/Android.bp
+++ b/uwb/aidl/Android.bp
@@ -47,6 +47,7 @@
 
 aidl_interface {
     name: "android.hardware.uwb.fira_android",
+    owner: "google",
     vendor_available: true,
     srcs: ["android/hardware/uwb/fira_android/*.aidl"],
     stability: "vintf",
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
index cbe2068..6ec8d57 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -44,4 +44,9 @@
   CCC_SUPPORTED_PULSE_SHAPE_COMBOS = 166,
   CCC_SUPPORTED_RAN_MULTIPLIER = 167,
   SUPPORTED_AOA_RESULT_REQ_ANTENNA_INTERLEAVING = 227,
+  SUPPORTED_MIN_RANGING_INTERVAL_MS = 228,
+  SUPPORTED_RANGE_DATA_NTF_CONFIG = 229,
+  SUPPORTED_RSSI_REPORTING = 230,
+  SUPPORTED_DIAGNOSTICS = 231,
+  SUPPORTED_MIN_SLOT_DURATION = 232,
 }
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
index cd2e122..fbcfbff 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
@@ -36,4 +36,5 @@
 enum UwbVendorGidAndroidOids {
   ANDROID_GET_POWER_STATS = 0,
   ANDROID_SET_COUNTRY_CODE = 1,
+  ANDROID_RANGE_DIAGNOSTICS = 2,
 }
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl
index d35728f..8413f06 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl
@@ -43,4 +43,6 @@
   NB_OF_RANGE_MEASUREMENTS = 227,
   NB_OF_AZIMUTH_MEASUREMENTS = 228,
   NB_OF_ELEVATION_MEASUREMENTS = 229,
+  ENABLE_DIAGNOSTICS = 232,
+  DIAGRAMS_FRAME_REPORTS_FIELDS = 233,
 }
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
index 0140fdd..b182f9d 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -150,4 +150,38 @@
      *  0 - Feature not supported.
      */
     SUPPORTED_AOA_RESULT_REQ_ANTENNA_INTERLEAVING = 0xE3,
+
+    /**
+     * 4 byte value to indicate supported min ranging interval in ms.
+     */
+    SUPPORTED_MIN_RANGING_INTERVAL_MS = 0xE4,
+
+    /**
+     * 4 byte bitmask to indicate the supported RANGE_DATA_NTF_CONFIG values
+     *
+     * Bitmask where each bit corresponds to values used in
+     * RANGE_DATA_NTF_CONFIG in SET_APP_CFG_CMD
+     */
+    SUPPORTED_RANGE_DATA_NTF_CONFIG = 0xE5,
+
+    /**
+     * 1 byte bitmask to indicate the supported RSSI_REPORTING values
+     * Values:
+     * 1 - Feature supported.
+     * 0 - Feature not supported.
+     */
+    SUPPORTED_RSSI_REPORTING = 0xE6,
+
+    /**
+     * 1 byte value to indicate support for diagnostics feature.
+     * Values:
+     *  1 - Feature supported.
+     *  0 - Feature not supported.
+     */
+    SUPPORTED_DIAGNOSTICS = 0xE7,
+
+    /**
+     * 4 byte value to indicate supported min slot duration in ms.
+     */
+    SUPPORTED_MIN_SLOT_DURATION = 0xE8,
 }
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
index e389a2d..4768f55 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
@@ -30,5 +30,11 @@
     ANDROID_GET_POWER_STATS = 0x0,
     // Used to set the current regulatory country code (determined usinag
     // SIM or hardcoded by OEM).
+    // Country code is sent as a 2 byte value corresponding to ISO-3166 country code.
+    // Note: "00" is used to indicate that the country code is unknown.
     ANDROID_SET_COUNTRY_CODE = 0x1,
+    // Used by the notification to get UWB ranging diagnostics stats.
+    // Supported only if the UwbVendorCapabilityTlvTypes.SUPPORTED_DIAGNOSTICS set
+    // to 1.
+    ANDROID_RANGE_DIAGNOSTICS = 0x2,
 }
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl
index f43b249..f303ed9 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl
@@ -66,4 +66,23 @@
     NB_OF_AZIMUTH_MEASUREMENTS = 0xE4,
     /** 1 byte data */
     NB_OF_ELEVATION_MEASUREMENTS = 0xE5,
+
+    /**
+     * Supported only if the UwbVendorCapabilityTlvTypes
+     * .SUPPORTED_DIAGNOSTICS set to 1.
+     */
+    /**
+     * 1 byte data
+     * 1 - Enable,
+     * 0 - Disable
+     */
+    ENABLE_DIAGNOSTICS = 0xE8,
+    /**
+     * 1 byte bitmask
+     * b0: Activate RSSIs field,
+     * b1: Activate AoAs field,
+     * b2: Activate CIRs field,
+     * b3 - b7: RFU
+     */
+    DIAGRAMS_FRAME_REPORTS_FIELDS = 0xE9,
 }
diff --git a/vibrator/aidl/Android.bp b/vibrator/aidl/Android.bp
index 86ef027..c5936e3 100644
--- a/vibrator/aidl/Android.bp
+++ b/vibrator/aidl/Android.bp
@@ -17,7 +17,7 @@
     stability: "vintf",
     backend: {
         java: {
-            sdk_version: "module_current",
+            sdk_version: "system_current",
         },
     },
     versions: [
diff --git a/vibrator/aidl/default/example_vendor_java_client/Android.bp b/vibrator/aidl/default/example_vendor_java_client/Android.bp
new file mode 100644
index 0000000..f615cb1
--- /dev/null
+++ b/vibrator/aidl/default/example_vendor_java_client/Android.bp
@@ -0,0 +1,34 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library {
+    name: "libexample_vib_getter",
+    srcs: ["getter.cpp"],
+    vendor: true,
+    shared_libs: [
+        "liblog",
+        "libbinder_ndk",
+    ],
+    header_libs: ["jni_headers"],
+    stl: "c++_shared",
+    visibility: [":__subpackages__"],
+}
+
+android_app {
+    name: "ExampleVibratorJavaVendorClient",
+    privileged: true,
+    vendor: true,
+    static_libs: ["android.hardware.vibrator-V1-java"],
+    jni_libs: ["libexample_vib_getter"],
+    jarjar_rules: "jarjar.txt",
+    stl: "c++_shared",
+    srcs: ["example/vib/MyActivity.java"],
+    sdk_version: "system_current",
+    visibility: [":__subpackages__"],
+}
diff --git a/vibrator/aidl/default/example_vendor_java_client/AndroidManifest.xml b/vibrator/aidl/default/example_vendor_java_client/AndroidManifest.xml
new file mode 100644
index 0000000..0561066
--- /dev/null
+++ b/vibrator/aidl/default/example_vendor_java_client/AndroidManifest.xml
@@ -0,0 +1,7 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:tools="http://schemas.android.com/tools"
+          package="example.vib">
+    <application>
+        <activity android:name=".MyActivity"/>
+    </application>
+</manifest>
diff --git a/vibrator/aidl/default/example_vendor_java_client/example/vib/MyActivity.java b/vibrator/aidl/default/example_vendor_java_client/example/vib/MyActivity.java
new file mode 100644
index 0000000..aadce8e
--- /dev/null
+++ b/vibrator/aidl/default/example_vendor_java_client/example/vib/MyActivity.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package example.vib;
+
+import android.app.Activity;
+import android.hardware.vibrator.IVibrator;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+public class MyActivity extends Activity {
+    private static native IBinder gimme(String name);
+
+    @Override
+    public void onCreate(Bundle b) {
+        super.onCreate(b);
+        System.loadLibrary("example_vib_getter");
+
+        // There is no API to get ahold of a Stable AIDL service from a vendor app
+        // in Java. This is because this is not the recommended way to get ahold
+        // of functionality in Android. The Android API Council recommendation is to
+        // implement uses-library APIs in the system/system_ext partition which add
+        // new APIs. AIDL as an API in Java is not recommended or supported way to
+        // communicate by apps - the recommendation is to use Java APIs. However,
+        // there also exists a large number of vendor apps which are coupled with
+        // hardware-specific code, and are therefore on the vendor partition. A
+        // large number of these use HIDL, and this is how they can continue to
+        // use that structure with AIDL.
+        IVibrator v =
+                IVibrator.Stub.asInterface(gimme("android.hardware.vibrator.IVibrator/default"));
+
+        try {
+            v.on(100 /*ms*/, null /*cb*/);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+
+        finish();
+    }
+}
diff --git a/vibrator/aidl/default/example_vendor_java_client/getter.cpp b/vibrator/aidl/default/example_vendor_java_client/getter.cpp
new file mode 100644
index 0000000..6115445
--- /dev/null
+++ b/vibrator/aidl/default/example_vendor_java_client/getter.cpp
@@ -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.
+ */
+
+#include <android/binder_auto_utils.h>
+#include <android/binder_ibinder_jni.h>
+#include <android/binder_manager.h>
+#include <jni.h>
+#include <log/log.h>
+
+extern "C" JNIEXPORT jobject JNICALL
+Java_example_vib_MyActivity_gimme__Ljava_lang_String_2(JNIEnv* env, jclass /**/, jstring str) {
+    ALOGI("%s", __func__);
+
+    // Best practice is probably libnativehelper ScopedUtfChars or
+    // libbase ScopeGuard (for platform code), but this is with minimal
+    // dependencies.
+    const char* name = env->GetStringUTFChars(str, nullptr);
+
+    ALOGI("example vib gimme %s", name);
+
+    jobject jbinder = nullptr;
+
+    // Java does not have vendor variants. It's only safe to pass a service when
+    // 'vendor: true' if it is @VintfStability.
+    if (AServiceManager_isDeclared(name)) {
+        ndk::SpAIBinder binder = ndk::SpAIBinder(AServiceManager_waitForService(name));
+        jbinder = AIBinder_toJavaBinder(env, binder.get());
+    } else {
+        ALOGI("not declared");
+    }
+
+    env->ReleaseStringUTFChars(str, name);
+
+    return jbinder;
+}
diff --git a/vibrator/aidl/default/example_vendor_java_client/jarjar.txt b/vibrator/aidl/default/example_vendor_java_client/jarjar.txt
new file mode 100644
index 0000000..e7613a0
--- /dev/null
+++ b/vibrator/aidl/default/example_vendor_java_client/jarjar.txt
@@ -0,0 +1,2 @@
+rule android.hardware.** example.vib.ah.@1
+