Merge "Make VtsHalBootAidlTargetTest failures easier to debug." into main
diff --git a/METADATA b/METADATA
deleted file mode 100644
index d97975c..0000000
--- a/METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-third_party {
-  license_type: NOTICE
-}
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index 7b6109a..0f2fe99 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -310,6 +310,7 @@
         "android.hardware.audio_defaults",
         "latest_android_hardware_audio_common_import_interface",
         "latest_android_media_audio_common_types_import_interface",
+        "latest_android_media_audio_eraser_types_import_interface",
     ],
     srcs: [
         "android/hardware/audio/effect/AcousticEchoCanceler.aidl",
@@ -324,6 +325,7 @@
         "android/hardware/audio/effect/DynamicsProcessing.aidl",
         "android/hardware/audio/effect/EnvironmentalReverb.aidl",
         "android/hardware/audio/effect/Equalizer.aidl",
+        "android/hardware/audio/effect/Eraser.aidl",
         "android/hardware/audio/effect/Flags.aidl",
         "android/hardware/audio/effect/HapticGenerator.aidl",
         "android/hardware/audio/effect/IEffect.aidl",
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Descriptor.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Descriptor.aidl
index 115da1d..36f22ae 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Descriptor.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Descriptor.aidl
@@ -44,6 +44,7 @@
   const String EFFECT_TYPE_UUID_DYNAMICS_PROCESSING = "7261676f-6d75-7369-6364-28e2fd3ac39e";
   const String EFFECT_TYPE_UUID_ENV_REVERB = "c2e5d5f0-94bd-4763-9cac-4e234d06839e";
   const String EFFECT_TYPE_UUID_EQUALIZER = "0bed4300-ddd6-11db-8f34-0002a5d5c51b";
+  const String EFFECT_TYPE_UUID_ERASER = "fa81a9ac-588b-11ed-9b6a-0242ac120002";
   const String EFFECT_TYPE_UUID_HAPTIC_GENERATOR = "1411e6d6-aecd-4021-a1cf-a6aceb0d71e5";
   const String EFFECT_TYPE_UUID_LOUDNESS_ENHANCER = "fe3199be-aed0-413f-87bb-11260eb63cf1";
   const String EFFECT_TYPE_UUID_NS = "58b4b260-8e06-11e0-aa8e-0002a5d5c51b";
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Eraser.aidl
similarity index 81%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
copy to audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Eraser.aidl
index c1dc51c..5d8abd5 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Eraser.aidl
@@ -31,10 +31,15 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
+package android.hardware.audio.effect;
 @VintfStability
-union AcquiredInfoAndVendorCode {
-  android.hardware.biometrics.fingerprint.AcquiredInfo acquiredInfo = android.hardware.biometrics.fingerprint.AcquiredInfo.UNKNOWN;
-  int vendorCode;
+union Eraser {
+  android.hardware.audio.effect.VendorExtension vendor;
+  android.media.audio.eraser.Capability capability;
+  android.media.audio.eraser.Configuration configuration;
+  @VintfStability
+  union Id {
+    android.hardware.audio.effect.VendorExtension vendorExtensionTag;
+    android.hardware.audio.effect.Eraser.Tag commonTag;
+  }
 }
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl
index 8addab7..aa1a86f 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl
@@ -55,6 +55,9 @@
   parcelable HapticScale {
     int id;
     android.hardware.audio.effect.HapticGenerator.VibratorScale scale = android.hardware.audio.effect.HapticGenerator.VibratorScale.MUTE;
+    float scaleFactor = (-1.0f) /* -1.000000f */;
+    float adaptiveScaleFactor = (-1.0f) /* -1.000000f */;
+    const float UNDEFINED_SCALE_FACTOR = (-1.0f) /* -1.000000f */;
   }
   @VintfStability
   parcelable VibratorInformation {
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl
index ff33c42..40a49de 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl
@@ -63,6 +63,7 @@
     android.hardware.audio.effect.Volume.Id volumeTag;
     android.hardware.audio.effect.Parameter.Tag commonTag;
     android.hardware.audio.effect.Spatializer.Id spatializerTag;
+    android.hardware.audio.effect.Eraser.Id eraserTag;
   }
   @VintfStability
   parcelable Common {
@@ -95,5 +96,6 @@
     android.hardware.audio.effect.Visualizer visualizer;
     android.hardware.audio.effect.Volume volume;
     android.hardware.audio.effect.Spatializer spatializer;
+    android.hardware.audio.effect.Eraser eraser;
   }
 }
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/State.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/State.aidl
index 17f9814..873fb43 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/State.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/State.aidl
@@ -37,4 +37,5 @@
   INIT,
   IDLE,
   PROCESSING,
+  DRAINING,
 }
diff --git a/audio/aidl/android/hardware/audio/core/IStreamOut.aidl b/audio/aidl/android/hardware/audio/core/IStreamOut.aidl
index f26dc1c..111969f 100644
--- a/audio/aidl/android/hardware/audio/core/IStreamOut.aidl
+++ b/audio/aidl/android/hardware/audio/core/IStreamOut.aidl
@@ -214,7 +214,8 @@
      *
      * The range of supported values for speed and pitch factors is provided by
      * the 'IModule.getSupportedPlaybackRateFactors' method. Out of range speed
-     * and pitch values must not be rejected if the fallback mode is 'MUTE'.
+     * and pitch values may result in silent playback instead of returning an
+     * error in the case when the fallback mode is 'MUTE'.
      *
      * @param playbackRate Playback parameters to set.
      * @throws EX_ILLEGAL_ARGUMENT If provided parameters are out of acceptable range.
diff --git a/audio/aidl/android/hardware/audio/effect/CommandId.aidl b/audio/aidl/android/hardware/audio/effect/CommandId.aidl
index d940b42..de573bf 100644
--- a/audio/aidl/android/hardware/audio/effect/CommandId.aidl
+++ b/audio/aidl/android/hardware/audio/effect/CommandId.aidl
@@ -33,25 +33,39 @@
     /**
      * Start effect engine processing.
      * An effect instance must start processing data and transfer to PROCESSING state if it is in
-     * IDLE state and have all necessary information. Otherwise it must:
-     * 1. Throw a EX_ILLEGAL_STATE exception if effect is not in IDLE state, or
-     * 2. Throw a EX_TRANSACTION_FAILED for all other errors.
+     * IDLE or DRAINING state and has all necessary information. Otherwise, it must:
+     * 1. Throw an EX_ILLEGAL_STATE exception if the effect is not in IDLE or DRAINING state, or
+     * 2. Throw an EX_TRANSACTION_FAILED for all other errors.
      *
-     * Depending on parameters set to the effect instance, effect may do process or reverse
-     * process after START command.
+     * If an effect instance in DRAINING state receives a START command, it must transit back to
+     * PROCESSING state.
      */
     START = 0,
     /**
-     * Stop effect engine processing with all resource kept.
-     * The currently processed audio data will be discarded if the effect engine is in PROCESSING
-     * state.
-     * Effect instance must do nothing and return ok when it receive STOP command in IDLE state.
+     * Stop effect engine processing with all resources kept.
+     * If the effect is in **PROCESSING** state:
+     *   - It must transition to **IDLE** state if no intermediate operations are required.
+     *   - It must transition to **DRAINING** state if draining (e.g., fading) is required.
+     *     - The instance must automatically transition to **IDLE** after draining.
+     *     - It must ignore any new `STOP` commands during **DRAINING**.
+     *     - `START` commands during **DRAINING** must transition the instance back to
+     *       **PROCESSING**.
+     * If the effect instance is already in **IDLE** state, it must do nothing and return success.
+     *
+     * If the effect instance transitions to DRAINING state:
+     * 1. It must automatically transition to IDLE after completing draining tasks.
+     * 2. It must ignore any new STOP commands received during the DRAINING state.
+     * 3. START commands during DRAINING must immediately transfer the instance back to PROCESSING.
+     *
      */
     STOP = 1,
     /**
      * Keep all parameter settings but reset the buffer content, stop engine processing, and transit
-     * instance state to IDLE if its in PROCESSING state.
+     * the instance state to IDLE if it is in PROCESSING state.
      * Effect instance must be able to handle RESET command at IDLE and PROCESSING states.
+     *
+     * If the implementation includes intermediate operations such as draining, the RESET command
+     * must bypass DRAINING and immediately transition the state to IDLE.
      */
     RESET = 2,
 
diff --git a/audio/aidl/android/hardware/audio/effect/Descriptor.aidl b/audio/aidl/android/hardware/audio/effect/Descriptor.aidl
index b152f76..62e9bd4 100644
--- a/audio/aidl/android/hardware/audio/effect/Descriptor.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Descriptor.aidl
@@ -70,6 +70,10 @@
      */
     const String EFFECT_TYPE_UUID_EQUALIZER = "0bed4300-ddd6-11db-8f34-0002a5d5c51b";
     /**
+     * UUID for Audio eraser effect type.
+     */
+    const String EFFECT_TYPE_UUID_ERASER = "fa81a9ac-588b-11ed-9b6a-0242ac120002";
+    /**
      * UUID for Haptic Generator type.
      */
     const String EFFECT_TYPE_UUID_HAPTIC_GENERATOR = "1411e6d6-aecd-4021-a1cf-a6aceb0d71e5";
diff --git a/audio/aidl/android/hardware/audio/effect/Eraser.aidl b/audio/aidl/android/hardware/audio/effect/Eraser.aidl
new file mode 100644
index 0000000..990c6c0
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Eraser.aidl
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.VendorExtension;
+import android.media.audio.eraser.Capability;
+import android.media.audio.eraser.Configuration;
+import android.media.audio.eraser.Mode;
+
+/**
+ * The Audio Eraser Effect is an audio effect that combines multiple capabilities to manipulate and
+ * enhance audio streams.
+ *
+ * The Audio Eraser Effect integrates three primary components:
+ *
+ * Sound Separator: Detects and splits the input audio into multiple sound sources.
+ * Sound Classifier: Classifies each separated sound source into predefined categories based on the
+ * AudioSet ontology.
+ * Remixer: Adjusts the gain factor (volume) of each classified sound source according to specified
+ * configurations, then recombines them into a single output audio stream.
+ *
+ * The Audio Eraser Effect operates in different modes, each leveraging a subset of these
+ * components to achieve specific functionalities as defined in `android.media.audio.eraser.Mode`.
+ *
+ * Flow Diagrams for each operation mode as below.
+ *
+ * ERASER:
+ *                                                  +-----------------+
+ *                                              +-->| Sound Classifier|---+
+ *                                              |   +-----------------+   |
+ *                                              |                         |
+ *+----------------+       +----------------+   |   +-----------------+   |   +----------------+
+ *|   Input Audio  |------>| Sound Separator|---+-->| Sound Classifier|---+-->|    Remixer     |
+ *+----------------+       +----------------+   |   +-----------------+   |   +--------+-------+
+ *                                              |                         |            |
+ *                                              |   +-----------------+   |            |
+ *                                              +-->| Sound Classifier|---+            |
+ *                                                  +-----------------+                |
+ *                                                            |                        v
+ *                                                            v               +----------------+
+ *                                               {Classification Metadata}    |  Output Audio  |
+ *                                                                            +----------------+
+ *
+ * CLASSIFIER:
+ *+----------------+       +-----------------+       +-----------------+
+ *|   Input Audio  |------>| Sound Classifier|------>| Original Audio  |
+ *+----------------+       +-----------------+       +-----------------+
+ *                                  |
+ *                                  v
+ *                       {Classification Metadata}
+ *
+ */
+@VintfStability
+union Eraser {
+    /**
+     * Parameter Id with union tag to identify the parameters for getParameter().
+     */
+    @VintfStability
+    union Id {
+        VendorExtension vendorExtensionTag;
+        Eraser.Tag commonTag;
+    }
+
+    /**
+     * Vendor extension parameters which can be customized.
+     */
+    VendorExtension vendor;
+
+    /**
+     * Eraser capability, defines supported input/output data formats, available work modes, and
+     * the specific capabilities of the sound classifier and separator
+     */
+    Capability capability;
+
+    /**
+     * Eraser configuration, contains the list of configurations for the eraser effect.
+     */
+    Configuration configuration;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl b/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl
index 3cc5acb..f882d63 100644
--- a/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl
+++ b/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl
@@ -56,13 +56,51 @@
     @VintfStability
     parcelable HapticScale {
         /**
+         * Representation of undefined scale factor, applied by default for backwards compatibility.
+         */
+        const float UNDEFINED_SCALE_FACTOR = -1.0f;
+
+        /**
          * Audio track ID.
          */
         int id;
+
         /**
          * Haptic intensity.
+         *
+         * This represents haptics scale as fixed levels defined by VibrationScale. If the field
+         * scaleFactor is defined then this will be ignored in favor of scaleFactor, otherwise this
+         * will be used to define the intensity for the haptics.
          */
         VibratorScale scale = VibratorScale.MUTE;
+
+        /**
+         * Haptic scale factor.
+         *
+         * This is a continuous scale representation of VibratorScale, allowing flexible number of
+         * scale levels. If this field is defined then it will be used to define the intensity of
+         * the haptics, instead of the old VibratorScale field. If this field is undefined then the
+         * old VibratorScale field will be used.
+         *
+         * The value zero represents the same as VibratorScale.MUTE and the value one represents
+         * VibratorScale.NONE. Values in (0,1) should scale down, and values > 1 should scale up
+         * within hardware bounds. Negative values will be ignored.
+         */
+        float scaleFactor = -1.0f; // UNDEFINED_SCALE_FACTOR
+
+        /**
+         * Haptic adaptive scale factor.
+         *
+         * This is an additional scale value that should be applied on top of the vibrator scale to
+         * adapt to the device current state. This should be applied to linearly scale the haptic
+         * data after scale/scaleFactor is applied.
+         *
+         * The value zero mutes the haptics, even if the scale/scaleFactor are not set to MUTE/zero.
+         * The value one will not scale the haptics, and can be used as a constant for no-op.
+         * Values in (0,1) should scale down. Values > 1 should scale up within hardware bounds.
+         * Negative values will be ignored.
+         */
+        float adaptiveScaleFactor = -1.0f; // UNDEFINED_SCALE_FACTOR
     }
 
     /**
diff --git a/audio/aidl/android/hardware/audio/effect/Parameter.aidl b/audio/aidl/android/hardware/audio/effect/Parameter.aidl
index 6fd9161..d57e67d 100644
--- a/audio/aidl/android/hardware/audio/effect/Parameter.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Parameter.aidl
@@ -26,6 +26,7 @@
 import android.hardware.audio.effect.DynamicsProcessing;
 import android.hardware.audio.effect.EnvironmentalReverb;
 import android.hardware.audio.effect.Equalizer;
+import android.hardware.audio.effect.Eraser;
 import android.hardware.audio.effect.HapticGenerator;
 import android.hardware.audio.effect.LoudnessEnhancer;
 import android.hardware.audio.effect.NoiseSuppression;
@@ -111,6 +112,10 @@
          * Parameter tag defined for Spatializer parameters.
          */
         Spatializer.Id spatializerTag;
+        /**
+         * Parameter tag defined for eraser parameters.
+         */
+        Eraser.Id eraserTag;
     }
 
     /**
@@ -198,6 +203,8 @@
         Visualizer visualizer;
         Volume volume;
         Spatializer spatializer;
+        // Eraser added at android.hardware.audio.effect.V3
+        Eraser eraser;
     }
     Specific specific;
 
diff --git a/audio/aidl/android/hardware/audio/effect/State.aidl b/audio/aidl/android/hardware/audio/effect/State.aidl
index 85a4afc..1b698d7 100644
--- a/audio/aidl/android/hardware/audio/effect/State.aidl
+++ b/audio/aidl/android/hardware/audio/effect/State.aidl
@@ -24,18 +24,18 @@
  * it should transfer to IDLE state after handle the command successfully. Effect instance should
  * consume minimal resource and transfer to INIT state after it was close().
  *
- * Refer to State.gv for detailed state diagram.
+ * Refer to the state machine diagram `state.gv` for a detailed state diagram.
  */
 @VintfStability
 @Backing(type="byte")
 enum State {
-
     /**
      * An effect instance is in INIT state by default after it was created with
      * IFactory.createEffect(). When an effect instance is in INIT state, it should have instance
      * context initialized, and ready to handle IEffect.setParameter(), IEffect.open() as well as
      * all getter interfaces.
      *
+     * **Requirements in INIT state:**
      * In INIT state, effect instance must:
      * 1. Not handle any IEffect.command() and return EX_ILLEGAL_STATE with any Command.Id.
      * 2. Be able to handle all parameter setting with IEffect.setParameter().
@@ -43,28 +43,32 @@
      * IEffect.getState().
      * 4. Be able to handle IEffect.open() successfully after configuration.
      *
-     * Client is expected to do necessary configuration with IEffect.setParameter(), get all
-     * resource ready with IEffect.open(), and make sure effect instance transfer to IDLE state
-     * before sending commands with IEffect.command() interface. Effect instance must transfer
-     * from INIT to IDLE state after handle IEffect.open() call successfully.
+     * **State Transitions:**
+     * - Transitions to **IDLE** after successful `IEffect.open()`.
+     * - Remains in **INIT** on `IEffect.getState()` and `IEffect.getDescriptor()`.
+     * - Transitions to the final state on `IFactory.destroyEffect()`.
      */
     INIT,
+
     /**
      * An effect instance transfer to IDLE state after it was open successfully with IEffect.open()
      * in INIT state, or after it was stop/reset with Command.Id.STOP/RESET in PROCESSING state.
      *
-     * In IDLE state, effect instance must:
+     * **Requirements in IDLE state:**
      * 1. Be able to start effect processing engine with IEffect.command(Command.Id.START) call.
      * 2. Be able to handle all parameter setting with IEffect.setParameter().
      * 3. Be able to handle all getter interface calls like IEffect.getParameter() and
      * IEffect.getState().
      *
-     * The following state transfer can happen in IDLE state:
-     * 1. Transfer to PROCESSING if instance receive an START command and start processing data
-     * successfully.
-     * 2. Transfer to INIT if instance receive a close() call.
+     * **State Transitions:**
+     * - Transitions to **PROCESSING** on `IEffect.command(CommandId.START)` after starting
+     *   processing data successfully.
+     * - Transitions to **INIT** on `IEffect.close()`.
+     * - Remains in **IDLE** on `IEffect.getParameter()`, `IEffect.setParameter()`,
+     *   `IEffect.getDescriptor()`, `IEffect.command(CommandId.RESET)`, and `IEffect.reopen()`.
      */
     IDLE,
+
     /**
      * An effect instance is in PROCESSING state after it receive an START command and start
      * processing data successfully. Effect instance will transfer from PROCESSING to IDLE state if
@@ -75,12 +79,50 @@
      * the case of a close() call received when instance in PROCESSING state, it should try to stop
      * processing and transfer to IDLE first before close().
      *
-     * In PROCESSING state, effect instance must:
+     * **Requirements in PROCESSING state:**
      * 1. Return EX_ILLEGAL_STATE if it's not able to handle any parameter settings at runtime.
      * 2. Be able to handle STOP and RESET for IEffect.command() interface, and return
      * EX_ILLEGAL_STATE for all other commands.
      * 3. Must be able to handle all get* interface calls like IEffect.getParameter() and
      * IEffect.getState().
+     *
+     * **State Transitions:**
+     * - Transitions to **IDLE** on `IEffect.command(CommandId.STOP)` ( if no draining is required
+     *   or implemented) or `IEffect.command(CommandId.RESET)`.
+     * - Transitions to **DRAINING** on `IEffect.command(CommandId.STOP)` if draining is required.
+     * - Remains in **PROCESSING** on `IEffect.getParameter()`, `IEffect.setParameter()`,
+     *   `IEffect.getDescriptor()`, and `IEffect.reopen()`.
+     *
+     * **Notes:**
+     * - Clients should avoid calling `IEffect.close()` directly in this state; instead, they should
+     *   stop processing with `CommandId.STOP` before closing.
+     * - If `IEffect.close()` is called in this state, the effect instance should stop processing,
+     *   transition to **IDLE**, and then close.
      */
     PROCESSING,
+
+    /**
+     * DRAINING is an optional transitional state where the effect instance completes processing
+     * remaining input buffers or finalizes operations (e.g., fading) before stopping completely.
+     * This state is typically entered after a `CommandId.STOP` command in the PROCESSING state when
+     * draining is required.
+     *
+     * **Requirements in DRAINING state:**
+     * 1. Must handle `CommandId.START` and transition back to **PROCESSING**.
+     * 2. Must handle getter interface calls like `IEffect.getParameter()` and `IEffect.getState()`.
+     * 3. Must automatically transition to **IDLE** after draining is complete.
+     *
+     * **State Transitions:**
+     * - Transitions to **PROCESSING** on `IEffect.command(CommandId.START)`.
+     * - Transitions to **IDLE** on `IEffect.command(CommandId.RESET)`.
+     * - Transitions to **IDLE** automatically after draining is complete.
+     * - Remains in **DRAINING** on `IEffect.getParameter()`, `IEffect.setParameter()`,
+     *   `IEffect.getDescriptor()`, and `IEffect.reopen()`.
+     *
+     * **Notes:**
+     * - If not implemented, the effect instance may transition directly from **PROCESSING** to
+     *   **IDLE** without this intermediate state.
+     * - Any `CommandId.STOP` commands received during **DRAINING** should be ignored.
+     */
+    DRAINING,
 }
diff --git a/audio/aidl/android/hardware/audio/effect/state.gv b/audio/aidl/android/hardware/audio/effect/state.gv
index 22c70c8..2a8194e 100644
--- a/audio/aidl/android/hardware/audio/effect/state.gv
+++ b/audio/aidl/android/hardware/audio/effect/state.gv
@@ -13,26 +13,56 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 // To render: "dot -Tpng state.gv -o state.png"
+
 digraph effect_state_machine {
-    node[shape = point style = filled fillcolor = black width = 0.5] I;
-    node[shape = doublecircle] F;
-    node[shape = oval width = 1];
-    node[fillcolor = lightgreen] INIT;
-    node[fillcolor = lightblue] IDLE;
-    node[fillcolor = lightyellow] PROCESSING;
 
-    I -> INIT[label = "IFactory.createEffect" labelfontcolor = "navy"];
-    INIT -> F[label = "IFactory.destroyEffect"];
-    INIT -> IDLE[label = "IEffect.open()" labelfontcolor = "lime"];
-    IDLE -> PROCESSING[label = "IEffect.command(START"];
-    PROCESSING -> IDLE[label = "IEffect.command(STOP)\nIEffect.command(RESET)"];
-    IDLE -> INIT[label = "IEffect.close()"];
+    rankdir=LR; // Left to Right layout
 
-    INIT -> INIT[label = "IEffect.getState\nIEffect.getDescriptor"];
-    IDLE -> IDLE[label = "IEffect.getParameter\nIEffect.setParameter\nIEffect.getDescriptor\nIEffect.command(RESET)\nIEffect.reopen"];
-    PROCESSING
-            -> PROCESSING
-                    [label = "IEffect.getParameter\nIEffect.setParameter\nIEffect.getDescriptor\nIEffect.reopen"];
+    label="Effect State Machine";
+    fontsize=20;
+    labelloc=top;
+
+    node [fontname="Helvetica", fontsize=12, style=filled];
+
+    // Initial state node
+    I [shape=point, fillcolor=black, width=0.2];
+
+    // Final state node
+    F [shape=doublecircle, fillcolor=white, width=0.2];
+
+    // Define other nodes with colors
+    INIT [shape=ellipse, fillcolor=lightgreen];
+    IDLE [shape=ellipse, fillcolor=lightblue];
+    PROCESSING [shape=ellipse, fillcolor=lightyellow];
+    DRAINING [shape=ellipse, fillcolor=lightgrey];
+
+    // Transitions
+    I -> INIT [label="IFactory.createEffect", fontcolor="navy"];
+
+    INIT -> F [label="IFactory.destroyEffect"];
+
+    INIT -> IDLE [label="IEffect.open()", fontcolor="lime"];
+
+    IDLE -> PROCESSING [label="IEffect.command(START)"];
+
+    PROCESSING -> IDLE [label="IEffect.command(STOP)\nIEffect.command(RESET)"];
+
+    PROCESSING -> DRAINING [label="IEffect.command(STOP)", fontcolor="orange"];
+
+    DRAINING -> IDLE [label="Draining complete\n(IEffect.command(RESET)\nautomatic)"];
+
+    DRAINING -> PROCESSING [label="IEffect.command(START)\n(Interrupt draining)"];
+
+    IDLE -> INIT [label="IEffect.close()"];
+
+    // Self-loops
+    INIT -> INIT [label="IEffect.getState\nIEffect.getDescriptor"];
+
+    IDLE -> IDLE [label="IEffect.getParameter\nIEffect.setParameter\nIEffect.getDescriptor\nIEffect.command(RESET)\nIEffect.reopen"];
+
+    PROCESSING -> PROCESSING [label="IEffect.getParameter\nIEffect.setParameter\nIEffect.getDescriptor\nIEffect.reopen"];
+
+    DRAINING -> DRAINING [label="IEffect.getParameter\nIEffect.setParameter\nIEffect.getDescriptor\nIEffect.reopen\nFading"];
+
 }
diff --git a/audio/aidl/common/tests/utils_tests.cpp b/audio/aidl/common/tests/utils_tests.cpp
index 1b8b8df..1522d7e 100644
--- a/audio/aidl/common/tests/utils_tests.cpp
+++ b/audio/aidl/common/tests/utils_tests.cpp
@@ -86,7 +86,7 @@
             std::make_pair(6UL, AudioChannelLayout::LAYOUT_5POINT1),
             std::make_pair(8UL, AudioChannelLayout::LAYOUT_7POINT1),
             std::make_pair(16UL, AudioChannelLayout::LAYOUT_9POINT1POINT6),
-            std::make_pair(13UL, AudioChannelLayout::LAYOUT_13POINT_360RA),
+            std::make_pair(13UL, AudioChannelLayout::LAYOUT_13POINT0),
             std::make_pair(24UL, AudioChannelLayout::LAYOUT_22POINT2),
             std::make_pair(3UL, AudioChannelLayout::LAYOUT_STEREO_HAPTIC_A),
             std::make_pair(4UL, AudioChannelLayout::LAYOUT_STEREO_HAPTIC_AB)};
diff --git a/audio/aidl/default/EffectContext.cpp b/audio/aidl/default/EffectContext.cpp
index 26c88b2..b354dd1 100644
--- a/audio/aidl/default/EffectContext.cpp
+++ b/audio/aidl/default/EffectContext.cpp
@@ -258,4 +258,18 @@
     return RetCode::SUCCESS;
 }
 
+RetCode EffectContext::startDraining() {
+    mIsDraining = true;
+    return RetCode::SUCCESS;
+}
+
+RetCode EffectContext::finishDraining() {
+    mIsDraining = false;
+    return RetCode::SUCCESS;
+}
+
+bool EffectContext::isDraining() {
+    return mIsDraining;
+}
+
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/EffectImpl.cpp b/audio/aidl/default/EffectImpl.cpp
index 3e61335..7857f53 100644
--- a/audio/aidl/default/EffectImpl.cpp
+++ b/audio/aidl/default/EffectImpl.cpp
@@ -79,7 +79,6 @@
     std::lock_guard lg(mImplMutex);
     RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "alreadyClosed");
 
-    // TODO: b/302036943 add reopen implementation
     RETURN_IF(!mImplContext, EX_NULL_POINTER, "nullContext");
     mImplContext->dupeFmqWithReopen(ret);
     return ndk::ScopedAStatus::ok();
@@ -347,7 +346,7 @@
 
     {
         std::lock_guard lg(mImplMutex);
-        if (mState != State::PROCESSING) {
+        if (mState != State::PROCESSING && mState != State::DRAINING) {
             LOG(DEBUG) << getEffectNameWithVersion()
                        << " skip process in state: " << toString(mState);
             return;
diff --git a/audio/aidl/default/EffectThread.cpp b/audio/aidl/default/EffectThread.cpp
index b515385..1a52c13 100644
--- a/audio/aidl/default/EffectThread.cpp
+++ b/audio/aidl/default/EffectThread.cpp
@@ -68,7 +68,11 @@
 RetCode EffectThread::startThread() {
     {
         std::lock_guard lg(mThreadMutex);
-        mStop = false;
+        if (mDraining) {
+            mDraining = false;
+        } else {
+            mStop = false;
+        }
         mCv.notify_one();
     }
 
@@ -87,6 +91,25 @@
     return RetCode::SUCCESS;
 }
 
+RetCode EffectThread::startDraining() {
+    std::lock_guard lg(mThreadMutex);
+    mDraining = true;
+    mCv.notify_one();
+
+    LOG(VERBOSE) << mName << __func__;
+    return RetCode::SUCCESS;
+}
+
+RetCode EffectThread::finishDraining() {
+    std::lock_guard lg(mThreadMutex);
+    mDraining = false;
+    mStop = true;
+    mCv.notify_one();
+
+    LOG(VERBOSE) << mName << __func__;
+    return RetCode::SUCCESS;
+}
+
 void EffectThread::threadLoop() {
     pthread_setname_np(pthread_self(), mName.substr(0, kMaxTaskNameLen - 1).c_str());
     setpriority(PRIO_PROCESS, 0, mPriority);
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index e96cf81..f9fa799 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -184,8 +184,12 @@
     const int32_t nominalLatencyMs = getNominalLatencyMs(*portConfigIt);
     // Since this is a private method, it is assumed that
     // validity of the portConfigId has already been checked.
-    const int32_t minimumStreamBufferSizeFrames =
-            calculateBufferSizeFrames(nominalLatencyMs, portConfigIt->sampleRate.value().value);
+    int32_t minimumStreamBufferSizeFrames = 0;
+    if (!calculateBufferSizeFrames(
+                portConfigIt->format.value(), nominalLatencyMs,
+                portConfigIt->sampleRate.value().value, &minimumStreamBufferSizeFrames).isOk()) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
     if (in_bufferSizeFrames < minimumStreamBufferSizeFrames) {
         LOG(ERROR) << __func__ << ": " << mType << ": insufficient buffer size "
                    << in_bufferSizeFrames << ", must be at least " << minimumStreamBufferSizeFrames;
@@ -378,6 +382,18 @@
     return kLatencyMs;
 }
 
+ndk::ScopedAStatus Module::calculateBufferSizeFrames(
+        const ::aidl::android::media::audio::common::AudioFormatDescription &format,
+        int32_t latencyMs, int32_t sampleRateHz, int32_t *bufferSizeFrames) {
+    if (format.type == AudioFormatType::PCM) {
+        *bufferSizeFrames = calculateBufferSizeFramesForPcm(latencyMs, sampleRateHz);
+        return ndk::ScopedAStatus::ok();
+    }
+    LOG(ERROR) << __func__ << ": " << mType << ": format " << format.toString()
+        << " is not supported";
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
 ndk::ScopedAStatus Module::createMmapBuffer(
         const ::aidl::android::hardware::audio::core::StreamContext& context __unused,
         ::aidl::android::hardware::audio::core::StreamDescriptor* desc __unused) {
@@ -1123,8 +1139,14 @@
     *_aidl_return = in_requested;
     auto maxSampleRateIt = std::max_element(sampleRates.begin(), sampleRates.end());
     const int32_t latencyMs = getNominalLatencyMs(*(maxSampleRateIt->second));
-    _aidl_return->minimumStreamBufferSizeFrames =
-            calculateBufferSizeFrames(latencyMs, maxSampleRateIt->first);
+    if (!calculateBufferSizeFrames(
+                maxSampleRateIt->second->format.value(), latencyMs, maxSampleRateIt->first,
+                &_aidl_return->minimumStreamBufferSizeFrames).isOk()) {
+        if (patchesBackup.has_value()) {
+            mPatches = std::move(*patchesBackup);
+        }
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
     _aidl_return->latenciesMs.clear();
     _aidl_return->latenciesMs.insert(_aidl_return->latenciesMs.end(),
                                      _aidl_return->sinkPortConfigIds.size(), latencyMs);
diff --git a/audio/aidl/default/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml
index a54f4db..2e860d8 100644
--- a/audio/aidl/default/audio_effects_config.xml
+++ b/audio/aidl/default/audio_effects_config.xml
@@ -36,6 +36,7 @@
         <library name="downmix" path="libdownmixaidl.so"/>
         <library name="dynamics_processing" path="libdynamicsprocessingaidl.so"/>
         <library name="equalizersw" path="libequalizersw.so"/>
+        <library name="erasersw" path="liberasersw.so"/>
         <library name="haptic_generator" path="libhapticgeneratoraidl.so"/>
         <library name="loudness_enhancer" path="libloudnessenhanceraidl.so"/>
         <library name="nssw" path="libnssw.so"/>
@@ -75,6 +76,7 @@
         <effect name="bassboost" library="bundle" uuid="8631f300-72e2-11df-b57e-0002a5d5c51b"/>
         <effect name="downmix" library="downmix" uuid="93f04452-e4fe-41cc-91f9-e475b6d1d69f"/>
         <effect name="dynamics_processing" library="dynamics_processing" uuid="e0e6539b-1781-7261-676f-6d7573696340"/>
+        <effect name="eraser" library="erasersw" uuid="fa81ab46-588b-11ed-9b6a-0242ac120002"/>
         <effect name="haptic_generator" library="haptic_generator" uuid="97c4acd1-8b82-4f2f-832e-c2fe5d7a9931"/>
         <effect name="loudness_enhancer" library="loudness_enhancer" uuid="fa415329-2034-4bea-b5dc-5b381c8d1e2c"/>
         <effect name="reverb_env_aux" library="reverb" uuid="4a387fc0-8ab3-11df-8bad-0002a5d5c51b"/>
diff --git a/audio/aidl/default/config/audioPolicy/api/current.txt b/audio/aidl/default/config/audioPolicy/api/current.txt
index e57c108..3814fe6 100644
--- a/audio/aidl/default/config/audioPolicy/api/current.txt
+++ b/audio/aidl/default/config/audioPolicy/api/current.txt
@@ -50,7 +50,7 @@
     enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO;
     enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO;
     enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_NONE;
-    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_13POINT_360RA;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_13POINT0;
     enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_22POINT2;
     enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT0POINT2;
     enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT1;
diff --git a/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd b/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
index 108a6a3..cfe0a6e 100644
--- a/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
+++ b/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
@@ -463,7 +463,7 @@
             <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_13POINT0"/>
             <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"/>
diff --git a/audio/aidl/default/eraser/Android.bp b/audio/aidl/default/eraser/Android.bp
new file mode 100644
index 0000000..c495d8e
--- /dev/null
+++ b/audio/aidl/default/eraser/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+    default_team: "trendy_team_android_media_audio_framework",
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+    name: "liberasersw",
+    defaults: [
+        "aidlaudioeffectservice_defaults",
+    ],
+    srcs: [
+        "Eraser.cpp",
+        ":effectCommonFile",
+    ],
+    relative_install_path: "soundfx",
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default:__subpackages__",
+    ],
+}
diff --git a/audio/aidl/default/eraser/Eraser.cpp b/audio/aidl/default/eraser/Eraser.cpp
new file mode 100644
index 0000000..59cc9a2
--- /dev/null
+++ b/audio/aidl/default/eraser/Eraser.cpp
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHAL_Eraser"
+
+#include "Eraser.h"
+
+#include <android-base/logging.h>
+#include <system/audio_effects/effect_uuid.h>
+
+#include <optional>
+
+using aidl::android::hardware::audio::common::getChannelCount;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::EraserSw;
+using aidl::android::hardware::audio::effect::getEffectImplUuidEraserSw;
+using aidl::android::hardware::audio::effect::getEffectTypeUuidEraser;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::media::audio::common::AudioChannelLayout;
+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 != getEffectImplUuidEraserSw()) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (!instanceSpp) {
+        LOG(ERROR) << __func__ << " invalid input parameter!";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+
+    *instanceSpp = ndk::SharedRefBase::make<EraserSw>();
+    LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
+    return EX_NONE;
+}
+
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+    if (!in_impl_uuid || *in_impl_uuid != getEffectImplUuidEraserSw()) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    *_aidl_return = EraserSw::kDescriptor;
+    return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+const std::string EraserSw::kEffectName = "EraserSw";
+const Descriptor EraserSw::kDescriptor = {
+        .common = {.id = {.type = getEffectTypeUuidEraser(), .uuid = getEffectImplUuidEraserSw()},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::FIRST,
+                             .hwAcceleratorMode = Flags::HardwareAccelerator::NONE},
+                   .name = EraserSw::kEffectName,
+                   .implementor = "The Android Open Source Project"}};
+
+ndk::ScopedAStatus EraserSw::getDescriptor(Descriptor* _aidl_return) {
+    LOG(DEBUG) << __func__ << kDescriptor.toString();
+    *_aidl_return = kDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EraserSw::setParameterSpecific(const Parameter::Specific& specific) {
+    RETURN_IF(Parameter::Specific::eraser != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+              "EffectNotSupported");
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    auto& param = specific.get<Parameter::Specific::eraser>();
+    return mContext->setParam(param.getTag(), param);
+}
+
+ndk::ScopedAStatus EraserSw::getParameterSpecific(const Parameter::Id& id,
+                                                  Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    auto tag = id.getTag();
+    RETURN_IF(Parameter::Id::eraserTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+    auto eraserId = id.get<Parameter::Id::eraserTag>();
+    auto eraserTag = eraserId.getTag();
+    switch (eraserTag) {
+        case Eraser::Id::commonTag: {
+            auto specificTag = eraserId.get<Eraser::Id::commonTag>();
+            std::optional<Eraser> param = mContext->getParam(specificTag);
+            if (!param.has_value()) {
+                return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                        "EraserTagNotSupported");
+            }
+            specific->set<Parameter::Specific::eraser>(param.value());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "EraserTagNotSupported");
+        }
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> EraserSw::createContext(const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+    } else {
+        mContext = std::make_shared<EraserSwContext>(1 /* statusFmqDepth */, common);
+    }
+    return mContext;
+}
+
+RetCode EraserSw::releaseContext() {
+    if (mContext) {
+        mContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+EraserSw::~EraserSw() {
+    cleanUp();
+    LOG(DEBUG) << __func__;
+}
+
+ndk::ScopedAStatus EraserSw::command(CommandId command) {
+    std::lock_guard lg(mImplMutex);
+    RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "instanceNotOpen");
+
+    switch (command) {
+        case CommandId::START:
+            RETURN_OK_IF(mState == State::PROCESSING);
+            mState = State::PROCESSING;
+            mContext->enable();
+            startThread();
+            RETURN_IF(notifyEventFlag(mDataMqNotEmptyEf) != RetCode::SUCCESS, EX_ILLEGAL_STATE,
+                      "notifyEventFlagNotEmptyFailed");
+            break;
+        case CommandId::STOP:
+            RETURN_OK_IF(mState == State::IDLE || mState == State::DRAINING);
+            if (mVersion < kDrainSupportedVersion) {
+                mState = State::IDLE;
+                stopThread();
+                mContext->disable();
+            } else {
+                mState = State::DRAINING;
+                startDraining();
+                mContext->startDraining();
+            }
+            RETURN_IF(notifyEventFlag(mDataMqNotEmptyEf) != RetCode::SUCCESS, EX_ILLEGAL_STATE,
+                      "notifyEventFlagNotEmptyFailed");
+            break;
+        case CommandId::RESET:
+            mState = State::IDLE;
+            RETURN_IF(notifyEventFlag(mDataMqNotEmptyEf) != RetCode::SUCCESS, EX_ILLEGAL_STATE,
+                      "notifyEventFlagNotEmptyFailed");
+            stopThread();
+            mImplContext->disable();
+            mImplContext->reset();
+            mImplContext->resetBuffer();
+            break;
+        default:
+            LOG(ERROR) << getEffectNameWithVersion() << __func__ << " instance still processing";
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "CommandIdNotSupported");
+    }
+    LOG(VERBOSE) << getEffectNameWithVersion() << __func__
+                 << " transfer to state: " << toString(mState);
+    return ndk::ScopedAStatus::ok();
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status EraserSw::effectProcessImpl(float* in, float* out, int samples) {
+    RETURN_VALUE_IF(!mContext, (IEffect::Status{EX_NULL_POINTER, 0, 0}), "nullContext");
+    IEffect::Status procStatus{STATUS_NOT_ENOUGH_DATA, 0, 0};
+    procStatus = mContext->process(in, out, samples);
+    if (mState == State::DRAINING && procStatus.status == STATUS_NOT_ENOUGH_DATA) {
+        drainingComplete_l();
+    }
+
+    return procStatus;
+}
+
+void EraserSw::drainingComplete_l() {
+    if (mState != State::DRAINING) return;
+
+    LOG(DEBUG) << getEffectNameWithVersion() << __func__;
+    finishDraining();
+    mState = State::IDLE;
+}
+
+EraserSwContext::EraserSwContext(int statusDepth, const Parameter::Common& common)
+    : EffectContext(statusDepth, common) {
+    LOG(DEBUG) << __func__;
+}
+
+EraserSwContext::~EraserSwContext() {
+    LOG(DEBUG) << __func__;
+}
+
+template <typename TAG>
+std::optional<Eraser> EraserSwContext::getParam(TAG tag) {
+    if (mParamsMap.find(tag) != mParamsMap.end()) {
+        return mParamsMap.at(tag);
+    }
+    return std::nullopt;
+}
+
+template <typename TAG>
+ndk::ScopedAStatus EraserSwContext::setParam(TAG tag, Eraser eraser) {
+    mParamsMap[tag] = eraser;
+    return ndk::ScopedAStatus::ok();
+}
+
+IEffect::Status EraserSwContext::process(float* in, float* out, int samples) {
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+    IEffect::Status procStatus = {EX_ILLEGAL_ARGUMENT, 0, 0};
+    const auto inputChannelCount = getChannelCount(mCommon.input.base.channelMask);
+    const auto outputChannelCount = getChannelCount(mCommon.output.base.channelMask);
+    if (inputChannelCount < outputChannelCount) {
+        LOG(ERROR) << __func__ << " invalid channel count, in: " << inputChannelCount
+                   << " out: " << outputChannelCount;
+        return procStatus;
+    }
+
+    if (samples <= 0 || 0 != samples % inputChannelCount) {
+        LOG(ERROR) << __func__ << " invalid samples: " << samples;
+        return procStatus;
+    }
+
+    const int iFrames = samples / inputChannelCount;
+    const float gainPerSample = 1.f / iFrames;
+    for (int i = 0; i < iFrames; i++) {
+        if (isDraining()) {
+            const float gain = (iFrames - i - 1) * gainPerSample;
+            for (size_t c = 0; c < outputChannelCount; c++) {
+                out[c] = in[c] * gain;
+            }
+        } else {
+            std::memcpy(out, in, outputChannelCount * sizeof(float));
+        }
+
+        in += inputChannelCount;
+        out += outputChannelCount;
+    }
+
+    // drain for one cycle
+    if (isDraining()) {
+        procStatus.status = STATUS_NOT_ENOUGH_DATA;
+        finishDraining();
+    } else {
+        procStatus.status = STATUS_OK;
+    }
+    procStatus.fmqConsumed = static_cast<int32_t>(iFrames * inputChannelCount);
+    procStatus.fmqProduced = static_cast<int32_t>(iFrames * outputChannelCount);
+
+    return procStatus;
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/eraser/Eraser.h b/audio/aidl/default/eraser/Eraser.h
new file mode 100644
index 0000000..7bf2f57
--- /dev/null
+++ b/audio/aidl/default/eraser/Eraser.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "effect-impl/EffectContext.h"
+#include "effect-impl/EffectImpl.h"
+
+#include <fmq/AidlMessageQueue.h>
+
+#include <unordered_map>
+#include <vector>
+
+namespace aidl::android::hardware::audio::effect {
+
+class EraserSwContext final : public EffectContext {
+  public:
+    EraserSwContext(int statusDepth, const Parameter::Common& common);
+    ~EraserSwContext() final;
+
+    template <typename TAG>
+    std::optional<Eraser> getParam(TAG tag);
+    template <typename TAG>
+    ndk::ScopedAStatus setParam(TAG tag, Eraser eraser);
+
+    IEffect::Status process(float* in, float* out, int samples);
+
+  private:
+    std::unordered_map<Eraser::Tag, Eraser> mParamsMap;
+};
+
+class EraserSw final : public EffectImpl {
+  public:
+    static const std::string kEffectName;
+    static const Capability kCapability;
+    static const Descriptor kDescriptor;
+    ~EraserSw() final;
+
+    ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) final;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) final;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) final;
+
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) final;
+    RetCode releaseContext() REQUIRES(mImplMutex) final;
+
+    std::string getEffectName() final { return kEffectName; };
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) final;
+
+    ndk::ScopedAStatus command(CommandId command) final;
+    void drainingComplete_l() REQUIRES(mImplMutex);
+
+  private:
+    static const std::vector<Range::SpatializerRange> kRanges;
+    std::shared_ptr<EraserSwContext> mContext GUARDED_BY(mImplMutex);
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index d03598a..cbc13d1 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -207,12 +207,15 @@
     virtual std::unique_ptr<Configuration> initializeConfig();
     virtual int32_t getNominalLatencyMs(
             const ::aidl::android::media::audio::common::AudioPortConfig& portConfig);
+    virtual ndk::ScopedAStatus calculateBufferSizeFrames(
+            const ::aidl::android::media::audio::common::AudioFormatDescription &format,
+            int32_t latencyMs, int32_t sampleRateHz, int32_t *bufferSizeFrames);
     virtual ndk::ScopedAStatus createMmapBuffer(
             const ::aidl::android::hardware::audio::core::StreamContext& context,
             ::aidl::android::hardware::audio::core::StreamDescriptor* desc);
 
     // Utility and helper functions accessible to subclasses.
-    static int32_t calculateBufferSizeFrames(int32_t latencyMs, int32_t sampleRateHz) {
+    static int32_t calculateBufferSizeFramesForPcm(int32_t latencyMs, int32_t sampleRateHz) {
         const int32_t rawSizeFrames =
                 aidl::android::hardware::audio::common::frameCountFromDurationMs(latencyMs,
                                                                                  sampleRateHz);
diff --git a/audio/aidl/default/include/effect-impl/EffectContext.h b/audio/aidl/default/include/effect-impl/EffectContext.h
index 02a4caa..9e44349 100644
--- a/audio/aidl/default/include/effect-impl/EffectContext.h
+++ b/audio/aidl/default/include/effect-impl/EffectContext.h
@@ -86,7 +86,12 @@
     virtual RetCode disable();
     virtual RetCode reset();
 
+    virtual RetCode startDraining();
+    virtual RetCode finishDraining();
+    virtual bool isDraining();
+
   protected:
+    bool mIsDraining = false;
     int mVersion = 0;
     size_t mInputFrameSize = 0;
     size_t mOutputFrameSize = 0;
diff --git a/audio/aidl/default/include/effect-impl/EffectThread.h b/audio/aidl/default/include/effect-impl/EffectThread.h
index ec2a658..9abcdb8 100644
--- a/audio/aidl/default/include/effect-impl/EffectThread.h
+++ b/audio/aidl/default/include/effect-impl/EffectThread.h
@@ -38,6 +38,8 @@
     RetCode destroyThread();
     RetCode startThread();
     RetCode stopThread();
+    RetCode startDraining();
+    RetCode finishDraining();
 
     // Will call process() in a loop if the thread is running.
     void threadLoop();
@@ -49,6 +51,9 @@
      */
     virtual void process() = 0;
 
+  protected:
+    bool mDraining GUARDED_BY(mThreadMutex) = false;
+
   private:
     static constexpr int kMaxTaskNameLen = 15;
 
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index 4a71be9..5f0a608 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -14,6 +14,7 @@
         "latest_android_hardware_audio_common_ndk_static",
         "latest_android_hardware_audio_effect_ndk_static",
         "latest_android_media_audio_common_types_ndk_static",
+        "latest_android_media_audio_eraser_types_ndk_static",
         "use_libaidlvintf_gtest_helper_static",
         "VtsHalTargetTestDefaults",
     ],
@@ -139,6 +140,9 @@
     name: "VtsHalHapticGeneratorTargetTest",
     defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalHapticGeneratorTargetTest.cpp"],
+    shared_libs: [
+        "libaudioutils",
+    ],
 }
 
 cc_test {
diff --git a/audio/aidl/vts/EffectHelper.h b/audio/aidl/vts/EffectHelper.h
index 570ecef..eedac3d 100644
--- a/audio/aidl/vts/EffectHelper.h
+++ b/audio/aidl/vts/EffectHelper.h
@@ -124,7 +124,7 @@
             return;
         }
 
-        ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+        ASSERT_TRUE(expectState(effect, State::IDLE));
         updateFrameSize(common);
     }
 
@@ -155,7 +155,7 @@
         if (effect) {
             ASSERT_STATUS(status, effect->close());
             if (status == EX_NONE) {
-                ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
+                ASSERT_TRUE(expectState(effect, State::INIT));
             }
         }
     }
@@ -166,12 +166,14 @@
         ASSERT_STATUS(status, effect->getDescriptor(&desc));
     }
 
-    static void expectState(std::shared_ptr<IEffect> effect, State expectState,
-                            binder_status_t status = EX_NONE) {
-        ASSERT_NE(effect, nullptr);
-        State state;
-        ASSERT_STATUS(status, effect->getState(&state));
-        ASSERT_EQ(expectState, state);
+    static bool expectState(std::shared_ptr<IEffect> effect, State expectState) {
+        if (effect == nullptr) return false;
+
+        if (State state; EX_NONE != effect->getState(&state).getStatus() || expectState != state) {
+            return false;
+        }
+
+        return true;
     }
 
     static void commandIgnoreRet(std::shared_ptr<IEffect> effect, CommandId command) {
@@ -190,12 +192,14 @@
 
         switch (command) {
             case CommandId::START:
-                ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+                ASSERT_TRUE(expectState(effect, State::PROCESSING));
                 break;
             case CommandId::STOP:
-                FALLTHROUGH_INTENDED;
+                ASSERT_TRUE(expectState(effect, State::IDLE) ||
+                            expectState(effect, State::DRAINING));
+                break;
             case CommandId::RESET:
-                ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+                ASSERT_TRUE(expectState(effect, State::IDLE));
                 break;
             default:
                 return;
@@ -371,6 +375,24 @@
         return functor(result);
     }
 
+    // keep writing data to the FMQ until effect transit from DRAINING to IDLE
+    static void waitForDrain(std::vector<float>& inputBuffer, std::vector<float>& outputBuffer,
+                             const std::shared_ptr<IEffect>& effect,
+                             std::unique_ptr<EffectHelper::StatusMQ>& statusMQ,
+                             std::unique_ptr<EffectHelper::DataMQ>& inputMQ,
+                             std::unique_ptr<EffectHelper::DataMQ>& outputMQ, int version) {
+        State state;
+        while (effect->getState(&state).getStatus() == EX_NONE && state == State::DRAINING) {
+            EXPECT_NO_FATAL_FAILURE(
+                    EffectHelper::writeToFmq(statusMQ, inputMQ, inputBuffer, version));
+            EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(
+                    statusMQ, 1, outputMQ, outputBuffer.size(), outputBuffer, std::nullopt));
+        }
+        ASSERT_TRUE(State::IDLE == state);
+        EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, outputBuffer));
+        return;
+    }
+
     static void processAndWriteToOutput(std::vector<float>& inputBuffer,
                                         std::vector<float>& outputBuffer,
                                         const std::shared_ptr<IEffect>& effect,
@@ -404,8 +426,9 @@
         // Disable the process
         if (callStopReset) {
             ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+            EXPECT_NO_FATAL_FAILURE(waitForDrain(inputBuffer, outputBuffer, effect, statusMQ,
+                                                 inputMQ, outputMQ, version));
         }
-        EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, outputBuffer));
 
         if (callStopReset) {
             ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
@@ -484,6 +507,17 @@
         mOutputSamples = common.output.frameCount * mOutputFrameSize / sizeof(float);
     }
 
+    void generateInput(std::vector<float>& input, float inputFrequency, float samplingFrequency,
+                       size_t inputSize = 0) {
+        if (inputSize == 0 || inputSize > input.size()) {
+            inputSize = input.size();
+        }
+
+        for (size_t i = 0; i < inputSize; i++) {
+            input[i] = sin(2 * M_PI * inputFrequency * i / samplingFrequency);
+        }
+    }
+
     bool mIsSpatializer;
     Descriptor mDescriptor;
     size_t mInputFrameSize, mOutputFrameSize;
diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
index 6bce107..93c2a61 100644
--- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -376,7 +376,8 @@
 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) {
+                   const std::vector<PropType>& invalidValues, bool* isSupported,
+                   const std::vector<PropType>* ambivalentValues = nullptr) {
     PropType initialValue{};
     ScopedAStatus status = (inst->*getter)(&initialValue);
     if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
@@ -395,6 +396,15 @@
         EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, (inst->*setter)(v))
                 << "for an invalid value: " << ::testing::PrintToString(v);
     }
+    if (ambivalentValues != nullptr) {
+        for (const auto v : *ambivalentValues) {
+            const auto status = (inst->*setter)(v);
+            if (!status.isOk()) {
+                EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, status)
+                        << "for an ambivalent value: " << ::testing::PrintToString(v);
+            }
+        }
+    }
     EXPECT_IS_OK((inst->*setter)(initialValue)) << "Failed to restore the initial value";
 }
 
@@ -3936,11 +3946,6 @@
             AudioPlaybackRate{1.0f, 1.0f, tsVoice, fbFail},
             AudioPlaybackRate{factors.maxSpeed, factors.maxPitch, tsVoice, fbMute},
             AudioPlaybackRate{factors.minSpeed, factors.minPitch, tsVoice, fbMute},
-            // Out of range speed / pitch values must not be rejected if the fallback mode is "mute"
-            AudioPlaybackRate{factors.maxSpeed * 2, factors.maxPitch * 2, tsDefault, fbMute},
-            AudioPlaybackRate{factors.minSpeed / 2, factors.minPitch / 2, tsDefault, fbMute},
-            AudioPlaybackRate{factors.maxSpeed * 2, factors.maxPitch * 2, tsVoice, fbMute},
-            AudioPlaybackRate{factors.minSpeed / 2, factors.minPitch / 2, tsVoice, fbMute},
     };
     const std::vector<AudioPlaybackRate> invalidValues = {
             AudioPlaybackRate{factors.maxSpeed, factors.maxPitch * 2, tsDefault, fbFail},
@@ -3956,6 +3961,14 @@
             AudioPlaybackRate{1.0f, 1.0f, tsDefault,
                               AudioPlaybackRate::TimestretchFallbackMode::SYS_RESERVED_DEFAULT},
     };
+    const std::vector<AudioPlaybackRate> ambivalentValues = {
+            // Out of range speed / pitch values may optionally be rejected if the fallback mode
+            // is "mute".
+            AudioPlaybackRate{factors.maxSpeed * 2, factors.maxPitch * 2, tsDefault, fbMute},
+            AudioPlaybackRate{factors.minSpeed / 2, factors.minPitch / 2, tsDefault, fbMute},
+            AudioPlaybackRate{factors.maxSpeed * 2, factors.maxPitch * 2, tsVoice, fbMute},
+            AudioPlaybackRate{factors.minSpeed / 2, factors.minPitch / 2, tsVoice, fbMute},
+    };
     bool atLeastOneSupports = false;
     for (const auto& port : offloadMixPorts) {
         const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, port);
@@ -3965,7 +3978,8 @@
         bool isSupported = false;
         EXPECT_NO_FATAL_FAILURE(TestAccessors<AudioPlaybackRate>(
                 stream.get(), &IStreamOut::getPlaybackRateParameters,
-                &IStreamOut::setPlaybackRateParameters, validValues, invalidValues, &isSupported));
+                &IStreamOut::setPlaybackRateParameters, validValues, invalidValues, &isSupported,
+                &ambivalentValues));
         if (isSupported) atLeastOneSupports = true;
     }
     if (!atLeastOneSupports) {
diff --git a/audio/aidl/vts/VtsHalDownmixTargetTest.cpp b/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
index bf22839..322fdc0 100644
--- a/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
@@ -52,7 +52,7 @@
         AudioChannelLayout::LAYOUT_5POINT1POINT4, AudioChannelLayout::LAYOUT_6POINT1,
         AudioChannelLayout::LAYOUT_7POINT1,       AudioChannelLayout::LAYOUT_7POINT1POINT2,
         AudioChannelLayout::LAYOUT_7POINT1POINT4, AudioChannelLayout::LAYOUT_9POINT1POINT4,
-        AudioChannelLayout::LAYOUT_9POINT1POINT6, AudioChannelLayout::LAYOUT_13POINT_360RA,
+        AudioChannelLayout::LAYOUT_9POINT1POINT6, AudioChannelLayout::LAYOUT_13POINT0,
         AudioChannelLayout::LAYOUT_22POINT2};
 
 static const std::vector<int32_t> kChannels = {
diff --git a/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
index f106d83..3b1f3d9 100644
--- a/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
+++ b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
@@ -116,6 +116,10 @@
 
     bool isAllParamsValid();
 
+    void setParamsAndProcess(std::vector<float>& input, std::vector<float>& output);
+
+    float calculateDb(const std::vector<float>& input, size_t startSamplePos);
+
     // enqueue test parameters
     void addEngineConfig(const DynamicsProcessing::EngineArchitecture& cfg);
     void addPreEqChannelConfig(const std::vector<DynamicsProcessing::ChannelConfig>& cfg);
@@ -131,6 +135,9 @@
     static constexpr int kBandCount = 5;
     static constexpr int kSamplingFrequency = 44100;
     static constexpr int kFrameCount = 2048;
+    static constexpr int kInputFrequency = 1000;
+    static constexpr size_t kStartIndex = 15 * kSamplingFrequency / 1000;  // skip 15ms
+    static constexpr float kToleranceDb = 0.05;
     std::shared_ptr<IFactory> mFactory;
     std::shared_ptr<IEffect> mEffect;
     Descriptor mDescriptor;
@@ -390,6 +397,22 @@
     return true;
 }
 
+float DynamicsProcessingTestHelper::calculateDb(const std::vector<float>& input,
+                                                size_t startSamplePos = 0) {
+    return audio_utils_compute_power_mono(input.data() + startSamplePos, AUDIO_FORMAT_PCM_FLOAT,
+                                          input.size() - startSamplePos);
+}
+
+void DynamicsProcessingTestHelper::setParamsAndProcess(std::vector<float>& input,
+                                                       std::vector<float>& output) {
+    ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
+    if (isAllParamsValid()) {
+        ASSERT_NO_FATAL_FAILURE(
+                processAndWriteToOutput(input, output, mEffect, &mOpenEffectReturn));
+        ASSERT_GT(output.size(), kStartIndex);
+    }
+}
+
 void DynamicsProcessingTestHelper::addEngineConfig(
         const DynamicsProcessing::EngineArchitecture& cfg) {
     DynamicsProcessing dp;
@@ -593,6 +616,66 @@
         });
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestInputGain);
 
+class DynamicsProcessingInputGainDataTest
+    : public ::testing::TestWithParam<std::pair<std::shared_ptr<IFactory>, Descriptor>>,
+      public DynamicsProcessingTestHelper {
+  public:
+    DynamicsProcessingInputGainDataTest()
+        : DynamicsProcessingTestHelper((GetParam()), AudioChannelLayout::LAYOUT_MONO) {
+        mInput.resize(kFrameCount * mChannelCount);
+        generateSineWave(kInputFrequency /*Input Frequency*/, mInput);
+        mInputDb = calculateDb(mInput);
+    }
+
+    void SetUp() override {
+        SetUpDynamicsProcessingEffect();
+        SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
+    }
+
+    void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+    void cleanUpInputGainConfig() {
+        CleanUp();
+        mInputGain.clear();
+    }
+
+    std::vector<DynamicsProcessing::InputGain> mInputGain;
+    std::vector<float> mInput;
+    float mInputDb;
+};
+
+TEST_P(DynamicsProcessingInputGainDataTest, SetAndGetInputGain) {
+    std::vector<float> gainDbValues = {-85, -40, 0, 40, 85};
+    for (float gainDb : gainDbValues) {
+        cleanUpInputGainConfig();
+        for (int i = 0; i < mChannelCount; i++) {
+            mInputGain.push_back(DynamicsProcessing::InputGain(i, gainDb));
+        }
+        std::vector<float> output(mInput.size());
+        EXPECT_NO_FATAL_FAILURE(addInputGain(mInputGain));
+        EXPECT_NO_FATAL_FAILURE(setParamsAndProcess(mInput, output));
+        if (!isAllParamsValid()) {
+            continue;
+        }
+        float outputDb = calculateDb(output, kStartIndex);
+        EXPECT_NEAR(outputDb, mInputDb + gainDb, kToleranceDb)
+                << "InputGain: " << gainDb << ", OutputDb: " << outputDb;
+    }
+}
+
+INSTANTIATE_TEST_SUITE_P(DynamicsProcessingTest, DynamicsProcessingInputGainDataTest,
+                         testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                 IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())),
+                         [](const auto& info) {
+                             auto descriptor = info.param;
+                             std::string name = getPrefix(descriptor.second);
+                             std::replace_if(
+                                     name.begin(), name.end(),
+                                     [](const char c) { return !std::isalnum(c); }, '_');
+                             return name;
+                         });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingInputGainDataTest);
+
 /**
  * Test DynamicsProcessing Limiter Config
  */
@@ -686,11 +769,6 @@
 
     void TearDown() override { TearDownDynamicsProcessingEffect(); }
 
-    float calculateDb(std::vector<float> input, size_t start = 0) {
-        return audio_utils_compute_power_mono(input.data() + start, AUDIO_FORMAT_PCM_FLOAT,
-                                              input.size() - start);
-    }
-
     void computeThreshold(float ratio, float outputDb, float& threshold) {
         EXPECT_NE(ratio, 0);
         threshold = (mInputDb - (ratio * outputDb)) / (1 - ratio);
@@ -703,16 +781,10 @@
         ratio = inputOverThreshold / outputOverThreshold;
     }
 
-    void setParamsAndProcess(std::vector<float>& output) {
+    void setLimiterParamsAndProcess(std::vector<float>& input, std::vector<float>& output) {
         EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
         EXPECT_NO_FATAL_FAILURE(addLimiterConfig(mLimiterConfigList));
-        ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
-        if (isAllParamsValid()) {
-            ASSERT_NO_FATAL_FAILURE(
-                    processAndWriteToOutput(mInput, output, mEffect, &mOpenEffectReturn));
-            EXPECT_GT(output.size(), kStartIndex);
-        }
-        cleanUpLimiterConfig();
+        EXPECT_NO_FATAL_FAILURE(setParamsAndProcess(input, output));
     }
 
     void cleanUpLimiterConfig() {
@@ -723,10 +795,8 @@
     static constexpr float kDefaultAttackTime = 0;
     static constexpr float kDefaultReleaseTime = 0;
     static constexpr float kDefaultRatio = 4;
-    static constexpr float kDefaultThreshold = 0;
+    static constexpr float kDefaultThreshold = -10;
     static constexpr float kDefaultPostGain = 0;
-    static constexpr int kInputFrequency = 1000;
-    static constexpr size_t kStartIndex = 15 * kSamplingFrequency / 1000;  // skip 15ms
     std::vector<DynamicsProcessing::LimiterConfig> mLimiterConfigList;
     std::vector<float> mInput;
     float mInputDb;
@@ -738,17 +808,18 @@
     std::vector<float> output(mInput.size());
     float previousThreshold = -FLT_MAX;
     for (float threshold : thresholdValues) {
+        cleanUpLimiterConfig();
         for (int i = 0; i < mChannelCount; i++) {
             fillLimiterConfig(mLimiterConfigList, i, true, kDefaultLinkerGroup, kDefaultAttackTime,
                               kDefaultReleaseTime, kDefaultRatio, threshold, kDefaultPostGain);
         }
-        EXPECT_NO_FATAL_FAILURE(setParamsAndProcess(output));
+        EXPECT_NO_FATAL_FAILURE(setLimiterParamsAndProcess(mInput, output));
         if (!isAllParamsValid()) {
             continue;
         }
         float outputDb = calculateDb(output, kStartIndex);
         if (threshold >= mInputDb || kDefaultRatio == 1) {
-            EXPECT_EQ(std::round(mInputDb), std::round(outputDb));
+            EXPECT_NEAR(mInputDb, outputDb, kToleranceDb);
         } else {
             float calculatedThreshold = 0;
             EXPECT_NO_FATAL_FAILURE(computeThreshold(kDefaultRatio, outputDb, calculatedThreshold));
@@ -761,48 +832,68 @@
 TEST_P(DynamicsProcessingLimiterConfigDataTest, IncreasingRatio) {
     std::vector<float> ratioValues = {1, 10, 20, 30, 40, 50};
     std::vector<float> output(mInput.size());
-    float threshold = -10;
     float previousRatio = 0;
     for (float ratio : ratioValues) {
+        cleanUpLimiterConfig();
         for (int i = 0; i < mChannelCount; i++) {
             fillLimiterConfig(mLimiterConfigList, i, true, kDefaultLinkerGroup, kDefaultAttackTime,
-                              kDefaultReleaseTime, ratio, threshold, kDefaultPostGain);
+                              kDefaultReleaseTime, ratio, kDefaultThreshold, kDefaultPostGain);
         }
-        EXPECT_NO_FATAL_FAILURE(setParamsAndProcess(output));
+        EXPECT_NO_FATAL_FAILURE(setLimiterParamsAndProcess(mInput, output));
         if (!isAllParamsValid()) {
             continue;
         }
         float outputDb = calculateDb(output, kStartIndex);
 
-        if (threshold >= mInputDb) {
-            EXPECT_EQ(std::round(mInputDb), std::round(outputDb));
+        if (kDefaultThreshold >= mInputDb) {
+            EXPECT_NEAR(mInputDb, outputDb, kToleranceDb);
         } else {
             float calculatedRatio = 0;
-            EXPECT_NO_FATAL_FAILURE(computeRatio(threshold, outputDb, calculatedRatio));
+            EXPECT_NO_FATAL_FAILURE(computeRatio(kDefaultThreshold, outputDb, calculatedRatio));
             ASSERT_GT(calculatedRatio, previousRatio);
             previousRatio = calculatedRatio;
         }
     }
 }
 
+TEST_P(DynamicsProcessingLimiterConfigDataTest, IncreasingPostGain) {
+    std::vector<float> postGainDbValues = {-85, -40, 0, 40, 85};
+    std::vector<float> output(mInput.size());
+    for (float postGainDb : postGainDbValues) {
+        cleanUpLimiterConfig();
+        for (int i = 0; i < mChannelCount; i++) {
+            fillLimiterConfig(mLimiterConfigList, i, true, kDefaultLinkerGroup, kDefaultAttackTime,
+                              kDefaultReleaseTime, kDefaultRatio, -1, postGainDb);
+        }
+        EXPECT_NO_FATAL_FAILURE(setLimiterParamsAndProcess(mInput, output));
+        if (!isAllParamsValid()) {
+            continue;
+        }
+        float outputDb = calculateDb(output, kStartIndex);
+        EXPECT_NEAR(outputDb, mInputDb + postGainDb, kToleranceDb)
+                << "PostGain: " << postGainDb << ", OutputDb: " << outputDb;
+    }
+}
+
 TEST_P(DynamicsProcessingLimiterConfigDataTest, LimiterEnableDisable) {
     std::vector<bool> limiterEnableValues = {false, true};
     std::vector<float> output(mInput.size());
     for (bool isEnabled : limiterEnableValues) {
+        cleanUpLimiterConfig();
         for (int i = 0; i < mChannelCount; i++) {
             // Set non-default values
             fillLimiterConfig(mLimiterConfigList, i, isEnabled, kDefaultLinkerGroup,
                               5 /*attack time*/, 5 /*release time*/, 10 /*ratio*/,
                               -10 /*threshold*/, 5 /*postgain*/);
         }
-        EXPECT_NO_FATAL_FAILURE(setParamsAndProcess(output));
+        EXPECT_NO_FATAL_FAILURE(setLimiterParamsAndProcess(mInput, output));
         if (!isAllParamsValid()) {
             continue;
         }
         if (isEnabled) {
             EXPECT_NE(mInputDb, calculateDb(output, kStartIndex));
         } else {
-            EXPECT_NEAR(mInputDb, calculateDb(output, kStartIndex), 0.05);
+            EXPECT_NEAR(mInputDb, calculateDb(output, kStartIndex), kToleranceDb);
         }
     }
 }
@@ -818,6 +909,7 @@
                                      [](const char c) { return !std::isalnum(c); }, '_');
                              return name;
                          });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingLimiterConfigDataTest);
 
 /**
  * Test DynamicsProcessing ChannelConfig
diff --git a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
index a29920e..bf48a87 100644
--- a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
@@ -43,13 +43,13 @@
 static const std::vector<TagVectorPair> kParamsIncreasingVector = {
         {EnvironmentalReverb::roomLevelMb, {-3500, -2800, -2100, -1400, -700, 0}},
         {EnvironmentalReverb::roomHfLevelMb, {-4000, -3200, -2400, -1600, -800, 0}},
-        {EnvironmentalReverb::decayTimeMs, {800, 1600, 2400, 3200, 4000}},
-        {EnvironmentalReverb::decayHfRatioPm, {100, 600, 1100, 1600, 2000}},
+        {EnvironmentalReverb::decayTimeMs, {400, 800, 1200, 1600, 2000}},
+        {EnvironmentalReverb::decayHfRatioPm, {1000, 900, 800, 700}},
         {EnvironmentalReverb::levelMb, {-3500, -2800, -2100, -1400, -700, 0}},
 };
 
 static const TagVectorPair kDiffusionParam = {EnvironmentalReverb::diffusionPm,
-                                              {200, 400, 600, 800, 1000}};
+                                              {100, 300, 500, 700, 900}};
 static const TagVectorPair kDensityParam = {EnvironmentalReverb::densityPm,
                                             {0, 200, 400, 600, 800, 1000}};
 
@@ -281,7 +281,7 @@
 
     static constexpr int kDurationMilliSec = 500;
     static constexpr int kBufferSize = kSamplingFrequency * kDurationMilliSec / 1000;
-    static constexpr int kInputFrequency = 1000;
+    static constexpr int kInputFrequency = 2000;
 
     int mStereoChannelCount =
             getChannelCount(AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
diff --git a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
index 2b6dc3d..2802bf9 100644
--- a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
@@ -21,11 +21,13 @@
 #define LOG_TAG "VtsHalHapticGeneratorTargetTest"
 #include <android-base/logging.h>
 #include <android/binder_enums.h>
+#include <audio_utils/power.h>
 
 #include "EffectHelper.h"
 
 using namespace android;
 
+using aidl::android::hardware::audio::common::getChannelCount;
 using aidl::android::hardware::audio::effect::Descriptor;
 using aidl::android::hardware::audio::effect::getEffectTypeUuidHapticGenerator;
 using aidl::android::hardware::audio::effect::HapticGenerator;
@@ -34,406 +36,412 @@
 using aidl::android::hardware::audio::effect::Parameter;
 using android::hardware::audio::common::testing::detail::TestExecutionTracer;
 
-/**
- * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
- * VtsAudioEffectTargetTest.
- */
-enum ParamName {
-    PARAM_INSTANCE_NAME,
-    PARAM_HAPTIC_SCALE_ID,
-    PARAM_HAPTIC_SCALE_VIBRATOR_SCALE,
-    PARAM_VIBRATION_INFORMATION_RESONANT_FREQUENCY,
-    PARAM_VIBRATION_INFORMATION_Q_FACTOR,
-    PARAM_VIBRATION_INFORMATION_MAX_AMPLITUDE,
-};
-using HapticGeneratorParamTestParam =
-        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int,
-                   HapticGenerator::VibratorScale, float, float, float>;
-
-/*
- * Testing parameter range, assuming the parameter supported by effect is in this range.
- * Parameter should be within the valid range defined in the documentation,
- * for any supported value test expects EX_NONE from IEffect.setParameter(),
- * otherwise expect EX_ILLEGAL_ARGUMENT.
- */
-
-// TODO : Update the test values once range/capability is updated by implementation
 const int MIN_ID = std::numeric_limits<int>::min();
 const int MAX_ID = std::numeric_limits<int>::max();
 const float MIN_FLOAT = std::numeric_limits<float>::min();
 const float MAX_FLOAT = std::numeric_limits<float>::max();
 
-const std::vector<int> kHapticScaleIdValues = {MIN_ID, 0, MAX_ID};
-const std::vector<HapticGenerator::VibratorScale> kVibratorScaleValues = {
+std::vector<HapticGenerator::VibratorScale> kScaleValues = {
         ndk::enum_range<HapticGenerator::VibratorScale>().begin(),
         ndk::enum_range<HapticGenerator::VibratorScale>().end()};
 
+const std::vector<float> kScaleFactorValues = {HapticGenerator::HapticScale::UNDEFINED_SCALE_FACTOR,
+                                               0.0f, 0.5f, 1.0f, MAX_FLOAT};
+const std::vector<float> kAdaptiveScaleFactorValues = {
+        HapticGenerator::HapticScale::UNDEFINED_SCALE_FACTOR, 0.0f, 0.5f, 1.0f, MAX_FLOAT};
+
 const std::vector<float> kResonantFrequencyValues = {MIN_FLOAT, 100, MAX_FLOAT};
 const std::vector<float> kQFactorValues = {MIN_FLOAT, 100, MAX_FLOAT};
 const std::vector<float> kMaxAmplitude = {MIN_FLOAT, 100, MAX_FLOAT};
 
-class HapticGeneratorParamTest : public ::testing::TestWithParam<HapticGeneratorParamTestParam>,
-                                 public EffectHelper {
+constexpr int HAPTIC_SCALE_FACTORS_EFFECT_MIN_VERSION = 3;
+
+static const std::vector<int32_t> kHapticOutputLayouts = {
+        AudioChannelLayout::LAYOUT_MONO_HAPTIC_A, AudioChannelLayout::LAYOUT_MONO_HAPTIC_AB,
+        AudioChannelLayout::LAYOUT_STEREO_HAPTIC_A, AudioChannelLayout::LAYOUT_STEREO_HAPTIC_AB};
+
+class HapticGeneratorHelper : public EffectHelper {
   public:
-    HapticGeneratorParamTest()
-        : mParamHapticScaleId(std::get<PARAM_HAPTIC_SCALE_ID>(GetParam())),
-          mParamVibratorScale(std::get<PARAM_HAPTIC_SCALE_VIBRATOR_SCALE>(GetParam())),
-          mParamResonantFrequency(
-                  std::get<PARAM_VIBRATION_INFORMATION_RESONANT_FREQUENCY>(GetParam())),
-          mParamQFactor(std::get<PARAM_VIBRATION_INFORMATION_Q_FACTOR>(GetParam())),
-          mParamMaxAmplitude(std::get<PARAM_VIBRATION_INFORMATION_MAX_AMPLITUDE>(GetParam())) {
-        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
-    }
-    void SetUp() override {
+    void SetUpHapticGenerator(int32_t chMask = AudioChannelLayout::CHANNEL_HAPTIC_A) {
         ASSERT_NE(nullptr, mFactory);
         ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+        EXPECT_STATUS(EX_NONE, mEffect->getInterfaceVersion(&mEffectInterfaceVersion));
+
+        AudioChannelLayout layout =
+                AudioChannelLayout::make<AudioChannelLayout::layoutMask>(chMask);
 
         Parameter::Common common = createParamCommon(
-                0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
-                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
-        IEffect::OpenEffectReturn ret;
+                0 /* session */, 1 /* ioHandle */, kSamplingFrequency /* iSampleRate */,
+                kSamplingFrequency /* oSampleRate */, kFrameCount /* iFrameCount */,
+                kFrameCount /* oFrameCount */, layout, layout);
         ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt, &ret, EX_NONE));
         ASSERT_NE(nullptr, mEffect);
     }
 
-    void TearDown() override {
+    void TearDownHapticGenerator() {
         ASSERT_NO_FATAL_FAILURE(close(mEffect));
         ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+        ret = IEffect::OpenEffectReturn{};
     }
 
-    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    Parameter createScaleParam(const std::vector<HapticGenerator::HapticScale>& hapticScales) {
+        return Parameter::make<Parameter::specific>(
+                Parameter::Specific::make<Parameter::Specific::hapticGenerator>(
+                        HapticGenerator::make<HapticGenerator::hapticScales>(hapticScales)));
+    }
+
+    Parameter createVibratorParam(HapticGenerator::VibratorInformation vibrationInfo) {
+        return Parameter::make<Parameter::specific>(
+                Parameter::Specific::make<Parameter::Specific::hapticGenerator>(
+                        HapticGenerator::make<HapticGenerator::vibratorInfo>(vibrationInfo)));
+    }
+
+    void setAndVerifyParameter(Parameter hapticParameter, HapticGenerator::Tag tag,
+                               binder_exception_t expected = EX_NONE) {
+        EXPECT_STATUS(expected, mEffect->setParameter(hapticParameter))
+                << hapticParameter.toString();
+        if (expected == EX_NONE) {
+            // get parameter
+            Parameter getParam;
+            auto second = Parameter::Id::make<Parameter::Id::hapticGeneratorTag>(
+                    HapticGenerator::Id::make<HapticGenerator::Id::commonTag>(
+                            HapticGenerator::Tag(tag)));
+            // If the set is successful, get param should match
+            EXPECT_STATUS(expected, mEffect->getParameter(second, &getParam));
+            EXPECT_EQ(hapticParameter, getParam) << "\nexpectedParam:" << hapticParameter.toString()
+                                                 << "\ngetParam:" << getParam.toString();
+        }
+    }
+
+    HapticGenerator::VibratorInformation createVibratorInfo(float resonantFrequency, float qFactor,
+                                                            float amplitude) {
+        return HapticGenerator::VibratorInformation(resonantFrequency, qFactor, amplitude);
+    }
+
+    static const long kFrameCount = 10000;
+    static constexpr int kSamplingFrequency = 44100;
+    static constexpr int kDefaultScaleID = 0;
+    static constexpr float kDefaultMaxAmp = 1;
+    static constexpr float kDefaultResonantFrequency = 150;
+    static constexpr float kDefaultQfactor = 8;
+    static constexpr HapticGenerator::VibratorScale kDefaultScale =
+            HapticGenerator::VibratorScale::NONE;
     std::shared_ptr<IFactory> mFactory;
     std::shared_ptr<IEffect> mEffect;
-    Descriptor mDescriptor;
-    int mParamHapticScaleId = 0;
-    HapticGenerator::VibratorScale mParamVibratorScale = HapticGenerator::VibratorScale::MUTE;
-    float mParamResonantFrequency = 0;
-    float mParamQFactor = 0;
-    float mParamMaxAmplitude = 0;
+    IEffect::OpenEffectReturn ret;
+    Parameter mHapticSpecificParameter;
+    Parameter::Id mHapticIdParameter;
+    int mEffectInterfaceVersion;
+};
 
-    void SetAndGetHapticGeneratorParameters() {
-        for (auto& it : mTags) {
-            auto& tag = std::get<ParamTestEnum::PARAM_TEST_TAG>(it);
-            auto& setHg = std::get<ParamTestEnum::PARAM_TEST_TARGET>(it);
+/**
+ *Tests do the following:
+ * -Testing parameter range supported by the effect.
+ * -For any supported value test expects EX_NONE from IEffect.setParameter(),
+ *  otherwise expect EX_ILLEGAL_ARGUMENT.
+ * -Validating the effect by comparing the output energies of the supported parameters.
+ **/
 
-            // set parameter
-            Parameter expectParam;
-            Parameter::Specific specific;
-            specific.set<Parameter::Specific::hapticGenerator>(setHg);
-            expectParam.set<Parameter::specific>(specific);
+using EffectInstance = std::pair<std::shared_ptr<IFactory>, Descriptor>;
 
-            const bool valid =
-                    isParameterValid<HapticGenerator, Range::hapticGenerator>(setHg, mDescriptor);
-            const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
-            EXPECT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
+class HapticGeneratorScaleParamTest : public ::testing::TestWithParam<EffectInstance>,
+                                      public HapticGeneratorHelper {
+  public:
+    HapticGeneratorScaleParamTest() { std::tie(mFactory, mDescriptor) = GetParam(); }
+    void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpHapticGenerator()); }
+    void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownHapticGenerator()); }
+};
 
-            // only get if parameter in range and set success
-            if (expected == EX_NONE) {
-                Parameter getParam;
-                Parameter::Id id;
-                HapticGenerator::Id hgId;
-                hgId.set<HapticGenerator::Id::commonTag>(tag);
-                id.set<Parameter::Id::hapticGeneratorTag>(hgId);
-                EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
-                EXPECT_EQ(expectParam, getParam) << expectParam.toString() << "\n"
-                                                 << getParam.toString();
+TEST_P(HapticGeneratorScaleParamTest, SetAndGetScales) {
+    std::vector<HapticGenerator::HapticScale> hapticScales;
+    for (int i = 0; i < static_cast<int>(kScaleValues.size()); i++) {
+        hapticScales.push_back({.id = i, .scale = kScaleValues[i]});
+    }
+    ASSERT_NO_FATAL_FAILURE(
+            setAndVerifyParameter(createScaleParam(hapticScales), HapticGenerator::hapticScales));
+}
+
+TEST_P(HapticGeneratorScaleParamTest, SetAndGetScaleFactors) {
+    if (mEffectInterfaceVersion < HAPTIC_SCALE_FACTORS_EFFECT_MIN_VERSION) {
+        GTEST_SKIP() << "Skipping HapticGenerator ScaleFactors test for effect version "
+                     << std::to_string(mEffectInterfaceVersion);
+    }
+
+    std::vector<HapticGenerator::HapticScale> hapticScales;
+    for (int i = 0; i < static_cast<int>(kScaleFactorValues.size()); i++) {
+        hapticScales.push_back(
+                {.id = i, .scale = kScaleValues[0], .scaleFactor = kScaleFactorValues[i]});
+    }
+    ASSERT_NO_FATAL_FAILURE(
+            setAndVerifyParameter(createScaleParam(hapticScales), HapticGenerator::hapticScales));
+}
+
+TEST_P(HapticGeneratorScaleParamTest, SetAndGetAdaptiveScaleFactors) {
+    if (mEffectInterfaceVersion < HAPTIC_SCALE_FACTORS_EFFECT_MIN_VERSION) {
+        GTEST_SKIP() << "Skipping HapticGenerator AdaptiveScaleFactors test for effect version "
+                     << std::to_string(mEffectInterfaceVersion);
+    }
+
+    std::vector<HapticGenerator::HapticScale> hapticScales;
+    for (int i = 0; i < static_cast<int>(kAdaptiveScaleFactorValues.size()); i++) {
+        hapticScales.push_back({.id = i,
+                                .scale = kScaleValues[0],
+                                .scaleFactor = kScaleFactorValues[3],
+                                .adaptiveScaleFactor = kAdaptiveScaleFactorValues[i]});
+    }
+    ASSERT_NO_FATAL_FAILURE(
+            setAndVerifyParameter(createScaleParam(hapticScales), HapticGenerator::hapticScales));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        HapticGeneratorValidTest, HapticGeneratorScaleParamTest,
+        testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                IFactory::descriptor, getEffectTypeUuidHapticGenerator())),
+        [](const testing::TestParamInfo<HapticGeneratorScaleParamTest::ParamType>& info) {
+            auto descriptor = info.param;
+            return getPrefix(descriptor.second);
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorScaleParamTest);
+
+enum VibratorParamName {
+    VIBRATOR_PARAM_INSTANCE,
+    VIBRATOR_PARAM_RESONANT_FREQUENCY,
+    VIBRATOR_PARAM_Q_FACTOR,
+    VIBRATOR_PARAM_MAX_AMPLITUDE,
+};
+
+using HapticGeneratorVibratorInfoTestParam = std::tuple<EffectInstance, float, float, float>;
+
+class HapticGeneratorVibratorInfoParamTest
+    : public ::testing::TestWithParam<HapticGeneratorVibratorInfoTestParam>,
+      public HapticGeneratorHelper {
+  public:
+    HapticGeneratorVibratorInfoParamTest()
+        : mParamResonantFrequency(std::get<VIBRATOR_PARAM_RESONANT_FREQUENCY>(GetParam())),
+          mParamQFactor(std::get<VIBRATOR_PARAM_Q_FACTOR>(GetParam())),
+          mParamMaxAmplitude(std::get<VIBRATOR_PARAM_MAX_AMPLITUDE>(GetParam())) {
+        std::tie(mFactory, mDescriptor) = std::get<VIBRATOR_PARAM_INSTANCE>(GetParam());
+    }
+    void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpHapticGenerator()); }
+    void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownHapticGenerator()); }
+
+    float mParamResonantFrequency = kDefaultResonantFrequency;
+    float mParamQFactor = kDefaultQfactor;
+    float mParamMaxAmplitude = kDefaultMaxAmp;
+};
+
+TEST_P(HapticGeneratorVibratorInfoParamTest, SetAndGetVibratorInformation) {
+    auto vibratorInfo =
+            createVibratorInfo(mParamResonantFrequency, mParamQFactor, mParamMaxAmplitude);
+    if (isParameterValid<HapticGenerator, Range::hapticGenerator>(vibratorInfo, mDescriptor)) {
+        ASSERT_NO_FATAL_FAILURE(setAndVerifyParameter(createVibratorParam(vibratorInfo),
+                                                      HapticGenerator::vibratorInfo));
+    } else {
+        ASSERT_NO_FATAL_FAILURE(setAndVerifyParameter(createVibratorParam(vibratorInfo),
+                                                      HapticGenerator::vibratorInfo,
+                                                      EX_ILLEGAL_ARGUMENT));
+    }
+}
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorVibratorInfoParamTest);
+
+INSTANTIATE_TEST_SUITE_P(
+        HapticGeneratorValidTest, HapticGeneratorVibratorInfoParamTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, getEffectTypeUuidHapticGenerator())),
+                           testing::ValuesIn(kResonantFrequencyValues),
+                           testing::ValuesIn(kQFactorValues), testing::ValuesIn(kMaxAmplitude)),
+        [](const testing::TestParamInfo<HapticGeneratorVibratorInfoParamTest::ParamType>& info) {
+            auto descriptor = std::get<VIBRATOR_PARAM_INSTANCE>(info.param).second;
+            std::string resonantFrequency =
+                    std::to_string(std::get<VIBRATOR_PARAM_RESONANT_FREQUENCY>(info.param));
+            std::string qFactor = std::to_string(std::get<VIBRATOR_PARAM_Q_FACTOR>(info.param));
+            std::string maxAmplitude =
+                    std::to_string(std::get<VIBRATOR_PARAM_MAX_AMPLITUDE>(info.param));
+            std::string name = getPrefix(descriptor) + "_resonantFrequency" + resonantFrequency +
+                               "_qFactor" + qFactor + "_maxAmplitude" + maxAmplitude;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+/**
+ * The data tests do the following
+ * -Generate test input.
+ * -Check if the parameters are supported. Skip the unsupported parameter values.
+ * -Validate increase in haptic output energy energy.
+ **/
+
+enum DataTestParam { EFFECT_INSTANCE, LAYOUT };
+using HapticGeneratorDataTestParam = std::tuple<EffectInstance, int32_t>;
+
+class HapticGeneratorDataTest : public ::testing::TestWithParam<HapticGeneratorDataTestParam>,
+                                public HapticGeneratorHelper {
+  public:
+    HapticGeneratorDataTest() : mChMask(std::get<LAYOUT>(GetParam())) {
+        std::tie(mFactory, mDescriptor) = std::get<EFFECT_INSTANCE>(GetParam());
+        mAudioChannelCount =
+                getChannelCount(AudioChannelLayout::make<AudioChannelLayout::layoutMask>(mChMask),
+                                ~AudioChannelLayout::LAYOUT_HAPTIC_AB);
+        mHapticChannelCount =
+                getChannelCount(AudioChannelLayout::make<AudioChannelLayout::layoutMask>(mChMask),
+                                AudioChannelLayout::LAYOUT_HAPTIC_AB);
+
+        mAudioSamples = kFrameCount * mAudioChannelCount;
+        mHapticSamples = kFrameCount * mHapticChannelCount;
+        mInput.resize(mHapticSamples + mAudioSamples, 0);
+        mOutput.resize(mHapticSamples + mAudioSamples, 0);
+    }
+
+    void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpHapticGenerator(mChMask)); }
+    void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownHapticGenerator()); }
+
+    void generateSinePeriod() {
+        size_t cycleSize = kSamplingFrequency / kInputFrequency;
+        size_t startSize = 0;
+        while (startSize < mAudioSamples) {
+            for (size_t i = 0; i < cycleSize; i++) {
+                mInput[i + startSize] = sin(2 * M_PI * kInputFrequency * i / kSamplingFrequency);
+            }
+            startSize += mAudioSamples / 4;
+        }
+    }
+
+    void setBaseVibratorParam() {
+        auto vibratorInfo =
+                createVibratorInfo(kDefaultResonantFrequency, kDefaultQfactor, kDefaultMaxAmp);
+        if (isParameterValid<HapticGenerator, Range::hapticGenerator>(vibratorInfo, mDescriptor)) {
+            ASSERT_NO_FATAL_FAILURE(setAndVerifyParameter(createVibratorParam(vibratorInfo),
+                                                          HapticGenerator::vibratorInfo));
+        } else {
+            GTEST_SKIP() << "Invalid base vibrator values, skipping the test\n";
+        }
+    }
+
+    void setBaseScaleParam() {
+        ASSERT_NO_FATAL_FAILURE(setAndVerifyParameter(
+                createScaleParam({HapticGenerator::HapticScale(kDefaultScaleID, kDefaultScale)}),
+                HapticGenerator::hapticScales));
+    }
+
+    void validateIncreasingEnergy(HapticGenerator::Tag tag) {
+        float baseEnergy = -1;
+        for (auto param : mHapticParam) {
+            ASSERT_NO_FATAL_FAILURE(setAndVerifyParameter(param, tag));
+            SCOPED_TRACE("Param: " + param.toString());
+            ASSERT_NO_FATAL_FAILURE(processAndWriteToOutput(mInput, mOutput, mEffect, &ret));
+            float hapticOutputEnergy = audio_utils_compute_energy_mono(
+                    mOutput.data() + mAudioSamples, AUDIO_FORMAT_PCM_FLOAT, mHapticSamples);
+            EXPECT_GT(hapticOutputEnergy, baseEnergy);
+            baseEnergy = hapticOutputEnergy;
+        }
+    }
+
+    float findAbsMax(auto begin, auto end) {
+        return *std::max_element(begin, end,
+                                 [](float a, float b) { return std::abs(a) < std::abs(b); });
+    }
+
+    void findMaxAmplitude() {
+        for (float amp = 0.1; amp <= 1; amp += 0.1) {
+            auto vibratorInfo = createVibratorInfo(kDefaultResonantFrequency, kDefaultQfactor, amp);
+            if (!isParameterValid<HapticGenerator, Range::hapticGenerator>(vibratorInfo,
+                                                                           mDescriptor)) {
+                continue;
+            }
+            ASSERT_NO_FATAL_FAILURE(setAndVerifyParameter(createVibratorParam(vibratorInfo),
+                                                          HapticGenerator::vibratorInfo));
+            ASSERT_NO_FATAL_FAILURE(processAndWriteToOutput(mInput, mOutput, mEffect, &ret));
+            float outAmplitude = findAbsMax(mOutput.begin() + mAudioSamples, mOutput.end());
+            if (outAmplitude > mMaxAmplitude) {
+                mMaxAmplitude = outAmplitude;
+            } else {
+                break;
             }
         }
     }
 
-    void addHapticScaleParam(int id, HapticGenerator::VibratorScale scale) {
-        HapticGenerator setHg;
-        std::vector<HapticGenerator::HapticScale> hapticScales = {{.id = id, .scale = scale}};
-        setHg.set<HapticGenerator::hapticScales>(hapticScales);
-        mTags.push_back({HapticGenerator::hapticScales, setHg});
-    }
-
-    void addVibratorInformationParam(float resonantFrequencyHz, float qFactor, float maxAmplitude) {
-        HapticGenerator hg;
-        HapticGenerator::VibratorInformation vibrationInfo = {
-                .resonantFrequencyHz = resonantFrequencyHz,
-                .qFactor = qFactor,
-                .maxAmplitude = maxAmplitude};
-        hg.set<HapticGenerator::vibratorInfo>(vibrationInfo);
-        mTags.push_back({HapticGenerator::vibratorInfo, hg});
-    }
-
-  private:
-    enum ParamTestEnum { PARAM_TEST_TAG, PARAM_TEST_TARGET };
-    std::vector<std::tuple<HapticGenerator::Tag, HapticGenerator>> mTags;
-
-    void CleanUp() { mTags.clear(); }
+    const int kInputFrequency = 1000;
+    float mMaxAmplitude = 0;
+    size_t mHapticSamples;
+    int32_t mChMask;
+    int32_t mAudioChannelCount;
+    int32_t mHapticChannelCount;
+    size_t mAudioSamples;
+    float mBaseHapticOutputEnergy;
+    std::vector<Parameter> mHapticParam;
+    // both input and output buffer includes audio and haptic samples
+    std::vector<float> mInput;
+    std::vector<float> mOutput;
 };
 
-TEST_P(HapticGeneratorParamTest, SetAndGetHapticScale) {
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(mParamHapticScaleId, mParamVibratorScale));
-    SetAndGetHapticGeneratorParameters();
+TEST_P(HapticGeneratorDataTest, IncreasingVibratorScaleTest) {
+    generateInput(mInput, kInputFrequency, kSamplingFrequency, mAudioSamples);
+    ASSERT_NO_FATAL_FAILURE(setBaseVibratorParam());
+    for (HapticGenerator::VibratorScale scale : kScaleValues) {
+        mHapticParam.push_back(
+                createScaleParam({HapticGenerator::HapticScale(kDefaultScaleID, scale)}));
+    }
+    ASSERT_NO_FATAL_FAILURE(validateIncreasingEnergy(HapticGenerator::hapticScales));
 }
 
-TEST_P(HapticGeneratorParamTest, SetAndGetMultipleHapticScales) {
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(mParamHapticScaleId, mParamVibratorScale));
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(mParamHapticScaleId, mParamVibratorScale));
-    SetAndGetHapticGeneratorParameters();
+TEST_P(HapticGeneratorDataTest, IncreasingMaxAmplitudeTest) {
+    generateInput(mInput, kInputFrequency, kSamplingFrequency, mAudioSamples);
+    ASSERT_NO_FATAL_FAILURE(setBaseScaleParam());
+    findMaxAmplitude();
+    std::vector<float> increasingAmplitudeValues = {0.25f * mMaxAmplitude, 0.5f * mMaxAmplitude,
+                                                    0.75f * mMaxAmplitude, mMaxAmplitude};
+    for (float amplitude : increasingAmplitudeValues) {
+        auto vibratorInfo =
+                createVibratorInfo(kDefaultResonantFrequency, kDefaultQfactor, amplitude);
+        if (!isParameterValid<HapticGenerator, Range::hapticGenerator>(vibratorInfo, mDescriptor)) {
+            continue;
+        }
+        mHapticParam.push_back(createVibratorParam(vibratorInfo));
+    }
+    ASSERT_NO_FATAL_FAILURE(validateIncreasingEnergy(HapticGenerator::vibratorInfo));
 }
 
-TEST_P(HapticGeneratorParamTest, SetAndGetVibratorInformation) {
-    EXPECT_NO_FATAL_FAILURE(addVibratorInformationParam(mParamResonantFrequency, mParamQFactor,
-                                                        mParamMaxAmplitude));
-    SetAndGetHapticGeneratorParameters();
+TEST_P(HapticGeneratorDataTest, DescreasingResonantFrequencyTest) {
+    std::vector<float> descreasingResonantFrequency = {800, 600, 400, 200};
+    generateInput(mInput, kInputFrequency, kSamplingFrequency, mAudioSamples);
+    ASSERT_NO_FATAL_FAILURE(setBaseScaleParam());
+    for (float resonantFrequency : descreasingResonantFrequency) {
+        auto vibratorInfo = createVibratorInfo(resonantFrequency, kDefaultQfactor, kDefaultMaxAmp);
+        if (!isParameterValid<HapticGenerator, Range::hapticGenerator>(vibratorInfo, mDescriptor)) {
+            continue;
+        }
+        mHapticParam.push_back(createVibratorParam(vibratorInfo));
+    }
+    ASSERT_NO_FATAL_FAILURE(validateIncreasingEnergy(HapticGenerator::vibratorInfo));
+}
+
+TEST_P(HapticGeneratorDataTest, IncreasingQfactorTest) {
+    std::vector<float> increasingQfactor = {16, 24, 32, 40};
+    generateSinePeriod();
+    ASSERT_NO_FATAL_FAILURE(setBaseScaleParam());
+    for (float qFactor : increasingQfactor) {
+        auto vibratorInfo = createVibratorInfo(kDefaultResonantFrequency, qFactor, kDefaultMaxAmp);
+        if (!isParameterValid<HapticGenerator, Range::hapticGenerator>(vibratorInfo, mDescriptor)) {
+            continue;
+        }
+        mHapticParam.push_back(createVibratorParam(vibratorInfo));
+    }
+    ASSERT_NO_FATAL_FAILURE(validateIncreasingEnergy(HapticGenerator::vibratorInfo));
 }
 
 INSTANTIATE_TEST_SUITE_P(
-        HapticGeneratorValidTest, HapticGeneratorParamTest,
+        DataTest, HapticGeneratorDataTest,
         ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
                                    IFactory::descriptor, getEffectTypeUuidHapticGenerator())),
-                           testing::ValuesIn(kHapticScaleIdValues),
-                           testing::ValuesIn(kVibratorScaleValues),
-                           testing::ValuesIn(kResonantFrequencyValues),
-                           testing::ValuesIn(kQFactorValues), testing::ValuesIn(kMaxAmplitude)),
-        [](const testing::TestParamInfo<HapticGeneratorParamTest::ParamType>& info) {
-            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
-            std::string hapticScaleID = std::to_string(std::get<PARAM_HAPTIC_SCALE_ID>(info.param));
-            std::string hapticScaleVibScale = std::to_string(
-                    static_cast<int>(std::get<PARAM_HAPTIC_SCALE_VIBRATOR_SCALE>(info.param)));
-            std::string resonantFrequency = std::to_string(
-                    std::get<PARAM_VIBRATION_INFORMATION_RESONANT_FREQUENCY>(info.param));
-            std::string qFactor =
-                    std::to_string(std::get<PARAM_VIBRATION_INFORMATION_Q_FACTOR>(info.param));
-            std::string maxAmplitude =
-                    std::to_string(std::get<PARAM_VIBRATION_INFORMATION_MAX_AMPLITUDE>(info.param));
-            std::string name = getPrefix(descriptor) + "_hapticScaleId" + hapticScaleID +
-                               "_hapticScaleVibScale" + hapticScaleVibScale + "_resonantFrequency" +
-                               resonantFrequency + "_qFactor" + qFactor + "_maxAmplitude" +
-                               maxAmplitude;
-            std::replace_if(
-                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+                           testing::ValuesIn(kHapticOutputLayouts)),
+        [](const testing::TestParamInfo<HapticGeneratorDataTest::ParamType>& info) {
+            auto descriptor = std::get<EFFECT_INSTANCE>(info.param).second;
+            std::string layout = "0x" + std::format("{:x}", std::get<LAYOUT>(info.param));
+            std::string name = getPrefix(descriptor) + "_layout_" + layout;
             return name;
         });
-
-INSTANTIATE_TEST_SUITE_P(
-        HapticGeneratorInvalidTest, HapticGeneratorParamTest,
-        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
-                                   IFactory::descriptor, getEffectTypeUuidHapticGenerator())),
-                           testing::Values(MIN_ID),
-                           testing::Values(HapticGenerator::VibratorScale::NONE),
-                           testing::Values(MIN_FLOAT), testing::Values(MIN_FLOAT),
-                           testing::Values(MIN_FLOAT)),
-        [](const testing::TestParamInfo<HapticGeneratorParamTest::ParamType>& info) {
-            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
-            std::string hapticScaleID = std::to_string(std::get<PARAM_HAPTIC_SCALE_ID>(info.param));
-            std::string hapticScaleVibScale = std::to_string(
-                    static_cast<int>(std::get<PARAM_HAPTIC_SCALE_VIBRATOR_SCALE>(info.param)));
-            std::string resonantFrequency = std::to_string(
-                    std::get<PARAM_VIBRATION_INFORMATION_RESONANT_FREQUENCY>(info.param));
-            std::string qFactor =
-                    std::to_string(std::get<PARAM_VIBRATION_INFORMATION_Q_FACTOR>(info.param));
-            std::string maxAmplitude =
-                    std::to_string(std::get<PARAM_VIBRATION_INFORMATION_MAX_AMPLITUDE>(info.param));
-            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
-                               descriptor.common.name + "_UUID_" +
-                               toString(descriptor.common.id.uuid) + "_hapticScaleId" +
-                               hapticScaleID + "_hapticScaleVibScale" + hapticScaleVibScale +
-                               "_resonantFrequency" + resonantFrequency + "_qFactor" + qFactor +
-                               "_maxAmplitude" + maxAmplitude;
-            std::replace_if(
-                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
-            return name;
-        });
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorParamTest);
-
-// Test HapticScale[] hapticScales parameter
-using HapticGeneratorScalesTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>>;
-class HapticGeneratorScalesTest : public ::testing::TestWithParam<HapticGeneratorScalesTestParam>,
-                                  public EffectHelper {
-  public:
-    HapticGeneratorScalesTest() {
-        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
-    }
-
-    void SetUp() override {
-        ASSERT_NE(nullptr, mFactory);
-        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
-
-        Parameter::Common common = createParamCommon(
-                0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
-                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
-        IEffect::OpenEffectReturn ret;
-        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt, &ret, EX_NONE));
-        ASSERT_NE(nullptr, mEffect);
-    }
-
-    void TearDown() override {
-        ASSERT_NO_FATAL_FAILURE(close(mEffect));
-        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
-        CleanUp();
-    }
-
-    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
-    std::shared_ptr<IFactory> mFactory;
-    std::shared_ptr<IEffect> mEffect;
-    Descriptor mDescriptor;
-
-    void addHapticScaleParam(std::vector<HapticGenerator::HapticScale> scales) {
-        mHapticScales.push_back(HapticGenerator::make<HapticGenerator::hapticScales>(scales));
-        for (const auto& scale : scales) {
-            expectMap.insert_or_assign(scale.id, scale.scale);
-        }
-    }
-
-    void SetHapticScaleParameters() {
-        // std::unordered_set<HapticGenerator::HapticScale> target;
-        for (auto& it : mHapticScales) {
-            Parameter::Specific specific =
-                    Parameter::Specific::make<Parameter::Specific::hapticGenerator>(it);
-            Parameter param = Parameter::make<Parameter::specific>(specific);
-            EXPECT_STATUS(EX_NONE, mEffect->setParameter(param)) << param.toString();
-        }
-    }
-
-    void checkHapticScaleParameter() {
-        // get parameter
-        Parameter targetParam;
-        HapticGenerator::Id hgId = HapticGenerator::Id::make<HapticGenerator::Id::commonTag>(
-                HapticGenerator::hapticScales);
-        Parameter::Id id = Parameter::Id::make<Parameter::Id::hapticGeneratorTag>(hgId);
-        EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &targetParam));
-        ASSERT_EQ(Parameter::specific, targetParam.getTag());
-        Parameter::Specific specific = targetParam.get<Parameter::specific>();
-        ASSERT_EQ(Parameter::Specific::hapticGenerator, specific.getTag());
-        HapticGenerator hg = specific.get<Parameter::Specific::hapticGenerator>();
-        ASSERT_EQ(HapticGenerator::hapticScales, hg.getTag());
-        std::vector<HapticGenerator::HapticScale> scales = hg.get<HapticGenerator::hapticScales>();
-        ASSERT_EQ(scales.size(), expectMap.size());
-        for (const auto& scale : scales) {
-            auto itor = expectMap.find(scale.id);
-            ASSERT_NE(expectMap.end(), itor);
-            ASSERT_EQ(scale.scale, itor->second);
-            expectMap.erase(scale.id);
-        }
-        ASSERT_EQ(0ul, expectMap.size());
-    }
-
-    const static HapticGenerator::HapticScale kHapticScaleWithMinId;
-    const static HapticGenerator::HapticScale kHapticScaleWithMinIdNew;
-    const static HapticGenerator::HapticScale kHapticScale;
-    const static HapticGenerator::HapticScale kHapticScaleNew;
-    const static HapticGenerator::HapticScale kHapticScaleWithMaxId;
-    const static HapticGenerator::HapticScale kHapticScaleWithMaxIdNew;
-
-    std::vector<HapticGenerator> mHapticScales;
-
-    void CleanUp() {
-        mHapticScales.clear();
-        expectMap.clear();
-    }
-
-  private:
-    std::map<int /* trackID */, HapticGenerator::VibratorScale> expectMap;
-};
-
-const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleWithMinId = {
-        .id = MIN_ID, .scale = HapticGenerator::VibratorScale::MUTE};
-const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleWithMinIdNew = {
-        .id = MIN_ID, .scale = HapticGenerator::VibratorScale::VERY_LOW};
-const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScale = {
-        .id = 1, .scale = HapticGenerator::VibratorScale::LOW};
-const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleNew = {
-        .id = 1, .scale = HapticGenerator::VibratorScale::NONE};
-const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleWithMaxId = {
-        .id = MAX_ID, .scale = HapticGenerator::VibratorScale::VERY_HIGH};
-const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleWithMaxIdNew = {
-        .id = MAX_ID, .scale = HapticGenerator::VibratorScale::MUTE};
-
-TEST_P(HapticGeneratorScalesTest, SetAndUpdateOne) {
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScale}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleNew}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMinId}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMinIdNew}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMaxId}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMaxIdNew}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-
-    EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
-}
-
-TEST_P(HapticGeneratorScalesTest, SetAndUpdateVector) {
-    EXPECT_NO_FATAL_FAILURE(
-            addHapticScaleParam({kHapticScale, kHapticScaleWithMaxId, kHapticScaleWithMinId}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(
-            {kHapticScaleNew, kHapticScaleWithMaxIdNew, kHapticScaleWithMinIdNew}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-
-    EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
-}
-
-TEST_P(HapticGeneratorScalesTest, SetAndUpdateMultipleVector) {
-    EXPECT_NO_FATAL_FAILURE(
-            addHapticScaleParam({kHapticScale, kHapticScaleWithMaxId, kHapticScaleWithMinId}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(
-            {kHapticScaleNew, kHapticScaleWithMaxIdNew, kHapticScaleWithMinIdNew}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-    EXPECT_NO_FATAL_FAILURE(
-            addHapticScaleParam({kHapticScale, kHapticScaleWithMaxId, kHapticScaleWithMinId}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-
-    EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
-}
-
-TEST_P(HapticGeneratorScalesTest, SetOneAndAddMoreVector) {
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScale}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMaxId, kHapticScaleWithMinId}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-
-    EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
-}
-
-TEST_P(HapticGeneratorScalesTest, SetMultipleAndAddOneVector) {
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMaxId, kHapticScaleWithMinId}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScale}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-
-    EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
-}
-
-TEST_P(HapticGeneratorScalesTest, SetMultipleVectorRepeat) {
-    EXPECT_NO_FATAL_FAILURE(
-            addHapticScaleParam({kHapticScaleWithMaxId, kHapticScale, kHapticScaleWithMinId}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-    EXPECT_NO_FATAL_FAILURE(
-            addHapticScaleParam({kHapticScaleWithMaxId, kHapticScale, kHapticScaleWithMinId}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-    EXPECT_NO_FATAL_FAILURE(
-            addHapticScaleParam({kHapticScaleWithMaxId, kHapticScale, kHapticScaleWithMinId}));
-    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
-
-    EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
-}
-
-INSTANTIATE_TEST_SUITE_P(
-        HapticGeneratorScalesTest, HapticGeneratorScalesTest,
-        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
-                IFactory::descriptor, getEffectTypeUuidHapticGenerator()))),
-        [](const testing::TestParamInfo<HapticGeneratorScalesTest::ParamType>& info) {
-            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
-            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
-                               descriptor.common.name + "_UUID_" +
-                               toString(descriptor.common.id.uuid);
-            std::replace_if(
-                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
-            return name;
-        });
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorScalesTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorDataTest);
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
diff --git a/automotive/TEST_MAPPING b/automotive/TEST_MAPPING
index c64c880..483a85f 100644
--- a/automotive/TEST_MAPPING
+++ b/automotive/TEST_MAPPING
@@ -19,10 +19,58 @@
     	"name": "CtsCarBuiltinApiHostTestCases"
     },
     {
-      "name": "CarServiceTest"
+      "name": "CarServiceAudioTest"
+    },
+    {
+      "name": "CarServiceCarTest"
+    },
+    {
+      "name": "CarServiceClusterTest"
+    },
+    {
+      "name": "CarServiceDiagnosticTest"
+    },
+    {
+      "name": "CarServiceDrivingStateTest"
+    },
+    {
+      "name": "CarServiceEvsTest"
+    },
+    {
+      "name": "CarServiceGarageModeTest"
+    },
+    {
+      "name": "CarServiceInputTest"
+    },
+    {
+      "name": "CarServiceOsTest"
+    },
+    {
+      "name": "CarServicePmTest"
+    },
+    {
+      "name": "CarServicePowerTest"
+    },
+    {
+      "name": "CarServicePropertyTest"
+    },
+    {
+      "name": "CarServiceRemoteAccessTest"
+    },
+    {
+      "name": "CarServiceStorageMonitoringTest"
+    },
+    {
+      "name": "CarServiceTelemetryTest"
     },
     {
       "name": "CarServiceUnitTest"
+    },
+    {
+      "name": "CarServiceVmsTest"
+    },
+    {
+      "name": "CarServiceWatchdogTest"
     }
   ]
 }
\ No newline at end of file
diff --git a/automotive/evs/aidl/Android.bp b/automotive/evs/aidl/Android.bp
index 9f5ab97..8983ae4 100644
--- a/automotive/evs/aidl/Android.bp
+++ b/automotive/evs/aidl/Android.bp
@@ -46,20 +46,23 @@
         ndk: {
             min_sdk_version: "29",
         },
+        rust: {
+            enabled: true,
+        },
     },
     versions_with_info: [
         {
             version: "1",
             imports: [
                 "android.hardware.common-V2",
-                "android.hardware.graphics.common-V5",
+                "android.hardware.graphics.common-V6",
             ],
         },
         {
             version: "2",
             imports: [
                 "android.hardware.common-V2",
-                "android.hardware.graphics.common-V5",
+                "android.hardware.graphics.common-V6",
             ],
         },
 
diff --git a/automotive/evs/aidl/impl/default/manifest_evs-default-service.xml b/automotive/evs/aidl/impl/default/manifest_evs-default-service.xml
index 50692f7..9ddc6ad 100644
--- a/automotive/evs/aidl/impl/default/manifest_evs-default-service.xml
+++ b/automotive/evs/aidl/impl/default/manifest_evs-default-service.xml
@@ -2,6 +2,6 @@
     <hal format="aidl">
         <name>android.hardware.automotive.evs</name>
         <fqname>IEvsEnumerator/hw/0</fqname>
-        <version>1</version>
+        <version>2</version>
     </hal>
 </manifest>
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/automotive/evs/aidl/rust_impl/Android.bp
similarity index 60%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
copy to automotive/evs/aidl/rust_impl/Android.bp
index c7be950..ac8b90f 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ b/automotive/evs/aidl/rust_impl/Android.bp
@@ -14,22 +14,17 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
-
-import android.hardware.biometrics.fingerprint.AcquiredInfo;
-
-/**
- * @hide
- */
-@VintfStability
-union AcquiredInfoAndVendorCode {
-    /**
-     * Acquired info as specified in AcqauiredInfo.aidl
-     */
-    AcquiredInfo acquiredInfo = AcquiredInfo.UNKNOWN;
-
-    /**
-     * Vendor specific code
-     */
-    int vendorCode;
+rust_binary {
+    name: "android.hardware.automotive.evs-aidl-rust-service",
+    relative_install_path: "hw",
+    vendor: true,
+    srcs: ["src/*.rs"],
+    crate_root: "src/main.rs",
+    vintf_fragments: ["manifest_evs-rust-service.xml"],
+    init_rc: ["evs-rust-service.rc"],
+    rustlibs: [
+        "android.hardware.automotive.evs-V2-rust",
+        "libbinder_rs",
+        "liblog_rust",
+    ],
 }
diff --git a/automotive/evs/aidl/rust_impl/README.md b/automotive/evs/aidl/rust_impl/README.md
new file mode 100644
index 0000000..bf00aed
--- /dev/null
+++ b/automotive/evs/aidl/rust_impl/README.md
@@ -0,0 +1,21 @@
+# Rust Skeleton EVS HAL implementation.
+
+WARNING: This is not a reference EVS HAL implementation and therefore does not
+provide any actual functionality.
+
+This folder contains a skeleton EVS HAL implementation in Rust to demonstrate
+how vendors could implement their EVS HAL in Rust. To compile and run this
+implementation, please include below package to the device build script:
+
+* `android.hardware.automotive.evs-aidl-rust-service`
+
+Please note that this service will attempt to register the service as
+`IEvsEnumerator/rust/0` and therefore is also required to be declared in the
+service context by adding below line to a proper `service_contexts` file:
+
+> android.hardware.automotive.evs.IEvsEnumerator/rust/0 u:object_r:hal_evs_service:s0
+
+This implementation intentionally returns `binder::StatusCode::UNKNOWN_ERROR`
+for any API call except deprecated API for ultrasonics; the process will be
+panicked on these methods instead. Hence, this implementation does not comply
+with VTS tests and vendors must replace each method with actual implementation.
diff --git a/automotive/evs/aidl/rust_impl/evs-rust-service.rc b/automotive/evs/aidl/rust_impl/evs-rust-service.rc
new file mode 100644
index 0000000..3741b21
--- /dev/null
+++ b/automotive/evs/aidl/rust_impl/evs-rust-service.rc
@@ -0,0 +1,8 @@
+service vendor.evs-hal-rust-default /vendor/bin/hw/android.hardware.automotive.evs-aidl-rust-service
+    class early_hal
+    priority -20
+    user graphics
+    group automotive_evs camera
+    onrestart restart cardisplayproxyd
+    onrestart restart evsmanagerd
+    disabled
diff --git a/automotive/evs/aidl/rust_impl/manifest_evs-rust-service.xml b/automotive/evs/aidl/rust_impl/manifest_evs-rust-service.xml
new file mode 100644
index 0000000..813cbb2
--- /dev/null
+++ b/automotive/evs/aidl/rust_impl/manifest_evs-rust-service.xml
@@ -0,0 +1,7 @@
+<manifest version="2.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.automotive.evs</name>
+        <version>2</version>
+        <fqname>IEvsEnumerator/rust/0</fqname>
+    </hal>
+</manifest>
diff --git a/automotive/evs/aidl/rust_impl/src/default_evs_hal.rs b/automotive/evs/aidl/rust_impl/src/default_evs_hal.rs
new file mode 100644
index 0000000..72b2d53
--- /dev/null
+++ b/automotive/evs/aidl/rust_impl/src/default_evs_hal.rs
@@ -0,0 +1,113 @@
+//
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+use android_hardware_automotive_evs::aidl::android::hardware::automotive::evs::{
+    CameraDesc::CameraDesc, DisplayState::DisplayState, IEvsCamera::IEvsCamera,
+    IEvsDisplay::IEvsDisplay, IEvsEnumerator::IEvsEnumerator,
+    IEvsEnumeratorStatusCallback::IEvsEnumeratorStatusCallback,
+    IEvsUltrasonicsArray::IEvsUltrasonicsArray, Stream::Stream,
+    UltrasonicsArrayDesc::UltrasonicsArrayDesc,
+};
+
+pub struct DefaultEvsHal {}
+
+impl binder::Interface for DefaultEvsHal {}
+
+impl IEvsEnumerator for DefaultEvsHal {
+    fn closeCamera(
+        &self,
+        _: &binder::Strong<(dyn IEvsCamera + 'static)>,
+    ) -> std::result::Result<(), binder::Status> {
+        Err(binder::StatusCode::UNKNOWN_ERROR.into())
+    }
+
+    fn closeDisplay(
+        &self,
+        _: &binder::Strong<(dyn IEvsDisplay + 'static)>,
+    ) -> std::result::Result<(), binder::Status> {
+        Err(binder::StatusCode::UNKNOWN_ERROR.into())
+    }
+
+    fn closeUltrasonicsArray(
+        &self,
+        _: &binder::Strong<(dyn IEvsUltrasonicsArray + 'static)>,
+    ) -> std::result::Result<(), binder::Status> {
+        unimplemented!()
+    }
+
+    fn getCameraList(&self) -> std::result::Result<std::vec::Vec<CameraDesc>, binder::Status> {
+        Err(binder::StatusCode::UNKNOWN_ERROR.into())
+    }
+
+    fn getDisplayIdList(&self) -> std::result::Result<std::vec::Vec<u8>, binder::Status> {
+        Err(binder::StatusCode::UNKNOWN_ERROR.into())
+    }
+
+    fn getDisplayState(&self) -> std::result::Result<DisplayState, binder::Status> {
+        Err(binder::StatusCode::UNKNOWN_ERROR.into())
+    }
+
+    fn getStreamList(
+        &self,
+        _: &CameraDesc,
+    ) -> std::result::Result<std::vec::Vec<Stream>, binder::Status> {
+        Err(binder::StatusCode::UNKNOWN_ERROR.into())
+    }
+
+    fn getUltrasonicsArrayList(
+        &self,
+    ) -> std::result::Result<std::vec::Vec<UltrasonicsArrayDesc>, binder::Status> {
+        unimplemented!()
+    }
+
+    fn isHardware(&self) -> std::result::Result<bool, binder::Status> {
+        Err(binder::StatusCode::UNKNOWN_ERROR.into())
+    }
+
+    fn openCamera(
+        &self,
+        _: &str,
+        _: &Stream,
+    ) -> std::result::Result<binder::Strong<(dyn IEvsCamera + 'static)>, binder::Status> {
+        Err(binder::StatusCode::UNKNOWN_ERROR.into())
+    }
+
+    fn openDisplay(
+        &self,
+        _: i32,
+    ) -> std::result::Result<binder::Strong<(dyn IEvsDisplay + 'static)>, binder::Status> {
+        Err(binder::StatusCode::UNKNOWN_ERROR.into())
+    }
+
+    fn openUltrasonicsArray(
+        &self,
+        _: &str,
+    ) -> std::result::Result<binder::Strong<(dyn IEvsUltrasonicsArray + 'static)>, binder::Status>
+    {
+        unimplemented!()
+    }
+
+    fn registerStatusCallback(
+        &self,
+        _: &binder::Strong<(dyn IEvsEnumeratorStatusCallback + 'static)>,
+    ) -> std::result::Result<(), binder::Status> {
+        Err(binder::StatusCode::UNKNOWN_ERROR.into())
+    }
+
+    fn getDisplayStateById(&self, _: i32) -> std::result::Result<DisplayState, binder::Status> {
+        Err(binder::StatusCode::UNKNOWN_ERROR.into())
+    }
+}
diff --git a/automotive/evs/aidl/rust_impl/src/main.rs b/automotive/evs/aidl/rust_impl/src/main.rs
new file mode 100644
index 0000000..df312c0
--- /dev/null
+++ b/automotive/evs/aidl/rust_impl/src/main.rs
@@ -0,0 +1,42 @@
+//
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+mod default_evs_hal;
+
+use crate::default_evs_hal::DefaultEvsHal;
+
+use android_hardware_automotive_evs::aidl::android::hardware::automotive::evs::IEvsEnumerator::BnEvsEnumerator;
+
+use log::info;
+
+fn main() {
+    binder::ProcessState::start_thread_pool();
+
+    let service = DefaultEvsHal {};
+
+    // Register HAL implementation as rust/0 instance.
+    let service_name = "android.hardware.automotive.evs.IEvsEnumerator/rust/0";
+    let service_binder = BnEvsEnumerator::new_binder(service, binder::BinderFeatures::default());
+
+    binder::add_service(service_name, service_binder.as_binder())
+        .expect(format!("Failed to register {}.", service_name).as_str());
+    info!("EVS Hardware Enumerator is ready");
+
+    binder::ProcessState::join_thread_pool();
+
+    // In normal operation, we don't expect the thread pool to exit.
+    info!("EVS Hardware Enumerator is shutting down");
+}
diff --git a/automotive/ivn_android_device/impl/default/src/IvnAndroidDeviceService.cpp b/automotive/ivn_android_device/impl/default/src/IvnAndroidDeviceService.cpp
index 4166fdc..b284205 100644
--- a/automotive/ivn_android_device/impl/default/src/IvnAndroidDeviceService.cpp
+++ b/automotive/ivn_android_device/impl/default/src/IvnAndroidDeviceService.cpp
@@ -24,6 +24,7 @@
 #include <json/json.h>
 
 #include <fstream>
+#include <string>
 
 namespace android {
 namespace hardware {
diff --git a/automotive/vehicle/Android.bp b/automotive/vehicle/Android.bp
index e614937..606e108 100644
--- a/automotive/vehicle/Android.bp
+++ b/automotive/vehicle/Android.bp
@@ -22,7 +22,7 @@
     name: "VehicleHalInterfaceDefaults",
     static_libs: [
         "android.hardware.automotive.vehicle-V3-ndk",
-        "android.hardware.automotive.vehicle.property-V3-ndk",
+        "android.hardware.automotive.vehicle.property-V4-ndk",
     ],
 }
 
@@ -30,6 +30,14 @@
     name: "VehicleHalInterfaceRustDefaults",
     rustlibs: [
         "android.hardware.automotive.vehicle-V3-rust",
-        "android.hardware.automotive.vehicle.property-V3-rust",
+        "android.hardware.automotive.vehicle.property-V4-rust",
+    ],
+}
+
+aidl_interface_defaults {
+    name: "android.hardware.automotive.vehicle-latest-defaults",
+    imports: [
+        "android.hardware.automotive.vehicle-V3",
+        "android.hardware.automotive.vehicle.property-V4",
     ],
 }
diff --git a/automotive/vehicle/aidl/aidl_test/Android.bp b/automotive/vehicle/aidl/aidl_test/Android.bp
index f517df8..1e43070 100644
--- a/automotive/vehicle/aidl/aidl_test/Android.bp
+++ b/automotive/vehicle/aidl/aidl_test/Android.bp
@@ -40,7 +40,7 @@
 cc_test {
     name: "VehiclePropertyAnnotationCppTest",
     srcs: ["VehiclePropertyAnnotationCppTest.cpp"],
-    header_libs: ["IVehicleGeneratedHeaders-V3"],
+    header_libs: ["IVehicleGeneratedHeaders-V4"],
     defaults: ["VehicleHalInterfaceDefaults"],
     test_suites: ["general-tests"],
 }
@@ -49,11 +49,11 @@
     name: "VehiclePropertyAnnotationJavaTest",
     srcs: [
         "VehiclePropertyAnnotationJavaTest.java",
-        ":IVehicleGeneratedJavaFiles-V3",
+        ":IVehicleGeneratedJavaFiles-V4",
     ],
     static_libs: [
         "android.hardware.automotive.vehicle-V3-java",
-        "android.hardware.automotive.vehicle.property-V3-java",
+        "android.hardware.automotive.vehicle.property-V4-java",
         "androidx.test.runner",
         "truth",
     ],
diff --git a/automotive/vehicle/aidl/generated_lib/3/cpp/AccessForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/3/cpp/AccessForVehicleProperty.h
index 51a3025..6f6c91c 100644
--- a/automotive/vehicle/aidl/generated_lib/3/cpp/AccessForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/3/cpp/AccessForVehicleProperty.h
@@ -27,6 +27,10 @@
 #include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
 #include <aidl/android/hardware/automotive/vehicle/VehiclePropertyAccess.h>
 
+// Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+#include <PerDisplayMaxBrightness.h>
+// End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+
 #include <unordered_map>
 
 namespace aidl {
@@ -302,6 +306,9 @@
         {VehicleProperty::CROSS_TRAFFIC_MONITORING_WARNING_STATE, VehiclePropertyAccess::READ},
         {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyAccess::READ},
+        // Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+        {PER_DISPLAY_MAX_BRIGHTNESS, VehiclePropertyAccess::READ},
+        // End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/generated_lib/3/cpp/ChangeModeForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/3/cpp/ChangeModeForVehicleProperty.h
index 60e9a72..88f2f88 100644
--- a/automotive/vehicle/aidl/generated_lib/3/cpp/ChangeModeForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/3/cpp/ChangeModeForVehicleProperty.h
@@ -27,6 +27,10 @@
 #include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
 #include <aidl/android/hardware/automotive/vehicle/VehiclePropertyChangeMode.h>
 
+// Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+#include <PerDisplayMaxBrightness.h>
+// End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+
 #include <unordered_map>
 
 namespace aidl {
@@ -302,6 +306,9 @@
         {VehicleProperty::CROSS_TRAFFIC_MONITORING_WARNING_STATE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyChangeMode::ON_CHANGE},
+        // Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+        {PER_DISPLAY_MAX_BRIGHTNESS, VehiclePropertyChangeMode::STATIC},
+        // End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
 };
 
 }  // namespace vehicle
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/automotive/vehicle/aidl/generated_lib/3/cpp/PerDisplayMaxBrightness.h
similarity index 62%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
copy to automotive/vehicle/aidl/generated_lib/3/cpp/PerDisplayMaxBrightness.h
index c7be950..2b50db3 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ b/automotive/vehicle/aidl/generated_lib/3/cpp/PerDisplayMaxBrightness.h
@@ -14,22 +14,13 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+#pragma once
 
-import android.hardware.biometrics.fingerprint.AcquiredInfo;
+#include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
 
-/**
- * @hide
- */
-@VintfStability
-union AcquiredInfoAndVendorCode {
-    /**
-     * Acquired info as specified in AcqauiredInfo.aidl
-     */
-    AcquiredInfo acquiredInfo = AcquiredInfo.UNKNOWN;
+namespace aidl::android::hardware::automotive::vehicle {
 
-    /**
-     * Vendor specific code
-     */
-    int vendorCode;
-}
+// Same as VehicleProperty::PER_DISPLAY_MAX_BRIGHTNESS as defined in v4.
+static constexpr VehicleProperty PER_DISPLAY_MAX_BRIGHTNESS = (VehicleProperty)0x11410F4E;
+
+}  // namespace aidl::android::hardware::automotive::vehicle
diff --git a/automotive/vehicle/aidl/generated_lib/3/cpp/VersionForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/3/cpp/VersionForVehicleProperty.h
index 0e80bd8..0d24273 100644
--- a/automotive/vehicle/aidl/generated_lib/3/cpp/VersionForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/3/cpp/VersionForVehicleProperty.h
@@ -26,6 +26,10 @@
 
 #include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
 
+// Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+#include <PerDisplayMaxBrightness.h>
+// End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+
 #include <unordered_map>
 
 namespace aidl {
@@ -301,6 +305,9 @@
         {VehicleProperty::CROSS_TRAFFIC_MONITORING_WARNING_STATE, 3},
         {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED, 3},
         {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, 3},
+        // Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+        {PER_DISPLAY_MAX_BRIGHTNESS, 2},
+        // End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/generated_lib/3/java/AccessForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/3/java/AccessForVehicleProperty.java
index afb6cab..f899df8 100644
--- a/automotive/vehicle/aidl/generated_lib/3/java/AccessForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/3/java/AccessForVehicleProperty.java
@@ -28,6 +28,10 @@
 
 public final class AccessForVehicleProperty {
 
+    // Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+    private static final int PER_DISPLAY_MAX_BRIGHTNESS = 0x11410F4E;
+    // End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+
     public static final Map<Integer, Integer> values = Map.ofEntries(
         Map.entry(VehicleProperty.INFO_VIN, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.INFO_MAKE, VehiclePropertyAccess.READ),
@@ -294,7 +298,10 @@
         Map.entry(VehicleProperty.CROSS_TRAFFIC_MONITORING_ENABLED, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.CROSS_TRAFFIC_MONITORING_WARNING_STATE, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyAccess.READ_WRITE),
-        Map.entry(VehicleProperty.LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyAccess.READ)
+        Map.entry(VehicleProperty.LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyAccess.READ),
+        // Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+        Map.entry(PER_DISPLAY_MAX_BRIGHTNESS, VehiclePropertyAccess.READ)
+        // End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
     );
 
 }
diff --git a/automotive/vehicle/aidl/generated_lib/3/java/ChangeModeForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/3/java/ChangeModeForVehicleProperty.java
index 12aff40..09989bf 100644
--- a/automotive/vehicle/aidl/generated_lib/3/java/ChangeModeForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/3/java/ChangeModeForVehicleProperty.java
@@ -28,6 +28,10 @@
 
 public final class ChangeModeForVehicleProperty {
 
+    // Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+    private static final int PER_DISPLAY_MAX_BRIGHTNESS = 0x11410F4E;
+    // End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+
     public static final Map<Integer, Integer> values = Map.ofEntries(
         Map.entry(VehicleProperty.INFO_VIN, VehiclePropertyChangeMode.STATIC),
         Map.entry(VehicleProperty.INFO_MAKE, VehiclePropertyChangeMode.STATIC),
@@ -294,7 +298,10 @@
         Map.entry(VehicleProperty.CROSS_TRAFFIC_MONITORING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.CROSS_TRAFFIC_MONITORING_WARNING_STATE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
-        Map.entry(VehicleProperty.LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyChangeMode.ON_CHANGE)
+        Map.entry(VehicleProperty.LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyChangeMode.ON_CHANGE),
+        // Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
+        Map.entry(PER_DISPLAY_MAX_BRIGHTNESS, VehiclePropertyChangeMode.STATIC)
+        // End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS.
     );
 
 }
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp
index 28c95ce..aef2909 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp
@@ -27,7 +27,7 @@
     defaults: ["VehicleHalDefaults"],
     static_libs: ["VehicleHalUtils"],
     header_libs: [
-        "IVehicleGeneratedHeaders-V3",
+        "IVehicleGeneratedHeaders-V4",
     ],
     shared_libs: ["libjsoncpp"],
 }
@@ -44,7 +44,7 @@
     defaults: ["VehicleHalDefaults"],
     static_libs: ["VehicleHalUtils"],
     header_libs: [
-        "IVehicleGeneratedHeaders-V3",
+        "IVehicleGeneratedHeaders-V4",
         "libbinder_headers",
     ],
     cflags: ["-DENABLE_VEHICLE_HAL_TEST_PROPERTIES"],
@@ -60,7 +60,7 @@
     defaults: ["VehicleHalDefaults"],
     static_libs: ["VehicleHalUtils"],
     header_libs: [
-        "IVehicleGeneratedHeaders-V3",
+        "IVehicleGeneratedHeaders-V4",
     ],
     shared_libs: ["libjsoncpp"],
 }
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/Android.bp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/Android.bp
index abf15c5..90ea027 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/Android.bp
@@ -27,8 +27,6 @@
         "VehicleHalJsonConfigLoader",
         "VehicleHalUtils",
         "libgtest",
-    ],
-    shared_libs: [
         "libjsoncpp",
     ],
     defaults: ["VehicleHalDefaults"],
@@ -43,8 +41,6 @@
         "VehicleHalJsonConfigLoaderEnableTestProperties",
         "VehicleHalUtils",
         "libgtest",
-    ],
-    shared_libs: [
         "libjsoncpp",
     ],
     defaults: ["VehicleHalDefaults"],
diff --git a/automotive/vehicle/aidl/impl/default_config/TEST_MAPPING b/automotive/vehicle/aidl/impl/default_config/TEST_MAPPING
new file mode 100644
index 0000000..15ac9cb
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/default_config/TEST_MAPPING
@@ -0,0 +1,8 @@
+{
+    "ravenwood-presubmit": [
+        {
+            "name": "CarServiceHostUnitTest",
+            "host": true
+        }
+    ]
+}
diff --git a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
index 2d1e9ab..489d638 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
+++ b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
@@ -3195,19 +3195,22 @@
             }
         },
         {
-            "property": "VehicleProperty::DISPLAY_BRIGHTNESS",
+            "property": "VehicleProperty::PER_DISPLAY_BRIGHTNESS"
+        },
+        {
+            "property": "VehicleProperty::PER_DISPLAY_MAX_BRIGHTNESS",
             "defaultValue": {
                 "int32Values": [
+                    0,
+                    100,
+                    1,
+                    100,
+                    2,
+                    100,
+                    3,
                     100
                 ]
-            },
-            "areas": [
-                {
-                    "areaId": 0,
-                    "minInt32Value": 0,
-                    "maxInt32Value": 100
-                }
-            ]
+            }
         },
         {
             "property": "VehicleProperty::VALET_MODE_ENABLED",
diff --git a/automotive/vehicle/aidl/impl/default_config/test/Android.bp b/automotive/vehicle/aidl/impl/default_config/test/Android.bp
index 70933be..a88913e 100644
--- a/automotive/vehicle/aidl/impl/default_config/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/default_config/test/Android.bp
@@ -29,12 +29,10 @@
         "VehicleHalUtils",
         "libgmock",
         "libgtest",
+        "libjsoncpp",
     ],
     header_libs: [
-        "IVehicleGeneratedHeaders-V3",
-    ],
-    shared_libs: [
-        "libjsoncpp",
+        "IVehicleGeneratedHeaders-V4",
     ],
     data: [
         ":VehicleHalDefaultProperties_JSON",
@@ -52,15 +50,13 @@
         "VehicleHalUtils",
         "libgmock",
         "libgtest",
+        "libjsoncpp",
     ],
     cflags: [
         "-DENABLE_VEHICLE_HAL_TEST_PROPERTIES",
     ],
     header_libs: [
-        "IVehicleGeneratedHeaders-V3",
-    ],
-    shared_libs: [
-        "libjsoncpp",
+        "IVehicleGeneratedHeaders-V4",
     ],
     data: [
         ":VehicleHalDefaultProperties_JSON",
diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/Android.bp
index 4bc0b12..0d814ea 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/Android.bp
@@ -28,8 +28,6 @@
         "VehicleHalUtils",
         "FakeVehicleHalValueGenerators",
         "FakeObd2Frame",
-    ],
-    shared_libs: [
         "libjsoncpp",
     ],
     data: [
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index b301557..a6247a7 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -1056,6 +1056,10 @@
     VhalResult<void> isAdasPropertyAvailableResult;
     VhalResult<bool> isCruiseControlTypeStandardResult;
     switch (propId) {
+        case toInt(VehicleProperty::DISPLAY_BRIGHTNESS):
+        case toInt(VehicleProperty::PER_DISPLAY_BRIGHTNESS):
+            ALOGD("DISPLAY_BRIGHTNESS: %s", value.toString().c_str());
+            return {};
         case toInt(VehicleProperty::AP_POWER_STATE_REPORT):
             *isSpecialValue = true;
             return setApPowerStateReport(value);
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
index 9f002dd..62c1147 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
@@ -40,10 +40,10 @@
         "FakeUserHal",
         "libgtest",
         "libgmock",
+        "libjsoncpp",
     ],
     shared_libs: [
         "libgrpc++",
-        "libjsoncpp",
         "libprotobuf-cpp-full",
     ],
     data: [
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
index 73bb521..8750375 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
@@ -83,6 +83,17 @@
     return configs;
 }
 
+std::optional<aidlvhal::VehiclePropConfig> GRPCVehicleHardware::getPropertyConfig(
+        int32_t propId) const {
+    // TODO(b/354055835): Use GRPC call to get one config instead of getting all the configs.
+    for (const auto& config : getAllPropertyConfigs()) {
+        if (config.prop == propId) {
+            return config;
+        }
+    }
+    return std::nullopt;
+}
+
 aidlvhal::StatusCode GRPCVehicleHardware::setValues(
         std::shared_ptr<const SetValuesCallback> callback,
         const std::vector<aidlvhal::SetValueRequest>& requests) {
@@ -265,6 +276,7 @@
     return {
             .callerShouldDumpState = protoDumpResult.caller_should_dump_state(),
             .buffer = protoDumpResult.buffer(),
+            .refreshPropertyConfigs = protoDumpResult.refresh_property_configs(),
     };
 }
 
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
index 1edf658..15f473c 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
@@ -50,6 +50,10 @@
     // Get all the property configs.
     std::vector<aidlvhal::VehiclePropConfig> getAllPropertyConfigs() const override;
 
+    // Get the config for the specified propId.
+    std::optional<aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
+    getPropertyConfig(int32_t propId) const override;
+
     // Set property values asynchronously. Server could return before the property set requests
     // are sent to vehicle bus or before property set confirmation is received. The callback is
     // safe to be called after the function returns and is safe to be called in a different thread.
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
index d7cbe1b..7697c03 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
@@ -226,6 +226,7 @@
     auto dumpResult = mHardware->dump(dumpOptionStrings);
     result->set_caller_should_dump_state(dumpResult.callerShouldDumpState);
     result->set_buffer(dumpResult.buffer);
+    result->set_refresh_property_configs(dumpResult.refreshPropertyConfigs);
     return ::grpc::Status::OK;
 }
 
diff --git a/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h b/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
index f49d91b..0684655 100644
--- a/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
@@ -20,6 +20,7 @@
 #include <VehicleHalTypes.h>
 
 #include <memory>
+#include <optional>
 #include <vector>
 
 namespace android {
@@ -46,33 +47,53 @@
     int32_t areaId;
 };
 
+namespace aidlvhal = ::aidl::android::hardware::automotive::vehicle;
+
 // An abstract interface to access vehicle hardware.
 // For virtualized VHAL, GrpcVehicleHardware would communicate with a VehicleHardware
 // implementation in another VM through GRPC. For non-virtualzied VHAL, VHAL directly communicates
 // with a VehicleHardware through this interface.
 class IVehicleHardware {
   public:
-    using SetValuesCallback = std::function<void(
-            std::vector<aidl::android::hardware::automotive::vehicle::SetValueResult>)>;
-    using GetValuesCallback = std::function<void(
-            std::vector<aidl::android::hardware::automotive::vehicle::GetValueResult>)>;
-    using PropertyChangeCallback = std::function<void(
-            std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>)>;
+    using SetValuesCallback = std::function<void(std::vector<aidlvhal::SetValueResult>)>;
+    using GetValuesCallback = std::function<void(std::vector<aidlvhal::GetValueResult>)>;
+    using PropertyChangeCallback = std::function<void(std::vector<aidlvhal::VehiclePropValue>)>;
     using PropertySetErrorCallback = std::function<void(std::vector<SetValueErrorEvent>)>;
 
     virtual ~IVehicleHardware() = default;
 
     // Get all the property configs.
-    virtual std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
-    getAllPropertyConfigs() const = 0;
+    virtual std::vector<aidlvhal::VehiclePropConfig> getAllPropertyConfigs() const = 0;
+
+    // Get the property configs for the specified propId. This is used for early-boot
+    // native VHAL clients to access certain property configs when not all property configs are
+    // available. For example, a config discovery process might be required to determine the
+    // property config for HVAC. However, for early boot properties, e.g. VHAL_HEARTBEAT, it
+    // could return before the config discovery process.
+    //
+    // Currently Android system may try to access the following properties during early boot:
+    // STORAGE_ENCRYPTION_BINDING_SEED, WATCHDOG_ALIVE, WATCHDOG_TERMINATE_PROCESS, VHAL_HEARTBEAT,
+    // CURRENT_POWER_POLICY, POWER_POLICY_REQ, POWER_POLICY_GROUP_REQ. They should return
+    // quickly otherwise the whole bootup process might be blocked.
+    virtual std::optional<aidlvhal::VehiclePropConfig> getPropertyConfig(int32_t propId) const {
+        // The default implementation is to use getAllPropertyConfigs(). This should be
+        // overridden if getAllPropertyConfigs() takes a while to return for initial boot or
+        // relies on ethernet or other communication channel that is not available during early
+        // boot.
+        for (const auto& config : getAllPropertyConfigs()) {
+            if (config.prop == propId) {
+                return config;
+            }
+        }
+        return std::nullopt;
+    }
 
     // Set property values asynchronously. Server could return before the property set requests
     // are sent to vehicle bus or before property set confirmation is received. The callback is
     // safe to be called after the function returns and is safe to be called in a different thread.
-    virtual aidl::android::hardware::automotive::vehicle::StatusCode setValues(
+    virtual aidlvhal::StatusCode setValues(
             std::shared_ptr<const SetValuesCallback> callback,
-            const std::vector<aidl::android::hardware::automotive::vehicle::SetValueRequest>&
-                    requests) = 0;
+            const std::vector<aidlvhal::SetValueRequest>& requests) = 0;
 
     // Get property values asynchronously. Server could return before the property values are ready.
     // The callback is safe to be called after the function returns and is safe to be called in a
@@ -86,7 +107,7 @@
     virtual DumpResult dump(const std::vector<std::string>& options) = 0;
 
     // Check whether the system is healthy, return {@code StatusCode::OK} for healthy.
-    virtual aidl::android::hardware::automotive::vehicle::StatusCode checkHealth() = 0;
+    virtual aidlvhal::StatusCode checkHealth() = 0;
 
     // Register a callback that would be called when there is a property change event from vehicle.
     // This function must only be called once during initialization.
@@ -179,16 +200,14 @@
     // 5. The second subscriber is removed, 'unsubscribe' is called.
     //    The impl can optionally disable the polling for vehicle speed.
     //
-    virtual aidl::android::hardware::automotive::vehicle::StatusCode subscribe(
-            [[maybe_unused]] aidl::android::hardware::automotive::vehicle::SubscribeOptions
-                    options) {
-        return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
+    virtual aidlvhal::StatusCode subscribe([[maybe_unused]] aidlvhal::SubscribeOptions options) {
+        return aidlvhal::StatusCode::OK;
     }
 
     // A [propId, areaId] is unsubscribed. This applies for both continuous or on-change property.
-    virtual aidl::android::hardware::automotive::vehicle::StatusCode unsubscribe(
-            [[maybe_unused]] int32_t propId, [[maybe_unused]] int32_t areaId) {
-        return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
+    virtual aidlvhal::StatusCode unsubscribe([[maybe_unused]] int32_t propId,
+                                             [[maybe_unused]] int32_t areaId) {
+        return aidlvhal::StatusCode::OK;
     }
 
     // This function is deprecated, subscribe/unsubscribe should be used instead.
@@ -216,10 +235,10 @@
     //
     // If the impl is always polling at {@code maxSampleRate} as specified in config, then this
     // function can be a no-op.
-    virtual aidl::android::hardware::automotive::vehicle::StatusCode updateSampleRate(
-            [[maybe_unused]] int32_t propId, [[maybe_unused]] int32_t areaId,
-            [[maybe_unused]] float sampleRate) {
-        return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
+    virtual aidlvhal::StatusCode updateSampleRate([[maybe_unused]] int32_t propId,
+                                                  [[maybe_unused]] int32_t areaId,
+                                                  [[maybe_unused]] float sampleRate) {
+        return aidlvhal::StatusCode::OK;
     }
 };
 
diff --git a/automotive/vehicle/aidl/impl/proto/Android.bp b/automotive/vehicle/aidl/impl/proto/Android.bp
index b2edf75..0d3df49 100644
--- a/automotive/vehicle/aidl/impl/proto/Android.bp
+++ b/automotive/vehicle/aidl/impl/proto/Android.bp
@@ -106,3 +106,21 @@
         "-Wno-unused-parameter",
     ],
 }
+
+rust_protobuf {
+    name: "libvehicle_hal_property_protos",
+    crate_name: "vehicle_hal_property_protos",
+    protos: [":VehicleHalProtoFiles"],
+    source_stem: "vehicle_hal_property_protos",
+    host_supported: true,
+    vendor_available: true,
+    product_available: true,
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
+    exported_include_dirs: ["."],
+    proto_flags: [
+        "-I external/protobuf/src",
+    ],
+}
diff --git a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/DumpResult.proto b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/DumpResult.proto
index 25bb7d4..fbfb505 100644
--- a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/DumpResult.proto
+++ b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/DumpResult.proto
@@ -25,4 +25,6 @@
     bool caller_should_dump_state = 1;
     /* The dumped information for the caller to print. */
     string buffer = 2;
+    /* To pass if DefaultVehicleHal should refresh the property configs. */
+    bool refresh_property_configs = 3;
 }
diff --git a/automotive/vehicle/aidl/impl/vhal/Android.bp b/automotive/vehicle/aidl/impl/vhal/Android.bp
index 5cc071d..54d148e 100644
--- a/automotive/vehicle/aidl/impl/vhal/Android.bp
+++ b/automotive/vehicle/aidl/impl/vhal/Android.bp
@@ -66,7 +66,7 @@
     ],
     header_libs: [
         "IVehicleHardware",
-        "IVehicleGeneratedHeaders-V3",
+        "IVehicleGeneratedHeaders-V4",
     ],
     shared_libs: [
         "libbinder_ndk",
diff --git a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
index b58d0f5..932a2e2 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
@@ -199,6 +199,8 @@
 
     bool checkDumpPermission();
 
+    bool isConfigSupportedForCurrentVhalVersion(const aidlvhal::VehiclePropConfig& config) const;
+
     bool getAllPropConfigsFromHardwareLocked() const EXCLUDES(mConfigLock);
 
     // The looping handler function to process all onBinderDied or onBinderUnlinked events in
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index e062a28..0ead819 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -340,32 +340,37 @@
     return myVersion;
 }
 
+bool DefaultVehicleHal::isConfigSupportedForCurrentVhalVersion(
+        const VehiclePropConfig& config) const {
+    int32_t myVersion = getVhalInterfaceVersion();
+    if (!isSystemProp(config.prop)) {
+        return true;
+    }
+    VehicleProperty property = static_cast<VehicleProperty>(config.prop);
+    std::string propertyName = aidl::android::hardware::automotive::vehicle::toString(property);
+    auto it = VersionForVehicleProperty.find(property);
+    if (it == VersionForVehicleProperty.end()) {
+        ALOGE("The property: %s is not a supported system property, ignore", propertyName.c_str());
+        return false;
+    }
+    int requiredVersion = it->second;
+    if (myVersion < requiredVersion) {
+        ALOGE("The property: %s is not supported for current client VHAL version, "
+              "require %d, current version: %d, ignore",
+              propertyName.c_str(), requiredVersion, myVersion);
+        return false;
+    }
+    return true;
+}
+
 bool DefaultVehicleHal::getAllPropConfigsFromHardwareLocked() const {
     ALOGD("Get all property configs from hardware");
     auto configs = mVehicleHardware->getAllPropertyConfigs();
     std::vector<VehiclePropConfig> filteredConfigs;
-    int32_t myVersion = getVhalInterfaceVersion();
-    for (auto& config : configs) {
-        if (!isSystemProp(config.prop)) {
+    for (const auto& config : configs) {
+        if (isConfigSupportedForCurrentVhalVersion(config)) {
             filteredConfigs.push_back(std::move(config));
-            continue;
         }
-        VehicleProperty property = static_cast<VehicleProperty>(config.prop);
-        std::string propertyName = aidl::android::hardware::automotive::vehicle::toString(property);
-        auto it = VersionForVehicleProperty.find(property);
-        if (it == VersionForVehicleProperty.end()) {
-            ALOGE("The property: %s is not a supported system property, ignore",
-                  propertyName.c_str());
-            continue;
-        }
-        int requiredVersion = it->second;
-        if (myVersion < requiredVersion) {
-            ALOGE("The property: %s is not supported for current client VHAL version, "
-                  "require %d, current version: %d, ignore",
-                  propertyName.c_str(), requiredVersion, myVersion);
-            continue;
-        }
-        filteredConfigs.push_back(std::move(config));
     }
 
     {
@@ -431,6 +436,19 @@
 
 Result<VehiclePropConfig> DefaultVehicleHal::getConfig(int32_t propId) const {
     Result<VehiclePropConfig> result;
+
+    if (!mConfigInit) {
+        std::optional<VehiclePropConfig> config = mVehicleHardware->getPropertyConfig(propId);
+        if (!config.has_value()) {
+            return Error() << "no config for property, ID: " << propId;
+        }
+        if (!isConfigSupportedForCurrentVhalVersion(config.value())) {
+            return Error() << "property not supported for current VHAL interface, ID: " << propId;
+        }
+
+        return config.value();
+    }
+
     getConfigsByPropId([this, &result, propId](const auto& configsByPropId) {
         SharedScopedLockAssertion lockAssertion(mConfigLock);
 
@@ -685,6 +703,22 @@
 ScopedAStatus DefaultVehicleHal::getPropConfigs(const std::vector<int32_t>& props,
                                                 VehiclePropConfigs* output) {
     std::vector<VehiclePropConfig> configs;
+
+    if (!mConfigInit) {
+        for (int32_t prop : props) {
+            auto maybeConfig = mVehicleHardware->getPropertyConfig(prop);
+            if (!maybeConfig.has_value() ||
+                !isConfigSupportedForCurrentVhalVersion(maybeConfig.value())) {
+                return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                        toInt(StatusCode::INVALID_ARG),
+                        StringPrintf("no config for property, ID: %" PRId32, prop).c_str());
+            }
+            configs.push_back(maybeConfig.value());
+        }
+
+        return vectorToStableLargeParcelable(std::move(configs), output);
+    }
+
     ScopedAStatus status = ScopedAStatus::ok();
     getConfigsByPropId([this, &configs, &status, &props](const auto& configsByPropId) {
         SharedScopedLockAssertion lockAssertion(mConfigLock);
diff --git a/automotive/vehicle/aidl/impl/vhal/src/fuzzer.cpp b/automotive/vehicle/aidl/impl/vhal/src/fuzzer.cpp
index ac1e3b1..6d994bb 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/fuzzer.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/fuzzer.cpp
@@ -25,6 +25,8 @@
 using ::ndk::SharedRefBase;
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    // TODO(b/183141167): need to rewrite 'dump' to avoid SIGPIPE.
+    signal(SIGPIPE, SIG_IGN);
     std::unique_ptr<FakeVehicleHardware> hardware = std::make_unique<FakeVehicleHardware>();
     std::shared_ptr<DefaultVehicleHal> vhal =
             ::ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
diff --git a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
index 11a8fc7..4891bf5 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
@@ -650,6 +650,8 @@
 
     auto hardware = std::make_unique<MockVehicleHardware>();
     hardware->setPropertyConfigs(testConfigs);
+    // Store the pointer for testing. We are sure it is valid.
+    MockVehicleHardware* hardwarePtr = hardware.get();
     auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
     std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
 
@@ -658,6 +660,7 @@
 
     ASSERT_TRUE(status.isOk()) << "getPropConfigs failed: " << status.getMessage();
     ASSERT_EQ(output.payloads, testConfigs);
+    ASSERT_FALSE(hardwarePtr->getAllPropertyConfigsCalled());
 }
 
 TEST_F(DefaultVehicleHalTest, testGetPropConfigsInvalidArg) {
@@ -704,6 +707,34 @@
     ASSERT_TRUE(maybeGetValueResults.has_value()) << "no results in callback";
     EXPECT_EQ(maybeGetValueResults.value().payloads, expectedResults) << "results mismatch";
     EXPECT_EQ(countClients(), static_cast<size_t>(1));
+    ASSERT_FALSE(getHardware()->getAllPropertyConfigsCalled());
+}
+
+TEST_F(DefaultVehicleHalTest, testGetValuesSmall_AfterGetAllPropConfigs) {
+    GetValueRequests requests;
+    std::vector<GetValueResult> expectedResults;
+    std::vector<GetValueRequest> expectedHardwareRequests;
+
+    // If we already called getAllPropConfigs, the configs will be cached.
+    VehiclePropConfigs output;
+    getClient()->getAllPropConfigs(&output);
+
+    ASSERT_TRUE(getValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
+
+    getHardware()->addGetValueResponses(expectedResults);
+
+    auto status = getClient()->getValues(getCallbackClient(), requests);
+
+    ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage();
+
+    EXPECT_EQ(getHardware()->nextGetValueRequests(), expectedHardwareRequests)
+            << "requests to hardware mismatch";
+
+    auto maybeGetValueResults = getCallback()->nextGetValueResults();
+    ASSERT_TRUE(maybeGetValueResults.has_value()) << "no results in callback";
+    EXPECT_EQ(maybeGetValueResults.value().payloads, expectedResults) << "results mismatch";
+    EXPECT_EQ(countClients(), static_cast<size_t>(1));
+    ASSERT_TRUE(getHardware()->getAllPropertyConfigsCalled());
 }
 
 TEST_F(DefaultVehicleHalTest, testGetValuesLarge) {
@@ -1016,6 +1047,34 @@
     ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results in callback";
     ASSERT_EQ(maybeSetValueResults.value().payloads, expectedResults) << "results mismatch";
     EXPECT_EQ(countClients(), static_cast<size_t>(1));
+    ASSERT_FALSE(getHardware()->getAllPropertyConfigsCalled());
+}
+
+TEST_F(DefaultVehicleHalTest, testSetValuesSmall_AfterGetAllPropConfigs) {
+    SetValueRequests requests;
+    std::vector<SetValueResult> expectedResults;
+    std::vector<SetValueRequest> expectedHardwareRequests;
+
+    // If we already called getAllPropConfigs, the configs will be cached.
+    VehiclePropConfigs output;
+    getClient()->getAllPropConfigs(&output);
+
+    ASSERT_TRUE(setValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
+
+    getHardware()->addSetValueResponses(expectedResults);
+
+    auto status = getClient()->setValues(getCallbackClient(), requests);
+
+    ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+    EXPECT_EQ(getHardware()->nextSetValueRequests(), expectedHardwareRequests)
+            << "requests to hardware mismatch";
+
+    auto maybeSetValueResults = getCallback()->nextSetValueResults();
+    ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results in callback";
+    ASSERT_EQ(maybeSetValueResults.value().payloads, expectedResults) << "results mismatch";
+    EXPECT_EQ(countClients(), static_cast<size_t>(1));
+    ASSERT_TRUE(getHardware()->getAllPropertyConfigsCalled());
 }
 
 TEST_F(DefaultVehicleHalTest, testSetValuesLarge) {
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
index db15c89..e796ce5 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
@@ -45,9 +45,20 @@
 
 std::vector<VehiclePropConfig> MockVehicleHardware::getAllPropertyConfigs() const {
     std::scoped_lock<std::mutex> lockGuard(mLock);
+    mGetAllPropertyConfigsCalled = true;
     return mPropertyConfigs;
 }
 
+std::optional<VehiclePropConfig> MockVehicleHardware::getPropertyConfig(int32_t propId) const {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    for (const auto& config : mPropertyConfigs) {
+        if (config.prop == propId) {
+            return config;
+        }
+    }
+    return std::nullopt;
+}
+
 StatusCode MockVehicleHardware::setValues(std::shared_ptr<const SetValuesCallback> callback,
                                           const std::vector<SetValueRequest>& requests) {
     std::scoped_lock<std::mutex> lockGuard(mLock);
@@ -336,6 +347,11 @@
     (*mPropertySetErrorCallback)(errorEvents);
 }
 
+bool MockVehicleHardware::getAllPropertyConfigsCalled() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return mGetAllPropertyConfigsCalled;
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
index eeca582..06e01a8 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
@@ -47,6 +47,8 @@
 
     std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
     getAllPropertyConfigs() const override;
+    std::optional<aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
+    getPropertyConfig(int32_t propId) const override;
     aidl::android::hardware::automotive::vehicle::StatusCode setValues(
             std::shared_ptr<const SetValuesCallback> callback,
             const std::vector<aidl::android::hardware::automotive::vehicle::SetValueRequest>&
@@ -98,6 +100,9 @@
     std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions>
     getSubscribeOptions();
     void clearSubscribeOptions();
+    // Whether getAllPropertyConfigs() has been called, which blocks all all property configs
+    // being ready.
+    bool getAllPropertyConfigsCalled();
 
   private:
     mutable std::mutex mLock;
@@ -143,6 +148,8 @@
 
     DumpResult mDumpResult;
 
+    mutable bool mGetAllPropertyConfigsCalled GUARDED_BY(mLock) = false;
+
     // RecurrentTimer is thread-safe.
     std::shared_ptr<RecurrentTimer> mRecurrentTimer;
     std::unordered_map<int32_t, std::unordered_map<int32_t, std::shared_ptr<std::function<void()>>>>
diff --git a/automotive/vehicle/tools/generate_emu_metadata/src/com/android/car/tool/EmuMetadataGenerator.java b/automotive/vehicle/tools/generate_emu_metadata/src/com/android/car/tool/EmuMetadataGenerator.java
index bea5951..7f4ceb8 100644
--- a/automotive/vehicle/tools/generate_emu_metadata/src/com/android/car/tool/EmuMetadataGenerator.java
+++ b/automotive/vehicle/tools/generate_emu_metadata/src/com/android/car/tool/EmuMetadataGenerator.java
@@ -79,17 +79,18 @@
             + "either this or input_files must be specified\n" + INPUT_FILES_OPTION
             + ": one or more Java files, this is used to decide the input "
             + "directory\n" + PACKAGE_NAME_OPTION
-            + ": the optional package name for the interface, by default is " + DEFAULT_PACKAGE_NAME
-            + "\n" + OUTPUT_JSON_OPTION + ": The output JSON file\n" + OUTPUT_EMPTY_FILE_OPTION
-            + ": Only used for check_mode, this file will be created if "
+            + ": the optional package name for the interface, by default is "
+            + DEFAULT_PACKAGE_NAME + "\n" + OUTPUT_JSON_OPTION + ": The output JSON file\n"
+            + OUTPUT_EMPTY_FILE_OPTION + ": Only used for check_mode, this file will be created if "
             + "check  passed\n" + CHECK_AGAINST_OPTION
             + ": An optional JSON file to check against. If specified, the "
-            + "generated output file will be checked against this file, if they are not the same, "
+            + ("generated output file will be checked against this file, if they are not the "
+                    + "same, ")
             + "the script will fail, otherwise, the output_empty_file will be created\n"
             + "For example: \n"
             + "EnumMetadataGenerator --input_dir out/soong/.intermediates/hardware/"
             + "interfaces/automotive/vehicle/aidl_property/android.hardware.automotive.vehicle."
-            + "property-V3-java-source/gen/ --package_name android.hardware.automotive.vehicle "
+            + "property-V4-java-source/gen/ --package_name android.hardware.automotive.vehicle "
             + "--output_json /tmp/android.hardware.automotive.vehicle-types-meta.json";
     private static final String VEHICLE_PROPERTY_FILE = "VehicleProperty.java";
     private static final String CHECK_FILE_PATH =
diff --git a/automotive/vehicle/vhal_static_cpp_lib.mk b/automotive/vehicle/vhal_static_cpp_lib.mk
index 6b3d486..9371453 100644
--- a/automotive/vehicle/vhal_static_cpp_lib.mk
+++ b/automotive/vehicle/vhal_static_cpp_lib.mk
@@ -17,4 +17,4 @@
 
 LOCAL_STATIC_LIBRARIES += \
     android.hardware.automotive.vehicle-V3-ndk \
-    android.hardware.automotive.vehicle.property-V3-ndk
+    android.hardware.automotive.vehicle.property-V4-ndk
diff --git a/automotive/vehicle/vts/Android.bp b/automotive/vehicle/vts/Android.bp
index 303e5a6..d55dc33 100644
--- a/automotive/vehicle/vts/Android.bp
+++ b/automotive/vehicle/vts/Android.bp
@@ -44,7 +44,7 @@
         "vhalclient_defaults",
     ],
     header_libs: [
-        "IVehicleGeneratedHeaders-V3",
+        "IVehicleGeneratedHeaders-V4",
     ],
     test_suites: [
         "general-tests",
diff --git a/biometrics/common/aidl/Android.bp b/biometrics/common/aidl/Android.bp
index 4afecb4..8c9a357 100644
--- a/biometrics/common/aidl/Android.bp
+++ b/biometrics/common/aidl/Android.bp
@@ -22,6 +22,12 @@
         cpp: {
             enabled: false,
         },
+        ndk: {
+            apex_available: [
+                "//apex_available:anyapex",
+                "//apex_available:platform",
+            ],
+        },
         rust: {
             enabled: true,
         },
diff --git a/biometrics/common/config/Android.bp b/biometrics/common/config/Android.bp
index d38ffe8..b86aafa 100644
--- a/biometrics/common/config/Android.bp
+++ b/biometrics/common/config/Android.bp
@@ -22,7 +22,7 @@
     //   SPDX-license-identifier-Apache-2.0
     name: "android.hardware.biometrics.common.config",
     export_include_dirs: ["include"],
-    vendor: true,
+    vendor_available: true,
     srcs: [
         "Config.cpp",
     ],
@@ -30,6 +30,10 @@
         "libbase",
         "libbinder_ndk",
     ],
+    apex_available: [
+        "//apex_available:anyapex",
+        "//apex_available:platform",
+    ],
 }
 
 cc_test_host {
diff --git a/biometrics/common/config/include/config/Config.h b/biometrics/common/config/include/config/Config.h
index 0367832..b1affdc 100644
--- a/biometrics/common/config/include/config/Config.h
+++ b/biometrics/common/config/include/config/Config.h
@@ -100,7 +100,11 @@
         } else if (std::holds_alternative<OptIntVec>(v)) {
             for (auto x : std::get<OptIntVec>(v))
                 if (x.has_value()) os << x.value() << " ";
+        } else if (std::holds_alternative<OptString>(v)) {
+            OptString ov = std::get<OptString>(v);
+            if (ov.has_value()) os << ov.value();
         }
+
         return os.str();
     }
     std::string toString() const {
diff --git a/biometrics/common/thread/Android.bp b/biometrics/common/thread/Android.bp
index e7a7e4c..c1ebe3b 100644
--- a/biometrics/common/thread/Android.bp
+++ b/biometrics/common/thread/Android.bp
@@ -10,10 +10,14 @@
     //   SPDX-license-identifier-Apache-2.0
     name: "android.hardware.biometrics.common.thread",
     export_include_dirs: ["include"],
-    vendor: true,
+    vendor_available: true,
     srcs: [
         "WorkerThread.cpp",
     ],
+    apex_available: [
+        "//apex_available:anyapex",
+        "//apex_available:platform",
+    ],
 }
 
 cc_test_host {
diff --git a/biometrics/common/util/Android.bp b/biometrics/common/util/Android.bp
index 599c491..a0bd211 100644
--- a/biometrics/common/util/Android.bp
+++ b/biometrics/common/util/Android.bp
@@ -6,7 +6,7 @@
     //   SPDX-license-identifier-Apache-2.0
     name: "android.hardware.biometrics.common.util",
     export_include_dirs: ["include"],
-    vendor: true,
+    vendor_available: true,
     srcs: [
         "CancellationSignal.cpp",
     ],
@@ -15,4 +15,8 @@
         "libbinder_ndk",
         "android.hardware.biometrics.common-V4-ndk",
     ],
+    apex_available: [
+        "//apex_available:anyapex",
+        "//apex_available:platform",
+    ],
 }
diff --git a/biometrics/face/aidl/Android.bp b/biometrics/face/aidl/Android.bp
index fadcde7..54d01a7 100644
--- a/biometrics/face/aidl/Android.bp
+++ b/biometrics/face/aidl/Android.bp
@@ -11,7 +11,7 @@
     name: "android.hardware.biometrics.face",
     vendor_available: true,
     srcs: [
-        "android/hardware/biometrics/face/**/*.aidl",
+        "android/hardware/biometrics/face/*.aidl",
     ],
     imports: [
         "android.hardware.biometrics.common-V4",
@@ -36,6 +36,10 @@
             additional_shared_libraries: [
                 "libnativewindow",
             ],
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.hardware.biometrics.face.virtual",
+            ],
         },
     },
     versions_with_info: [
@@ -74,5 +78,39 @@
 
     ],
     frozen: true,
+}
 
+aidl_interface {
+    name: "android.hardware.biometrics.face.virtualhal",
+    srcs: [
+        "android/hardware/biometrics/face/virtualhal/*.aidl",
+    ],
+    imports: [
+        "android.hardware.biometrics.common-V4",
+        "android.hardware.keymaster-V4",
+        "android.hardware.biometrics.face-V4",
+    ],
+    vendor_available: true,
+    unstable: true,
+    backend: {
+        java: {
+            platform_apis: true,
+        },
+        rust: {
+            enabled: false,
+        },
+        cpp: {
+            enabled: false,
+        },
+        ndk: {
+            additional_shared_libraries: [
+                "libnativewindow",
+            ],
+            apex_available: [
+                "com.android.hardware.biometrics.face.virtual",
+                "//apex_available:platform",
+            ],
+        },
+    },
+    frozen: false,
 }
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
index 26cb361..0dbf052 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
@@ -73,7 +73,7 @@
      * Note that this interface allows multiple in-flight challenges. Invoking generateChallenge
      * twice does not invalidate the first challenge. The challenge is invalidated only when:
      *   1) Its lifespan exceeds the challenge timeout defined in the TEE.
-     *   2) IFingerprint#revokeChallenge is invoked
+     *   2) IFace#revokeChallenge is invoked
      *
      * For example, the following is a possible table of valid challenges:
      * ----------------------------------------------
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/AcquiredInfoAndVendorCode.aidl
similarity index 86%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
copy to biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/AcquiredInfoAndVendorCode.aidl
index c7be950..a254120 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/AcquiredInfoAndVendorCode.aidl
@@ -14,14 +14,13 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+package android.hardware.biometrics.face.virtualhal;
 
-import android.hardware.biometrics.fingerprint.AcquiredInfo;
+import android.hardware.biometrics.face.AcquiredInfo;
 
 /**
  * @hide
  */
-@VintfStability
 union AcquiredInfoAndVendorCode {
     /**
      * Acquired info as specified in AcqauiredInfo.aidl
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/EnrollmentProgressStep.aidl
similarity index 82%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/EnrollmentProgressStep.aidl
index bf038f6..7fbcf5d 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/EnrollmentProgressStep.aidl
@@ -14,14 +14,13 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+package android.hardware.biometrics.face.virtualhal;
 
-import android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode;
+import android.hardware.biometrics.face.virtualhal.AcquiredInfoAndVendorCode;
 
 /**
  * @hide
  */
-@VintfStability
 parcelable EnrollmentProgressStep {
     /**
      * The duration of the enrollment step in milli-seconds
@@ -30,7 +29,7 @@
 
     /**
      * The sequence of acquired info and vendor code to be issued by HAL during the step.
-     * The codes are evenly spreaded over the duration
+     * The codes are evenly spread over the duration
      */
     AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
 }
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IVirtualHal.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/IVirtualHal.aidl
similarity index 71%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IVirtualHal.aidl
copy to biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/IVirtualHal.aidl
index cb9135e..1d3d934 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IVirtualHal.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/IVirtualHal.aidl
@@ -14,19 +14,18 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+package android.hardware.biometrics.face.virtualhal;
 
 import android.hardware.biometrics.common.SensorStrength;
-import android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode;
-import android.hardware.biometrics.fingerprint.FingerprintSensorType;
-import android.hardware.biometrics.fingerprint.NextEnrollment;
-import android.hardware.biometrics.fingerprint.SensorLocation;
+import android.hardware.biometrics.face.FaceSensorType;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.virtualhal.AcquiredInfoAndVendorCode;
+import android.hardware.biometrics.face.virtualhal.NextEnrollment;
 
 /**
  * @hide
  */
-@VintfStability
-oneway interface IVirtualHal {
+interface IVirtualHal {
     /**
      * The operation failed due to invalid input parameters, the error messages should
      * gives more details
@@ -34,13 +33,13 @@
     const int STATUS_INVALID_PARAMETER = 1;
 
     /**
-     * Set Fingerprint Virtual HAL behavior parameters
+     * Set Face Virtual HAL behavior parameters
      */
 
     /**
      * setEnrollments
      *
-     * Set the ids of the fingerprints that were currently enrolled in the Virtual HAL,
+     * Set the ids of the faces that were currently enrolled in the Virtual HAL,
      *
      * @param ids ids can contain 1 or more ids, each must be larger than 0
      */
@@ -49,7 +48,7 @@
     /**
      * setEnrollmentHit
      *
-     * Set current fingerprint enrollment ids in Fingerprint Virtual HAL,
+     * Set current face enrollment ids in Face Virtual HAL,
      *
      * @param ids ids can contain 1 or more ids, each must be larger than 0
      */
@@ -67,7 +66,7 @@
     /**
      * setAuthenticatorId
      *
-     * Set authenticator id in virtual HAL, the id is returned in ISession#getAuthenticatorId() call
+     * Set authenticator id in virtual HAL, the id is returned in ISession#AuthenticatorId() call
      *
      * @param id authenticator id value, only applied to the sensor with SensorStrength::STRONG.
      */
@@ -116,7 +115,7 @@
      * setOperationAuthenticateDuration
      *
      * Set authentication duration covering the HAL authetication from start to end, including
-     * fingerprint capturing, and matching, acquired info reporting. In case a sequence of acquired
+     * face capturing, and matching, acquired info reporting. In case a sequence of acquired
      * info code are specified via setOperationAuthenticateAcquired(), the reporting is evenly
      * distributed over the duration.
      *
@@ -130,7 +129,9 @@
      * setOperationAuthenticateError
      *
      * Force authentication to error out for non-zero error
-     * Check hardware/interfaces/biometrics/fingerprint/aidl/default/README.md for valid error codes
+     * Check
+     * hardware/interfaces/biometrics/face/aidl/default/aidl/android/hardware/biometrics/face/Error.aidl
+     * for valid error codes
      *
      * @param error if error < 1000
      *                  non-vendor error
@@ -143,27 +144,15 @@
      * setOperationAuthenticateAcquired
      *
      * Set one of more acquired info codes for the virtual hal to report during authentication
-     * Check hardware/interfaces/biometrics/fingerprint/aidl/default/README.md for valid acquired
-     * info codes
+     * Check
+     * hardware/interfaces/biometrics/face/aidl/aidl/android/hardware/biometrics/face/AcquiredInfo.aidl
+     * for valid acquired info codes
      *
      * @param acquired[], one or more acquired info codes
      */
     void setOperationAuthenticateAcquired(in AcquiredInfoAndVendorCode[] acquired);
 
     /**
-     * setOperationEnrollError
-     *
-     * Force enrollment operation to error out for non-zero error
-     * Check hardware/interfaces/biometrics/fingerprint/aidl/default/README.md for valid error codes
-     *
-     * @param error if error < 1000
-     *                  non-vendor error
-     *              else
-     *                  vendor error
-     */
-    void setOperationEnrollError(in int error);
-
-    /**
      * setOperationEnrollLatency
      *
      * Set enrollment latency in the virtual hal in a fixed value (single element) or random
@@ -202,42 +191,11 @@
     void setOperationDetectInteractionLatency(in int[] latencyMs);
 
     /**
-     * setOperationDetectInteractionError
+     * setOperationDetectInteractionFails
      *
-     * Force detect interaction operation to error out for non-zero error
-     * Check hardware/interfaces/biometrics/fingerprint/aidl/default/README.md for valid error codes
-     *
-     * @param error if error < 1000
-     *                  non-vendor error
-     *              else
-     *                  vendor error
+     * Force detect interaction operation to fail
      */
-    void setOperationDetectInteractionError(in int error);
-
-    /**
-     * setOperationDetectInteractionDuration
-     *
-     * Set detect interaction duration covering the HAL authetication from start to end, including
-     * fingerprint detect and acquired info reporting. In case a sequence of acquired info code are
-     * specified via setOperationDetectInteractionAcquired(), the reporting is evenly distributed
-     * over the duration.
-     *
-     * This method fails with STATUS_INVALID_PARAMETERS if the passed-in value is negative
-     *
-     * @param duration  value is in milli-seconds
-     */
-    void setOperationDetectInteractionDuration(in int durationMs);
-
-    /**
-     * setOperationDetectInteractionAcquired
-     *
-     * Set one of more acquired info codes for the virtual hal to report during detect interaction
-     * Check hardware/interfaces/biometrics/fingerprint/aidl/default/README.md for valid acquired
-     * info codes
-     *
-     * @param acquired[], one or more acquired info codes
-     */
-    void setOperationDetectInteractionAcquired(in AcquiredInfoAndVendorCode[] acquired);
+    void setOperationDetectInteractionFails(in boolean error);
 
     /**
      * setLockout
@@ -261,6 +219,15 @@
     void setLockoutEnable(in boolean enable);
 
     /**
+     * setLockoutTimedEnable
+     *
+     * Whether to enable authentication-fail-based time-based-lockout tracking or not.
+     *
+     * @param enable, set true to enable the time-basedlockout tracking
+     */
+    void setLockoutTimedEnable(in boolean enable);
+
+    /**
      * setLockoutTimedThreshold
      *
      * Set the number of consecutive authentication failures that triggers the timed-based lock to
@@ -303,16 +270,28 @@
     void resetConfigurations();
 
     /**
-     * The following functions are used to configure Fingerprint Virtual HAL sensor properties
-     *  refer to SensorProps.aidl and CommonProps.aidl for details of each property
+     * setType
+     *
+     * Configure virtual face sensor type
+     *
+     * @param type, sensor type as specified in FaceSensorType.aidl
+     *
      */
-    void setType(in FingerprintSensorType type);
-    void setSensorId(in int id);
+    void setType(in FaceSensorType type);
+
+    /**
+     *  setSensorStrength
+     *
+     *  Configure virtual face sensor strength
+     *
+     * @param sensor strength as specified in common/SensorStrength.aidl
+     */
     void setSensorStrength(in SensorStrength strength);
-    void setMaxEnrollmentPerUser(in int max);
-    void setSensorLocation(in SensorLocation loc);
-    void setNavigationGuesture(in boolean v);
-    void setDetectInteraction(in boolean v);
-    void setDisplayTouch(in boolean v);
-    void setControlIllumination(in boolean v);
+
+    /**
+     * getFaceHal
+     *
+     * @return IFace interface associated with IVirtualHal instance
+     */
+    IFace getFaceHal();
 }
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/NextEnrollment.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/NextEnrollment.aidl
similarity index 87%
rename from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/NextEnrollment.aidl
rename to biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/NextEnrollment.aidl
index 4b50850..d3547a8 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/NextEnrollment.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/NextEnrollment.aidl
@@ -14,12 +14,11 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+package android.hardware.biometrics.face.virtualhal;
 
 /**
  * @hide
  */
-@VintfStability
 parcelable NextEnrollment {
     /**
      *  Identifier of the next enrollment if successful
@@ -31,7 +30,7 @@
      *  and sequence of acquired info codes to be generated by HAL.
      *  See EnrollmentProgressStep.aidl for more details
      */
-    android.hardware.biometrics.fingerprint.EnrollmentProgressStep[] progressSteps;
+    android.hardware.biometrics.face.virtualhal.EnrollmentProgressStep[] progressSteps;
 
     /**
      * Success or failure of the next enrollment
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/README.md b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/README.md
new file mode 100644
index 0000000..bf1a4b1
--- /dev/null
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/README.md
@@ -0,0 +1,3 @@
+The aidl files in this directory are used to control/configure face virtual hal
+via IVirtualHal interface
+
diff --git a/biometrics/face/aidl/default/Android.bp b/biometrics/face/aidl/default/Android.bp
index 685639c..dc11af6 100644
--- a/biometrics/face/aidl/default/Android.bp
+++ b/biometrics/face/aidl/default/Android.bp
@@ -9,21 +9,13 @@
 }
 
 filegroup {
-    name: "face-example.rc",
-    srcs: ["face-example.rc"],
+    name: "face-virtual.rc",
+    srcs: ["face-virtual.rc"],
 }
 
-filegroup {
-    name: "face-example.xml",
-    srcs: ["face-example.xml"],
-}
-
-cc_binary {
-    name: "android.hardware.biometrics.face-service.example",
-    relative_install_path: "hw",
-    init_rc: [":face-example.rc"],
-    vintf_fragments: [":face-example.xml"],
-    vendor: true,
+cc_library_static {
+    name: "android.hardware.biometrics.face-service.lib",
+    vendor_available: true,
 
     shared_libs: [
         "libbinder_ndk",
@@ -32,32 +24,86 @@
     ],
     srcs: [
         "FakeLockoutTracker.cpp",
-        "main.cpp",
         "Face.cpp",
         "FakeFaceEngine.cpp",
         "Session.cpp",
+        "FaceConfig.cpp",
+        "VirtualHal.cpp",
+        "main.cpp",
     ],
     include_dirs: [
         "frameworks/native/aidl/gui",
     ],
     stl: "c++_static",
-    static_libs: [
+    whole_static_libs: [
         "android.hardware.biometrics.common-V4-ndk",
+        "android.hardware.biometrics.common.config",
         "android.hardware.biometrics.common.thread",
         "android.hardware.biometrics.common.util",
+        "android.hardware.biometrics.face.virtualhal-ndk",
         "android.hardware.biometrics.face-V4-ndk",
         "android.hardware.common-V2-ndk",
         "android.hardware.keymaster-V4-ndk",
         "libandroid.hardware.biometrics.face.VirtualProps",
         "libbase",
     ],
+    apex_available: [
+        "com.android.hardware.biometrics.face.virtual",
+        "//apex_available:platform",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.biometrics.face-service.example",
+    system_ext_specific: true,
+    relative_install_path: "hw",
+
+    shared_libs: [
+        "libbinder_ndk",
+        "liblog",
+        "libnativewindow",
+    ],
+    whole_static_libs: [
+        "android.hardware.biometrics.face-service.lib",
+    ],
+    installable: false, // install APEX instead
+    apex_available: [
+        "com.android.hardware.biometrics.face.virtual",
+        "//apex_available:platform",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.biometrics.face-service.default",
+    vendor: true,
+    relative_install_path: "hw",
+    init_rc: ["face-default.rc"],
+    vintf_fragment_modules: ["android.hardware.biometrics.face-service.default.vintf"],
+    shared_libs: [
+        "libbinder_ndk",
+        "liblog",
+        "libnativewindow",
+    ],
+    whole_static_libs: [
+        "android.hardware.biometrics.face-service.lib",
+    ],
+}
+
+vintf_fragment {
+    name: "android.hardware.biometrics.face-service.default.vintf",
+    src: "face-default.xml",
+    vendor: true,
 }
 
 sysprop_library {
     name: "android.hardware.biometrics.face.VirtualProps",
     srcs: ["face.sysprop"],
-    property_owner: "Vendor",
-    vendor: true,
+    property_owner: "Platform",
+    vendor_available: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.hardware.biometrics.face.virtual",
+    ],
 }
 
 cc_test {
@@ -66,6 +112,7 @@
         "tests/FakeFaceEngineTest.cpp",
         "FakeFaceEngine.cpp",
         "FakeLockoutTracker.cpp",
+        "FaceConfig.cpp",
     ],
     shared_libs: [
         "libbase",
@@ -81,6 +128,8 @@
         "android.hardware.biometrics.common-V4-ndk",
         "android.hardware.keymaster-V4-ndk",
         "android.hardware.biometrics.common.util",
+        "android.hardware.biometrics.common.config",
+        "android.hardware.biometrics.common.thread",
     ],
     vendor: true,
     test_suites: ["general-tests"],
@@ -92,6 +141,7 @@
     srcs: [
         "tests/FakeLockoutTrackerTest.cpp",
         "FakeLockoutTracker.cpp",
+        "FaceConfig.cpp",
     ],
     shared_libs: [
         "libbase",
@@ -107,8 +157,45 @@
         "android.hardware.biometrics.common-V4-ndk",
         "android.hardware.keymaster-V4-ndk",
         "android.hardware.biometrics.common.util",
+        "android.hardware.biometrics.common.config",
+        "android.hardware.biometrics.common.thread",
     ],
     vendor: true,
     test_suites: ["general-tests"],
     require_root: true,
 }
+
+cc_test {
+    name: "android.hardware.biometrics.face.VirtualHalTest",
+    srcs: [
+        "tests/VirtualHalTest.cpp",
+        "FakeLockoutTracker.cpp",
+        "Face.cpp",
+        "FakeFaceEngine.cpp",
+        "Session.cpp",
+        "VirtualHal.cpp",
+        "FaceConfig.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libnativewindow",
+        "liblog",
+    ],
+    include_dirs: [
+        "frameworks/native/aidl/gui",
+    ],
+    static_libs: [
+        "android.hardware.biometrics.common-V4-ndk",
+        "android.hardware.biometrics.common.config",
+        "android.hardware.biometrics.common.thread",
+        "android.hardware.biometrics.common.util",
+        "android.hardware.biometrics.face-V4-ndk",
+        "android.hardware.common-V2-ndk",
+        "android.hardware.keymaster-V4-ndk",
+        "libandroid.hardware.biometrics.face.VirtualProps",
+        "android.hardware.biometrics.face.virtualhal-ndk",
+    ],
+    test_suites: ["general-tests"],
+    require_root: true,
+}
diff --git a/biometrics/face/aidl/default/Face.cpp b/biometrics/face/aidl/default/Face.cpp
index 5ae0df6..1543007 100644
--- a/biometrics/face/aidl/default/Face.cpp
+++ b/biometrics/face/aidl/default/Face.cpp
@@ -34,9 +34,7 @@
 namespace aidl::android::hardware::biometrics::face {
 
 const int kSensorId = 4;
-const common::SensorStrength kSensorStrength = FakeFaceEngine::GetSensorStrength();
 const int kMaxEnrollmentsPerUser = 5;
-const FaceSensorType kSensorType = FakeFaceEngine::GetSensorType();
 const bool kHalControlsPreview = true;
 const std::string kHwComponentId = "faceSensor";
 const std::string kHardwareVersion = "vendor/model/revision";
@@ -62,13 +60,13 @@
 
     common::CommonProps commonProps;
     commonProps.sensorId = kSensorId;
-    commonProps.sensorStrength = kSensorStrength;
+    commonProps.sensorStrength = FakeFaceEngine::GetSensorStrength();
     commonProps.maxEnrollmentsPerUser = kMaxEnrollmentsPerUser;
     commonProps.componentInfo = {std::move(hw_component_info), std::move(sw_component_info)};
 
     SensorProps props;
     props.commonProps = std::move(commonProps);
-    props.sensorType = kSensorType;
+    props.sensorType = FakeFaceEngine::GetSensorType();
     props.halControlsPreview = kHalControlsPreview;
     props.enrollPreviewWidth = 1080;
     props.enrollPreviewHeight = 1920;
@@ -141,6 +139,30 @@
     return STATUS_OK;
 }
 
+const char* Face::type2String(FaceSensorType type) {
+    switch (type) {
+        case FaceSensorType::RGB:
+            return "rgb";
+        case FaceSensorType::IR:
+            return "ir";
+        default:
+            return "unknown";
+    }
+}
+
+const char* Face::strength2String(common::SensorStrength strength) {
+    switch (strength) {
+        case common::SensorStrength::STRONG:
+            return "STRONG";
+        case common::SensorStrength::WEAK:
+            return "WEAK";
+        case common::SensorStrength::CONVENIENCE:
+            return "CONVENIENCE";
+        default:
+            return "unknown";
+    }
+}
+
 void Face::onHelp(int fd) {
     dprintf(fd, "Virtual Face HAL commands:\n");
     dprintf(fd, "         help: print this help\n");
@@ -167,7 +189,6 @@
     RESET_CONFIG_O(lockout);
     RESET_CONFIG_O(operation_authenticate_fails);
     RESET_CONFIG_O(operation_detect_interaction_fails);
-    RESET_CONFIG_O(operation_enroll_fails);
     RESET_CONFIG_V(operation_authenticate_latency);
     RESET_CONFIG_V(operation_detect_interaction_latency);
     RESET_CONFIG_V(operation_enroll_latency);
diff --git a/biometrics/face/aidl/default/Face.h b/biometrics/face/aidl/default/Face.h
index 93fddb0..dbe6341 100644
--- a/biometrics/face/aidl/default/Face.h
+++ b/biometrics/face/aidl/default/Face.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <aidl/android/hardware/biometrics/face/BnFace.h>
+#include "FaceConfig.h"
 #include "Session.h"
 
 namespace aidl::android::hardware::biometrics::face {
@@ -33,9 +34,20 @@
     binder_status_t dump(int fd, const char** args, uint32_t numArgs);
     binder_status_t handleShellCommand(int in, int out, int err, const char** argv, uint32_t argc);
 
+    static FaceConfig& cfg() {
+        static FaceConfig* cfg = nullptr;
+        if (cfg == nullptr) {
+            cfg = new FaceConfig();
+            cfg->init();
+        }
+        return *cfg;
+    }
+    void resetConfigToDefault();
+    static const char* type2String(FaceSensorType type);
+    static const char* strength2String(common::SensorStrength strength);
+
   private:
     std::shared_ptr<Session> mSession;
-    void resetConfigToDefault();
     void onHelp(int);
 };
 
diff --git a/biometrics/face/aidl/default/FaceConfig.cpp b/biometrics/face/aidl/default/FaceConfig.cpp
new file mode 100644
index 0000000..a91d7cc
--- /dev/null
+++ b/biometrics/face/aidl/default/FaceConfig.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "FaceConfig"
+
+#include "FaceConfig.h"
+
+#include <android-base/logging.h>
+
+#include <face.sysprop.h>
+
+using namespace ::android::face::virt;
+
+namespace aidl::android::hardware::biometrics::face {
+
+// Wrapper to system property access functions
+#define CREATE_GETTER_SETTER_WRAPPER(_NAME_, _T_)           \
+    ConfigValue _NAME_##Getter() {                          \
+        return FaceHalProperties::_NAME_();                 \
+    }                                                       \
+    bool _NAME_##Setter(const ConfigValue& v) {             \
+        return FaceHalProperties::_NAME_(std::get<_T_>(v)); \
+    }
+
+CREATE_GETTER_SETTER_WRAPPER(type, OptString)
+CREATE_GETTER_SETTER_WRAPPER(enrollments, OptIntVec)
+CREATE_GETTER_SETTER_WRAPPER(enrollment_hit, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(next_enrollment, OptString)
+CREATE_GETTER_SETTER_WRAPPER(authenticator_id, OptInt64)
+CREATE_GETTER_SETTER_WRAPPER(challenge, OptInt64)
+CREATE_GETTER_SETTER_WRAPPER(strength, OptString)
+CREATE_GETTER_SETTER_WRAPPER(operation_authenticate_fails, OptBool)
+CREATE_GETTER_SETTER_WRAPPER(operation_authenticate_latency, OptIntVec)
+CREATE_GETTER_SETTER_WRAPPER(operation_authenticate_duration, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(operation_authenticate_error, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(operation_authenticate_acquired, OptString)
+CREATE_GETTER_SETTER_WRAPPER(operation_enroll_latency, OptIntVec)
+CREATE_GETTER_SETTER_WRAPPER(operation_detect_interaction_fails, OptBool)
+CREATE_GETTER_SETTER_WRAPPER(operation_detect_interaction_latency, OptIntVec)
+CREATE_GETTER_SETTER_WRAPPER(lockout, OptBool)
+CREATE_GETTER_SETTER_WRAPPER(lockout_enable, OptBool)
+CREATE_GETTER_SETTER_WRAPPER(lockout_timed_enable, OptBool)
+CREATE_GETTER_SETTER_WRAPPER(lockout_timed_threshold, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(lockout_timed_duration, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(lockout_permanent_threshold, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(features, OptIntVec)
+
+// Name, Getter, Setter, Parser and default value
+#define NGS(_NAME_) #_NAME_, _NAME_##Getter, _NAME_##Setter
+static Config::Data configData[] = {
+        {NGS(type), &Config::parseString, "rgb"},
+        {NGS(enrollments), &Config::parseIntVec, ""},
+        {NGS(enrollment_hit), &Config::parseInt32, "0"},
+        {NGS(next_enrollment), &Config::parseString,
+         "1:1000-[21,7,1,1103],1500-[1108,1],2000-[1113,1],2500-[1118,1]:true"},
+        {NGS(authenticator_id), &Config::parseInt64, "0"},
+        {NGS(challenge), &Config::parseInt64, ""},
+        {NGS(strength), &Config::parseString, "strong"},
+        {NGS(operation_authenticate_fails), &Config::parseBool, "false"},
+        {NGS(operation_authenticate_latency), &Config::parseIntVec, ""},
+        {NGS(operation_authenticate_duration), &Config::parseInt32, "500"},
+        {NGS(operation_authenticate_error), &Config::parseInt32, "0"},
+        {NGS(operation_authenticate_acquired), &Config::parseString, ""},
+        {NGS(operation_enroll_latency), &Config::parseIntVec, ""},
+        {NGS(operation_detect_interaction_latency), &Config::parseIntVec, ""},
+        {NGS(operation_detect_interaction_fails), &Config::parseBool, "false"},
+        {NGS(lockout), &Config::parseBool, "false"},
+        {NGS(lockout_enable), &Config::parseBool, "false"},
+        {NGS(lockout_timed_enable), &Config::parseBool, "false"},
+        {NGS(lockout_timed_threshold), &Config::parseInt32, "3"},
+        {NGS(lockout_timed_duration), &Config::parseInt32, "10000"},
+        {NGS(lockout_permanent_threshold), &Config::parseInt32, "5"},
+        {NGS(features), &Config::parseIntVec, ""}};
+
+Config::Data* FaceConfig::getConfigData(int* size) {
+    *size = sizeof(configData) / sizeof(configData[0]);
+    return configData;
+}
+
+}  // namespace aidl::android::hardware::biometrics::face
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/CipherModeParameters.aidl b/biometrics/face/aidl/default/FaceConfig.h
similarity index 64%
copy from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/CipherModeParameters.aidl
copy to biometrics/face/aidl/default/FaceConfig.h
index bfa5daa..64b62e0 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/CipherModeParameters.aidl
+++ b/biometrics/face/aidl/default/FaceConfig.h
@@ -1,6 +1,5 @@
-
 /*
- * Copyright 2024 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,11 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.hardware.security.see.hwcrypto.types;
 
-/*
- * Type encapsulating nonce used on non-authenticated AES symmetric encryption.
- */
-parcelable CipherModeParameters {
-    byte[16] nonce;
-}
+#pragma once
+
+#include "config/Config.h"
+
+namespace aidl::android::hardware::biometrics::face {
+
+class FaceConfig : public Config {
+    Config::Data* getConfigData(int* size) override;
+};
+
+}  // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/FakeFaceEngine.cpp b/biometrics/face/aidl/default/FakeFaceEngine.cpp
index bf75874..70d9f2d 100644
--- a/biometrics/face/aidl/default/FakeFaceEngine.cpp
+++ b/biometrics/face/aidl/default/FakeFaceEngine.cpp
@@ -23,6 +23,7 @@
 
 #include <face.sysprop.h>
 
+#include "Face.h"
 #include "util/CancellationSignal.h"
 #include "util/Util.h"
 
@@ -31,23 +32,23 @@
 namespace aidl::android::hardware::biometrics::face {
 
 FaceSensorType FakeFaceEngine::GetSensorType() {
-    std::string type = FaceHalProperties::type().value_or("");
+    std::string type = Face::cfg().get<std::string>("type");
     if (type == "IR") {
         return FaceSensorType::IR;
     } else {
-        FaceHalProperties::type("RGB");
+        Face::cfg().set<std::string>("type", "RGB");
         return FaceSensorType::RGB;
     }
 }
 
 common::SensorStrength FakeFaceEngine::GetSensorStrength() {
-    std::string strength = FaceHalProperties::strength().value_or("");
+    std::string strength = Face::cfg().get<std::string>("strength");
     if (strength == "convenience") {
         return common::SensorStrength::CONVENIENCE;
     } else if (strength == "weak") {
         return common::SensorStrength::WEAK;
     } else {
-        FaceHalProperties::strength("strong");
+        // Face::cfg().set<std::string>("strength", "strong");
         return common::SensorStrength::STRONG;
     }
 }
@@ -56,13 +57,13 @@
     BEGIN_OP(0);
     std::uniform_int_distribution<int64_t> dist;
     auto challenge = dist(mRandom);
-    FaceHalProperties::challenge(challenge);
+    Face::cfg().set<int64_t>("challenge", challenge);
     cb->onChallengeGenerated(challenge);
 }
 
 void FakeFaceEngine::revokeChallengeImpl(ISessionCallback* cb, int64_t challenge) {
     BEGIN_OP(0);
-    FaceHalProperties::challenge({});
+    Face::cfg().set<int64_t>("challenge", 0);
     cb->onChallengeRevoked(challenge);
 }
 void FakeFaceEngine::getEnrollmentConfigImpl(ISessionCallback* /*cb*/,
@@ -71,7 +72,7 @@
                                 EnrollmentType /*enrollmentType*/,
                                 const std::vector<Feature>& /*features*/,
                                 const std::future<void>& cancel) {
-    BEGIN_OP(getLatency(FaceHalProperties::operation_enroll_latency()));
+    BEGIN_OP(getLatency(Face::cfg().getopt<OptIntVec>("operation_enroll_latency")));
 
     // Do proper HAT verification in the real implementation.
     if (hat.mac.empty()) {
@@ -80,18 +81,19 @@
         return;
     }
 
-    // Format: <id>:<progress_ms-[acquiredInfo,...],...:<success>
-    // ------:-----------------------------------------:--------------
-    //          |           |                              |--->enrollment success (true/false)
-    //          |           |--> progress_steps
+    // Format:
+    //    <id>:<progress_ms-[acquiredInfo,...],...:<success>
+    //    -------:--------------------------------------------------:--------------
+    //          |           |                                                   |--->enrollment
+    //          success (true/false) |           |--> progress_steps
     //          |
     //          |-->enrollment id
     //
     //
-    //   progress_steps
+    //   progress_steps:
     //        <progress_duration>-[acquiredInfo,...]+
     //        ----------------------------  ---------------------
-    //                 |                            |-> sequence of acquiredInfo code
+    //                 |                              |-> sequence of acquiredInfo code
     //                 | --> time duration of the step in ms
     //
     //        E.g.   1:2000-[21,1108,5,6,1],1000-[1113,4,1]:true
@@ -101,7 +103,7 @@
     //
     std::string defaultNextEnrollment =
             "1:1000-[21,7,1,1103],1500-[1108,1],2000-[1113,1],2500-[1118,1]:true";
-    auto nextEnroll = FaceHalProperties::next_enrollment().value_or(defaultNextEnrollment);
+    auto nextEnroll = Face::cfg().get<std::string>("next_enrollment");
     auto parts = Util::split(nextEnroll, ":");
     if (parts.size() != 3) {
         LOG(ERROR) << "Fail: invalid next_enrollment:" << nextEnroll;
@@ -137,19 +139,19 @@
 
         if (left == 0 && !IS_TRUE(parts[2])) {  // end and failed
             LOG(ERROR) << "Fail: requested by caller: " << nextEnroll;
-            FaceHalProperties::next_enrollment({});
+            Face::cfg().setopt<OptString>("next_enrollment", std::nullopt);
             cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
         } else {  // progress and update props if last time
             LOG(INFO) << "onEnroll: " << enrollmentId << " left: " << left;
             if (left == 0) {
-                auto enrollments = FaceHalProperties::enrollments();
+                auto enrollments = Face::cfg().getopt<OptIntVec>("enrollments");
                 enrollments.emplace_back(enrollmentId);
-                FaceHalProperties::enrollments(enrollments);
-                FaceHalProperties::next_enrollment({});
+                Face::cfg().setopt<OptIntVec>("enrollments", enrollments);
+                Face::cfg().setopt<OptString>("next_enrollment", std::nullopt);
                 // change authenticatorId after new enrollment
-                auto id = FaceHalProperties::authenticator_id().value_or(0);
+                auto id = Face::cfg().get<std::int64_t>("authenticator_id");
                 auto newId = id + 1;
-                FaceHalProperties::authenticator_id(newId);
+                Face::cfg().set<std::int64_t>("authenticator_id", newId);
                 LOG(INFO) << "Enrolled: " << enrollmentId;
             }
             cb->onEnrollmentProgress(enrollmentId, left);
@@ -159,10 +161,12 @@
 
 void FakeFaceEngine::authenticateImpl(ISessionCallback* cb, int64_t /*operationId*/,
                                       const std::future<void>& cancel) {
-    BEGIN_OP(getLatency(FaceHalProperties::operation_authenticate_latency()));
+    BEGIN_OP(getLatency(Face::cfg().getopt<OptIntVec>("operation_authenticate_latency")));
 
-    auto id = FaceHalProperties::enrollment_hit().value_or(0);
-    auto enrolls = FaceHalProperties::enrollments();
+    // SLEEP_MS(3000);  //emulate hw HAL
+
+    auto id = Face::cfg().get<std::int32_t>("enrollment_hit");
+    auto enrolls = Face::cfg().getopt<OptIntVec>("enrollments");
     auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
 
     auto vec2str = [](std::vector<AcquiredInfo> va) {
@@ -192,10 +196,12 @@
     }
 
     int64_t now = Util::getSystemNanoTime();
-    int64_t duration =
-            FaceHalProperties::operation_authenticate_duration().value_or(defaultAuthDuration);
-    auto acquired =
-            FaceHalProperties::operation_authenticate_acquired().value_or(defaultAcquiredInfo);
+    int64_t duration = Face::cfg().get<std::int32_t>("operation_authenticate_duration");
+    auto acquired = Face::cfg().get<std::string>("operation_authenticate_acquired");
+    if (acquired.empty()) {
+        Face::cfg().set<std::string>("operation_authenticate_acquired", defaultAcquiredInfo);
+        acquired = defaultAcquiredInfo;
+    }
     auto acquiredInfos = Util::parseIntSequence(acquired);
     int N = acquiredInfos.size();
 
@@ -211,21 +217,21 @@
 
     int i = 0;
     do {
-        if (FaceHalProperties::lockout().value_or(false)) {
+        if (Face::cfg().get<bool>("lockout")) {
             LOG(ERROR) << "Fail: lockout";
             cb->onLockoutPermanent();
             cb->onError(Error::HW_UNAVAILABLE, 0 /* vendorError */);
             return;
         }
 
-        if (FaceHalProperties::operation_authenticate_fails().value_or(false)) {
+        if (Face::cfg().get<bool>("operation_authenticate_fails")) {
             LOG(ERROR) << "Fail: operation_authenticate_fails";
             mLockoutTracker.addFailedAttempt(cb);
             cb->onAuthenticationFailed();
             return;
         }
 
-        auto err = FaceHalProperties::operation_authenticate_error().value_or(0);
+        auto err = Face::cfg().get<std::int32_t>("operation_authenticate_error");
         if (err != 0) {
             LOG(ERROR) << "Fail: operation_authenticate_error";
             auto ec = convertError(err);
@@ -249,6 +255,15 @@
             LOG(INFO) << "AcquiredInfo:" << i << ": (" << (int)ac.first << "," << (int)ac.second
                       << ")";
             i++;
+
+            // the captured face id may change during authentication period
+            auto idnew = Face::cfg().get<std::int32_t>("enrollment_hit");
+            if (id != idnew) {
+                isEnrolled = std::find(enrolls.begin(), enrolls.end(), idnew) != enrolls.end();
+                LOG(INFO) << "enrollment_hit changed from " << id << " to " << idnew;
+                id = idnew;
+                break;
+            }
         }
 
         SLEEP_MS(duration / N);
@@ -292,9 +307,9 @@
 }
 
 void FakeFaceEngine::detectInteractionImpl(ISessionCallback* cb, const std::future<void>& cancel) {
-    BEGIN_OP(getLatency(FaceHalProperties::operation_detect_interaction_latency()));
+    BEGIN_OP(getLatency(Face::cfg().getopt<OptIntVec>("operation_detect_interaction_latency")));
 
-    if (FaceHalProperties::operation_detect_interaction_fails().value_or(false)) {
+    if (Face::cfg().get<bool>("operation_detect_interaction_fails")) {
         LOG(ERROR) << "Fail: operation_detect_interaction_fails";
         cb->onError(Error::VENDOR, 0 /* vendorError */);
         return;
@@ -306,8 +321,8 @@
         return;
     }
 
-    auto id = FaceHalProperties::enrollment_hit().value_or(0);
-    auto enrolls = FaceHalProperties::enrollments();
+    auto id = Face::cfg().get<std::int32_t>("enrollment_hit");
+    auto enrolls = Face::cfg().getopt<OptIntVec>("enrollments");
     auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
     if (id <= 0 || !isEnrolled) {
         LOG(ERROR) << "Fail: not enrolled";
@@ -321,7 +336,7 @@
 void FakeFaceEngine::enumerateEnrollmentsImpl(ISessionCallback* cb) {
     BEGIN_OP(0);
     std::vector<int32_t> enrollments;
-    for (const auto& enrollmentId : FaceHalProperties::enrollments()) {
+    for (const auto& enrollmentId : Face::cfg().getopt<OptIntVec>("enrollments")) {
         if (enrollmentId) {
             enrollments.push_back(*enrollmentId);
         }
@@ -334,20 +349,20 @@
     BEGIN_OP(0);
 
     std::vector<std::optional<int32_t>> newEnrollments;
-    for (const auto& enrollment : FaceHalProperties::enrollments()) {
+    for (const auto& enrollment : Face::cfg().getopt<OptIntVec>("enrollments")) {
         auto id = enrollment.value_or(0);
         if (std::find(enrollmentIds.begin(), enrollmentIds.end(), id) == enrollmentIds.end()) {
             newEnrollments.emplace_back(id);
         }
     }
-    FaceHalProperties::enrollments(newEnrollments);
+    Face::cfg().setopt<OptIntVec>("enrollments", newEnrollments);
     cb->onEnrollmentsRemoved(enrollmentIds);
 }
 
 void FakeFaceEngine::getFeaturesImpl(ISessionCallback* cb) {
     BEGIN_OP(0);
 
-    if (FaceHalProperties::enrollments().empty()) {
+    if (Face::cfg().getopt<OptIntVec>("enrollments").empty()) {
         cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
         return;
     }
@@ -365,7 +380,7 @@
                                     Feature feature, bool enabled) {
     BEGIN_OP(0);
 
-    if (FaceHalProperties::enrollments().empty()) {
+    if (Face::cfg().getopt<OptIntVec>("enrollments").empty()) {
         LOG(ERROR) << "Unable to set feature, enrollments are empty";
         cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
         return;
@@ -377,7 +392,7 @@
         return;
     }
 
-    auto features = FaceHalProperties::features();
+    auto features = Face::cfg().getopt<OptIntVec>("features");
 
     auto itr = std::find_if(features.begin(), features.end(), [feature](const auto& theFeature) {
         return *theFeature == (int)feature;
@@ -389,7 +404,7 @@
         features.push_back((int)feature);
     }
 
-    FaceHalProperties::features(features);
+    Face::cfg().setopt<OptIntVec>("features", features);
     cb->onFeatureSet(feature);
 }
 
@@ -399,22 +414,22 @@
     if (GetSensorStrength() != common::SensorStrength::STRONG) {
         cb->onAuthenticatorIdRetrieved(0);
     } else {
-        cb->onAuthenticatorIdRetrieved(FaceHalProperties::authenticator_id().value_or(0));
+        cb->onAuthenticatorIdRetrieved(Face::cfg().get<std::int64_t>("authenticator_id"));
     }
 }
 
 void FakeFaceEngine::invalidateAuthenticatorIdImpl(ISessionCallback* cb) {
     BEGIN_OP(0);
-    int64_t authenticatorId = FaceHalProperties::authenticator_id().value_or(0);
+    int64_t authenticatorId = Face::cfg().get<std::int64_t>("authenticator_id");
     int64_t newId = authenticatorId + 1;
-    FaceHalProperties::authenticator_id(newId);
+    Face::cfg().set<std::int64_t>("authenticator_id", newId);
     cb->onAuthenticatorIdInvalidated(newId);
 }
 
 void FakeFaceEngine::resetLockoutImpl(ISessionCallback* cb,
                                       const keymaster::HardwareAuthToken& /*hat*/) {
     BEGIN_OP(0);
-    FaceHalProperties::lockout(false);
+    Face::cfg().set<bool>("lockout", false);
     mLockoutTracker.reset();
     cb->onLockoutCleared();
 }
diff --git a/biometrics/face/aidl/default/FakeLockoutTracker.cpp b/biometrics/face/aidl/default/FakeLockoutTracker.cpp
index 70bf08e..35d7c28 100644
--- a/biometrics/face/aidl/default/FakeLockoutTracker.cpp
+++ b/biometrics/face/aidl/default/FakeLockoutTracker.cpp
@@ -19,6 +19,7 @@
 #include "FakeLockoutTracker.h"
 #include <android-base/logging.h>
 #include <face.sysprop.h>
+#include "Face.h"
 #include "util/Util.h"
 
 using namespace ::android::face::virt;
@@ -36,15 +37,15 @@
 }
 
 void FakeLockoutTracker::addFailedAttempt(ISessionCallback* cb) {
-    bool lockoutEnabled = FaceHalProperties::lockout_enable().value_or(false);
-    bool timedLockoutenabled = FaceHalProperties::lockout_timed_enable().value_or(false);
+    bool lockoutEnabled = Face::cfg().get<bool>("lockout_enable");
+    bool timedLockoutenabled = Face::cfg().get<bool>("lockout_timed_enable");
     if (lockoutEnabled) {
         mFailedCount++;
         mTimedFailedCount++;
         mLastFailedTime = Util::getSystemNanoTime();
-        int32_t lockoutTimedThreshold = FaceHalProperties::lockout_timed_threshold().value_or(3);
+        int32_t lockoutTimedThreshold = Face::cfg().get<std::int32_t>("lockout_timed_threshold");
         int32_t lockoutPermanetThreshold =
-                FaceHalProperties::lockout_permanent_threshold().value_or(5);
+                Face::cfg().get<std::int32_t>("lockout_permanent_threshold");
         if (mFailedCount >= lockoutPermanetThreshold) {
             mCurrentMode = LockoutMode::kPermanent;
             LOG(ERROR) << "FakeLockoutTracker: lockoutPermanent";
@@ -68,7 +69,7 @@
 }
 
 int32_t FakeLockoutTracker::getTimedLockoutDuration() {
-    return FaceHalProperties::lockout_timed_duration().value_or(10 * 1000);
+    return Face::cfg().get<std::int32_t>("lockout_timed_duration");
 }
 
 int64_t FakeLockoutTracker::getLockoutTimeLeft() {
diff --git a/biometrics/face/aidl/default/VirtualHal.cpp b/biometrics/face/aidl/default/VirtualHal.cpp
new file mode 100644
index 0000000..52ac23b
--- /dev/null
+++ b/biometrics/face/aidl/default/VirtualHal.cpp
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unordered_map>
+
+#include "VirtualHal.h"
+
+#include <android-base/logging.h>
+
+#include "util/CancellationSignal.h"
+
+#undef LOG_TAG
+#define LOG_TAG "FaceVirtualHalAidl"
+
+namespace aidl::android::hardware::biometrics::face {
+using AcquiredInfoAndVendorCode = virtualhal::AcquiredInfoAndVendorCode;
+using Tag = AcquiredInfoAndVendorCode::Tag;
+
+::ndk::ScopedAStatus VirtualHal::setEnrollments(const std::vector<int32_t>& enrollments) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().setopt<OptIntVec>("enrollments", intVec2OptIntVec(enrollments));
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setEnrollmentHit(int32_t enrollment_hit) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<std::int32_t>("enrollment_hit", enrollment_hit);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setNextEnrollment(
+        const ::aidl::android::hardware::biometrics::face::NextEnrollment& next_enrollment) {
+    Face::cfg().sourcedFromAidl();
+    std::ostringstream os;
+    os << next_enrollment.id << ":";
+
+    int stepSize = next_enrollment.progressSteps.size();
+    for (int i = 0; i < stepSize; i++) {
+        auto& step = next_enrollment.progressSteps[i];
+        os << step.durationMs;
+        int acSize = step.acquiredInfoAndVendorCodes.size();
+        for (int j = 0; j < acSize; j++) {
+            if (j == 0) os << "-[";
+            auto& acquiredInfoAndVendorCode = step.acquiredInfoAndVendorCodes[j];
+            if (acquiredInfoAndVendorCode.getTag() == AcquiredInfoAndVendorCode::vendorCode)
+                os << acquiredInfoAndVendorCode.get<Tag::vendorCode>();
+            else if (acquiredInfoAndVendorCode.getTag() == AcquiredInfoAndVendorCode::acquiredInfo)
+                os << (int)acquiredInfoAndVendorCode.get<Tag::acquiredInfo>();
+            else
+                LOG(FATAL) << "ERROR: wrong AcquiredInfoAndVendorCode union tag";
+            if (j == acSize - 1)
+                os << "]";
+            else
+                os << ",";
+        }
+        if (i == stepSize - 1)
+            os << ":";
+        else
+            os << ",";
+    }
+
+    os << (next_enrollment.result ? "true" : "false");
+    Face::cfg().set<std::string>("next_enrollment", os.str());
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setAuthenticatorId(int64_t in_id) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<int64_t>("authenticator_id", in_id);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setChallenge(int64_t in_challenge) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<int64_t>("challenge", in_challenge);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setOperationAuthenticateFails(bool in_fail) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<bool>("operation_authenticate_fails", in_fail);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setOperationAuthenticateLatency(
+        const std::vector<int32_t>& in_latency) {
+    ndk::ScopedAStatus status = sanityCheckLatency(in_latency);
+    if (!status.isOk()) {
+        return status;
+    }
+
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().setopt<OptIntVec>("operation_authenticate_latency", intVec2OptIntVec(in_latency));
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setOperationAuthenticateDuration(int32_t in_duration) {
+    if (in_duration < 0) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IVirtualHal::STATUS_INVALID_PARAMETER, "Error: duration can not be negative"));
+    }
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<int32_t>("operation_authenticate_duration", in_duration);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setOperationAuthenticateError(int32_t in_error) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<int32_t>("operation_authenticate_error", in_error);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setOperationAuthenticateAcquired(
+        const std::vector<AcquiredInfoAndVendorCode>& in_acquired) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().setopt<OptIntVec>("operation_authenticate_acquired",
+                                  acquiredInfoVec2OptIntVec(in_acquired));
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setOperationEnrollLatency(const std::vector<int32_t>& in_latency) {
+    ndk::ScopedAStatus status = sanityCheckLatency(in_latency);
+    if (!status.isOk()) {
+        return status;
+    }
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().setopt<OptIntVec>("operation_enroll_latency", intVec2OptIntVec(in_latency));
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setOperationDetectInteractionLatency(
+        const std::vector<int32_t>& in_latency) {
+    ndk::ScopedAStatus status = sanityCheckLatency(in_latency);
+    if (!status.isOk()) {
+        return status;
+    }
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().setopt<OptIntVec>("operation_detect_interact_latency",
+                                  intVec2OptIntVec(in_latency));
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setOperationDetectInteractionFails(bool in_fails) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<bool>("operation_detect_interaction_fails", in_fails);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setLockout(bool in_lockout) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<bool>("lockout", in_lockout);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setLockoutEnable(bool in_enable) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<bool>("lockout_enable", in_enable);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setLockoutTimedEnable(bool in_enable) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<bool>("lockout_timed_enable", in_enable);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setLockoutTimedThreshold(int32_t in_threshold) {
+    if (in_threshold < 0) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IVirtualHal::STATUS_INVALID_PARAMETER, "Error: threshold can not be negative"));
+    }
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<int32_t>("lockout_timed_threshold", in_threshold);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setLockoutTimedDuration(int32_t in_duration) {
+    if (in_duration < 0) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IVirtualHal::STATUS_INVALID_PARAMETER, "Error: duration can not be negative"));
+    }
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<int32_t>("lockout_timed_duration", in_duration);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setLockoutPermanentThreshold(int32_t in_threshold) {
+    if (in_threshold < 0) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IVirtualHal::STATUS_INVALID_PARAMETER, "Error: threshold can not be negative"));
+    }
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<int32_t>("lockout_permanent_threshold", in_threshold);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::resetConfigurations() {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().init();
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setType(
+        ::aidl::android::hardware::biometrics::face::FaceSensorType in_type) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<std::string>("type", Face::type2String(in_type));
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setSensorStrength(common::SensorStrength in_strength) {
+    Face::cfg().sourcedFromAidl();
+    Face::cfg().set<std::string>("strength", Face::strength2String(in_strength));
+    return ndk::ScopedAStatus::ok();
+}
+
+OptIntVec VirtualHal::intVec2OptIntVec(const std::vector<int32_t>& in_vec) {
+    OptIntVec optIntVec;
+    std::transform(in_vec.begin(), in_vec.end(), std::back_inserter(optIntVec),
+                   [](int value) { return std::optional<int>(value); });
+    return optIntVec;
+}
+
+OptIntVec VirtualHal::acquiredInfoVec2OptIntVec(
+        const std::vector<AcquiredInfoAndVendorCode>& in_vec) {
+    OptIntVec optIntVec;
+    std::transform(in_vec.begin(), in_vec.end(), std::back_inserter(optIntVec),
+                   [](AcquiredInfoAndVendorCode ac) {
+                       int value;
+                       if (ac.getTag() == AcquiredInfoAndVendorCode::acquiredInfo)
+                           value = (int)ac.get<Tag::acquiredInfo>();
+                       else if (ac.getTag() == AcquiredInfoAndVendorCode::vendorCode)
+                           value = ac.get<Tag::vendorCode>();
+                       else
+                           LOG(FATAL) << "ERROR: wrong AcquiredInfoAndVendorCode tag";
+                       return std::optional<int>(value);
+                   });
+    return optIntVec;
+}
+
+::ndk::ScopedAStatus VirtualHal::sanityCheckLatency(const std::vector<int32_t>& in_latency) {
+    if (in_latency.size() == 0 || in_latency.size() > 2) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IVirtualHal::STATUS_INVALID_PARAMETER,
+                "Error: input input array must contain 1 or 2 elements"));
+    }
+
+    for (auto x : in_latency) {
+        if (x < 0) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IVirtualHal::STATUS_INVALID_PARAMETER,
+                    "Error: input data must not be negative"));
+        }
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::getFaceHal(std::shared_ptr<IFace>* pFace) {
+    *pFace = mFp;
+    return ndk::ScopedAStatus::ok();
+}
+}  // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/VirtualHal.h b/biometrics/face/aidl/default/VirtualHal.h
new file mode 100644
index 0000000..f2ac552
--- /dev/null
+++ b/biometrics/face/aidl/default/VirtualHal.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/biometrics/face/virtualhal/BnVirtualHal.h>
+
+#include "Face.h"
+
+namespace aidl::android::hardware::biometrics::face {
+using namespace virtualhal;
+class VirtualHal : public BnVirtualHal {
+  public:
+    VirtualHal(std::shared_ptr<Face> fp) : mFp(fp) {}
+
+    ::ndk::ScopedAStatus setEnrollments(const std::vector<int32_t>& in_id) override;
+    ::ndk::ScopedAStatus setEnrollmentHit(int32_t in_hit_id) override;
+    ::ndk::ScopedAStatus setNextEnrollment(
+            const ::aidl::android::hardware::biometrics::face::NextEnrollment& in_next_enrollment)
+            override;
+    ::ndk::ScopedAStatus setAuthenticatorId(int64_t in_id) override;
+    ::ndk::ScopedAStatus setChallenge(int64_t in_challenge) override;
+    ::ndk::ScopedAStatus setOperationAuthenticateFails(bool in_fail) override;
+    ::ndk::ScopedAStatus setOperationAuthenticateLatency(
+            const std::vector<int32_t>& in_latency) override;
+    ::ndk::ScopedAStatus setOperationAuthenticateDuration(int32_t in_duration) override;
+    ::ndk::ScopedAStatus setOperationAuthenticateError(int32_t in_error) override;
+    ::ndk::ScopedAStatus setOperationAuthenticateAcquired(
+            const std::vector<AcquiredInfoAndVendorCode>& in_acquired) override;
+    ::ndk::ScopedAStatus setOperationEnrollLatency(const std::vector<int32_t>& in_latency) override;
+    ::ndk::ScopedAStatus setOperationDetectInteractionLatency(
+            const std::vector<int32_t>& in_latency) override;
+    ::ndk::ScopedAStatus setOperationDetectInteractionFails(bool in_fails) override;
+    ::ndk::ScopedAStatus setLockout(bool in_lockout) override;
+    ::ndk::ScopedAStatus setLockoutEnable(bool in_enable) override;
+    ::ndk::ScopedAStatus setLockoutTimedEnable(bool in_enable) override;
+    ::ndk::ScopedAStatus setLockoutTimedThreshold(int32_t in_threshold) override;
+    ::ndk::ScopedAStatus setLockoutTimedDuration(int32_t in_duration) override;
+    ::ndk::ScopedAStatus setLockoutPermanentThreshold(int32_t in_threshold) override;
+    ::ndk::ScopedAStatus resetConfigurations() override;
+    ::ndk::ScopedAStatus setType(
+            ::aidl::android::hardware::biometrics::face::FaceSensorType in_type) override;
+    ::ndk::ScopedAStatus setSensorStrength(common::SensorStrength in_strength) override;
+    ::ndk::ScopedAStatus getFaceHal(std::shared_ptr<IFace>* _aidl_return);
+
+  private:
+    OptIntVec intVec2OptIntVec(const std::vector<int32_t>& intVec);
+    OptIntVec acquiredInfoVec2OptIntVec(const std::vector<AcquiredInfoAndVendorCode>& intVec);
+    ::ndk::ScopedAStatus sanityCheckLatency(const std::vector<int32_t>& in_latency);
+    std::shared_ptr<Face> mFp;
+};
+
+}  // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/apex/Android.bp b/biometrics/face/aidl/default/apex/Android.bp
index 86c4e12..c4632d4 100644
--- a/biometrics/face/aidl/default/apex/Android.bp
+++ b/biometrics/face/aidl/default/apex/Android.bp
@@ -23,7 +23,7 @@
     key: "com.android.hardware.key",
     certificate: ":com.android.hardware.certificate",
     updatable: false,
-    vendor: true,
+    system_ext_specific: true,
 
     binaries: [
         // hal
@@ -31,9 +31,7 @@
     ],
     prebuilts: [
         // init_rc
-        "face-example-apex.rc",
-        // vintf_fragment
-        "face-example-apex.xml",
+        "face-virtual-apex.rc",
     ],
 
     overrides: [
@@ -42,21 +40,7 @@
 }
 
 prebuilt_etc {
-    name: "face-example-apex.rc",
-    src: ":gen-face-example-apex.rc",
-    installable: false,
-}
-
-genrule {
-    name: "gen-face-example-apex.rc",
-    srcs: [":face-example.rc"],
-    out: ["face-example-apex.rc"],
-    cmd: "sed -e 's@/vendor/bin/@/apex/com.android.hardware.biometrics.face.virtual/bin/@' $(in) > $(out)",
-}
-
-prebuilt_etc {
-    name: "face-example-apex.xml",
-    src: ":face-example.xml",
-    sub_dir: "vintf",
+    name: "face-virtual-apex.rc",
+    src: ":face-virtual.rc",
     installable: false,
 }
diff --git a/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt b/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt
index e69de29..6ad579c 100644
--- a/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt
+++ b/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt
@@ -0,0 +1,133 @@
+props {
+  owner: Vendor
+  module: "android.face.virt.FaceHalProperties"
+  prop {
+    api_name: "authenticator_id"
+    type: Long
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.authenticator_id"
+  }
+  prop {
+    api_name: "challenge"
+    type: Long
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.challenge"
+  }
+  prop {
+    api_name: "enrollment_hit"
+    type: Integer
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.enrollment_hit"
+  }
+  prop {
+    api_name: "enrollments"
+    type: IntegerList
+    access: ReadWrite
+    prop_name: "persist.vendor.face.virtual.enrollments"
+  }
+  prop {
+    api_name: "features"
+    type: IntegerList
+    access: ReadWrite
+    prop_name: "persist.vendor.face.virtual.features"
+  }
+  prop {
+    api_name: "lockout"
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.lockout"
+  }
+  prop {
+    api_name: "lockout_enable"
+    access: ReadWrite
+    prop_name: "persist.vendor.face.virtual.lockout_enable"
+  }
+  prop {
+    api_name: "lockout_permanent_threshold"
+    type: Integer
+    access: ReadWrite
+    prop_name: "persist.vendor.face.virtual.lockout_permanent_threshold"
+  }
+  prop {
+    api_name: "lockout_timed_duration"
+    type: Integer
+    access: ReadWrite
+    prop_name: "persist.vendor.face.virtual.lockout_timed_duration"
+  }
+  prop {
+    api_name: "lockout_timed_enable"
+    access: ReadWrite
+    prop_name: "persist.vendor.face.virtual.lockout_timed_enable"
+  }
+  prop {
+    api_name: "lockout_timed_threshold"
+    type: Integer
+    access: ReadWrite
+    prop_name: "persist.vendor.face.virtual.lockout_timed_threshold"
+  }
+  prop {
+    api_name: "next_enrollment"
+    type: String
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.next_enrollment"
+  }
+  prop {
+    api_name: "operation_authenticate_acquired"
+    type: String
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.operation_authenticate_acquired"
+  }
+  prop {
+    api_name: "operation_authenticate_duration"
+    type: Integer
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.operation_authenticate_duration"
+  }
+  prop {
+    api_name: "operation_authenticate_error"
+    type: Integer
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.operation_authenticate_error"
+  }
+  prop {
+    api_name: "operation_authenticate_fails"
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.operation_authenticate_fails"
+  }
+  prop {
+    api_name: "operation_authenticate_latency"
+    type: IntegerList
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.operation_authenticate_latency"
+  }
+  prop {
+    api_name: "operation_detect_interaction_fails"
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.operation_detect_interaction_fails"
+  }
+  prop {
+    api_name: "operation_detect_interaction_latency"
+    type: IntegerList
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.operation_detect_interaction_latency"
+  }
+  prop {
+    api_name: "operation_enroll_latency"
+    type: IntegerList
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.operation_enroll_latency"
+  }
+  prop {
+    api_name: "strength"
+    type: String
+    access: ReadWrite
+    prop_name: "persist.vendor.face.virtual.strength"
+    enum_values: "convenience|weak|strong"
+  }
+  prop {
+    api_name: "type"
+    type: String
+    access: ReadWrite
+    prop_name: "persist.vendor.face.virtual.type"
+    enum_values: "IR|RGB"
+  }
+}
diff --git a/biometrics/face/aidl/default/face-default.rc b/biometrics/face/aidl/default/face-default.rc
new file mode 100644
index 0000000..7ce4249
--- /dev/null
+++ b/biometrics/face/aidl/default/face-default.rc
@@ -0,0 +1,8 @@
+service vendor.face-default /vendor/bin/hw/android.hardware.biometrics.face-service.default default
+    class hal
+    user nobody
+    group nobody
+    interface aidl android.hardware.biometrics.face.IFace/default
+    oneshot
+    disabled
+
diff --git a/biometrics/face/aidl/default/face-example.xml b/biometrics/face/aidl/default/face-default.xml
similarity index 81%
rename from biometrics/face/aidl/default/face-example.xml
rename to biometrics/face/aidl/default/face-default.xml
index 2b39b3d..94569de 100644
--- a/biometrics/face/aidl/default/face-example.xml
+++ b/biometrics/face/aidl/default/face-default.xml
@@ -2,6 +2,6 @@
     <hal format="aidl">
         <name>android.hardware.biometrics.face</name>
         <version>4</version>
-        <fqname>IFace/virtual</fqname>
+        <fqname>IFace/default</fqname>
     </hal>
 </manifest>
diff --git a/biometrics/face/aidl/default/face-example.rc b/biometrics/face/aidl/default/face-example.rc
deleted file mode 100644
index b0d82c6..0000000
--- a/biometrics/face/aidl/default/face-example.rc
+++ /dev/null
@@ -1,8 +0,0 @@
-service vendor.face-example /vendor/bin/hw/android.hardware.biometrics.face-service.example
-    class hal
-    user nobody
-    group nobody
-    interface aidl android.hardware.biometrics.face.IFace/virtual
-    oneshot
-    disabled
-
diff --git a/biometrics/face/aidl/default/face-virtual.rc b/biometrics/face/aidl/default/face-virtual.rc
new file mode 100644
index 0000000..8fb0a7b
--- /dev/null
+++ b/biometrics/face/aidl/default/face-virtual.rc
@@ -0,0 +1,8 @@
+service face-virtual /apex/com.android.hardware.biometrics.face.virtual/bin/hw/android.hardware.biometrics.face-service.example virtual
+    class hal
+    user nobody
+    group nobody
+    interface aidl android.hardware.biometrics.face.virtualhal.IVirtualHal/virtual
+    oneshot
+    disabled
+
diff --git a/biometrics/face/aidl/default/face.sysprop b/biometrics/face/aidl/default/face.sysprop
index 997fd67..ec2b92b 100644
--- a/biometrics/face/aidl/default/face.sysprop
+++ b/biometrics/face/aidl/default/face.sysprop
@@ -7,7 +7,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.type"
     type: String
-    scope: Internal
+    scope: Public
     access: ReadWrite
     enum_values: "IR|RGB"
     api_name: "type"
@@ -17,7 +17,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.strength"
     type: String
-    scope: Internal
+    scope: Public
     access: ReadWrite
     enum_values: "convenience|weak|strong"
     api_name: "strength"
@@ -27,7 +27,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.enrollments"
     type: IntegerList
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "enrollments"
 }
@@ -36,7 +36,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.features"
     type: IntegerList
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "features"
 }
@@ -46,7 +46,7 @@
 prop {
     prop_name: "vendor.face.virtual.enrollment_hit"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "enrollment_hit"
 }
@@ -60,7 +60,7 @@
 prop {
     prop_name: "vendor.face.virtual.next_enrollment"
     type: String
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "next_enrollment"
 }
@@ -69,7 +69,7 @@
 prop {
     prop_name: "vendor.face.virtual.authenticator_id"
     type: Long
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "authenticator_id"
 }
@@ -78,7 +78,7 @@
 prop {
     prop_name: "vendor.face.virtual.challenge"
     type: Long
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "challenge"
 }
@@ -87,7 +87,7 @@
 prop {
     prop_name: "vendor.face.virtual.lockout"
     type: Boolean
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "lockout"
 }
@@ -96,7 +96,7 @@
 prop {
     prop_name: "vendor.face.virtual.operation_authenticate_fails"
     type: Boolean
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_authenticate_fails"
 }
@@ -105,27 +105,18 @@
 prop {
     prop_name: "vendor.face.virtual.operation_detect_interaction_fails"
     type: Boolean
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_detect_interaction_fails"
 }
 
-# force all enroll operations to fail
-prop {
-    prop_name: "vendor.face.virtual.operation_enroll_fails"
-    type: Boolean
-    scope: Internal
-    access: ReadWrite
-    api_name: "operation_enroll_fails"
-}
-
 # add a latency to authentication operations
 # Note that this latency is the initial authentication latency that occurs before
 # the HAL will send AcquiredInfo::START and AcquiredInfo::FIRST_FRAME_RECEIVED
 prop {
     prop_name: "vendor.face.virtual.operation_authenticate_latency"
     type: IntegerList
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_authenticate_latency"
 }
@@ -134,7 +125,7 @@
 prop {
     prop_name: "vendor.face.virtual.operation_detect_interaction_latency"
     type: IntegerList
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_detect_interaction_latency"
 }
@@ -143,7 +134,7 @@
 prop {
     prop_name: "vendor.face.virtual.operation_enroll_latency"
     type: IntegerList
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_enroll_latency"
 }
@@ -153,7 +144,7 @@
 prop {
     prop_name: "vendor.face.virtual.operation_authenticate_duration"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_authenticate_duration"
 }
@@ -162,7 +153,7 @@
 prop {
     prop_name: "vendor.face.virtual.operation_authenticate_error"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_authenticate_error"
 }
@@ -171,7 +162,7 @@
 prop {
     prop_name: "vendor.face.virtual.operation_authenticate_acquired"
     type: String
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_authenticate_acquired"
 }
@@ -180,7 +171,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.lockout_enable"
     type: Boolean
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "lockout_enable"
 }
@@ -189,7 +180,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.lockout_timed_enable"
     type: Boolean
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "lockout_timed_enable"
 }
@@ -198,7 +189,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.lockout_timed_threshold"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "lockout_timed_threshold"
 }
@@ -207,7 +198,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.lockout_timed_duration"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "lockout_timed_duration"
 }
@@ -216,7 +207,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.lockout_permanent_threshold"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "lockout_permanent_threshold"
 }
diff --git a/biometrics/face/aidl/default/main.cpp b/biometrics/face/aidl/default/main.cpp
index 38e1c63..75a4479 100644
--- a/biometrics/face/aidl/default/main.cpp
+++ b/biometrics/face/aidl/default/main.cpp
@@ -14,25 +14,49 @@
  * limitations under the License.
  */
 
+#undef LOG_TAG
+#define LOG_TAG "FaceVirtualHal"
+
 #include "Face.h"
+#include "VirtualHal.h"
 
 #include <android-base/logging.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
 
 using aidl::android::hardware::biometrics::face::Face;
+using aidl::android::hardware::biometrics::face::VirtualHal;
 
-int main() {
-    LOG(INFO) << "Face HAL started";
+int main(int argc, char** argv) {
+    if (argc < 2) {
+        LOG(ERROR) << "Missing argument -> exiting, Valid arguments:[default|virtual]";
+        return EXIT_FAILURE;
+    }
+    LOG(INFO) << "Face HAL started: " << argv[1];
     ABinderProcess_setThreadPoolMaxThreadCount(0);
     std::shared_ptr<Face> hal = ndk::SharedRefBase::make<Face>();
+    std::shared_ptr<VirtualHal> hal_vhal = ndk::SharedRefBase::make<VirtualHal>(hal);
 
-    const std::string instance = std::string(Face::descriptor) + "/virtual";
-    binder_status_t status =
-            AServiceManager_registerLazyService(hal->asBinder().get(), instance.c_str());
-    CHECK_EQ(status, STATUS_OK);
+    if (strcmp(argv[1], "default") == 0) {
+        const std::string instance = std::string(Face::descriptor) + "/default";
+        auto binder = hal->asBinder();
+        binder_status_t status =
+                AServiceManager_registerLazyService(binder.get(), instance.c_str());
+        CHECK_EQ(status, STATUS_OK);
+        LOG(INFO) << "started IFace/default";
+    } else if (strcmp(argv[1], "virtual") == 0) {
+        const std::string instance = std::string(VirtualHal::descriptor) + "/virtual";
+        auto binder = hal_vhal->asBinder();
+        binder_status_t status =
+                AServiceManager_registerLazyService(binder.get(), instance.c_str());
+        CHECK_EQ(status, STATUS_OK);
+        LOG(INFO) << "started IVirtualHal/virtual";
+    } else {
+        LOG(ERROR) << "Unexpected argument: " << argv[1];
+        return EXIT_FAILURE;
+    }
     AServiceManager_forceLazyServicesPersist(true);
 
     ABinderProcess_joinThreadPool();
-    return EXIT_FAILURE;  // should not reach
+    return EXIT_FAILURE;  // should not reach here
 }
diff --git a/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp b/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp
index 8c39b58..d448532 100644
--- a/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp
+++ b/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp
@@ -21,6 +21,7 @@
 #include <aidl/android/hardware/biometrics/face/BnSessionCallback.h>
 #include <android-base/logging.h>
 
+#include "Face.h"
 #include "FakeFaceEngine.h"
 #include "util/Util.h"
 
@@ -141,12 +142,12 @@
     }
 
     void TearDown() override {
-        FaceHalProperties::enrollments({});
-        FaceHalProperties::challenge({});
-        FaceHalProperties::features({});
-        FaceHalProperties::authenticator_id({});
-        FaceHalProperties::strength("");
-        FaceHalProperties::operation_detect_interaction_latency({});
+        Face::cfg().setopt<OptIntVec>("enrollments", {});
+        Face::cfg().set<std::int64_t>("challenge", 0);
+        Face::cfg().setopt<OptIntVec>("features", {});
+        Face::cfg().set<std::int64_t>("authenticator_id", 0);
+        Face::cfg().set<std::string>("strength", "");
+        Face::cfg().setopt<OptIntVec>("operation_detect_interaction_latency", {});
     }
 
     FakeFaceEngine mEngine;
@@ -160,81 +161,83 @@
 
 TEST_F(FakeFaceEngineTest, GenerateChallenge) {
     mEngine.generateChallengeImpl(mCallback.get());
-    ASSERT_EQ(FaceHalProperties::challenge().value(), mCallback->mLastChallenge);
+    ASSERT_EQ(Face::cfg().get<std::int64_t>("challenge"), mCallback->mLastChallenge);
 }
 
 TEST_F(FakeFaceEngineTest, RevokeChallenge) {
-    auto challenge = FaceHalProperties::challenge().value_or(10);
+    auto challenge = Face::cfg().get<std::int64_t>("challenge");
     mEngine.revokeChallengeImpl(mCallback.get(), challenge);
-    ASSERT_FALSE(FaceHalProperties::challenge().has_value());
+    ASSERT_FALSE(Face::cfg().get<std::int64_t>("challenge"));
     ASSERT_EQ(challenge, mCallback->mLastChallengeRevoked);
 }
 
 TEST_F(FakeFaceEngineTest, ResetLockout) {
-    FaceHalProperties::lockout(true);
+    Face::cfg().set<bool>("lockout", true);
     mEngine.resetLockoutImpl(mCallback.get(), {});
     ASSERT_FALSE(mCallback->mLockoutPermanent);
-    ASSERT_FALSE(FaceHalProperties::lockout().value_or(true));
+    ASSERT_FALSE(Face::cfg().get<bool>("lockout"));
 }
 
 TEST_F(FakeFaceEngineTest, AuthenticatorId) {
-    FaceHalProperties::authenticator_id(50);
+    Face::cfg().set<std::int64_t>("authenticator_id", 50);
     mEngine.getAuthenticatorIdImpl(mCallback.get());
     ASSERT_EQ(50, mCallback->mLastAuthenticatorId);
     ASSERT_FALSE(mCallback->mAuthenticatorIdInvalidated);
 }
 
 TEST_F(FakeFaceEngineTest, GetAuthenticatorIdWeakReturnsZero) {
-    FaceHalProperties::strength("weak");
-    FaceHalProperties::authenticator_id(500);
+    Face::cfg().set<std::string>("strength", "weak");
+    Face::cfg().set<std::int64_t>("authenticator_id", 500);
     mEngine.getAuthenticatorIdImpl(mCallback.get());
     ASSERT_EQ(0, mCallback->mLastAuthenticatorId);
     ASSERT_FALSE(mCallback->mAuthenticatorIdInvalidated);
 }
 
 TEST_F(FakeFaceEngineTest, AuthenticatorIdInvalidate) {
-    FaceHalProperties::authenticator_id(500);
+    Face::cfg().set<std::int64_t>("authenticator_id", 500);
     mEngine.invalidateAuthenticatorIdImpl(mCallback.get());
-    ASSERT_NE(500, FaceHalProperties::authenticator_id().value());
+    ASSERT_NE(500, Face::cfg().get<std::int64_t>("authenticator_id"));
     ASSERT_TRUE(mCallback->mAuthenticatorIdInvalidated);
 }
 
 TEST_F(FakeFaceEngineTest, Enroll) {
-    FaceHalProperties::next_enrollment("1,0:1000-[21,5,6,7,1],1100-[1118,1108,1]:true");
+    Face::cfg().set<std::string>("next_enrollment",
+                                 "1,0:1000-[21,5,6,7,1],1100-[1118,1108,1]:true");
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mEngine.enrollImpl(mCallback.get(), hat, {} /*enrollmentType*/, {} /*features*/,
                        mCancel.get_future());
-    ASSERT_FALSE(FaceHalProperties::next_enrollment().has_value());
-    ASSERT_EQ(1, FaceHalProperties::enrollments().size());
-    ASSERT_EQ(1, FaceHalProperties::enrollments()[0].value());
+    ASSERT_FALSE(Face::cfg().getopt<OptString>("next_enrollment").has_value());
+    ASSERT_EQ(1, Face::cfg().getopt<OptIntVec>("enrollments").size());
+    ASSERT_EQ(1, Face::cfg().getopt<OptIntVec>("enrollments")[0].value());
     ASSERT_EQ(1, mCallback->mLastEnrolled);
     ASSERT_EQ(0, mCallback->mRemaining);
 }
 
 TEST_F(FakeFaceEngineTest, EnrollFails) {
-    FaceHalProperties::next_enrollment("1,0:1000-[21,5,6,7,1],1100-[1118,1108,1]:false");
+    Face::cfg().set<std::string>("next_enrollment",
+                                 "1,0:1000-[21,5,6,7,1],1100-[1118,1108,1]:false");
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mEngine.enrollImpl(mCallback.get(), hat, {} /*enrollmentType*/, {} /*features*/,
                        mCancel.get_future());
-    ASSERT_FALSE(FaceHalProperties::next_enrollment().has_value());
-    ASSERT_EQ(0, FaceHalProperties::enrollments().size());
+    ASSERT_FALSE(Face::cfg().getopt<OptString>("next_enrollment").has_value());
+    ASSERT_EQ(0, Face::cfg().getopt<OptIntVec>("enrollments").size());
 }
 
 TEST_F(FakeFaceEngineTest, EnrollCancel) {
-    FaceHalProperties::next_enrollment("1:2000-[21,8,9],300:false");
+    Face::cfg().set<std::string>("next_enrollment", "1:2000-[21,8,9],300:false");
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mCancel.set_value();
     mEngine.enrollImpl(mCallback.get(), hat, {} /*enrollmentType*/, {} /*features*/,
                        mCancel.get_future());
     ASSERT_EQ(Error::CANCELED, mCallback->mError);
     ASSERT_EQ(-1, mCallback->mLastEnrolled);
-    ASSERT_EQ(0, FaceHalProperties::enrollments().size());
-    ASSERT_TRUE(FaceHalProperties::next_enrollment().has_value());
+    ASSERT_EQ(0, Face::cfg().getopt<OptIntVec>("enrollments").size());
+    ASSERT_FALSE(Face::cfg().get<std::string>("next_enrollment").empty());
 }
 
 TEST_F(FakeFaceEngineTest, Authenticate) {
-    FaceHalProperties::enrollments({100});
-    FaceHalProperties::enrollment_hit(100);
+    Face::cfg().setopt<OptIntVec>("enrollments", {100});
+    Face::cfg().set<std::int32_t>("enrollment_hit", 100);
     mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future());
 
     ASSERT_EQ(100, mCallback->mLastAuthenticated);
@@ -242,32 +245,32 @@
 }
 
 TEST_F(FakeFaceEngineTest, AuthenticateCancel) {
-    FaceHalProperties::enrollments({100});
-    FaceHalProperties::enrollment_hit(100);
+    Face::cfg().setopt<OptIntVec>("enrollments", {100});
+    Face::cfg().set<std::int32_t>("enrollment_hit", 100);
     mCancel.set_value();
     mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future());
     ASSERT_EQ(Error::CANCELED, mCallback->mError);
 }
 
 TEST_F(FakeFaceEngineTest, AuthenticateFailedForUnEnrolled) {
-    FaceHalProperties::enrollments({3});
-    FaceHalProperties::enrollment_hit(100);
+    Face::cfg().setopt<OptIntVec>("enrollments", {3});
+    Face::cfg().set<std::int32_t>("enrollment_hit", 100);
     mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future());
     ASSERT_EQ(Error::TIMEOUT, mCallback->mError);
     ASSERT_TRUE(mCallback->mAuthenticateFailed);
 }
 
 TEST_F(FakeFaceEngineTest, DetectInteraction) {
-    FaceHalProperties::enrollments({100});
-    FaceHalProperties::enrollment_hit(100);
+    Face::cfg().setopt<OptIntVec>("enrollments", {100});
+    Face::cfg().set<std::int32_t>("enrollment_hit", 100);
     ASSERT_EQ(0, mCallback->mInteractionDetectedCount);
     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
     ASSERT_EQ(1, mCallback->mInteractionDetectedCount);
 }
 
 TEST_F(FakeFaceEngineTest, DetectInteractionCancel) {
-    FaceHalProperties::enrollments({100});
-    FaceHalProperties::enrollment_hit(100);
+    Face::cfg().setopt<OptIntVec>("enrollments", {100});
+    Face::cfg().set<std::int32_t>("enrollment_hit", 100);
     mCancel.set_value();
     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
     ASSERT_EQ(Error::CANCELED, mCallback->mError);
@@ -279,7 +282,7 @@
 }
 
 TEST_F(FakeFaceEngineTest, SetFeature) {
-    FaceHalProperties::enrollments({1});
+    Face::cfg().setopt<OptIntVec>("enrollments", {1});
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
     auto features = mCallback->mFeatures;
@@ -294,7 +297,7 @@
 }
 
 TEST_F(FakeFaceEngineTest, ToggleFeature) {
-    FaceHalProperties::enrollments({1});
+    Face::cfg().setopt<OptIntVec>("enrollments", {1});
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
     mEngine.getFeaturesImpl(mCallback.get());
@@ -310,7 +313,7 @@
 }
 
 TEST_F(FakeFaceEngineTest, TurningOffNonExistentFeatureDoesNothing) {
-    FaceHalProperties::enrollments({1});
+    Face::cfg().setopt<OptIntVec>("enrollments", {1});
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, false);
     mEngine.getFeaturesImpl(mCallback.get());
@@ -319,7 +322,7 @@
 }
 
 TEST_F(FakeFaceEngineTest, SetMultipleFeatures) {
-    FaceHalProperties::enrollments({1});
+    Face::cfg().setopt<OptIntVec>("enrollments", {1});
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
     mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_DIVERSE_POSES, true);
@@ -335,7 +338,7 @@
 }
 
 TEST_F(FakeFaceEngineTest, SetMultipleFeaturesAndTurnOffSome) {
-    FaceHalProperties::enrollments({1});
+    Face::cfg().setopt<OptIntVec>("enrollments", {1});
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
     mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_DIVERSE_POSES, true);
@@ -352,7 +355,7 @@
 }
 
 TEST_F(FakeFaceEngineTest, Enumerate) {
-    FaceHalProperties::enrollments({120, 3});
+    Face::cfg().setopt<OptIntVec>("enrollments", {120, 3});
     mEngine.enumerateEnrollmentsImpl(mCallback.get());
     auto enrolls = mCallback->mLastEnrollmentsEnumerated;
     ASSERT_FALSE(enrolls.empty());
@@ -361,7 +364,7 @@
 }
 
 TEST_F(FakeFaceEngineTest, RemoveEnrollments) {
-    FaceHalProperties::enrollments({120, 3, 100});
+    Face::cfg().setopt<OptIntVec>("enrollments", {120, 3, 100});
     mEngine.removeEnrollmentsImpl(mCallback.get(), {120, 100});
     mEngine.enumerateEnrollmentsImpl(mCallback.get());
     auto enrolls = mCallback->mLastEnrollmentsEnumerated;
@@ -372,9 +375,9 @@
 }
 
 TEST_F(FakeFaceEngineTest, ResetLockoutWithAuth) {
-    FaceHalProperties::lockout(true);
-    FaceHalProperties::enrollments({33});
-    FaceHalProperties::enrollment_hit(33);
+    Face::cfg().set<bool>("lockout", true);
+    Face::cfg().setopt<OptIntVec>("enrollments", {33});
+    Face::cfg().set<std::int32_t>("enrollment_hit", 33);
     auto cancelFuture = mCancel.get_future();
     mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, cancelFuture);
 
@@ -382,28 +385,30 @@
 
     mEngine.resetLockoutImpl(mCallback.get(), {} /* hat */);
     ASSERT_FALSE(mCallback->mLockoutPermanent);
-    FaceHalProperties::enrollment_hit(33);
+    Face::cfg().set<std::int32_t>("enrollment_hit", 33);
     mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, cancelFuture);
     ASSERT_EQ(33, mCallback->mLastAuthenticated);
     ASSERT_FALSE(mCallback->mAuthenticateFailed);
 }
 
 TEST_F(FakeFaceEngineTest, LatencyDefault) {
-    FaceHalProperties::operation_detect_interaction_latency({});
-    ASSERT_EQ(DEFAULT_LATENCY,
-              mEngine.getLatency(FaceHalProperties::operation_detect_interaction_latency()));
+    Face::cfg().setopt<OptIntVec>("operation_detect_interaction_latency", {});
+    ASSERT_EQ(DEFAULT_LATENCY, mEngine.getLatency(Face::cfg().getopt<OptIntVec>(
+                                       "operation_detect_interaction_latency")));
 }
 
 TEST_F(FakeFaceEngineTest, LatencyFixed) {
-    FaceHalProperties::operation_detect_interaction_latency({10});
-    ASSERT_EQ(10, mEngine.getLatency(FaceHalProperties::operation_detect_interaction_latency()));
+    Face::cfg().setopt<OptIntVec>("operation_detect_interaction_latency", {10});
+    ASSERT_EQ(10, mEngine.getLatency(
+                          Face::cfg().getopt<OptIntVec>("operation_detect_interaction_latency")));
 }
 
 TEST_F(FakeFaceEngineTest, LatencyRandom) {
-    FaceHalProperties::operation_detect_interaction_latency({1, 1000});
+    Face::cfg().setopt<OptIntVec>("operation_detect_interaction_latency", {1, 1000});
     std::set<int32_t> latencySet;
     for (int i = 0; i < 100; i++) {
-        auto x = mEngine.getLatency(FaceHalProperties::operation_detect_interaction_latency());
+        auto x = mEngine.getLatency(
+                Face::cfg().getopt<OptIntVec>("operation_detect_interaction_latency"));
         ASSERT_TRUE(x >= 1 && x <= 1000);
         latencySet.insert(x);
     }
diff --git a/biometrics/face/aidl/default/tests/FakeLockoutTrackerTest.cpp b/biometrics/face/aidl/default/tests/FakeLockoutTrackerTest.cpp
index fa07d1d..8564f6b 100644
--- a/biometrics/face/aidl/default/tests/FakeLockoutTrackerTest.cpp
+++ b/biometrics/face/aidl/default/tests/FakeLockoutTrackerTest.cpp
@@ -21,6 +21,7 @@
 
 #include <android-base/logging.h>
 
+#include "Face.h"
 #include "FakeLockoutTracker.h"
 #include "util/Util.h"
 
@@ -103,19 +104,21 @@
     static constexpr int32_t LOCKOUT_TIMED_DURATION = 100;
 
     void SetUp() override {
-        FaceHalProperties::lockout_timed_threshold(LOCKOUT_TIMED_THRESHOLD);
-        FaceHalProperties::lockout_timed_duration(LOCKOUT_TIMED_DURATION);
-        FaceHalProperties::lockout_permanent_threshold(LOCKOUT_PERMANENT_THRESHOLD);
+        Face::cfg().set<std::int32_t>("lockout_timed_threshold", LOCKOUT_TIMED_THRESHOLD);
+        Face::cfg().set<std::int32_t>("lockout_timed_duration", LOCKOUT_TIMED_DURATION);
+        Face::cfg().set<std::int32_t>("lockout_permanent_threshold", LOCKOUT_PERMANENT_THRESHOLD);
+        Face::cfg().set<bool>("lockout_enable", false);
+        Face::cfg().set<bool>("lockout", false);
         mCallback = ndk::SharedRefBase::make<TestSessionCallback>();
     }
 
     void TearDown() override {
         // reset to default
-        FaceHalProperties::lockout_timed_threshold(5);
-        FaceHalProperties::lockout_timed_duration(20);
-        FaceHalProperties::lockout_permanent_threshold(10000);
-        FaceHalProperties::lockout_enable(false);
-        FaceHalProperties::lockout(false);
+        Face::cfg().set<std::int32_t>("lockout_timed_threshold", 5);
+        Face::cfg().set<std::int32_t>("lockout_timed_duration", 20);
+        Face::cfg().set<std::int32_t>("lockout_permanent_threshold", 10000);
+        Face::cfg().set<bool>("lockout_enable", false);
+        Face::cfg().set<bool>("lockout", false);
     }
 
     FakeLockoutTracker mLockoutTracker;
@@ -123,7 +126,7 @@
 };
 
 TEST_F(FakeLockoutTrackerTest, addFailedAttemptDisable) {
-    FaceHalProperties::lockout_enable(false);
+    Face::cfg().set<bool>("lockout_enable", false);
     for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD + 1; i++)
         mLockoutTracker.addFailedAttempt(mCallback.get());
     ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
@@ -131,7 +134,7 @@
 }
 
 TEST_F(FakeLockoutTrackerTest, addFailedAttemptPermanent) {
-    FaceHalProperties::lockout_enable(true);
+    Face::cfg().set<bool>("lockout_enable", true);
     ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
     for (int i = 0; i < LOCKOUT_PERMANENT_THRESHOLD - 1; i++)
         mLockoutTracker.addFailedAttempt(mCallback.get());
@@ -145,8 +148,8 @@
 }
 
 TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockoutTimed) {
-    FaceHalProperties::lockout_enable(true);
-    FaceHalProperties::lockout_timed_enable(true);
+    Face::cfg().set<bool>("lockout_enable", true);
+    Face::cfg().set<bool>("lockout_timed_enable", true);
     ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
     for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++)
         mLockoutTracker.addFailedAttempt(mCallback.get());
@@ -168,8 +171,8 @@
 }
 
 TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockout_TimedThenPermanent) {
-    FaceHalProperties::lockout_enable(true);
-    FaceHalProperties::lockout_timed_enable(true);
+    Face::cfg().set<bool>("lockout_enable", true);
+    Face::cfg().set<bool>("lockout_timed_enable", true);
     ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
     for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++)
         mLockoutTracker.addFailedAttempt(mCallback.get());
@@ -182,8 +185,8 @@
 }
 
 TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockoutTimedTwice) {
-    FaceHalProperties::lockout_enable(true);
-    FaceHalProperties::lockout_timed_enable(true);
+    Face::cfg().set<bool>("lockout_enable", true);
+    Face::cfg().set<bool>("lockout_timed_enable", true);
     ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
     ASSERT_EQ(0, mCallback->mLockoutTimed);
     for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++)
@@ -198,7 +201,7 @@
 }
 
 TEST_F(FakeLockoutTrackerTest, resetLockout) {
-    FaceHalProperties::lockout_enable(true);
+    Face::cfg().set<bool>("lockout_enable", true);
     ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
     for (int i = 0; i < LOCKOUT_PERMANENT_THRESHOLD; i++)
         mLockoutTracker.addFailedAttempt(mCallback.get());
diff --git a/biometrics/face/aidl/default/tests/VirtualHalTest.cpp b/biometrics/face/aidl/default/tests/VirtualHalTest.cpp
new file mode 100644
index 0000000..2f19805
--- /dev/null
+++ b/biometrics/face/aidl/default/tests/VirtualHalTest.cpp
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_process.h>
+#include <face.sysprop.h>
+#include <gtest/gtest.h>
+
+#include <android-base/logging.h>
+
+#include "Face.h"
+#include "VirtualHal.h"
+
+using namespace ::android::face::virt;
+using namespace ::aidl::android::hardware::biometrics::face;
+
+namespace aidl::android::hardware::biometrics::face {
+
+class VirtualHalTest : public ::testing::Test {
+  public:
+    static const int32_t STATUS_FAILED_TO_SET_PARAMETER = 2;
+
+  protected:
+    void SetUp() override {
+        mHal = ndk::SharedRefBase::make<Face>();
+        mVhal = ndk::SharedRefBase::make<VirtualHal>(mHal);
+        ASSERT_TRUE(mVhal != nullptr);
+        mHal->resetConfigToDefault();
+    }
+
+    void TearDown() override { mHal->resetConfigToDefault(); }
+
+    std::shared_ptr<VirtualHal> mVhal;
+
+    ndk::ScopedAStatus validateNonNegativeInputOfInt32(const char* name,
+                                                       ndk::ScopedAStatus (VirtualHal::*f)(int32_t),
+                                                       const std::vector<int32_t>& in_good);
+
+  private:
+    std::shared_ptr<Face> mHal;
+};
+
+ndk::ScopedAStatus VirtualHalTest::validateNonNegativeInputOfInt32(
+        const char* name, ndk::ScopedAStatus (VirtualHal::*f)(int32_t),
+        const std::vector<int32_t>& in_params_good) {
+    ndk::ScopedAStatus status;
+    for (auto& param : in_params_good) {
+        status = (*mVhal.*f)(param);
+        if (!status.isOk()) return status;
+        if (Face::cfg().get<int32_t>(name) != param) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    VirtualHalTest::STATUS_FAILED_TO_SET_PARAMETER,
+                    "Error: fail to set non-negative parameter"));
+        }
+    }
+
+    int32_t old_param = Face::cfg().get<int32_t>(name);
+    status = (*mVhal.*f)(-1);
+    if (status.isOk()) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                VirtualHalTest::STATUS_FAILED_TO_SET_PARAMETER, "Error: should return NOK"));
+    }
+    if (status.getServiceSpecificError() != IVirtualHal::STATUS_INVALID_PARAMETER) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                VirtualHalTest::STATUS_FAILED_TO_SET_PARAMETER,
+                "Error: unexpected return error code"));
+    }
+    if (Face::cfg().get<int32_t>(name) != old_param) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                VirtualHalTest::STATUS_FAILED_TO_SET_PARAMETER,
+                "Error: unexpected parameter change on failed attempt"));
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+TEST_F(VirtualHalTest, init) {
+    mVhal->setLockout(false);
+    ASSERT_TRUE(Face::cfg().get<bool>("lockout") == false);
+    ASSERT_TRUE(Face::cfg().get<std::string>("type") == "rgb");
+    ASSERT_TRUE(Face::cfg().get<std::string>("strength") == "strong");
+    std::int64_t id = Face::cfg().get<std::int64_t>("authenticator_id");
+    ASSERT_TRUE(Face::cfg().get<std::int64_t>("authenticator_id") == 0);
+    ASSERT_TRUE(Face::cfg().getopt<OptIntVec>("enrollments") == OptIntVec());
+}
+
+TEST_F(VirtualHalTest, enrollment_hit_int32) {
+    mVhal->setEnrollmentHit(11);
+    ASSERT_TRUE(Face::cfg().get<int32_t>("enrollment_hit") == 11);
+}
+
+TEST_F(VirtualHalTest, next_enrollment) {
+    struct {
+        std::string nextEnrollmentStr;
+        face::NextEnrollment nextEnrollment;
+    } testData[] = {
+            {"1:20:true", {1, {{20}}, true}},
+            {"1:50,60,70:true", {1, {{50}, {60}, {70}}, true}},
+            {"2:50-[21],60,70-[4,1002,1]:false",
+             {2,
+              {{50, {{AcquiredInfo::START}}},
+               {60},
+               {70, {{AcquiredInfo::TOO_DARK}, {1002}, {AcquiredInfo::GOOD}}}},
+              false}},
+    };
+
+    for (auto& d : testData) {
+        mVhal->setNextEnrollment(d.nextEnrollment);
+        ASSERT_TRUE(Face::cfg().get<std::string>("next_enrollment") == d.nextEnrollmentStr);
+    }
+}
+
+TEST_F(VirtualHalTest, authenticator_id_int64) {
+    mVhal->setAuthenticatorId(12345678900);
+    ASSERT_TRUE(Face::cfg().get<int64_t>("authenticator_id") == 12345678900);
+}
+
+TEST_F(VirtualHalTest, opeationAuthenticateFails_bool) {
+    mVhal->setOperationAuthenticateFails(true);
+    ASSERT_TRUE(Face::cfg().get<bool>("operation_authenticate_fails"));
+}
+
+TEST_F(VirtualHalTest, operationAuthenticateAcquired_int32_vector) {
+    using Tag = AcquiredInfoAndVendorCode::Tag;
+    std::vector<AcquiredInfoAndVendorCode> ac{
+            {AcquiredInfo::START}, {AcquiredInfo::TOO_FAR}, {1023}};
+    mVhal->setOperationAuthenticateAcquired(ac);
+    OptIntVec ac_get = Face::cfg().getopt<OptIntVec>("operation_authenticate_acquired");
+    ASSERT_TRUE(ac_get.size() == ac.size());
+    for (int i = 0; i < ac.size(); i++) {
+        int acCode = (ac[i].getTag() == Tag::acquiredInfo) ? (int)ac[i].get<Tag::acquiredInfo>()
+                                                           : ac[i].get<Tag::vendorCode>();
+        ASSERT_TRUE(acCode == ac_get[i]);
+    }
+}
+
+TEST_F(VirtualHalTest, type) {
+    struct {
+        FaceSensorType type;
+        const char* typeStr;
+    } typeMap[] = {{FaceSensorType::RGB, "rgb"},
+                   {FaceSensorType::IR, "ir"},
+                   {FaceSensorType::UNKNOWN, "unknown"}};
+    for (auto const& x : typeMap) {
+        mVhal->setType(x.type);
+        ASSERT_TRUE(Face::cfg().get<std::string>("type") == x.typeStr);
+    }
+}
+
+TEST_F(VirtualHalTest, sensorStrength) {
+    struct {
+        common::SensorStrength strength;
+        const char* strengthStr;
+    } strengths[] = {{common::SensorStrength::CONVENIENCE, "CONVENIENCE"},
+                     {common::SensorStrength::WEAK, "WEAK"},
+                     {common::SensorStrength::STRONG, "STRONG"}};
+
+    for (auto const& x : strengths) {
+        mVhal->setSensorStrength(x.strength);
+        ASSERT_TRUE(Face::cfg().get<std::string>("strength") == x.strengthStr);
+    }
+}
+
+TEST_F(VirtualHalTest, setLatency) {
+    ndk::ScopedAStatus status;
+    std::vector<int32_t> in_lats[] = {{1}, {2, 3}, {5, 4}};
+    for (auto const& in_lat : in_lats) {
+        status = mVhal->setOperationAuthenticateLatency(in_lat);
+        ASSERT_TRUE(status.isOk());
+        OptIntVec out_lat = Face::cfg().getopt<OptIntVec>("operation_authenticate_latency");
+        ASSERT_TRUE(in_lat.size() == out_lat.size());
+        for (int i = 0; i < in_lat.size(); i++) {
+            ASSERT_TRUE(in_lat[i] == out_lat[i]);
+        }
+    }
+
+    std::vector<int32_t> bad_in_lats[] = {{}, {1, 2, 3}, {1, -3}};
+    for (auto const& in_lat : bad_in_lats) {
+        status = mVhal->setOperationAuthenticateLatency(in_lat);
+        ASSERT_TRUE(!status.isOk());
+        ASSERT_TRUE(status.getServiceSpecificError() == IVirtualHal::STATUS_INVALID_PARAMETER);
+    }
+}
+
+TEST_F(VirtualHalTest, setOperationAuthenticateDuration) {
+    ndk::ScopedAStatus status = validateNonNegativeInputOfInt32(
+            "operation_authenticate_duration", &IVirtualHal::setOperationAuthenticateDuration,
+            {0, 33});
+    ASSERT_TRUE(status.isOk());
+}
+
+TEST_F(VirtualHalTest, setLockoutTimedDuration) {
+    ndk::ScopedAStatus status = validateNonNegativeInputOfInt32(
+            "lockout_timed_duration", &IVirtualHal::setLockoutTimedDuration, {0, 35});
+    ASSERT_TRUE(status.isOk());
+}
+
+TEST_F(VirtualHalTest, setLockoutTimedThreshold) {
+    ndk::ScopedAStatus status = validateNonNegativeInputOfInt32(
+            "lockout_timed_threshold", &IVirtualHal::setLockoutTimedThreshold, {0, 36});
+    ASSERT_TRUE(status.isOk());
+}
+
+TEST_F(VirtualHalTest, setLockoutPermanentThreshold) {
+    ndk::ScopedAStatus status = validateNonNegativeInputOfInt32(
+            "lockout_permanent_threshold", &IVirtualHal::setLockoutPermanentThreshold, {0, 37});
+    ASSERT_TRUE(status.isOk());
+}
+
+TEST_F(VirtualHalTest, setOthers) {
+    // Verify that there is no CHECK() failures
+    mVhal->setEnrollments({7, 6, 5});
+    mVhal->setChallenge(111222333444555666);
+    mVhal->setOperationAuthenticateError(4);
+    mVhal->setOperationEnrollLatency({4, 5});
+    mVhal->setLockout(false);
+    mVhal->setLockoutEnable(false);
+}
+
+}  // namespace aidl::android::hardware::biometrics::face
+
+int main(int argc, char** argv) {
+    testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/biometrics/fingerprint/aidl/Android.bp b/biometrics/fingerprint/aidl/Android.bp
index d0c1b8b..9f9e723 100644
--- a/biometrics/fingerprint/aidl/Android.bp
+++ b/biometrics/fingerprint/aidl/Android.bp
@@ -11,7 +11,7 @@
     name: "android.hardware.biometrics.fingerprint",
     vendor_available: true,
     srcs: [
-        "android/hardware/biometrics/fingerprint/**/*.aidl",
+        "android/hardware/biometrics/fingerprint/*.aidl",
     ],
     imports: [
         "android.hardware.biometrics.common-V4",
@@ -25,6 +25,12 @@
         cpp: {
             enabled: false,
         },
+        ndk: {
+            apex_available: [
+                "//apex_available:platform",
+                "//apex_available:anyapex",
+            ],
+        },
         rust: {
             enabled: true,
         },
@@ -60,5 +66,34 @@
         },
 
     ],
+    frozen: true,
+}
+
+aidl_interface {
+    name: "android.hardware.biometrics.fingerprint.virtualhal",
+    srcs: [
+        "android/hardware/biometrics/fingerprint/virtualhal/*.aidl",
+    ],
+    imports: [
+        "android.hardware.biometrics.common-V4",
+        "android.hardware.keymaster-V4",
+        "android.hardware.biometrics.fingerprint-V4",
+    ],
+    vendor_available: true,
+    unstable: true,
+    backend: {
+        java: {
+            platform_apis: true,
+        },
+        cpp: {
+            enabled: false,
+        },
+        ndk: {
+            apex_available: [
+                "com.android.hardware.biometrics.fingerprint.virtual",
+                "//apex_available:platform",
+            ],
+        },
+    },
     frozen: false,
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IVirtualHal.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IVirtualHal.aidl
deleted file mode 100644
index 33ae83c..0000000
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IVirtualHal.aidl
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file built
-// with the aidl_interface module type with versions property set. The module
-// type is used to build AIDL files in a way that they can be used across
-// independently updatable components of the system. If a device is shipped
-// with such a backward incompatible change, it has a high risk of breaking
-// later when a module using the interface is updated, e.g., Mainline modules.
-
-package android.hardware.biometrics.fingerprint;
-/* @hide */
-@VintfStability
-interface IVirtualHal {
-  oneway void setEnrollments(in int[] id);
-  oneway void setEnrollmentHit(in int hit_id);
-  oneway void setNextEnrollment(in android.hardware.biometrics.fingerprint.NextEnrollment next_enrollment);
-  oneway void setAuthenticatorId(in long id);
-  oneway void setChallenge(in long challenge);
-  oneway void setOperationAuthenticateFails(in boolean fail);
-  oneway void setOperationAuthenticateLatency(in int[] latencyMs);
-  oneway void setOperationAuthenticateDuration(in int durationMs);
-  oneway void setOperationAuthenticateError(in int error);
-  oneway void setOperationAuthenticateAcquired(in android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquired);
-  oneway void setOperationEnrollError(in int error);
-  oneway void setOperationEnrollLatency(in int[] latencyMs);
-  oneway void setOperationDetectInteractionLatency(in int[] latencyMs);
-  oneway void setOperationDetectInteractionError(in int error);
-  oneway void setOperationDetectInteractionDuration(in int durationMs);
-  oneway void setOperationDetectInteractionAcquired(in android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquired);
-  oneway void setLockout(in boolean lockout);
-  oneway void setLockoutEnable(in boolean enable);
-  oneway void setLockoutTimedThreshold(in int threshold);
-  oneway void setLockoutTimedDuration(in int durationMs);
-  oneway void setLockoutPermanentThreshold(in int threshold);
-  oneway void resetConfigurations();
-  oneway void setType(in android.hardware.biometrics.fingerprint.FingerprintSensorType type);
-  oneway void setSensorId(in int id);
-  oneway void setSensorStrength(in android.hardware.biometrics.common.SensorStrength strength);
-  oneway void setMaxEnrollmentPerUser(in int max);
-  oneway void setSensorLocation(in android.hardware.biometrics.fingerprint.SensorLocation loc);
-  oneway void setNavigationGuesture(in boolean v);
-  oneway void setDetectInteraction(in boolean v);
-  oneway void setDisplayTouch(in boolean v);
-  oneway void setControlIllumination(in boolean v);
-  const int STATUS_INVALID_PARAMETER = 1;
-}
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/AcquiredInfoAndVendorCode.aidl
similarity index 93%
rename from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
rename to biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/AcquiredInfoAndVendorCode.aidl
index c7be950..1fc7221 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/AcquiredInfoAndVendorCode.aidl
@@ -14,14 +14,13 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+package android.hardware.biometrics.fingerprint.virtualhal;
 
 import android.hardware.biometrics.fingerprint.AcquiredInfo;
 
 /**
  * @hide
  */
-@VintfStability
 union AcquiredInfoAndVendorCode {
     /**
      * Acquired info as specified in AcqauiredInfo.aidl
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/EnrollmentProgressStep.aidl
similarity index 87%
rename from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
rename to biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/EnrollmentProgressStep.aidl
index bf038f6..b0b2926 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/EnrollmentProgressStep.aidl
@@ -14,14 +14,13 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+package android.hardware.biometrics.fingerprint.virtualhal;
 
-import android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode;
+import android.hardware.biometrics.fingerprint.virtualhal.AcquiredInfoAndVendorCode;
 
 /**
  * @hide
  */
-@VintfStability
 parcelable EnrollmentProgressStep {
     /**
      * The duration of the enrollment step in milli-seconds
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IVirtualHal.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/IVirtualHal.aidl
similarity index 96%
rename from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IVirtualHal.aidl
rename to biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/IVirtualHal.aidl
index cb9135e..5af84ed 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IVirtualHal.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/IVirtualHal.aidl
@@ -14,19 +14,19 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+package android.hardware.biometrics.fingerprint.virtualhal;
 
 import android.hardware.biometrics.common.SensorStrength;
-import android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode;
 import android.hardware.biometrics.fingerprint.FingerprintSensorType;
-import android.hardware.biometrics.fingerprint.NextEnrollment;
+import android.hardware.biometrics.fingerprint.IFingerprint;
 import android.hardware.biometrics.fingerprint.SensorLocation;
+import android.hardware.biometrics.fingerprint.virtualhal.AcquiredInfoAndVendorCode;
+import android.hardware.biometrics.fingerprint.virtualhal.NextEnrollment;
 
 /**
  * @hide
  */
-@VintfStability
-oneway interface IVirtualHal {
+interface IVirtualHal {
     /**
      * The operation failed due to invalid input parameters, the error messages should
      * gives more details
@@ -315,4 +315,5 @@
     void setDetectInteraction(in boolean v);
     void setDisplayTouch(in boolean v);
     void setControlIllumination(in boolean v);
+    IFingerprint getFingerprintHal();
 }
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/NextEnrollment.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/NextEnrollment.aidl
similarity index 85%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/NextEnrollment.aidl
copy to biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/NextEnrollment.aidl
index 4b50850..2d704f1 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/NextEnrollment.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/NextEnrollment.aidl
@@ -14,12 +14,13 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+package android.hardware.biometrics.fingerprint.virtualhal;
+
+import android.hardware.biometrics.fingerprint.virtualhal.EnrollmentProgressStep;
 
 /**
  * @hide
  */
-@VintfStability
 parcelable NextEnrollment {
     /**
      *  Identifier of the next enrollment if successful
@@ -31,7 +32,7 @@
      *  and sequence of acquired info codes to be generated by HAL.
      *  See EnrollmentProgressStep.aidl for more details
      */
-    android.hardware.biometrics.fingerprint.EnrollmentProgressStep[] progressSteps;
+    EnrollmentProgressStep[] progressSteps;
 
     /**
      * Success or failure of the next enrollment
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/README.md b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/README.md
new file mode 100644
index 0000000..eaf2336
--- /dev/null
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/README.md
@@ -0,0 +1,2 @@
+The aidl files in this directory are used only by fingerprint virtual hal
+which is controlled/configured via IVirtualHal interface
diff --git a/biometrics/fingerprint/aidl/default/Android.bp b/biometrics/fingerprint/aidl/default/Android.bp
index 9b72c87..c6ffc51 100644
--- a/biometrics/fingerprint/aidl/default/Android.bp
+++ b/biometrics/fingerprint/aidl/default/Android.bp
@@ -8,10 +8,9 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
-cc_binary {
-    name: "android.hardware.biometrics.fingerprint-service.example",
-    vendor: true,
-    relative_install_path: "hw",
+cc_library_static {
+    name: "android.hardware.biometrics.fingerprint-service.lib",
+    vendor_available: true,
     local_include_dirs: ["include"],
     srcs: [
         "FakeLockoutTracker.cpp",
@@ -30,22 +29,86 @@
         "libbinder_ndk",
         "liblog",
     ],
-    static_libs: [
+    whole_static_libs: [
         "libandroid.hardware.biometrics.fingerprint.VirtualProps",
         "libbase",
-        "android.hardware.biometrics.fingerprint-V5-ndk",
+        "android.hardware.biometrics.fingerprint.virtualhal-ndk",
+        "android.hardware.biometrics.fingerprint-V4-ndk",
         "android.hardware.biometrics.common-V4-ndk",
         "android.hardware.biometrics.common.thread",
         "android.hardware.biometrics.common.util",
         "android.hardware.biometrics.common.config",
         "android.hardware.keymaster-V4-ndk",
     ],
+    product_variables: {
+        debuggable: {
+            cflags: ["-DFPS_DEBUGGABLE"],
+        },
+    },
+    apex_available: [
+        "com.android.hardware.biometrics.fingerprint.virtual",
+        "//apex_available:platform",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.biometrics.fingerprint-service.example",
+    system_ext_specific: true,
+    relative_install_path: "hw",
+    local_include_dirs: ["include"],
+    srcs: [
+    ],
+    stl: "c++_static",
+    shared_libs: [
+        "libbinder_ndk",
+        "liblog",
+    ],
+    whole_static_libs: [
+        "android.hardware.biometrics.fingerprint-service.lib",
+    ],
     installable: false, // install APEX instead
     product_variables: {
         debuggable: {
             cflags: ["-DFPS_DEBUGGABLE"],
         },
     },
+    apex_available: [
+        "com.android.hardware.biometrics.fingerprint.virtual",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.biometrics.fingerprint-service.default",
+    //system_ext_specific: true,
+    vendor: true,
+    relative_install_path: "hw",
+    init_rc: ["fingerprint-default.rc"],
+    vintf_fragment_modules: ["android.hardware.biometrics.fingerprint-service.default.vintf"],
+    local_include_dirs: ["include"],
+    srcs: [
+    ],
+    stl: "c++_static",
+    shared_libs: [
+        "libbinder_ndk",
+        "liblog",
+    ],
+    whole_static_libs: [
+        "android.hardware.biometrics.fingerprint-service.lib",
+    ],
+    product_variables: {
+        debuggable: {
+            cflags: ["-DFPS_DEBUGGABLE"],
+        },
+    },
+    apex_available: [
+        "//apex_available:platform",
+    ],
+}
+
+vintf_fragment {
+    name: "android.hardware.biometrics.fingerprint-service.default.vintf",
+    src: "fingerprint-default.xml",
+    vendor: true,
 }
 
 cc_test {
@@ -63,14 +126,13 @@
     ],
     static_libs: [
         "libandroid.hardware.biometrics.fingerprint.VirtualProps",
-        "android.hardware.biometrics.fingerprint-V5-ndk",
+        "android.hardware.biometrics.fingerprint-V4-ndk",
         "android.hardware.biometrics.common-V4-ndk",
         "android.hardware.keymaster-V4-ndk",
         "android.hardware.biometrics.common.util",
         "android.hardware.biometrics.common.config",
         "android.hardware.biometrics.common.thread",
     ],
-    vendor: true,
     test_suites: ["general-tests"],
     require_root: true,
 }
@@ -91,14 +153,13 @@
     ],
     static_libs: [
         "libandroid.hardware.biometrics.fingerprint.VirtualProps",
-        "android.hardware.biometrics.fingerprint-V5-ndk",
+        "android.hardware.biometrics.fingerprint-V4-ndk",
         "android.hardware.biometrics.common-V4-ndk",
         "android.hardware.keymaster-V4-ndk",
         "android.hardware.biometrics.common.util",
         "android.hardware.biometrics.common.config",
         "android.hardware.biometrics.common.thread",
     ],
-    vendor: true,
     test_suites: ["general-tests"],
     require_root: true,
 }
@@ -117,14 +178,13 @@
     ],
     static_libs: [
         "libandroid.hardware.biometrics.fingerprint.VirtualProps",
-        "android.hardware.biometrics.fingerprint-V5-ndk",
+        "android.hardware.biometrics.fingerprint-V4-ndk",
         "android.hardware.biometrics.common-V4-ndk",
         "android.hardware.keymaster-V4-ndk",
         "android.hardware.biometrics.common.util",
         "android.hardware.biometrics.common.thread",
         "android.hardware.biometrics.common.config",
     ],
-    vendor: true,
     test_suites: ["general-tests"],
     require_root: true,
 }
@@ -145,14 +205,13 @@
     ],
     static_libs: [
         "libandroid.hardware.biometrics.fingerprint.VirtualProps",
-        "android.hardware.biometrics.fingerprint-V5-ndk",
+        "android.hardware.biometrics.fingerprint-V4-ndk",
         "android.hardware.biometrics.common-V4-ndk",
         "android.hardware.keymaster-V4-ndk",
         "android.hardware.biometrics.common.util",
         "android.hardware.biometrics.common.thread",
         "android.hardware.biometrics.common.config",
     ],
-    vendor: true,
     test_suites: ["general-tests"],
     require_root: true,
 }
@@ -178,7 +237,8 @@
     ],
     static_libs: [
         "libandroid.hardware.biometrics.fingerprint.VirtualProps",
-        "android.hardware.biometrics.fingerprint-V5-ndk",
+        "android.hardware.biometrics.fingerprint-V4-ndk",
+        "android.hardware.biometrics.fingerprint.virtualhal-ndk",
         "android.hardware.biometrics.common-V4-ndk",
         "android.hardware.keymaster-V4-ndk",
         "android.hardware.biometrics.common.util",
@@ -190,7 +250,6 @@
             cflags: ["-DFPS_DEBUGGABLE"],
         },
     },
-    vendor: true,
     test_suites: ["general-tests"],
     require_root: true,
 }
@@ -198,39 +257,34 @@
 sysprop_library {
     name: "android.hardware.biometrics.fingerprint.VirtualProps",
     srcs: ["fingerprint.sysprop"],
-    property_owner: "Vendor",
-    vendor: true,
+    property_owner: "Platform",
+    vendor_available: true,
+    apex_available: [
+        "com.android.hardware.biometrics.fingerprint.virtual",
+        "//apex_available:platform",
+    ],
 }
 
 prebuilt_etc {
-    name: "fingerprint-example.rc",
-    src: "fingerprint-example.rc",
-    installable: false,
-}
-
-prebuilt_etc {
-    name: "fingerprint-example.xml",
-    src: "fingerprint-example.xml",
-    sub_dir: "vintf",
+    name: "fingerprint-virtual.rc",
+    src: "fingerprint-virtual.rc",
     installable: false,
 }
 
 apex {
     name: "com.android.hardware.biometrics.fingerprint.virtual",
     manifest: "apex_manifest.json",
-    file_contexts: "apex_file_contexts",
+    file_contexts: ":com.android.biometrics.virtual.fingerprint-file_contexts",
     key: "com.android.hardware.key",
     certificate: ":com.android.hardware.certificate",
     updatable: false,
-    vendor: true,
+    system_ext_specific: true,
 
     binaries: [
         "android.hardware.biometrics.fingerprint-service.example",
     ],
     prebuilts: [
         // init_rc
-        "fingerprint-example.rc",
-        // vintf_fragment
-        "fingerprint-example.xml",
+        "fingerprint-virtual.rc",
     ],
 }
diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
index 67eb837..7a43d7b 100644
--- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
+++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
@@ -389,10 +389,10 @@
     if (isLockoutTimerStarted) isLockoutTimerAborted = true;
 }
 
-void FakeFingerprintEngine::clearLockout(ISessionCallback* cb) {
+void FakeFingerprintEngine::clearLockout(ISessionCallback* cb, bool dueToTimeout) {
     Fingerprint::cfg().set<bool>("lockout", false);
     cb->onLockoutCleared();
-    mLockoutTracker.reset();
+    mLockoutTracker.reset(dueToTimeout);
 }
 
 ndk::ScopedAStatus FakeFingerprintEngine::onPointerDownImpl(int32_t /*pointerId*/, int32_t /*x*/,
@@ -536,7 +536,7 @@
 void FakeFingerprintEngine::lockoutTimerExpired(ISessionCallback* cb) {
     BEGIN_OP(0);
     if (!isLockoutTimerAborted) {
-        clearLockout(cb);
+        clearLockout(cb, true);
     }
     isLockoutTimerStarted = false;
     isLockoutTimerAborted = false;
diff --git a/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp b/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp
index a056db5..7d46845 100644
--- a/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp
+++ b/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp
@@ -23,8 +23,11 @@
 
 namespace aidl::android::hardware::biometrics::fingerprint {
 
-void FakeLockoutTracker::reset() {
-    mFailedCount = 0;
+void FakeLockoutTracker::reset(bool dueToTimeout) {
+    if (!dueToTimeout) {
+        mFailedCount = 0;
+    }
+    mFailedCountTimed = 0;
     mLockoutTimedStart = 0;
     mCurrentMode = LockoutMode::kNone;
 }
@@ -33,6 +36,7 @@
     bool enabled = Fingerprint::cfg().get<bool>("lockout_enable");
     if (enabled) {
         mFailedCount++;
+        mFailedCountTimed++;
         int32_t lockoutTimedThreshold =
                 Fingerprint::cfg().get<std::int32_t>("lockout_timed_threshold");
         int32_t lockoutPermanetThreshold =
@@ -40,7 +44,7 @@
         if (mFailedCount >= lockoutPermanetThreshold) {
             mCurrentMode = LockoutMode::kPermanent;
             Fingerprint::cfg().set<bool>("lockout", true);
-        } else if (mFailedCount >= lockoutTimedThreshold) {
+        } else if (mFailedCountTimed >= lockoutTimedThreshold) {
             if (mCurrentMode == LockoutMode::kNone) {
                 mCurrentMode = LockoutMode::kTimed;
                 mLockoutTimedStart = Util::getSystemNanoTime();
diff --git a/biometrics/fingerprint/aidl/default/VirtualHal.cpp b/biometrics/fingerprint/aidl/default/VirtualHal.cpp
index e107d2f..d161765 100644
--- a/biometrics/fingerprint/aidl/default/VirtualHal.cpp
+++ b/biometrics/fingerprint/aidl/default/VirtualHal.cpp
@@ -26,7 +26,7 @@
 #define LOG_TAG "FingerprintVirtualHalAidl"
 
 namespace aidl::android::hardware::biometrics::fingerprint {
-
+using AcquiredInfoAndVendorCode = virtualhal::AcquiredInfoAndVendorCode;
 using Tag = AcquiredInfoAndVendorCode::Tag;
 
 ::ndk::ScopedAStatus VirtualHal::setEnrollments(const std::vector<int32_t>& enrollments) {
@@ -41,8 +41,7 @@
     return ndk::ScopedAStatus::ok();
 }
 
-::ndk::ScopedAStatus VirtualHal::setNextEnrollment(
-        const ::aidl::android::hardware::biometrics::fingerprint::NextEnrollment& next_enrollment) {
+::ndk::ScopedAStatus VirtualHal::setNextEnrollment(const NextEnrollment& next_enrollment) {
     Fingerprint::cfg().sourcedFromAidl();
     std::ostringstream os;
     os << next_enrollment.id << ":";
@@ -333,4 +332,10 @@
     return ndk::ScopedAStatus::ok();
 }
 
+::ndk::ScopedAStatus VirtualHal::getFingerprintHal(
+        std::shared_ptr<::aidl::android::hardware::biometrics::fingerprint::IFingerprint>* pFp) {
+    LOG(INFO) << " calling getFingerprintHal in VirtualHal.cpp";
+    *pFp = mFp;
+    return ndk::ScopedAStatus::ok();
+}
 }  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/api/android.hardware.biometrics.fingerprint.VirtualProps-current.txt b/biometrics/fingerprint/aidl/default/api/android.hardware.biometrics.fingerprint.VirtualProps-current.txt
index e69de29..8c02a68 100644
--- a/biometrics/fingerprint/aidl/default/api/android.hardware.biometrics.fingerprint.VirtualProps-current.txt
+++ b/biometrics/fingerprint/aidl/default/api/android.hardware.biometrics.fingerprint.VirtualProps-current.txt
@@ -0,0 +1,178 @@
+props {
+  owner: Vendor
+  module: "android.fingerprint.virt.FingerprintHalProperties"
+  prop {
+    api_name: "authenticator_id"
+    type: Long
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.authenticator_id"
+  }
+  prop {
+    api_name: "challenge"
+    type: Long
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.challenge"
+  }
+  prop {
+    api_name: "control_illumination"
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.udfps.control_illumination"
+  }
+  prop {
+    api_name: "detect_interaction"
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.detect_interaction"
+  }
+  prop {
+    api_name: "display_touch"
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.udfps.display_touch"
+  }
+  prop {
+    api_name: "enrollment_hit"
+    type: Integer
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.enrollment_hit"
+  }
+  prop {
+    api_name: "enrollments"
+    type: IntegerList
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.enrollments"
+  }
+  prop {
+    api_name: "lockout"
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.lockout"
+  }
+  prop {
+    api_name: "lockout_enable"
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.lockout_enable"
+  }
+  prop {
+    api_name: "lockout_permanent_threshold"
+    type: Integer
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.lockout_permanent_threshold"
+  }
+  prop {
+    api_name: "lockout_timed_duration"
+    type: Integer
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.lockout_timed_duration"
+  }
+  prop {
+    api_name: "lockout_timed_threshold"
+    type: Integer
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.lockout_timed_threshold"
+  }
+  prop {
+    api_name: "max_enrollments"
+    type: Integer
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.max_enrollments"
+  }
+  prop {
+    api_name: "navigation_guesture"
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.navigation_guesture"
+  }
+  prop {
+    api_name: "next_enrollment"
+    type: String
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.next_enrollment"
+  }
+  prop {
+    api_name: "operation_authenticate_acquired"
+    type: String
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_authenticate_acquired"
+  }
+  prop {
+    api_name: "operation_authenticate_duration"
+    type: Integer
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_authenticate_duration"
+  }
+  prop {
+    api_name: "operation_authenticate_error"
+    type: Integer
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_authenticate_error"
+  }
+  prop {
+    api_name: "operation_authenticate_fails"
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_authenticate_fails"
+  }
+  prop {
+    api_name: "operation_authenticate_latency"
+    type: IntegerList
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_authenticate_latency"
+  }
+  prop {
+    api_name: "operation_detect_interaction_acquired"
+    type: String
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_acquired"
+  }
+  prop {
+    api_name: "operation_detect_interaction_duration"
+    type: Integer
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_duration"
+  }
+  prop {
+    api_name: "operation_detect_interaction_error"
+    type: Integer
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_error"
+  }
+  prop {
+    api_name: "operation_detect_interaction_latency"
+    type: IntegerList
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_latency"
+  }
+  prop {
+    api_name: "operation_enroll_error"
+    type: Integer
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_enroll_error"
+  }
+  prop {
+    api_name: "operation_enroll_latency"
+    type: IntegerList
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_enroll_latency"
+  }
+  prop {
+    api_name: "sensor_id"
+    type: Integer
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.sensor_id"
+  }
+  prop {
+    api_name: "sensor_location"
+    type: String
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.sensor_location"
+  }
+  prop {
+    api_name: "sensor_strength"
+    type: Integer
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.sensor_strength"
+  }
+  prop {
+    api_name: "type"
+    type: String
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.type"
+    enum_values: "default|rear|udfps|side"
+  }
+}
diff --git a/biometrics/fingerprint/aidl/default/fingerprint-default.rc b/biometrics/fingerprint/aidl/default/fingerprint-default.rc
new file mode 100644
index 0000000..7e46bc1
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/fingerprint-default.rc
@@ -0,0 +1,7 @@
+service vendor.fingerprint-default /vendor/bin/hw/android.hardware.biometrics.fingerprint-service.default default
+    class hal
+    user nobody
+    group nobody
+    interface aidl android.hardware.biometrics.fingerprint.IFingerprint/default
+    oneshot
+    disabled
diff --git a/biometrics/fingerprint/aidl/default/fingerprint-default.xml b/biometrics/fingerprint/aidl/default/fingerprint-default.xml
new file mode 100644
index 0000000..d140459
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/fingerprint-default.xml
@@ -0,0 +1,10 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.biometrics.fingerprint</name>
+        <version>4</version>
+        <interface>
+          <name>IFingerprint</name>
+          <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/biometrics/fingerprint/aidl/default/fingerprint-example.rc b/biometrics/fingerprint/aidl/default/fingerprint-example.rc
deleted file mode 100644
index da4ea45..0000000
--- a/biometrics/fingerprint/aidl/default/fingerprint-example.rc
+++ /dev/null
@@ -1,7 +0,0 @@
-service vendor.fingerprint-example /apex/com.android.hardware.biometrics.fingerprint.virtual/bin/hw/android.hardware.biometrics.fingerprint-service.example
-    class hal
-    user nobody
-    group nobody
-    interface aidl android.hardware.biometrics.fingerprint.IFingerprint/virtual
-    oneshot
-    disabled
diff --git a/biometrics/fingerprint/aidl/default/fingerprint-example.xml b/biometrics/fingerprint/aidl/default/fingerprint-example.xml
deleted file mode 100644
index ee529e9..0000000
--- a/biometrics/fingerprint/aidl/default/fingerprint-example.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<manifest version="1.0" type="device">
-    <hal format="aidl">
-        <name>android.hardware.biometrics.fingerprint</name>
-        <version>5</version>
-        <fqname>IFingerprint/virtual</fqname>
-    </hal>
-</manifest>
diff --git a/biometrics/fingerprint/aidl/default/fingerprint-virtual.rc b/biometrics/fingerprint/aidl/default/fingerprint-virtual.rc
new file mode 100644
index 0000000..5d1506c
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/fingerprint-virtual.rc
@@ -0,0 +1,7 @@
+service fingerprint-virtual /apex/com.android.hardware.biometrics.fingerprint.virtual/bin/hw/android.hardware.biometrics.fingerprint-service.example virtual
+    class hal
+    user nobody
+    group nobody
+    interface aidl android.hardware.biometrics.fingerprint.virtualhal.IVirtualHal/virtual
+    oneshot
+    disabled
diff --git a/biometrics/fingerprint/aidl/default/fingerprint.sysprop b/biometrics/fingerprint/aidl/default/fingerprint.sysprop
index 6a6c297..eb33432 100644
--- a/biometrics/fingerprint/aidl/default/fingerprint.sysprop
+++ b/biometrics/fingerprint/aidl/default/fingerprint.sysprop
@@ -7,7 +7,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.type"
     type: String
-    scope: Internal
+    scope: Public
     access: ReadWrite
     enum_values: "default|rear|udfps|side"
     api_name: "type"
@@ -17,7 +17,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.enrollments"
     type: IntegerList
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "enrollments"
 }
@@ -27,7 +27,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.enrollment_hit"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "enrollment_hit"
 }
@@ -42,7 +42,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.next_enrollment"
     type: String
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "next_enrollment"
 }
@@ -51,7 +51,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.authenticator_id"
     type: Long
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "authenticator_id"
 }
@@ -60,7 +60,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.challenge"
     type: Long
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "challenge"
 }
@@ -69,7 +69,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_authenticate_fails"
     type: Boolean
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_authenticate_fails"
 }
@@ -82,7 +82,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_error"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_detect_interaction_error"
 }
@@ -91,7 +91,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_enroll_error"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_enroll_error"
 }
@@ -104,7 +104,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_authenticate_latency"
     type: IntegerList
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_authenticate_latency"
 }
@@ -114,7 +114,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_latency"
     type: IntegerList
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_detect_interaction_latency"
 }
@@ -124,7 +124,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_enroll_latency"
     type: IntegerList
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_enroll_latency"
 }
@@ -134,7 +134,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_authenticate_duration"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_authenticate_duration"
 }
@@ -143,7 +143,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_authenticate_error"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_authenticate_error"
 }
@@ -153,7 +153,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.sensor_location"
     type: String
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "sensor_location"
 }
@@ -162,7 +162,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_authenticate_acquired"
     type: String
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_authenticate_acquired"
 }
@@ -172,7 +172,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_duration"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_detect_interaction_duration"
 }
@@ -184,7 +184,7 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_acquired"
     type: String
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "operation_detect_interaction_acquired"
 }
@@ -193,7 +193,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.sensor_id"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "sensor_id"
 }
@@ -203,7 +203,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.sensor_strength"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "sensor_strength"
 }
@@ -213,7 +213,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.max_enrollments"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "max_enrollments"
 }
@@ -222,7 +222,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.navigation_guesture"
     type: Boolean
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "navigation_guesture"
 }
@@ -231,7 +231,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.detect_interaction"
     type: Boolean
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "detect_interaction"
 }
@@ -240,7 +240,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.udfps.display_touch"
     type: Boolean
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "display_touch"
 }
@@ -249,7 +249,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.udfps.control_illumination"
     type: Boolean
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "control_illumination"
 }
@@ -258,7 +258,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.lockout"
     type: Boolean
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "lockout"
 }
@@ -267,7 +267,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.lockout_enable"
     type: Boolean
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "lockout_enable"
 }
@@ -276,7 +276,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.lockout_timed_threshold"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "lockout_timed_threshold"
 }
@@ -285,7 +285,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.lockout_timed_duration"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "lockout_timed_duration"
 }
@@ -294,7 +294,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.lockout_permanent_threshold"
     type: Integer
-    scope: Internal
+    scope: Public
     access: ReadWrite
     api_name: "lockout_permanent_threshold"
 }
diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
index 0d53575..362d0df 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
@@ -110,7 +110,7 @@
     std::pair<Error, int32_t> convertError(int32_t code);
     int32_t getRandomInRange(int32_t bound1, int32_t bound2);
     bool checkSensorLockout(ISessionCallback*);
-    void clearLockout(ISessionCallback* cb);
+    void clearLockout(ISessionCallback* cb, bool dueToTimeout = false);
     void waitForFingerDown(ISessionCallback* cb, const std::future<void>& cancel);
 
     FakeLockoutTracker mLockoutTracker;
diff --git a/biometrics/fingerprint/aidl/default/include/FakeLockoutTracker.h b/biometrics/fingerprint/aidl/default/include/FakeLockoutTracker.h
index a1b6128..a7f2f8e 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeLockoutTracker.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeLockoutTracker.h
@@ -24,12 +24,12 @@
 
 class FakeLockoutTracker {
   public:
-    FakeLockoutTracker() : mFailedCount(0) {}
+    FakeLockoutTracker() : mFailedCount(0), mFailedCountTimed(0) {}
     ~FakeLockoutTracker() {}
 
     enum class LockoutMode : int8_t { kNone = 0, kTimed, kPermanent };
 
-    void reset();
+    void reset(bool dueToTimeout = false);
     LockoutMode getMode();
     void addFailedAttempt();
     int64_t getLockoutTimeLeft();
@@ -44,6 +44,7 @@
 
   private:
     int32_t mFailedCount;
+    int32_t mFailedCountTimed;
     int64_t mLockoutTimedStart;
     LockoutMode mCurrentMode;
 };
diff --git a/biometrics/fingerprint/aidl/default/include/VirtualHal.h b/biometrics/fingerprint/aidl/default/include/VirtualHal.h
index e5f62fc..5488383 100644
--- a/biometrics/fingerprint/aidl/default/include/VirtualHal.h
+++ b/biometrics/fingerprint/aidl/default/include/VirtualHal.h
@@ -16,21 +16,21 @@
 
 #pragma once
 
-#include <aidl/android/hardware/biometrics/fingerprint/BnVirtualHal.h>
+#include <aidl/android/hardware/biometrics/fingerprint/virtualhal/BnVirtualHal.h>
 
 #include "Fingerprint.h"
 
 namespace aidl::android::hardware::biometrics::fingerprint {
 
+using namespace virtualhal;
+
 class VirtualHal : public BnVirtualHal {
   public:
-    VirtualHal(Fingerprint* fp) : mFp(fp) {}
+    VirtualHal(std::shared_ptr<Fingerprint> fp) : mFp(fp) {}
 
     ::ndk::ScopedAStatus setEnrollments(const std::vector<int32_t>& in_id) override;
     ::ndk::ScopedAStatus setEnrollmentHit(int32_t in_hit_id) override;
-    ::ndk::ScopedAStatus setNextEnrollment(
-            const ::aidl::android::hardware::biometrics::fingerprint::NextEnrollment&
-                    in_next_enrollment) override;
+    ::ndk::ScopedAStatus setNextEnrollment(const NextEnrollment& in_next_enrollment) override;
     ::ndk::ScopedAStatus setAuthenticatorId(int64_t in_id) override;
     ::ndk::ScopedAStatus setChallenge(int64_t in_challenge) override;
     ::ndk::ScopedAStatus setOperationAuthenticateFails(bool in_fail) override;
@@ -67,12 +67,15 @@
     ::ndk::ScopedAStatus setDetectInteraction(bool in_v) override;
     ::ndk::ScopedAStatus setDisplayTouch(bool in_v) override;
     ::ndk::ScopedAStatus setControlIllumination(bool in_v) override;
+    ::ndk::ScopedAStatus getFingerprintHal(
+            std::shared_ptr<::aidl::android::hardware::biometrics::fingerprint::IFingerprint>*
+                    _aidl_return);
 
   private:
     OptIntVec intVec2OptIntVec(const std::vector<int32_t>& intVec);
     OptIntVec acquiredInfoVec2OptIntVec(const std::vector<AcquiredInfoAndVendorCode>& intVec);
     ::ndk::ScopedAStatus sanityCheckLatency(const std::vector<int32_t>& in_latency);
-    Fingerprint* mFp;
+    std::shared_ptr<Fingerprint> mFp;
 };
 
 }  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/main.cpp b/biometrics/fingerprint/aidl/default/main.cpp
index ba0c8ec..8ca44d6 100644
--- a/biometrics/fingerprint/aidl/default/main.cpp
+++ b/biometrics/fingerprint/aidl/default/main.cpp
@@ -24,21 +24,38 @@
 using aidl::android::hardware::biometrics::fingerprint::Fingerprint;
 using aidl::android::hardware::biometrics::fingerprint::VirtualHal;
 
-int main() {
-    LOG(INFO) << "Fingerprint HAL started";
+int main(int argc, char** argv) {
+    if (argc < 2) {
+        LOG(ERROR) << "Missing argument -> exiting";
+        return EXIT_FAILURE;
+    }
+
+    LOG(INFO) << "Fingerprint HAL started: " << argv[1];
     ABinderProcess_setThreadPoolMaxThreadCount(0);
     std::shared_ptr<Fingerprint> hal = ndk::SharedRefBase::make<Fingerprint>();
-    auto binder = hal->asBinder();
-
-    std::shared_ptr<VirtualHal> hal_ext = ndk::SharedRefBase::make<VirtualHal>(hal.get());
-    auto binder_ext = hal_ext->asBinder();
+    std::shared_ptr<VirtualHal> hal_vhal = ndk::SharedRefBase::make<VirtualHal>(hal);
 
     if (hal->connected()) {
-        CHECK(STATUS_OK == AIBinder_setExtension(binder.get(), binder_ext.get()));
-        const std::string instance = std::string(Fingerprint::descriptor) + "/virtual";
-        binder_status_t status =
-                AServiceManager_registerLazyService(binder.get(), instance.c_str());
-        CHECK_EQ(status, STATUS_OK);
+        if (strcmp(argv[1], "default") == 0) {
+            const std::string instance = std::string(Fingerprint::descriptor) + "/default";
+            auto binder = hal->asBinder();
+            auto binder_ext = hal_vhal->asBinder();
+            CHECK(STATUS_OK == AIBinder_setExtension(binder.get(), binder_ext.get()));
+            binder_status_t status =
+                    AServiceManager_registerLazyService(binder.get(), instance.c_str());
+            CHECK_EQ(status, STATUS_OK);
+            LOG(INFO) << "started IFingerprint/default";
+        } else if (strcmp(argv[1], "virtual") == 0) {
+            const std::string instance = std::string(VirtualHal::descriptor) + "/virtual";
+            auto binder = hal_vhal->asBinder();
+            binder_status_t status =
+                    AServiceManager_registerLazyService(binder.get(), instance.c_str());
+            CHECK_EQ(status, STATUS_OK);
+            LOG(INFO) << "started IVirtualHal/virtual";
+        } else {
+            LOG(ERROR) << "Unexpected argument: " << argv[1];
+            return EXIT_FAILURE;
+        }
         AServiceManager_forceLazyServicesPersist(true);
     } else {
         LOG(ERROR) << "Fingerprint HAL is not connected";
diff --git a/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp
index 3c12b6d..4c1277b 100644
--- a/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp
+++ b/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp
@@ -75,7 +75,7 @@
         prevTimeLeft = currTimeLeft;
     }
     ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
-    mLockoutTracker.reset();
+    mLockoutTracker.reset(true);
 }
 
 TEST_F(FakeLockoutTrackerTest, addFailedAttemptPermanent) {
diff --git a/biometrics/fingerprint/aidl/default/tests/VirtualHalTest.cpp b/biometrics/fingerprint/aidl/default/tests/VirtualHalTest.cpp
index 3fe0b2a..8ffc96b 100644
--- a/biometrics/fingerprint/aidl/default/tests/VirtualHalTest.cpp
+++ b/biometrics/fingerprint/aidl/default/tests/VirtualHalTest.cpp
@@ -35,7 +35,7 @@
   protected:
     void SetUp() override {
         mHal = ndk::SharedRefBase::make<Fingerprint>();
-        mVhal = ndk::SharedRefBase::make<VirtualHal>(mHal.get());
+        mVhal = ndk::SharedRefBase::make<VirtualHal>(mHal);
         ASSERT_TRUE(mVhal != nullptr);
         mHal->resetConfigToDefault();
     }
diff --git a/biometrics/fingerprint/aidl/vts/Android.bp b/biometrics/fingerprint/aidl/vts/Android.bp
index fc32fe6..628f03f 100644
--- a/biometrics/fingerprint/aidl/vts/Android.bp
+++ b/biometrics/fingerprint/aidl/vts/Android.bp
@@ -16,8 +16,8 @@
     ],
     srcs: ["VtsHalBiometricsFingerprintTargetTest.cpp"],
     static_libs: [
-        "android.hardware.biometrics.common-V3-ndk",
-        "android.hardware.biometrics.fingerprint-V3-ndk",
+        "android.hardware.biometrics.common-V4-ndk",
+        "android.hardware.biometrics.fingerprint-V4-ndk",
         "android.hardware.keymaster-V4-ndk",
     ],
     shared_libs: [
diff --git a/bluetooth/1.0/vts/functional/Android.bp b/bluetooth/1.0/vts/functional/Android.bp
index 7d76b89..e68df09 100644
--- a/bluetooth/1.0/vts/functional/Android.bp
+++ b/bluetooth/1.0/vts/functional/Android.bp
@@ -30,7 +30,6 @@
     srcs: ["VtsHalBluetoothV1_0TargetTest.cpp"],
     static_libs: [
         "android.hardware.bluetooth@1.0",
-        "libbluetooth-types",
     ],
     test_config: "VtsHalBluetoothV1_0TargetTest.xml",
     test_suites: [
diff --git a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp
index 82dda61..d0edfad 100644
--- a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp
+++ b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp
@@ -20,7 +20,6 @@
 #include <android/hardware/bluetooth/1.0/IBluetoothHci.h>
 #include <android/hardware/bluetooth/1.0/IBluetoothHciCallbacks.h>
 #include <android/hardware/bluetooth/1.0/types.h>
-#include <hardware/bluetooth.h>
 #include <utils/Log.h>
 
 #include <VtsHalHidlTargetCallbackBase.h>
diff --git a/bluetooth/1.1/vts/functional/Android.bp b/bluetooth/1.1/vts/functional/Android.bp
index 6b3a3e7..27d50f5 100644
--- a/bluetooth/1.1/vts/functional/Android.bp
+++ b/bluetooth/1.1/vts/functional/Android.bp
@@ -31,7 +31,6 @@
     static_libs: [
         "android.hardware.bluetooth@1.1",
         "android.hardware.bluetooth@1.0",
-        "libbluetooth-types",
     ],
     test_config: "VtsHalBluetoothV1_1TargetTest.xml",
     test_suites: ["general-tests", "vts"],
diff --git a/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.cpp b/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.cpp
index 687765f..37b41c6 100644
--- a/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.cpp
+++ b/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.cpp
@@ -20,7 +20,6 @@
 #include <android/hardware/bluetooth/1.0/types.h>
 #include <android/hardware/bluetooth/1.1/IBluetoothHci.h>
 #include <android/hardware/bluetooth/1.1/IBluetoothHciCallbacks.h>
-#include <hardware/bluetooth.h>
 #include <utils/Log.h>
 
 #include <VtsHalHidlTargetCallbackBase.h>
diff --git a/bluetooth/aidl/Android.bp b/bluetooth/aidl/Android.bp
index c6a592f..721be73 100644
--- a/bluetooth/aidl/Android.bp
+++ b/bluetooth/aidl/Android.bp
@@ -23,6 +23,9 @@
             // translate code.
             enabled: true,
         },
+        rust: {
+            enabled: true,
+        },
         java: {
             sdk_version: "module_current",
         },
diff --git a/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp b/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp
index 4d90058..51931e7 100644
--- a/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp
+++ b/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp
@@ -397,12 +397,18 @@
   while (!event_queue.empty()) {
     std::vector<uint8_t> event;
     event_queue.front(event);
-    auto complete_view = ::bluetooth::hci::CommandCompleteView::Create(
+
+    auto event_view =
         ::bluetooth::hci::EventView::Create(::bluetooth::hci::PacketView<true>(
-            std::make_shared<std::vector<uint8_t>>(event))));
-    auto status_view = ::bluetooth::hci::CommandCompleteView::Create(
-        ::bluetooth::hci::EventView::Create(::bluetooth::hci::PacketView<true>(
-            std::make_shared<std::vector<uint8_t>>(event))));
+            std::make_shared<std::vector<uint8_t>>(event)));
+    if (!event_view.IsValid()) {
+      break;
+    }
+
+    auto status_view = ::bluetooth::hci::CommandStatusView::Create(event_view);
+    auto complete_view =
+        ::bluetooth::hci::CommandCompleteView::Create(event_view);
+
     bool is_complete_no_op =
         complete_view.IsValid() &&
         complete_view.GetCommandOpCode() == ::bluetooth::hci::OpCode::NONE;
diff --git a/bluetooth/audio/aidl/Android.bp b/bluetooth/audio/aidl/Android.bp
index ae55fa9..dbff368 100644
--- a/bluetooth/audio/aidl/Android.bp
+++ b/bluetooth/audio/aidl/Android.bp
@@ -38,6 +38,9 @@
         cpp: {
             enabled: false,
         },
+        rust: {
+            enabled: true,
+        },
         java: {
             sdk_version: "module_current",
             enabled: false,
@@ -86,7 +89,6 @@
 
     ],
     frozen: false,
-
 }
 
 // Note: This should always be one version ahead of the last frozen version
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/BroadcastCapability.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/BroadcastCapability.aidl
index 58710ef..2872362 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/BroadcastCapability.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/BroadcastCapability.aidl
@@ -38,6 +38,7 @@
   android.hardware.bluetooth.audio.AudioLocation supportedChannel;
   int channelCountPerStream;
   android.hardware.bluetooth.audio.BroadcastCapability.LeAudioCodecCapabilities leAudioCodecCapabilities;
+  @nullable android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv.AudioChannelAllocation audioLocation;
   @VintfStability
   parcelable VendorCapabilities {
     ParcelableHolder extension;
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecSpecificCapabilitiesLtv.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecSpecificCapabilitiesLtv.aidl
index 60c276b..93c3d8c 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecSpecificCapabilitiesLtv.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecSpecificCapabilitiesLtv.aidl
@@ -59,8 +59,10 @@
     int bitmask;
     const int US7500 = 0x01;
     const int US10000 = 0x02;
+    const int US20000 = 0x04;
     const int US7500PREFERRED = 0x10;
     const int US10000PREFERRED = 0x20;
+    const int US20000PREFERRED = 0x40;
   }
   parcelable SupportedAudioChannelCounts {
     int bitmask;
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl
index 943d396..97fcd1f 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl
@@ -59,6 +59,7 @@
   enum FrameDuration {
     US7500 = 0x00,
     US10000 = 0x01,
+    US20000 = 0x02,
   }
   parcelable AudioChannelAllocation {
     int bitmask;
@@ -91,6 +92,7 @@
     const int FRONT_RIGHT_WIDE = 0x02000000;
     const int LEFT_SURROUND = 0x04000000;
     const int RIGHT_SURROUND = 0x08000000;
+    const int MONO = 0x00000000;
   }
   parcelable OctetsPerCodecFrame {
     int value;
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioCodecConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioCodecConfiguration.aidl
index 031ee67..0613f6c 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioCodecConfiguration.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioCodecConfiguration.aidl
@@ -37,6 +37,7 @@
   android.hardware.bluetooth.audio.Lc3Configuration lc3Config;
   android.hardware.bluetooth.audio.LeAudioCodecConfiguration.VendorConfiguration vendorConfig;
   android.hardware.bluetooth.audio.AptxAdaptiveLeConfiguration aptxAdaptiveLeConfig;
+  android.hardware.bluetooth.audio.OpusConfiguration opusConfig;
   @VintfStability
   parcelable VendorConfiguration {
     ParcelableHolder extension;
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/UnicastCapability.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/UnicastCapability.aidl
index 894a2f3..6ed0e56 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/UnicastCapability.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/UnicastCapability.aidl
@@ -39,6 +39,7 @@
   int deviceCount;
   int channelCountPerDevice;
   android.hardware.bluetooth.audio.UnicastCapability.LeAudioCodecCapabilities leAudioCodecCapabilities;
+  @nullable android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv.AudioChannelAllocation audioLocation;
   @VintfStability
   parcelable VendorCapabilities {
     ParcelableHolder extension;
@@ -48,5 +49,6 @@
     android.hardware.bluetooth.audio.Lc3Capabilities lc3Capabilities;
     android.hardware.bluetooth.audio.UnicastCapability.VendorCapabilities vendorCapabillities;
     android.hardware.bluetooth.audio.AptxAdaptiveLeCapabilities aptxAdaptiveLeCapabilities;
+    android.hardware.bluetooth.audio.OpusCapabilities opusCapabilities;
   }
 }
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/BroadcastCapability.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/BroadcastCapability.aidl
index f1301fb..db3c10e 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/BroadcastCapability.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/BroadcastCapability.aidl
@@ -17,6 +17,7 @@
 package android.hardware.bluetooth.audio;
 
 import android.hardware.bluetooth.audio.AudioLocation;
+import android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv.AudioChannelAllocation;
 import android.hardware.bluetooth.audio.CodecType;
 import android.hardware.bluetooth.audio.Lc3Capabilities;
 
@@ -35,8 +36,11 @@
         @nullable VendorCapabilities[] vendorCapabillities;
     }
     CodecType codecType;
+    // @deprecated use audioLocation if present.
     AudioLocation supportedChannel;
     // Supported channel count for each stream
     int channelCountPerStream;
     LeAudioCodecCapabilities leAudioCodecCapabilities;
+    // The new audio location type, replacing supportedChannel
+    @nullable AudioChannelAllocation audioLocation;
 }
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecSpecificCapabilitiesLtv.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecSpecificCapabilitiesLtv.aidl
index fa302e3..94f0544 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecSpecificCapabilitiesLtv.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecSpecificCapabilitiesLtv.aidl
@@ -50,9 +50,11 @@
     parcelable SupportedFrameDurations {
         const int US7500 = 0x01;
         const int US10000 = 0x02;
+        const int US20000 = 0x04;
         /* Bits 2-3 are RFU */
         const int US7500PREFERRED = 0x10;
         const int US10000PREFERRED = 0x20;
+        const int US20000PREFERRED = 0x40;
 
         /* 8 bit wide bit mask */
         int bitmask;
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl
index c099ebe..2835325 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl
@@ -43,9 +43,11 @@
     enum FrameDuration {
         US7500 = 0x00,
         US10000 = 0x01,
+        US20000 = 0x02,
     }
 
     parcelable AudioChannelAllocation {
+        // @deprecated use MONO instead.
         const int NOT_ALLOWED = 0x00000000;
         const int FRONT_LEFT = 0x00000001;
         const int FRONT_RIGHT = 0x00000002;
@@ -75,6 +77,7 @@
         const int FRONT_RIGHT_WIDE = 0x02000000;
         const int LEFT_SURROUND = 0x04000000;
         const int RIGHT_SURROUND = 0x08000000;
+        const int MONO = 0x00000000;
 
         // Bit mask of Audio Locations
         int bitmask;
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioCodecConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioCodecConfiguration.aidl
index 7ce6ff3..20e6c0c 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioCodecConfiguration.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioCodecConfiguration.aidl
@@ -16,8 +16,9 @@
 
 package android.hardware.bluetooth.audio;
 
-import android.hardware.bluetooth.audio.Lc3Configuration;
 import android.hardware.bluetooth.audio.AptxAdaptiveLeConfiguration;
+import android.hardware.bluetooth.audio.Lc3Configuration;
+import android.hardware.bluetooth.audio.OpusConfiguration;
 
 @VintfStability
 union LeAudioCodecConfiguration {
@@ -28,4 +29,5 @@
     Lc3Configuration lc3Config;
     VendorConfiguration vendorConfig;
     AptxAdaptiveLeConfiguration aptxAdaptiveLeConfig;
+    OpusConfiguration opusConfig;
 }
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/UnicastCapability.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/UnicastCapability.aidl
index 07688a7..9f33672 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/UnicastCapability.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/UnicastCapability.aidl
@@ -16,10 +16,12 @@
 
 package android.hardware.bluetooth.audio;
 
+import android.hardware.bluetooth.audio.AptxAdaptiveLeCapabilities;
 import android.hardware.bluetooth.audio.AudioLocation;
+import android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv.AudioChannelAllocation;
 import android.hardware.bluetooth.audio.CodecType;
 import android.hardware.bluetooth.audio.Lc3Capabilities;
-import android.hardware.bluetooth.audio.AptxAdaptiveLeCapabilities;
+import android.hardware.bluetooth.audio.OpusCapabilities;
 
 /**
  * Used to specify the le audio unicast codec capabilities for hardware offload.
@@ -35,12 +37,16 @@
         Lc3Capabilities lc3Capabilities;
         VendorCapabilities vendorCapabillities;
         AptxAdaptiveLeCapabilities aptxAdaptiveLeCapabilities;
+        OpusCapabilities opusCapabilities;
     }
     CodecType codecType;
+    // @deprecated use audioLocation if present.
     AudioLocation supportedChannel;
     // The number of connected device
     int deviceCount;
     // Supported channel count for each device
     int channelCountPerDevice;
     LeAudioCodecCapabilities leAudioCodecCapabilities;
+    // The new audio location type, replacing supportedChannel
+    @nullable AudioChannelAllocation audioLocation;
 }
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
index 61c29d3..18fc4b2 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
@@ -82,6 +82,8 @@
          CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US7500},
         {CodecSpecificConfigurationLtv::FrameDuration::US10000,
          CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US10000},
+        {CodecSpecificConfigurationLtv::FrameDuration::US20000,
+         CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US20000},
 };
 
 std::map<int32_t, CodecSpecificConfigurationLtv::SamplingFrequency>
@@ -532,7 +534,8 @@
         direction_configurations,
     const std::vector<std::optional<AseDirectionRequirement>>& requirements,
     std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
-        valid_direction_configurations) {
+        valid_direction_configurations,
+    bool isExact) {
   if (!direction_configurations.has_value()) return;
 
   if (!valid_direction_configurations.has_value()) {
@@ -540,55 +543,93 @@
         std::vector<std::optional<AseDirectionConfiguration>>();
   }
 
-  // Exact matching process
-  // Need to respect the number of device
-  for (int i = 0; i < requirements.size(); ++i) {
-    auto requirement = requirements[i];
-    auto direction_configuration = direction_configurations.value()[i];
-    if (!direction_configuration.has_value()) {
-      valid_direction_configurations = std::nullopt;
-      return;
-    }
-    auto cfg = direction_configuration.value();
-    if (!filterMatchedAseConfiguration(cfg.aseConfiguration,
-                                       requirement.value().aseConfiguration)) {
-      valid_direction_configurations = std::nullopt;
-      return;  // No way to match
-    }
-    // For exact match, we require this direction to have the same allocation.
-    // If stereo, need stereo.
-    // If mono, need mono (modified to the correct required allocation)
-    auto req_allocation_bitmask = getLeAudioAseConfigurationAllocationBitmask(
-        requirement.value().aseConfiguration);
-    int req_channel_count = getCountFromBitmask(req_allocation_bitmask);
-    int cfg_bitmask =
-        getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration);
-    int cfg_channel_count = getCountFromBitmask(cfg_bitmask);
-    if (req_channel_count <= 1) {
-      // MONO case, is a match if also mono, modify to the same allocation
-      if (cfg_channel_count > 1) {
+  if (isExact) {
+    // Exact matching process
+    // Need to respect the number of device
+    for (int i = 0; i < requirements.size(); ++i) {
+      auto requirement = requirements[i];
+      auto direction_configuration = direction_configurations.value()[i];
+      if (!direction_configuration.has_value()) {
         valid_direction_configurations = std::nullopt;
-        return;  // Not a match
+        return;
       }
-      // Modify the bitmask to be the same as the requirement
-      for (auto& codec_cfg : cfg.aseConfiguration.codecConfiguration) {
-        if (codec_cfg.getTag() ==
-            CodecSpecificConfigurationLtv::Tag::audioChannelAllocation) {
-          codec_cfg
-              .get<CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>()
-              .bitmask = req_allocation_bitmask;
-          break;
+      auto cfg = direction_configuration.value();
+      if (!filterMatchedAseConfiguration(
+              cfg.aseConfiguration, requirement.value().aseConfiguration)) {
+        valid_direction_configurations = std::nullopt;
+        return;  // No way to match
+      }
+      // For exact match, we require this direction to have the same allocation.
+      // If stereo, need stereo.
+      // If mono, need mono (modified to the correct required allocation)
+      auto req_allocation_bitmask = getLeAudioAseConfigurationAllocationBitmask(
+          requirement.value().aseConfiguration);
+      int req_channel_count = getCountFromBitmask(req_allocation_bitmask);
+      int cfg_bitmask =
+          getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration);
+      int cfg_channel_count = getCountFromBitmask(cfg_bitmask);
+      if (req_channel_count <= 1) {
+        // MONO case, is a match if also mono, modify to the same allocation
+        if (cfg_channel_count > 1) {
+          valid_direction_configurations = std::nullopt;
+          return;  // Not a match
+        }
+        // Modify the bitmask to be the same as the requirement
+        for (auto& codec_cfg : cfg.aseConfiguration.codecConfiguration) {
+          if (codec_cfg.getTag() ==
+              CodecSpecificConfigurationLtv::Tag::audioChannelAllocation) {
+            codec_cfg
+                .get<CodecSpecificConfigurationLtv::Tag::
+                         audioChannelAllocation>()
+                .bitmask = req_allocation_bitmask;
+            break;
+          }
+        }
+      } else {
+        // STEREO case, is a match if same allocation
+        if (req_allocation_bitmask != cfg_bitmask) {
+          valid_direction_configurations = std::nullopt;
+          return;  // Not a match
         }
       }
-    } else {
-      // STEREO case, is a match if same allocation
-      if (req_allocation_bitmask != cfg_bitmask) {
+      // Push to list if valid
+      valid_direction_configurations.value().push_back(cfg);
+    }
+  } else {
+    // Loose matching process
+    for (auto& requirement : requirements) {
+      if (!requirement.has_value()) continue;
+      auto req_allocation_bitmask = getLeAudioAseConfigurationAllocationBitmask(
+          requirement.value().aseConfiguration);
+      auto req_channel_count = getCountFromBitmask(req_allocation_bitmask);
+
+      auto temp = std::vector<AseDirectionConfiguration>();
+
+      for (auto direction_configuration : direction_configurations.value()) {
+        if (!direction_configuration.has_value()) continue;
+        if (!filterMatchedAseConfiguration(
+                direction_configuration.value().aseConfiguration,
+                requirement.value().aseConfiguration))
+          continue;
+        // Valid if match any requirement.
+        temp.push_back(direction_configuration.value());
+      }
+
+      // Get the best matching config based on channel allocation
+      auto total_cfg_channel_count = 0;
+      auto req_valid_configs = getValidConfigurationsFromAllocation(
+          req_allocation_bitmask, temp, isExact);
+      // Count and check required channel counts
+      for (auto& cfg : req_valid_configs) {
+        total_cfg_channel_count += getCountFromBitmask(
+            getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration));
+        valid_direction_configurations.value().push_back(cfg);
+      }
+      if (total_cfg_channel_count != req_channel_count) {
         valid_direction_configurations = std::nullopt;
-        return;  // Not a match
+        return;
       }
     }
-    // Push to list if valid
-    valid_direction_configurations.value().push_back(cfg);
   }
 }
 
@@ -648,8 +689,8 @@
 std::optional<LeAudioAseConfigurationSetting>
 LeAudioOffloadAudioProvider::getRequirementMatchedAseConfigurationSettings(
     IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
-    const IBluetoothAudioProvider::LeAudioConfigurationRequirement&
-        requirement) {
+    const IBluetoothAudioProvider::LeAudioConfigurationRequirement& requirement,
+    bool isExact) {
   // Create a new LeAudioAseConfigurationSetting to return
   // Make context the same as the requirement
   LeAudioAseConfigurationSetting filtered_setting{
@@ -662,25 +703,27 @@
   // is the number of device.
 
   // The exact matching process is as follow:
-  // 1. Setting direction has the same number of cfg (ignore when null require)
+  // 1. Setting direction has the same number of cfg (ignore when null
+  // require)
   // 2. For each index, it's a 1-1 filter / mapping.
+  if (isExact) {
+    if (requirement.sinkAseRequirement.has_value() &&
+        requirement.sinkAseRequirement.value().size() !=
+            setting.sinkAseConfiguration.value().size()) {
+      return std::nullopt;
+    }
 
-  if (requirement.sinkAseRequirement.has_value() &&
-      requirement.sinkAseRequirement.value().size() !=
-          setting.sinkAseConfiguration.value().size()) {
-    return std::nullopt;
-  }
-
-  if (requirement.sourceAseRequirement.has_value() &&
-      requirement.sourceAseRequirement.value().size() !=
-          setting.sourceAseConfiguration.value().size()) {
-    return std::nullopt;
+    if (requirement.sourceAseRequirement.has_value() &&
+        requirement.sourceAseRequirement.value().size() !=
+            setting.sourceAseConfiguration.value().size()) {
+      return std::nullopt;
+    }
   }
 
   if (requirement.sinkAseRequirement.has_value()) {
     filterRequirementAseDirectionConfiguration(
         setting.sinkAseConfiguration, requirement.sinkAseRequirement.value(),
-        filtered_setting.sinkAseConfiguration);
+        filtered_setting.sinkAseConfiguration, isExact);
     if (!filtered_setting.sinkAseConfiguration.has_value()) {
       return std::nullopt;
     }
@@ -690,7 +733,7 @@
     filterRequirementAseDirectionConfiguration(
         setting.sourceAseConfiguration,
         requirement.sourceAseRequirement.value(),
-        filtered_setting.sourceAseConfiguration);
+        filtered_setting.sourceAseConfiguration, isExact);
     if (!filtered_setting.sourceAseConfiguration.has_value()) {
       return std::nullopt;
     }
@@ -704,9 +747,10 @@
     std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>&
         matched_ase_configuration_settings,
     const IBluetoothAudioProvider::LeAudioConfigurationRequirement& requirement,
-    bool isMatchContext) {
+    bool isMatchContext, bool isExact) {
   LOG(INFO) << __func__ << ": Trying to match for the requirement "
-            << requirement.toString() << ", match context = " << isMatchContext;
+            << requirement.toString() << ", match context = " << isMatchContext
+            << ", match exact = " << isExact;
   for (auto& setting : matched_ase_configuration_settings) {
     // Try to match context in metadata.
     if (isMatchContext) {
@@ -718,7 +762,8 @@
     }
 
     auto filtered_ase_configuration_setting =
-        getRequirementMatchedAseConfigurationSettings(setting, requirement);
+        getRequirementMatchedAseConfigurationSettings(setting, requirement,
+                                                      isExact);
     if (filtered_ase_configuration_setting.has_value()) {
       LOG(INFO) << __func__ << ": Result found: "
                 << getSettingOutputString(
@@ -768,7 +813,7 @@
   // A setting must match both source and sink.
   // First filter all setting matched with sink capability
   if (in_remoteSinkAudioCapabilities.has_value()) {
-    for (auto& setting : ase_configuration_settings)
+    for (auto& setting : ase_configuration_settings) {
       for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
         if (!capability.has_value()) continue;
         auto filtered_ase_configuration_setting =
@@ -779,6 +824,7 @@
               filtered_ase_configuration_setting.value());
         }
       }
+    }
   } else {
     sink_matched_ase_configuration_settings = ase_configuration_settings;
   }
@@ -808,27 +854,30 @@
 
     // Matching priority list:
     // Preferred context - exact match with allocation
+    // Preferred context - loose match with allocation
     // Any context - exact match with allocation
-
-    auto matched_setting_with_context = matchWithRequirement(
-        matched_ase_configuration_settings, requirement, true);
-    if (matched_setting_with_context.has_value()) {
-      result.push_back(matched_setting_with_context.value());
-    } else {
-      auto matched_setting = matchWithRequirement(
-          matched_ase_configuration_settings, requirement, false);
-      if (matched_setting.has_value()) {
-        result.push_back(matched_setting.value());
-      } else {
-        // Cannot find a match for this requirement
-        // Immediately return
-        LOG(ERROR)
-            << __func__
-            << ": Cannot find any match for this requirement, exitting...";
-        result.clear();
-        *_aidl_return = result;
-        return ndk::ScopedAStatus::ok();
+    // Any context - loose match with allocation
+    bool found = false;
+    for (bool match_context : {true, false}) {
+      for (bool match_exact : {true, false}) {
+        auto matched_setting =
+            matchWithRequirement(matched_ase_configuration_settings,
+                                 requirement, match_context, match_exact);
+        if (matched_setting.has_value()) {
+          result.push_back(matched_setting.value());
+          found = true;
+          break;
+        }
       }
+      if (found) break;
+    }
+
+    if (!found) {
+      LOG(ERROR) << __func__
+                 << ": Cannot find any match for this requirement, exitting...";
+      result.clear();
+      *_aidl_return = result;
+      return ndk::ScopedAStatus::ok();
     }
   }
 
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
index 798f183..3a82b73 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
@@ -139,7 +139,8 @@
           direction_configurations,
       const std::vector<std::optional<AseDirectionRequirement>>& requirements,
       std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
-          valid_direction_configurations);
+          valid_direction_configurations,
+      bool isExact);
   std::optional<LeAudioAseConfigurationSetting>
   getCapabilitiesMatchedAseConfigurationSettings(
       IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
@@ -149,7 +150,8 @@
   getRequirementMatchedAseConfigurationSettings(
       IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
       const IBluetoothAudioProvider::LeAudioConfigurationRequirement&
-          requirement);
+          requirement,
+      bool isExact);
   bool isMatchedQosRequirement(LeAudioAseQosConfiguration setting_qos,
                                AseQosDirectionRequirement requirement_qos);
   std::optional<LeAudioBroadcastConfigurationSetting>
@@ -173,7 +175,7 @@
           matched_ase_configuration_settings,
       const IBluetoothAudioProvider::LeAudioConfigurationRequirement&
           requirements,
-      bool isMatchContext);
+      bool isMatchContext, bool isExact);
 };
 
 class LeAudioOffloadOutputAudioProvider : public LeAudioOffloadAudioProvider {
diff --git a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
index 4481238..a52d761 100644
--- a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
+++ b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
@@ -2375,6 +2375,43 @@
     return capability;
   }
 
+  LeAudioDeviceCapabilities GetOpusRemoteSinkCapability() {
+    // Create a capability specifically for vendor OPUS
+    LeAudioDeviceCapabilities capability;
+
+    auto vendor_codec = CodecId::Vendor();
+    vendor_codec.codecId = 255;
+    vendor_codec.id = 224;
+    capability.codecId = vendor_codec;
+
+    auto pref_context_metadata = MetadataLtv::PreferredAudioContexts();
+    pref_context_metadata.values =
+        GetAudioContext(AudioContext::MEDIA | AudioContext::CONVERSATIONAL |
+                        AudioContext::GAME);
+    capability.metadata = {pref_context_metadata};
+
+    auto sampling_rate =
+        CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies();
+    sampling_rate.bitmask =
+        CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ16000 |
+        CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ8000 |
+        CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ48000;
+    auto frame_duration =
+        CodecSpecificCapabilitiesLtv::SupportedFrameDurations();
+    frame_duration.bitmask =
+        CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US7500 |
+        CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US10000 |
+        CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US20000;
+    auto octets = CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame();
+    octets.min = 0;
+    octets.max = 240;
+    auto frames = CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU();
+    frames.value = 2;
+    capability.codecSpecificCapabilities = {sampling_rate, frame_duration,
+                                            octets, frames};
+    return capability;
+  }
+
   LeAudioDeviceCapabilities GetDefaultRemoteSourceCapability() {
     // Create a capability
     LeAudioDeviceCapabilities capability;
@@ -2745,6 +2782,41 @@
     return requirement;
   }
 
+  LeAudioConfigurationRequirement GetOpusUnicastRequirement(
+      int32_t context_bits, bool is_sink_requirement,
+      bool is_source_requriement,
+      CodecSpecificConfigurationLtv::SamplingFrequency freq =
+          CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000) {
+    // Create a requirements
+    LeAudioConfigurationRequirement requirement;
+    requirement.audioContext = GetAudioContext(context_bits);
+
+    auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+    allocation.bitmask =
+        CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+        CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
+    auto direction_ase_requriement = AseDirectionRequirement();
+    auto vendor_codec = CodecId::Vendor();
+    vendor_codec.codecId = 255;
+    vendor_codec.id = 224;
+    direction_ase_requriement.aseConfiguration.codecId = vendor_codec;
+    direction_ase_requriement.aseConfiguration.targetLatency =
+        LeAudioAseConfiguration::TargetLatency::HIGHER_RELIABILITY;
+
+    direction_ase_requriement.aseConfiguration.codecConfiguration = {
+        freq, CodecSpecificConfigurationLtv::FrameDuration::US20000, allocation
+
+    };
+    if (is_sink_requirement)
+      requirement.sinkAseRequirement = {direction_ase_requriement};
+
+    if (is_source_requriement)
+      requirement.sourceAseRequirement = {direction_ase_requriement};
+
+    return requirement;
+  }
+
   LeAudioConfigurationRequirement GetUnicastGameRequirement(bool asymmetric) {
     // Create a requirements
     LeAudioConfigurationRequirement requirement;
@@ -3172,6 +3244,31 @@
 }
 
 TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+       GetOpusAseConfiguration) {
+  if (GetProviderFactoryInterfaceVersion() <
+      BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+    GTEST_SKIP();
+  }
+
+  std::vector<std::optional<LeAudioDeviceCapabilities>> sink_capabilities = {
+      GetOpusRemoteSinkCapability()};
+  std::vector<std::optional<LeAudioDeviceCapabilities>> source_capabilities = {
+      GetDefaultRemoteSourceCapability()};
+
+  std::vector<LeAudioAseConfigurationSetting> configurations;
+  std::vector<LeAudioConfigurationRequirement> sink_requirements = {
+      GetOpusUnicastRequirement(AudioContext::MEDIA, true /* sink */,
+                                false /* source */)};
+  auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      sink_capabilities, std::nullopt, sink_requirements, &configurations);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  if (!configurations.empty()) {
+    VerifyIfRequirementsSatisfied(sink_requirements, configurations);
+  }
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
        GetAseConfiguration_Multidirectional) {
   if (GetProviderFactoryInterfaceVersion() <
       BluetoothAudioHalVersion::VERSION_AIDL_V4) {
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index d931c4d..d4968a8 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -90,13 +90,15 @@
 
 cc_test {
     name: "BluetoothLeAudioCodecsProviderTest",
-    defaults: [
-        "latest_android_hardware_bluetooth_audio_ndk_shared",
-    ],
     srcs: [
         "aidl_session/BluetoothLeAudioCodecsProvider.cpp",
         "aidl_session/BluetoothLeAudioCodecsProviderTest.cpp",
     ],
+    defaults: [
+        "latest_android_hardware_audio_common_ndk_static",
+        "latest_android_hardware_bluetooth_audio_ndk_static",
+        "latest_android_media_audio_common_types_ndk_static",
+    ],
     header_libs: [
         "libxsdc-utils",
     ],
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp
index 37812fa..07e4997 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp
@@ -92,9 +92,10 @@
 /* Frame Durations */
 constexpr uint8_t kLeAudioCodecFrameDur7500us = 0x00;
 constexpr uint8_t kLeAudioCodecFrameDur10000us = 0x01;
+constexpr uint8_t kLeAudioCodecFrameDur20000us = 0x02;
 
 /* Audio Allocations */
-constexpr uint32_t kLeAudioLocationNotAllowed = 0x00000000;
+constexpr uint32_t kLeAudioLocationMonoAudio = 0x00000000;
 constexpr uint32_t kLeAudioLocationFrontLeft = 0x00000001;
 constexpr uint32_t kLeAudioLocationFrontRight = 0x00000002;
 constexpr uint32_t kLeAudioLocationFrontCenter = 0x00000004;
@@ -171,12 +172,14 @@
         {kLeAudioCodecFrameDur7500us,
          CodecSpecificConfigurationLtv::FrameDuration::US7500},
         {kLeAudioCodecFrameDur10000us,
-         CodecSpecificConfigurationLtv::FrameDuration::US10000}};
+         CodecSpecificConfigurationLtv::FrameDuration::US10000},
+        {kLeAudioCodecFrameDur20000us,
+         CodecSpecificConfigurationLtv::FrameDuration::US20000}};
 
 /* Helper map for matching various audio channel allocation notations */
 std::map<uint32_t, uint32_t> audio_channel_allocation_map = {
-    {kLeAudioLocationNotAllowed,
-     CodecSpecificConfigurationLtv::AudioChannelAllocation::NOT_ALLOWED},
+    {kLeAudioLocationMonoAudio,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::MONO},
     {kLeAudioLocationFrontLeft,
      CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT},
     {kLeAudioLocationFrontRight,
@@ -487,6 +490,9 @@
       case CodecSpecificConfigurationLtv::FrameDuration::US10000:
         qos.sduIntervalUs = 10000;
         break;
+      case CodecSpecificConfigurationLtv::FrameDuration::US20000:
+        qos.sduIntervalUs = 20000;
+        break;
     }
     qos.sduIntervalUs *= frameBlockValue;
   }
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
index 473777c..59c43a4 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
@@ -119,19 +119,36 @@
     // Mapping octetsPerCodecFrame to bitdepth for easier comparison.
     transport.bitdepth.push_back(codec_config.getOctetsPerCodecFrame());
     transport.frameDurationUs.push_back(codec_config.getFrameDurationUs());
-    switch (strategy_config.getAudioLocation()) {
-      case setting::AudioLocation::MONO:
+    if (strategy_config.hasAudioLocation()) {
+      switch (strategy_config.getAudioLocation()) {
+        case setting::AudioLocation::MONO:
+          if (strategy_config_channel_count == 1)
+            transport.channelMode.push_back(ChannelMode::MONO);
+          else
+            transport.channelMode.push_back(ChannelMode::DUALMONO);
+          break;
+        case setting::AudioLocation::STEREO:
+          transport.channelMode.push_back(ChannelMode::STEREO);
+          break;
+        default:
+          transport.channelMode.push_back(ChannelMode::UNKNOWN);
+          break;
+      }
+    } else if (strategy_config.hasAudioChannelAllocation()) {
+      auto count =
+          std::bitset<32>(strategy_config.getAudioChannelAllocation()).count();
+      if (count <= 1) {
         if (strategy_config_channel_count == 1)
           transport.channelMode.push_back(ChannelMode::MONO);
         else
           transport.channelMode.push_back(ChannelMode::DUALMONO);
-        break;
-      case setting::AudioLocation::STEREO:
+      } else if (count == 2) {
         transport.channelMode.push_back(ChannelMode::STEREO);
-        break;
-      default:
+      } else {
         transport.channelMode.push_back(ChannelMode::UNKNOWN);
-        break;
+      }
+    } else {
+      transport.channelMode.push_back(ChannelMode::UNKNOWN);
     }
   }
 
@@ -336,8 +353,12 @@
   for (const auto& scenario : supported_scenarios) {
     UnicastCapability unicast_encode_capability =
         GetUnicastCapability(scenario.getEncode());
+    LOG(INFO) << __func__ << ": Unicast capability encode = "
+              << unicast_encode_capability.toString();
     UnicastCapability unicast_decode_capability =
         GetUnicastCapability(scenario.getDecode());
+    LOG(INFO) << __func__ << ": Unicast capability decode = "
+              << unicast_decode_capability.toString();
     BroadcastCapability broadcast_capability = {.codecType =
                                                     CodecType::UNKNOWN};
 
@@ -384,22 +405,36 @@
     return {.codecType = CodecType::UNKNOWN};
   }
 
+  // Populate audio location
+  AudioLocation audio_location = AudioLocation::UNKNOWN;
+  if (strategy_configuration_iter->second.hasAudioLocation()) {
+    audio_location = GetAudioLocation(
+        strategy_configuration_iter->second.getAudioLocation());
+  }
+
+  // Populate audio channel allocation
+  std::optional<CodecSpecificConfigurationLtv::AudioChannelAllocation>
+      audio_channel_allocation = std::nullopt;
+  if (strategy_configuration_iter->second.hasAudioChannelAllocation()) {
+    LOG(INFO) << __func__ << ": has allocation";
+    CodecSpecificConfigurationLtv::AudioChannelAllocation tmp;
+    tmp.bitmask =
+        strategy_configuration_iter->second.getAudioChannelAllocation();
+    audio_channel_allocation = tmp;
+  }
+
   CodecType codec_type =
       GetCodecType(codec_configuration_iter->second.getCodec());
   if (codec_type == CodecType::LC3) {
     return ComposeUnicastCapability(
-        codec_type,
-        GetAudioLocation(
-            strategy_configuration_iter->second.getAudioLocation()),
+        codec_type, audio_location, audio_channel_allocation,
         strategy_configuration_iter->second.getConnectedDevice(),
         strategy_configuration_iter->second.getChannelCount(),
         ComposeLc3Capability(codec_configuration_iter->second));
   } else if (codec_type == CodecType::APTX_ADAPTIVE_LE ||
              codec_type == CodecType::APTX_ADAPTIVE_LEX) {
     return ComposeUnicastCapability(
-        codec_type,
-        GetAudioLocation(
-            strategy_configuration_iter->second.getAudioLocation()),
+        codec_type, audio_location, audio_channel_allocation,
         strategy_configuration_iter->second.getConnectedDevice(),
         strategy_configuration_iter->second.getChannelCount(),
         ComposeAptxAdaptiveLeCapability(codec_configuration_iter->second));
@@ -435,11 +470,27 @@
   std::vector<std::optional<Lc3Capabilities>> bcastLc3Cap(
       1, std::optional(ComposeLc3Capability(codec_configuration_iter->second)));
 
+  // Populate audio location
+  AudioLocation audio_location = AudioLocation::UNKNOWN;
+  if (strategy_configuration_iter->second.hasAudioLocation()) {
+    audio_location = GetAudioLocation(
+        strategy_configuration_iter->second.getAudioLocation());
+  }
+
+  // Populate audio channel allocation
+  std::optional<CodecSpecificConfigurationLtv::AudioChannelAllocation>
+      audio_channel_allocation = std::nullopt;
+  if (strategy_configuration_iter->second.hasAudioChannelAllocation()) {
+    LOG(INFO) << __func__ << ": has allocation";
+    CodecSpecificConfigurationLtv::AudioChannelAllocation tmp;
+    tmp.bitmask =
+        strategy_configuration_iter->second.getAudioChannelAllocation();
+    audio_channel_allocation = tmp;
+  }
+
   if (codec_type == CodecType::LC3) {
     return ComposeBroadcastCapability(
-        codec_type,
-        GetAudioLocation(
-            strategy_configuration_iter->second.getAudioLocation()),
+        codec_type, audio_location, audio_channel_allocation,
         strategy_configuration_iter->second.getChannelCount(), bcastLc3Cap);
   }
   return {.codecType = CodecType::UNKNOWN};
@@ -448,16 +499,21 @@
 template <class T>
 BroadcastCapability BluetoothLeAudioCodecsProvider::ComposeBroadcastCapability(
     const CodecType& codec_type, const AudioLocation& audio_location,
+    const std::optional<CodecSpecificConfigurationLtv::AudioChannelAllocation>&
+        audio_channel_allocation,
     const uint8_t& channel_count, const std::vector<T>& capability) {
   return {.codecType = codec_type,
           .supportedChannel = audio_location,
           .channelCountPerStream = channel_count,
-          .leAudioCodecCapabilities = std::optional(capability)};
+          .leAudioCodecCapabilities = std::optional(capability),
+          .audioLocation = audio_channel_allocation};
 }
 
 template <class T>
 UnicastCapability BluetoothLeAudioCodecsProvider::ComposeUnicastCapability(
     const CodecType& codec_type, const AudioLocation& audio_location,
+    const std::optional<CodecSpecificConfigurationLtv::AudioChannelAllocation>&
+        audio_channel_allocation,
     const uint8_t& device_cnt, const uint8_t& channel_count,
     const T& capability) {
   return {
@@ -467,6 +523,7 @@
       .channelCountPerDevice = channel_count,
       .leAudioCodecCapabilities =
           UnicastCapability::LeAudioCodecCapabilities(capability),
+      .audioLocation = audio_channel_allocation,
   };
 }
 
@@ -519,38 +576,87 @@
          codec_configuration.hasOctetsPerCodecFrame();
 }
 
+bool IsValidStereoAudioLocation(
+    const setting::StrategyConfiguration& strategy_configuration) {
+  if ((strategy_configuration.getConnectedDevice() == 2 &&
+       strategy_configuration.getChannelCount() == 1) ||
+      (strategy_configuration.getConnectedDevice() == 1 &&
+       strategy_configuration.getChannelCount() == 2)) {
+    // Stereo
+    // 1. two connected device, one for L one for R
+    // 2. one connected device for both L and R
+    return true;
+  } else if (strategy_configuration.getConnectedDevice() == 0 &&
+             strategy_configuration.getChannelCount() == 2) {
+    // Broadcast
+    return true;
+  }
+  return false;
+}
+
+bool IsValidMonoAudioLocation(
+    const setting::StrategyConfiguration& strategy_configuration) {
+  if (strategy_configuration.getConnectedDevice() == 1 &&
+      strategy_configuration.getChannelCount() == 1) {
+    return true;
+  }
+  return false;
+}
+
+bool IsValidAudioLocation(
+    const setting::StrategyConfiguration& strategy_configuration) {
+  if (strategy_configuration.getAudioLocation() ==
+      setting::AudioLocation::STEREO)
+    return IsValidStereoAudioLocation(strategy_configuration);
+  else if (strategy_configuration.getAudioLocation() ==
+           setting::AudioLocation::MONO)
+    return IsValidMonoAudioLocation(strategy_configuration);
+  return false;
+}
+
+bool IsValidAudioChannelAllocation(
+    const setting::StrategyConfiguration& strategy_configuration) {
+  // First, ensure that there's only 2 bitmask enabled
+  int audio_channel_allocation =
+      strategy_configuration.getAudioChannelAllocation();
+  int count = 0;
+  for (int bit = 0; bit < 32; ++bit)
+    if (audio_channel_allocation & (1 << bit)) ++count;
+  if (count > 2) {
+    LOG(WARNING) << "Cannot parse more than 2 audio location, input is "
+                 << audio_channel_allocation;
+    return false;
+  }
+
+  if (count == 2)
+    return IsValidStereoAudioLocation(strategy_configuration);
+  else
+    return IsValidMonoAudioLocation(strategy_configuration);
+}
+
 bool BluetoothLeAudioCodecsProvider::IsValidStrategyConfiguration(
     const setting::StrategyConfiguration& strategy_configuration) {
   if (!strategy_configuration.hasName() ||
-      !strategy_configuration.hasAudioLocation() ||
       !strategy_configuration.hasConnectedDevice() ||
       !strategy_configuration.hasChannelCount()) {
     return false;
   }
-  if (strategy_configuration.getAudioLocation() ==
-      setting::AudioLocation::STEREO) {
-    if ((strategy_configuration.getConnectedDevice() == 2 &&
-         strategy_configuration.getChannelCount() == 1) ||
-        (strategy_configuration.getConnectedDevice() == 1 &&
-         strategy_configuration.getChannelCount() == 2)) {
-      // Stereo
-      // 1. two connected device, one for L one for R
-      // 2. one connected device for both L and R
-      return true;
-    } else if (strategy_configuration.getConnectedDevice() == 0 &&
-               strategy_configuration.getChannelCount() == 2) {
-      // Broadcast
-      return true;
-    }
-  } else if (strategy_configuration.getAudioLocation() ==
-             setting::AudioLocation::MONO) {
-    if (strategy_configuration.getConnectedDevice() == 1 &&
-        strategy_configuration.getChannelCount() == 1) {
-      // Mono
-      return true;
-    }
-  }
-  return false;
+
+  // Both audio location field cannot be empty
+  if (!strategy_configuration.hasAudioLocation() &&
+      !strategy_configuration.hasAudioChannelAllocation())
+    return false;
+
+  // Any audio location field that presents must be valid
+  if (strategy_configuration.hasAudioLocation() &&
+      !IsValidAudioLocation(strategy_configuration))
+    return false;
+
+  if (strategy_configuration.hasAudioChannelAllocation() &&
+      !IsValidAudioChannelAllocation(strategy_configuration))
+    return false;
+
+  return true;
 }
 
 }  // namespace audio
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
index 5bf67e2..23b2bb6 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
@@ -23,6 +23,7 @@
 #include <vector>
 
 #include "aidl/android/hardware/bluetooth/audio/CodecInfo.h"
+#include "aidl/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.h"
 #include "aidl/android/hardware/bluetooth/audio/SessionType.h"
 #include "aidl_android_hardware_bluetooth_audio_setting.h"
 
@@ -84,12 +85,18 @@
   template <class T>
   static inline UnicastCapability ComposeUnicastCapability(
       const CodecType& codec_type, const AudioLocation& audio_location,
+      const std::optional<
+          CodecSpecificConfigurationLtv::AudioChannelAllocation>&
+          audio_channel_allocation,
       const uint8_t& device_cnt, const uint8_t& channel_count,
       const T& capability);
 
   template <class T>
   static inline BroadcastCapability ComposeBroadcastCapability(
       const CodecType& codec_type, const AudioLocation& audio_location,
+      const std::optional<
+          CodecSpecificConfigurationLtv::AudioChannelAllocation>&
+          audio_channel_allocation,
       const uint8_t& channel_count, const std::vector<T>& capability);
 
   static inline Lc3Capabilities ComposeLc3Capability(
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp
index dba2749..c47f7d5 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp
@@ -64,19 +64,101 @@
 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));
+    std::make_optional(1), std::nullopt);
 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));
+    std::make_optional(2), std::nullopt);
 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));
+    std::make_optional(1), std::nullopt);
 static const StrategyConfiguration kValidStrategyBroadcastStereo(
     std::make_optional("BROADCAST_STEREO"),
     std::make_optional(AudioLocation::STEREO), std::make_optional(0),
-    std::make_optional(2));
+    std::make_optional(2), std::nullopt);
+
+static const StrategyConfiguration kValidStrategyStereoOneCisInt(
+    std::make_optional("STEREO_ONE_CIS_PER_DEVICE"), std::nullopt,
+    std::make_optional(2), std::make_optional(1), std::make_optional(3));
+static const StrategyConfiguration kValidStrategyStereoTwoCisInt(
+    std::make_optional("STEREO_TWO_CISES_PER_DEVICE"), std::nullopt,
+    std::make_optional(1), std::make_optional(2), std::make_optional(3));
+static const StrategyConfiguration kValidStrategyMonoOneCisInt(
+    std::make_optional("MONO_ONE_CIS_PER_DEVICE"), std::nullopt,
+    std::make_optional(1), std::make_optional(1), std::make_optional(4));
+static const StrategyConfiguration kValidStrategyBroadcastStereoInt(
+    std::make_optional("BROADCAST_STEREO"), std::nullopt, std::make_optional(0),
+    std::make_optional(2), std::make_optional(3));
+
+static const StrategyConfiguration kValidStrategyStereoOneCisBoth(
+    std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
+    std::make_optional(AudioLocation::STEREO), std::make_optional(2),
+    std::make_optional(1), std::make_optional(3));
+static const StrategyConfiguration kValidStrategyStereoTwoCisBoth(
+    std::make_optional("STEREO_TWO_CISES_PER_DEVICE"),
+    std::make_optional(AudioLocation::STEREO), std::make_optional(1),
+    std::make_optional(2), std::make_optional(3));
+static const StrategyConfiguration kValidStrategyMonoOneCisBoth(
+    std::make_optional("MONO_ONE_CIS_PER_DEVICE"),
+    std::make_optional(AudioLocation::MONO), std::make_optional(1),
+    std::make_optional(1), std::make_optional(4));
+static const StrategyConfiguration kValidStrategyBroadcastStereoBoth(
+    std::make_optional("BROADCAST_STEREO"),
+    std::make_optional(AudioLocation::STEREO), std::make_optional(0),
+    std::make_optional(2), std::make_optional(3));
+
+// List of all invalid strategy configuration
+const auto kInvalidStrategyStereoTwoCisTwoDevice = 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), std::nullopt)});
+const auto kInvalidStrategyMonoTwoCisTwoDevice = 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), std::nullopt)});
+const auto kInvalidStrategyNoName = StrategyConfigurationList(
+    std::vector<StrategyConfiguration>{StrategyConfiguration(
+        std::nullopt, std::make_optional(AudioLocation::STEREO),
+        std::make_optional(2), std::make_optional(1), std::nullopt)});
+const auto kInvalidStrategyNoLocation = StrategyConfigurationList(
+    std::vector<StrategyConfiguration>{StrategyConfiguration(
+        std::make_optional("STEREO_ONE_CIS_PER_DEVICE"), std::nullopt,
+        std::make_optional(2), std::make_optional(1), std::nullopt)});
+const auto kInvalidStrategyNoDevice = StrategyConfigurationList(
+    std::vector<StrategyConfiguration>{StrategyConfiguration(
+        std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
+        std::make_optional(AudioLocation::STEREO), std::nullopt,
+        std::make_optional(1), std::nullopt)});
+const auto kInvalidStrategyNoChannel = StrategyConfigurationList(
+    std::vector<StrategyConfiguration>{StrategyConfiguration(
+        std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
+        std::make_optional(AudioLocation::STEREO), std::make_optional(2),
+        std::nullopt, std::nullopt)});
+const auto kInvalidStrategyIntMoreBitmask = 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(1), std::make_optional(7))});
+const auto kInvalidStrategyIntStereoTwoCisTwoDevice = StrategyConfigurationList(
+    std::vector<StrategyConfiguration>{StrategyConfiguration(
+        std::make_optional("STEREO_ONE_CIS_PER_DEVICE"), std::nullopt,
+        std::make_optional(2), std::make_optional(2), std::make_optional(3))});
+const auto kInvalidStrategyIntMonoTwoCisTwoDevice = StrategyConfigurationList(
+    std::vector<StrategyConfiguration>{StrategyConfiguration(
+        std::make_optional("MONO_ONE_CIS_PER_DEVICE"), std::nullopt,
+        std::make_optional(2), std::make_optional(2), std::make_optional(4))});
+const auto kInvalidStrategyIntBroadcast = StrategyConfigurationList(
+    std::vector<StrategyConfiguration>{StrategyConfiguration(
+        std::make_optional("MONO_ONE_CIS_PER_DEVICE"), std::nullopt,
+        std::make_optional(0), std::make_optional(1), std::make_optional(3))});
+const auto kInvalidStrategyBothStereoMonoInt = 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(1), std::make_optional(4))});
 
 // Define valid test list built from above valid components
 // Scenario, Configuration, CodecConfiguration, StrategyConfiguration
@@ -88,11 +170,16 @@
 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, kValidStrategyBroadcastStereo})};
+            kValidStrategyMonoOneCis, kValidStrategyBroadcastStereo,
+            kValidStrategyStereoOneCisInt, kValidStrategyStereoTwoCisInt,
+            kValidStrategyMonoOneCisInt, kValidStrategyBroadcastStereoInt,
+            kValidStrategyStereoOneCisBoth, kValidStrategyStereoTwoCisBoth,
+            kValidStrategyMonoOneCisBoth, kValidStrategyBroadcastStereoBoth})};
 
 class BluetoothLeAudioCodecsProviderTest
     : public ::testing::TestWithParam<OffloadSetting> {
@@ -270,49 +357,19 @@
   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>{}));
+        invalid_strategy_configuration_test_cases = {
+            kInvalidStrategyStereoTwoCisTwoDevice,
+            kInvalidStrategyMonoTwoCisTwoDevice,
+            kInvalidStrategyNoName,
+            kInvalidStrategyNoLocation,
+            kInvalidStrategyNoDevice,
+            kInvalidStrategyNoChannel,
+            kInvalidStrategyIntMoreBitmask,
+            kInvalidStrategyIntStereoTwoCisTwoDevice,
+            kInvalidStrategyIntMonoTwoCisTwoDevice,
+            kInvalidStrategyIntBroadcast,
+            kInvalidStrategyBothStereoMonoInt,
+            StrategyConfigurationList(std::vector<StrategyConfiguration>{})};
 
     return invalid_strategy_configuration_test_cases;
   }
diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml
index eaace78..b6ebbd9 100644
--- a/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml
+++ b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml
@@ -69,9 +69,9 @@
     <codecConfiguration name="APTX_ADAPTIVE_LEX_96k" codec="APTX_ADAPTIVE_LEX" samplingFrequency="96000" frameDurationUs="10000" octetsPerCodecFrame="816"/>
   </codecConfigurationList>
   <strategyConfigurationList>
-    <strategyConfiguration name="STEREO_ONE_CIS_PER_DEVICE" audioLocation="STEREO" connectedDevice="2" channelCount="1"/>
-    <strategyConfiguration name="STEREO_TWO_CISES_PER_DEVICE" audioLocation="STEREO" connectedDevice="1" channelCount="2"/>
-    <strategyConfiguration name="MONO_ONE_CIS_PER_DEVICE" audioLocation="MONO" connectedDevice="1" channelCount="1"/>
-    <strategyConfiguration name="BROADCAST_STEREO" audioLocation="STEREO" connectedDevice="0" channelCount="2"/>
+    <strategyConfiguration name="STEREO_ONE_CIS_PER_DEVICE" audioLocation="STEREO" connectedDevice="2" channelCount="1" audioChannelAllocation="3"/>
+    <strategyConfiguration name="STEREO_TWO_CISES_PER_DEVICE" audioLocation="STEREO" connectedDevice="1" channelCount="2" audioChannelAllocation="3"/>
+    <strategyConfiguration name="MONO_ONE_CIS_PER_DEVICE" audioLocation="MONO" connectedDevice="1" channelCount="1" audioChannelAllocation="4"/>
+    <strategyConfiguration name="BROADCAST_STEREO" audioLocation="STEREO" connectedDevice="0" channelCount="2" audioChannelAllocation="3"/>
   </strategyConfigurationList>
 </leAudioOffloadSetting>
diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd
index 03c8ade..d9ccab5 100644
--- a/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd
+++ b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd
@@ -56,9 +56,12 @@
   <xs:element name="strategyConfiguration">
     <xs:complexType>
       <xs:attribute name="name" type="xs:string"/>
+      <!-- Deprecated definition of Audio Location, please use audioLocationInt -->
       <xs:attribute name="audioLocation" type="audioLocation"/>
       <xs:attribute name="connectedDevice" type="xs:unsignedByte"/>
       <xs:attribute name="channelCount" type="xs:unsignedByte"/>
+      <!-- Integer Audio Location to populate to audioLocation if present -->
+      <xs:attribute name="audioChannelAllocation" type="xs:int"/>
     </xs:complexType>
   </xs:element>
   <xs:simpleType name="audioLocation">
diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt
index a882174..b6c2f03 100644
--- a/bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt
+++ b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt
@@ -81,10 +81,12 @@
 
   public class StrategyConfiguration {
     ctor public StrategyConfiguration();
+    method public int getAudioChannelAllocation();
     method public aidl.android.hardware.bluetooth.audio.setting.AudioLocation getAudioLocation();
     method public short getChannelCount();
     method public short getConnectedDevice();
     method public String getName();
+    method public void setAudioChannelAllocation(int);
     method public void setAudioLocation(aidl.android.hardware.bluetooth.audio.setting.AudioLocation);
     method public void setChannelCount(short);
     method public void setConnectedDevice(short);
diff --git a/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.json b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.json
index fbfa3f9..88e9ce4 100644
--- a/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.json
+++ b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.json
@@ -18,6 +18,7 @@
     " Example values which can be used as 'codec_configuration.compound_value'",
     "   Codec Coding formats:",
     "     LC3 = 6",
+    "     OPUS = 225",
     "   Sampling Frequencies: ",
     "     8000Hz = 1",
     "     11025Hz = 2",
@@ -34,7 +35,8 @@
     "     384000Hz = 13",
     "   Frame Durations:",
     "     7500us = 0",
-    "     10000us = 1"
+    "     10000us = 1",
+    "     20000us = 2"
   ],
   "configurations": [
     {
diff --git a/bluetooth/finder/aidl/vts/Android.bp b/bluetooth/finder/aidl/vts/Android.bp
index 49d2d45..29a0c0f 100644
--- a/bluetooth/finder/aidl/vts/Android.bp
+++ b/bluetooth/finder/aidl/vts/Android.bp
@@ -32,7 +32,6 @@
     ],
     static_libs: [
         "android.hardware.bluetooth.finder-V1-ndk",
-        "libbluetooth-types",
     ],
     test_config: "VtsHalBluetoothFinderTargetTest.xml",
     test_suites: [
diff --git a/bluetooth/ranging/aidl/vts/Android.bp b/bluetooth/ranging/aidl/vts/Android.bp
index 9984ce8..7f6ceff 100644
--- a/bluetooth/ranging/aidl/vts/Android.bp
+++ b/bluetooth/ranging/aidl/vts/Android.bp
@@ -17,8 +17,7 @@
         "libutils",
     ],
     static_libs: [
-        "android.hardware.bluetooth.ranging-V1-ndk",
-        "libbluetooth-types",
+        "android.hardware.bluetooth.ranging-V2-ndk",
     ],
     test_config: "VtsHalBluetoothRangingTargetTest.xml",
     test_suites: [
diff --git a/bluetooth/ranging/aidl/vts/VtsHalBluetoothRangingTargetTest.cpp b/bluetooth/ranging/aidl/vts/VtsHalBluetoothRangingTargetTest.cpp
index 702df95..4510f24 100644
--- a/bluetooth/ranging/aidl/vts/VtsHalBluetoothRangingTargetTest.cpp
+++ b/bluetooth/ranging/aidl/vts/VtsHalBluetoothRangingTargetTest.cpp
@@ -30,12 +30,15 @@
 using aidl::android::hardware::bluetooth::ranging::
     BnBluetoothChannelSoundingSessionCallback;
 using aidl::android::hardware::bluetooth::ranging::ChannelSoudingRawData;
+using aidl::android::hardware::bluetooth::ranging::ChannelSoundingProcedureData;
+using aidl::android::hardware::bluetooth::ranging::Config;
 using aidl::android::hardware::bluetooth::ranging::CsSecurityLevel;
 using aidl::android::hardware::bluetooth::ranging::IBluetoothChannelSounding;
 using aidl::android::hardware::bluetooth::ranging::
     IBluetoothChannelSoundingSession;
 using aidl::android::hardware::bluetooth::ranging::
     IBluetoothChannelSoundingSessionCallback;
+using aidl::android::hardware::bluetooth::ranging::ProcedureEnableConfig;
 using aidl::android::hardware::bluetooth::ranging::RangingResult;
 using aidl::android::hardware::bluetooth::ranging::Reason;
 using aidl::android::hardware::bluetooth::ranging::ResultType;
@@ -43,6 +46,12 @@
 using aidl::android::hardware::bluetooth::ranging::VendorSpecificData;
 using ndk::ScopedAStatus;
 
+enum class RangingHalVersion : uint8_t {
+  V_UNAVAILABLE = 0,
+  V_1,
+  V_2,
+};
+
 class BluetoothChannelSoundingSessionCallback
     : public BnBluetoothChannelSoundingSessionCallback {
  public:
@@ -80,6 +89,8 @@
     ALOGI("SetUp Ranging Test");
     bluetooth_channel_sounding_ = IBluetoothChannelSounding::fromBinder(
         ndk::SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+    hal_version_ = GetRangingHalVersion();
+    ASSERT_GT(hal_version_, RangingHalVersion::V_UNAVAILABLE);
     ASSERT_NE(bluetooth_channel_sounding_, nullptr);
   }
 
@@ -95,6 +106,8 @@
   ScopedAStatus getSupportedSessionTypes(
       std::optional<std::vector<SessionType>>* _aidl_return);
   ScopedAStatus getMaxSupportedCsSecurityLevel(CsSecurityLevel* _aidl_return);
+  ScopedAStatus getSupportedCsSecurityLevels(
+      std::vector<CsSecurityLevel>* _aidl_return);
   ScopedAStatus openSession(
       const BluetoothChannelSoundingParameters& in_params,
       const std::shared_ptr<IBluetoothChannelSoundingSessionCallback>&
@@ -111,6 +124,30 @@
     return status;
   }
 
+  RangingHalVersion GetRangingHalVersion() {
+    int32_t aidl_version = 0;
+    if (bluetooth_channel_sounding_ == nullptr) {
+      return RangingHalVersion::V_UNAVAILABLE;
+    }
+    auto aidl_ret_val =
+        bluetooth_channel_sounding_->getInterfaceVersion(&aidl_version);
+    if (!aidl_ret_val.isOk()) {
+      return RangingHalVersion::V_UNAVAILABLE;
+    }
+    switch (aidl_version) {
+      case 1:
+        return RangingHalVersion::V_1;
+      case 2:
+        return RangingHalVersion::V_2;
+      default:
+        return RangingHalVersion::V_UNAVAILABLE;
+    }
+    return RangingHalVersion::V_UNAVAILABLE;
+  }
+
+ public:
+  RangingHalVersion hal_version_ = RangingHalVersion::V_UNAVAILABLE;
+
  private:
   std::shared_ptr<IBluetoothChannelSounding> bluetooth_channel_sounding_;
 };
@@ -130,6 +167,13 @@
   return bluetooth_channel_sounding_->getMaxSupportedCsSecurityLevel(
       _aidl_return);
 }
+
+ScopedAStatus BluetoothRangingTest::getSupportedCsSecurityLevels(
+    std::vector<CsSecurityLevel>* _aidl_return) {
+  return bluetooth_channel_sounding_->getSupportedCsSecurityLevels(
+      _aidl_return);
+}
+
 ScopedAStatus BluetoothRangingTest::openSession(
     const BluetoothChannelSoundingParameters& in_params,
     const std::shared_ptr<IBluetoothChannelSoundingSessionCallback>&
@@ -155,11 +199,25 @@
 }
 
 TEST_P(BluetoothRangingTest, GetMaxSupportedCsSecurityLevel) {
+  if (hal_version_ > RangingHalVersion::V_1) {
+    GTEST_SKIP();
+  }
   CsSecurityLevel security_level;
   ScopedAStatus status = getMaxSupportedCsSecurityLevel(&security_level);
   ASSERT_TRUE(status.isOk());
 }
 
+TEST_P(BluetoothRangingTest, GetSupportedCsSecurityLevels) {
+  if (hal_version_ < RangingHalVersion::V_2) {
+    GTEST_SKIP();
+  }
+  std::vector<CsSecurityLevel> supported_security_levels;
+  ScopedAStatus status =
+      getSupportedCsSecurityLevels(&supported_security_levels);
+  ASSERT_GT(static_cast<uint8_t>(supported_security_levels.size()), 0);
+  ASSERT_TRUE(status.isOk());
+}
+
 TEST_P(BluetoothRangingTest, OpenSession) {
   BluetoothChannelSoundingParameters params;
   std::shared_ptr<BluetoothChannelSoundingSessionCallback> callback = nullptr;
@@ -205,6 +263,9 @@
 }
 
 TEST_P(BluetoothRangingTest, WriteRawData) {
+  if (hal_version_ > RangingHalVersion::V_1) {
+    GTEST_SKIP();
+  }
   std::shared_ptr<IBluetoothChannelSoundingSession> session;
   auto status = initBluetoothChannelSoundingSession(&session);
   ASSERT_TRUE(status.isOk());
@@ -215,6 +276,62 @@
   }
 }
 
+TEST_P(BluetoothRangingTest, WriteProcedureData) {
+  if (hal_version_ < RangingHalVersion::V_2) {
+    GTEST_SKIP();
+  }
+  std::shared_ptr<IBluetoothChannelSoundingSession> session;
+  auto status = initBluetoothChannelSoundingSession(&session);
+  ASSERT_TRUE(status.isOk());
+  if (session != nullptr) {
+    ChannelSoundingProcedureData procedure_data;
+    status = session->writeProcedureData(procedure_data);
+    ASSERT_TRUE(status.isOk());
+  }
+}
+
+TEST_P(BluetoothRangingTest, UpdateChannelSoundingConfig) {
+  if (hal_version_ < RangingHalVersion::V_2) {
+    GTEST_SKIP();
+  }
+  std::shared_ptr<IBluetoothChannelSoundingSession> session;
+  auto status = initBluetoothChannelSoundingSession(&session);
+  ASSERT_TRUE(status.isOk());
+  if (session != nullptr) {
+    Config config;
+    status = session->updateChannelSoundingConfig(config);
+    ASSERT_TRUE(status.isOk());
+  }
+}
+
+TEST_P(BluetoothRangingTest, UpdateProcedureEnableConfig) {
+  if (hal_version_ < RangingHalVersion::V_2) {
+    GTEST_SKIP();
+  }
+  std::shared_ptr<IBluetoothChannelSoundingSession> session;
+  auto status = initBluetoothChannelSoundingSession(&session);
+  ASSERT_TRUE(status.isOk());
+  if (session != nullptr) {
+    ProcedureEnableConfig procedure_enable_config;
+    status = session->updateProcedureEnableConfig(procedure_enable_config);
+    ASSERT_TRUE(status.isOk());
+  }
+}
+
+TEST_P(BluetoothRangingTest, UpdateBleConnInterval) {
+  if (hal_version_ < RangingHalVersion::V_2) {
+    GTEST_SKIP();
+  }
+  std::shared_ptr<IBluetoothChannelSoundingSession> session;
+  auto status = initBluetoothChannelSoundingSession(&session);
+  ASSERT_TRUE(status.isOk());
+  if (session != nullptr) {
+    int ble_conn_interval = 10;
+    status = session->updateBleConnInterval(ble_conn_interval);
+    ASSERT_TRUE(status.isOk());
+  }
+}
+
 TEST_P(BluetoothRangingTest, CloseSession) {
   std::shared_ptr<IBluetoothChannelSoundingSession> session;
   auto status = initBluetoothChannelSoundingSession(&session);
diff --git a/bluetooth/socket/OWNERS b/bluetooth/socket/OWNERS
new file mode 100644
index 0000000..e7a60e6
--- /dev/null
+++ b/bluetooth/socket/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 27441
+
+include platform/packages/modules/Bluetooth:/OWNERS
+
+jaydenk@google.com
diff --git a/bluetooth/socket/aidl/Android.bp b/bluetooth/socket/aidl/Android.bp
new file mode 100644
index 0000000..77679f8
--- /dev/null
+++ b/bluetooth/socket/aidl/Android.bp
@@ -0,0 +1,46 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.bluetooth.socket",
+    vendor_available: true,
+    host_supported: true,
+    srcs: ["android/hardware/bluetooth/socket/*.aidl"],
+    imports: [
+        "android.hardware.contexthub-V4",
+    ],
+    stability: "vintf",
+    backend: {
+        java: {
+            enabled: false,
+        },
+        ndk: {
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.btservices",
+            ],
+            min_sdk_version: "33",
+        },
+    },
+    frozen: false,
+}
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl b/bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/ChannelInfo.aidl
similarity index 87%
copy from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
copy to bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/ChannelInfo.aidl
index 1e304ab..b9b9593 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
+++ b/bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/ChannelInfo.aidl
@@ -31,7 +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.see.hwcrypto.types;
-enum ProtectionId {
-  WIDEVINE_OUTPUT_BUFFER = 1,
+package android.hardware.bluetooth.socket;
+@VintfStability
+union ChannelInfo {
+  android.hardware.bluetooth.socket.LeCocChannelInfo leCocChannelInfo;
+  android.hardware.bluetooth.socket.RfcommChannelInfo rfcommChannelInfo;
 }
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl b/bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/IBluetoothSocket.aidl
similarity index 81%
copy from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
copy to bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/IBluetoothSocket.aidl
index 5c26cc2..a961692 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
+++ b/bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/IBluetoothSocket.aidl
@@ -31,7 +31,11 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.security.see.hwcrypto;
-interface IHwCryptoOperations {
-  android.hardware.security.see.hwcrypto.CryptoOperationResult[] processCommandList(inout android.hardware.security.see.hwcrypto.CryptoOperationSet[] operations, out android.hardware.security.see.hwcrypto.CryptoOperationErrorAdditionalInfo additionalErrorInfo);
+package android.hardware.bluetooth.socket;
+@VintfStability
+interface IBluetoothSocket {
+  void registerCallback(in android.hardware.bluetooth.socket.IBluetoothSocketCallback callback);
+  android.hardware.bluetooth.socket.SocketCapabilities getSocketCapabilities();
+  void opened(in android.hardware.bluetooth.socket.SocketContext context);
+  void closed(long socketId);
 }
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl b/bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/IBluetoothSocketCallback.aidl
similarity index 86%
copy from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
copy to bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/IBluetoothSocketCallback.aidl
index 1e304ab..35bfb5b 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
+++ b/bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/IBluetoothSocketCallback.aidl
@@ -31,7 +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.see.hwcrypto.types;
-enum ProtectionId {
-  WIDEVINE_OUTPUT_BUFFER = 1,
+package android.hardware.bluetooth.socket;
+@VintfStability
+interface IBluetoothSocketCallback {
+  void openedComplete(long socketId, in android.hardware.bluetooth.socket.Status status, in String reason);
+  void close(long socketId, in String reason);
 }
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl b/bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/LeCocCapabilities.aidl
similarity index 91%
copy from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
copy to bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/LeCocCapabilities.aidl
index 1e304ab..447daa9 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
+++ b/bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/LeCocCapabilities.aidl
@@ -31,7 +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.see.hwcrypto.types;
-enum ProtectionId {
-  WIDEVINE_OUTPUT_BUFFER = 1,
+package android.hardware.bluetooth.socket;
+@VintfStability
+parcelable LeCocCapabilities {
+  int numberOfSupportedSockets;
+  int mtu;
 }
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl b/bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/LeCocChannelInfo.aidl
similarity index 86%
copy from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
copy to bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/LeCocChannelInfo.aidl
index 1e304ab..4d6fcb7 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
+++ b/bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/LeCocChannelInfo.aidl
@@ -31,7 +31,16 @@
 // 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.see.hwcrypto.types;
-enum ProtectionId {
-  WIDEVINE_OUTPUT_BUFFER = 1,
+package android.hardware.bluetooth.socket;
+@VintfStability
+parcelable LeCocChannelInfo {
+  int localCid;
+  int remoteCid;
+  int psm;
+  int localMtu;
+  int remoteMtu;
+  int localMps;
+  int remoteMps;
+  int initialRxCredits;
+  int initialTxCredits;
 }
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl b/bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/RfcommCapabilities.aidl
similarity index 91%
copy from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
copy to bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/RfcommCapabilities.aidl
index 1e304ab..06a75b4 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
+++ b/bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/RfcommCapabilities.aidl
@@ -31,7 +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.see.hwcrypto.types;
-enum ProtectionId {
-  WIDEVINE_OUTPUT_BUFFER = 1,
+package android.hardware.bluetooth.socket;
+@VintfStability
+parcelable RfcommCapabilities {
+  int numberOfSupportedSockets;
+  int maxFrameSize;
 }
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl b/bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/RfcommChannelInfo.aidl
similarity index 86%
copy from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
copy to bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/RfcommChannelInfo.aidl
index 1e304ab..3f9a140 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
+++ b/bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/RfcommChannelInfo.aidl
@@ -31,7 +31,16 @@
 // 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.see.hwcrypto.types;
-enum ProtectionId {
-  WIDEVINE_OUTPUT_BUFFER = 1,
+package android.hardware.bluetooth.socket;
+@VintfStability
+parcelable RfcommChannelInfo {
+  int localCid;
+  int remoteCid;
+  int localMtu;
+  int remoteMtu;
+  int initialRxCredits;
+  int initialTxCredits;
+  int dlci;
+  int maxFrameSize;
+  boolean muxInitiator;
 }
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl b/bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/SocketCapabilities.aidl
similarity index 86%
copy from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
copy to bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/SocketCapabilities.aidl
index 1e304ab..400f20c 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
+++ b/bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/SocketCapabilities.aidl
@@ -31,7 +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.see.hwcrypto.types;
-enum ProtectionId {
-  WIDEVINE_OUTPUT_BUFFER = 1,
+package android.hardware.bluetooth.socket;
+@VintfStability
+parcelable SocketCapabilities {
+  android.hardware.bluetooth.socket.LeCocCapabilities leCocCapabilities;
+  android.hardware.bluetooth.socket.RfcommCapabilities rfcommCapabilities;
 }
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl b/bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/SocketContext.aidl
similarity index 86%
copy from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
copy to bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/SocketContext.aidl
index 1e304ab..6844d31 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
+++ b/bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/SocketContext.aidl
@@ -31,7 +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.see.hwcrypto.types;
-enum ProtectionId {
-  WIDEVINE_OUTPUT_BUFFER = 1,
+package android.hardware.bluetooth.socket;
+@VintfStability
+parcelable SocketContext {
+  long socketId;
+  String name;
+  int aclConnectionHandle;
+  android.hardware.bluetooth.socket.ChannelInfo channelInfo;
+  android.hardware.contexthub.EndpointId endpointId;
 }
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl b/bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/Status.aidl
similarity index 92%
copy from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
copy to bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/Status.aidl
index 1e304ab..63f57a9 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
+++ b/bluetooth/socket/aidl/aidl_api/android.hardware.bluetooth.socket/current/android/hardware/bluetooth/socket/Status.aidl
@@ -31,7 +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.see.hwcrypto.types;
-enum ProtectionId {
-  WIDEVINE_OUTPUT_BUFFER = 1,
+package android.hardware.bluetooth.socket;
+@Backing(type="int") @VintfStability
+enum Status {
+  SUCCESS,
+  FAILURE,
 }
diff --git a/bluetooth/socket/aidl/android/hardware/bluetooth/socket/ChannelInfo.aidl b/bluetooth/socket/aidl/android/hardware/bluetooth/socket/ChannelInfo.aidl
new file mode 100644
index 0000000..afae1c0
--- /dev/null
+++ b/bluetooth/socket/aidl/android/hardware/bluetooth/socket/ChannelInfo.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.socket;
+
+import android.hardware.bluetooth.socket.LeCocChannelInfo;
+import android.hardware.bluetooth.socket.RfcommChannelInfo;
+
+/**
+ * Used to specify the channel information of different protocol.
+ */
+@VintfStability
+union ChannelInfo {
+    /**
+     * LE L2CAP COC channel information.
+     */
+    LeCocChannelInfo leCocChannelInfo;
+
+    /**
+     * RFCOMM channel information.
+     */
+    RfcommChannelInfo rfcommChannelInfo;
+}
diff --git a/bluetooth/socket/aidl/android/hardware/bluetooth/socket/IBluetoothSocket.aidl b/bluetooth/socket/aidl/android/hardware/bluetooth/socket/IBluetoothSocket.aidl
new file mode 100644
index 0000000..5853c10
--- /dev/null
+++ b/bluetooth/socket/aidl/android/hardware/bluetooth/socket/IBluetoothSocket.aidl
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.socket;
+
+import android.hardware.bluetooth.socket.IBluetoothSocketCallback;
+import android.hardware.bluetooth.socket.SocketCapabilities;
+import android.hardware.bluetooth.socket.SocketContext;
+
+/**
+ * The interface for host stack to register callback, get capabilities, and open/close socket.
+ */
+@VintfStability
+interface IBluetoothSocket {
+    /**
+     * API to register a callback for HAL implementation to send asynchronous events.
+     *
+     * @param callback An instance of the |IBluetoothSocketCallback| AIDL interface object
+     */
+    void registerCallback(in IBluetoothSocketCallback callback);
+
+    /**
+     * API to get supported offload socket capabilities.
+     *
+     * @return a socket capabilities
+     */
+    SocketCapabilities getSocketCapabilities();
+
+    /**
+     * API to notify the offload stack that the socket is opened.
+     *
+     * The HAL implementation must use IBluetoothSocketCallback.openedComplete() to indicate the
+     * result of this operation
+     *
+     * @param context Socket context including socket id, channel, hub, and endpoint info
+     */
+    void opened(in SocketContext context);
+
+    /**
+     * API to notify the offload stack that the socket is closed.
+     *
+     * When host app requests to close a socket or the HAL calls IBluetoothSocketCallback.close(),
+     * the host stack closes the socket and sends the notification.
+     *
+     * @param socketId Identifier assigned to the socket by the host stack
+     */
+    void closed(long socketId);
+}
diff --git a/bluetooth/socket/aidl/android/hardware/bluetooth/socket/IBluetoothSocketCallback.aidl b/bluetooth/socket/aidl/android/hardware/bluetooth/socket/IBluetoothSocketCallback.aidl
new file mode 100644
index 0000000..7cd635d
--- /dev/null
+++ b/bluetooth/socket/aidl/android/hardware/bluetooth/socket/IBluetoothSocketCallback.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.socket;
+
+import android.hardware.bluetooth.socket.Status;
+
+/**
+ * The interface from the Bluetooth offload socket to the host stack.
+ */
+@VintfStability
+interface IBluetoothSocketCallback {
+    /**
+     * Invoked when IBluetoothSocket.opened() has been completed.
+     *
+     * @param socketId Identifier assigned to the socket by the host stack
+     * @param status Status indicating success or failure
+     * @param reason Reason string of the operation failure for debugging purposes
+     */
+    void openedComplete(long socketId, in Status status, in String reason);
+
+    /**
+     * Invoked when offload app or stack requests host stack to close the socket.
+     *
+     * @param socketId Identifier assigned to the socket by the host stack
+     * @param reason Reason string for closing the socket for debugging purposes
+     */
+    void close(long socketId, in String reason);
+}
diff --git a/bluetooth/socket/aidl/android/hardware/bluetooth/socket/LeCocCapabilities.aidl b/bluetooth/socket/aidl/android/hardware/bluetooth/socket/LeCocCapabilities.aidl
new file mode 100644
index 0000000..003da11
--- /dev/null
+++ b/bluetooth/socket/aidl/android/hardware/bluetooth/socket/LeCocCapabilities.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.socket;
+
+/**
+ * Capabilities for LE L2CAP COC that the offload stack supports.
+ */
+@VintfStability
+parcelable LeCocCapabilities {
+    /**
+     * Maximum number of LE COC sockets supported. If not supported, the value must be zero.
+     */
+    int numberOfSupportedSockets;
+
+    /**
+     * Local Maximum Transmission Unit size in octets. The MTU size must be in range 23 to 65535.
+     *
+     * The actual value of the local MTU shared in the connection configuration is set in
+     * LeCocChannelInfo.localMtu in the IBluetoothSocket.opened() context parameter.
+     */
+    int mtu;
+
+    /**
+     * The value used by the Host stack for the local Maximum Packet Size shall be the value
+     * LE_ACL_Data_Packet_Length returned by the controller in response to the command HCI LE Read
+     * Buffer Size. Then, the MPS size must be in range 1 to 255. We do not make the MPS
+     * configurable in HAL because using the maximum value does not require a large amount of
+     * memory.
+     */
+}
diff --git a/bluetooth/socket/aidl/android/hardware/bluetooth/socket/LeCocChannelInfo.aidl b/bluetooth/socket/aidl/android/hardware/bluetooth/socket/LeCocChannelInfo.aidl
new file mode 100644
index 0000000..af1bd71
--- /dev/null
+++ b/bluetooth/socket/aidl/android/hardware/bluetooth/socket/LeCocChannelInfo.aidl
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.socket;
+
+/**
+ * LE L2CAP COC channel information
+ */
+@VintfStability
+parcelable LeCocChannelInfo {
+    /**
+     * L2cap local channel ID.
+     */
+    int localCid;
+
+    /**
+     * L2cap remote channel ID.
+     */
+    int remoteCid;
+
+    /**
+     * PSM for L2CAP LE CoC.
+     */
+    int psm;
+
+    /**
+     * Local Maximum Transmission Unit for LE COC specifying the maximum SDU size in bytes that the
+     * local L2CAP layer can receive.
+     */
+    int localMtu;
+
+    /**
+     * Remote Maximum Transmission Unit for LE COC specifying the maximum SDU size in bytes that the
+     * remote L2CAP layer can receive.
+     */
+    int remoteMtu;
+
+    /**
+     * Local Maximum PDU payload Size in bytes that the local L2CAP layer can receive.
+     */
+    int localMps;
+
+    /**
+     * Remote Maximum PDU payload Size in bytes that the remote L2CAP layer can receive.
+     */
+    int remoteMps;
+
+    /**
+     * Protocol initial credits at Rx path.
+     *
+     * The host stack will always set the initial credits to 0 when configuring the L2CAP COC
+     * channel, and this value will always be zero. It means offload stack should send initial
+     * credits to peer device through L2CAP signaling command L2CAP_FLOW_CONTROL_CREDIT_IND when
+     * IBluetoothSocket.opened() is successful.
+     */
+    int initialRxCredits;
+
+    /**
+     * Protocol initial credits at Tx path.
+     */
+    int initialTxCredits;
+}
diff --git a/bluetooth/socket/aidl/android/hardware/bluetooth/socket/RfcommCapabilities.aidl b/bluetooth/socket/aidl/android/hardware/bluetooth/socket/RfcommCapabilities.aidl
new file mode 100644
index 0000000..e5cffff
--- /dev/null
+++ b/bluetooth/socket/aidl/android/hardware/bluetooth/socket/RfcommCapabilities.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.socket;
+
+/**
+ * Capabilities for RFCOMM that the offload stack supports.
+ */
+@VintfStability
+parcelable RfcommCapabilities {
+    /**
+     * Maximum number of RFCOMM sockets supported. If not supported, the value must be zero.
+     */
+    int numberOfSupportedSockets;
+
+    /**
+     * Maximum frame size in octets negotiated during DLCI establishment. The frame size must be
+     * in range 23 to 32767.
+     */
+    int maxFrameSize;
+}
diff --git a/bluetooth/socket/aidl/android/hardware/bluetooth/socket/RfcommChannelInfo.aidl b/bluetooth/socket/aidl/android/hardware/bluetooth/socket/RfcommChannelInfo.aidl
new file mode 100644
index 0000000..7c10144
--- /dev/null
+++ b/bluetooth/socket/aidl/android/hardware/bluetooth/socket/RfcommChannelInfo.aidl
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.socket;
+
+/**
+ * RFCOMM channel information
+ */
+@VintfStability
+parcelable RfcommChannelInfo {
+    /**
+     * L2cap local channel ID for RFCOMM.
+     */
+    int localCid;
+
+    /**
+     * L2cap remote channel ID for RFCOMM.
+     */
+    int remoteCid;
+
+    /**
+     * Local Maximum Transmission Unit Size in bytes that the local L2CAP layer can receive.
+     */
+    int localMtu;
+
+    /**
+     * Remote Maximum Transmission Unit Size in bytes that the remote L2CAP layer can receive.
+     */
+    int remoteMtu;
+
+    /**
+     * Protocol initial credits at Rx path.
+     *
+     * The host stack will always set the initial credits to 0 when configuring the RFCOMM
+     * channel, and this value will always be zero. It means offload stack should send initial
+     * credits to peer device when IBluetoothSocket.opened() is successful.
+     */
+    int initialRxCredits;
+
+    /**
+     * Protocol initial credits at Tx path.
+     */
+    int initialTxCredits;
+
+    /**
+     * Data Link Connection Identifier (DLCI).
+     */
+    int dlci;
+
+    /**
+     * Maximum frame size negotiated during DLCI establishment.
+     */
+    int maxFrameSize;
+
+    /**
+     * Flag of whether the Android stack initiated the RFCOMM multiplexer control channel.
+     *
+     * This flag determines the value of the Command/Response (C/R) bit of RFCOMM frames.
+     */
+    boolean muxInitiator;
+}
diff --git a/bluetooth/socket/aidl/android/hardware/bluetooth/socket/SocketCapabilities.aidl b/bluetooth/socket/aidl/android/hardware/bluetooth/socket/SocketCapabilities.aidl
new file mode 100644
index 0000000..05a59ee
--- /dev/null
+++ b/bluetooth/socket/aidl/android/hardware/bluetooth/socket/SocketCapabilities.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.socket;
+
+import android.hardware.bluetooth.socket.LeCocCapabilities;
+import android.hardware.bluetooth.socket.RfcommCapabilities;
+
+/**
+ * Supported socket protocol capabilities.
+ */
+@VintfStability
+parcelable SocketCapabilities {
+    /**
+     * Supported LE CoC protocol capabilities.
+     */
+    LeCocCapabilities leCocCapabilities;
+
+    /**
+     * Supported RFCOMM protocol capabilities.
+     */
+    RfcommCapabilities rfcommCapabilities;
+}
diff --git a/bluetooth/socket/aidl/android/hardware/bluetooth/socket/SocketContext.aidl b/bluetooth/socket/aidl/android/hardware/bluetooth/socket/SocketContext.aidl
new file mode 100644
index 0000000..1f9be07
--- /dev/null
+++ b/bluetooth/socket/aidl/android/hardware/bluetooth/socket/SocketContext.aidl
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.socket;
+
+import android.hardware.bluetooth.socket.ChannelInfo;
+import android.hardware.contexthub.EndpointId;
+
+/**
+ * Socket context.
+ */
+@VintfStability
+parcelable SocketContext {
+    /**
+     * Identifier assigned to the socket by the host stack when the socket is connected to a remote
+     * device. Used to uniquely identify the socket in other callbacks and method invocations. It is
+     * valid only while the socket is connected.
+     */
+    long socketId;
+
+    /**
+     * Descriptive socket name provided by the host app when it creates this socket. This is not
+     * unique across the system, but can help the offload app understand the purpose of the socket
+     * when it receives a socket connection event.
+     */
+    String name;
+
+    /**
+     * ACL connection handle for the socket.
+     */
+    int aclConnectionHandle;
+
+    /**
+     * Channel information of the socket protocol.
+     */
+    ChannelInfo channelInfo;
+
+    /**
+     * Unique identifier for an endpoint at the hardware offload data path.
+     */
+    EndpointId endpointId;
+}
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/Void.aidl b/bluetooth/socket/aidl/android/hardware/bluetooth/socket/Status.aidl
similarity index 82%
copy from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/Void.aidl
copy to bluetooth/socket/aidl/android/hardware/bluetooth/socket/Status.aidl
index f9f608d..d881b09 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/Void.aidl
+++ b/bluetooth/socket/aidl/android/hardware/bluetooth/socket/Status.aidl
@@ -13,6 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.hardware.security.see.hwcrypto.types;
 
-parcelable Void {}
+package android.hardware.bluetooth.socket;
+
+@VintfStability
+@Backing(type="int")
+enum Status {
+    SUCCESS,
+    FAILURE,
+}
diff --git a/bluetooth/socket/aidl/default/Android.bp b/bluetooth/socket/aidl/default/Android.bp
new file mode 100644
index 0000000..a730057
--- /dev/null
+++ b/bluetooth/socket/aidl/default/Android.bp
@@ -0,0 +1,48 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+    name: "android.hardware.bluetooth.socket-service.default",
+    relative_install_path: "hw",
+    init_rc: ["bluetooth-socket-service-default.rc"],
+    vintf_fragments: [":manifest_android.hardware.bluetooth.socket-service.default.xml"],
+    vendor: true,
+    srcs: [
+        "BluetoothSocket.cpp",
+        "service.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.bluetooth.socket-V1-ndk",
+        "libbase",
+        "libbinder_ndk",
+        "libhidlbase",
+        "libutils",
+        "liblog",
+    ],
+}
+
+cc_fuzz {
+    name: "android.hardware.bluetooth.socket-service_fuzzer",
+    team: "trendy_team_bluetooth",
+    defaults: ["service_fuzzer_defaults"],
+    srcs: [
+        "fuzzer.cpp",
+        "BluetoothSocket.cpp",
+    ],
+    static_libs: [
+        "android.hardware.bluetooth.socket-V1-ndk",
+        "android.hardware.contexthub-V4-ndk",
+        "liblog",
+    ],
+    fuzz_config: {
+        cc: [
+            "jaydenk@google.com",
+        ],
+    },
+}
+
+filegroup {
+    name: "manifest_android.hardware.bluetooth.socket-service.default.xml",
+    srcs: ["bluetooth-socket-service-default.xml"],
+}
diff --git a/bluetooth/socket/aidl/default/BluetoothSocket.cpp b/bluetooth/socket/aidl/default/BluetoothSocket.cpp
new file mode 100644
index 0000000..5993393
--- /dev/null
+++ b/bluetooth/socket/aidl/default/BluetoothSocket.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BluetoothSocket.h"
+
+using aidl::android::hardware::bluetooth::socket::Status;
+
+namespace aidl::android::hardware::bluetooth::socket::impl {
+
+BluetoothSocket::BluetoothSocket() {}
+BluetoothSocket::~BluetoothSocket() {}
+
+::ndk::ScopedAStatus BluetoothSocket::registerCallback(
+    const std::shared_ptr<
+        ::aidl::android::hardware::bluetooth::socket::IBluetoothSocketCallback>&
+        in_callback) {
+  if (in_callback == nullptr) {
+    return ndk::ScopedAStatus::fromServiceSpecificError(STATUS_BAD_VALUE);
+  }
+  callback_ = in_callback;
+  return ::ndk::ScopedAStatus::ok();
+}
+::ndk::ScopedAStatus BluetoothSocket::getSocketCapabilities(
+    ::aidl::android::hardware::bluetooth::socket::SocketCapabilities*
+        _aidl_return) {
+  _aidl_return->leCocCapabilities.numberOfSupportedSockets = 0;
+  _aidl_return->leCocCapabilities.mtu = 0;
+  _aidl_return->rfcommCapabilities.numberOfSupportedSockets = 0;
+  _aidl_return->rfcommCapabilities.maxFrameSize = 0;
+  return ::ndk::ScopedAStatus::ok();
+}
+::ndk::ScopedAStatus BluetoothSocket::opened(
+    const ::aidl::android::hardware::bluetooth::socket::SocketContext&
+    /* in_context */) {
+  return ::ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+::ndk::ScopedAStatus BluetoothSocket::closed(int64_t /*in_socketId*/) {
+  return ::ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::bluetooth::socket::impl
diff --git a/bluetooth/socket/aidl/default/BluetoothSocket.h b/bluetooth/socket/aidl/default/BluetoothSocket.h
new file mode 100644
index 0000000..9bb41ec
--- /dev/null
+++ b/bluetooth/socket/aidl/default/BluetoothSocket.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/bluetooth/socket/BnBluetoothSocket.h>
+
+namespace aidl::android::hardware::bluetooth::socket::impl {
+
+class BluetoothSocket : public BnBluetoothSocket {
+ public:
+  BluetoothSocket();
+  ~BluetoothSocket();
+
+  ::ndk::ScopedAStatus registerCallback(
+      const std::shared_ptr<::aidl::android::hardware::bluetooth::socket::
+                                IBluetoothSocketCallback>& in_callback)
+      override;
+  ::ndk::ScopedAStatus getSocketCapabilities(
+      ::aidl::android::hardware::bluetooth::socket::SocketCapabilities*
+          _aidl_return) override;
+  ::ndk::ScopedAStatus opened(
+      const ::aidl::android::hardware::bluetooth::socket::SocketContext&
+          in_context) override;
+  ::ndk::ScopedAStatus closed(int64_t in_socketId) override;
+
+ private:
+  std::shared_ptr<IBluetoothSocketCallback> callback_;
+};
+
+}  // namespace aidl::android::hardware::bluetooth::socket::impl
diff --git a/bluetooth/socket/aidl/default/bluetooth-socket-service-default.rc b/bluetooth/socket/aidl/default/bluetooth-socket-service-default.rc
new file mode 100644
index 0000000..f1eb7f7
--- /dev/null
+++ b/bluetooth/socket/aidl/default/bluetooth-socket-service-default.rc
@@ -0,0 +1,4 @@
+service vendor.bluetooth.socket-default /vendor/bin/hw/android.hardware.bluetooth.socket-service.default
+    class hal
+    user nobody
+    group nobody
diff --git a/bluetooth/socket/aidl/default/bluetooth-socket-service-default.xml b/bluetooth/socket/aidl/default/bluetooth-socket-service-default.xml
new file mode 100644
index 0000000..b97074d
--- /dev/null
+++ b/bluetooth/socket/aidl/default/bluetooth-socket-service-default.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.bluetooth.socket</name>
+        <version>1</version>
+        <fqname>IBluetoothSocket/default</fqname>
+    </hal>
+</manifest>
diff --git a/bluetooth/socket/aidl/default/fuzzer.cpp b/bluetooth/socket/aidl/default/fuzzer.cpp
new file mode 100644
index 0000000..062db0f
--- /dev/null
+++ b/bluetooth/socket/aidl/default/fuzzer.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include "BluetoothSocket.h"
+
+using ::aidl::android::hardware::bluetooth::socket::impl::BluetoothSocket;
+using ::android::fuzzService;
+using ::ndk::SharedRefBase;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  auto bluetoothSocketAidl = SharedRefBase::make<BluetoothSocket>();
+
+  fuzzService(bluetoothSocketAidl->asBinder().get(),
+              FuzzedDataProvider(data, size));
+
+  return 0;
+}
diff --git a/bluetooth/socket/aidl/default/service.cpp b/bluetooth/socket/aidl/default/service.cpp
new file mode 100644
index 0000000..bd15084
--- /dev/null
+++ b/bluetooth/socket/aidl/default/service.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "aidl.android.hardware.bluetooth.socket.service.default"
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <utils/Log.h>
+
+#include "BluetoothSocket.h"
+
+using ::aidl::android::hardware::bluetooth::socket::impl::BluetoothSocket;
+
+int main(int /* argc */, char** /* argv */) {
+  ALOGI("Bluetooth Socket HAL registering");
+  if (!ABinderProcess_setThreadPoolMaxThreadCount(0)) {
+    ALOGE("Failed to set thread pool max thread count");
+    return 1;
+  }
+
+  std::shared_ptr<BluetoothSocket> service =
+      ndk::SharedRefBase::make<BluetoothSocket>();
+  std::string instance =
+      std::string() + BluetoothSocket::descriptor + "/default";
+  auto result =
+      AServiceManager_addService(service->asBinder().get(), instance.c_str());
+  if (result == STATUS_OK) {
+    ABinderProcess_joinThreadPool();
+  } else {
+    ALOGE("Could not register as a service!");
+  }
+  return EXIT_FAILURE;
+}
diff --git a/bluetooth/socket/aidl/vts/Android.bp b/bluetooth/socket/aidl/vts/Android.bp
new file mode 100644
index 0000000..c1ba562
--- /dev/null
+++ b/bluetooth/socket/aidl/vts/Android.bp
@@ -0,0 +1,28 @@
+package {
+    default_team: "trendy_team_bluetooth",
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsHalBluetoothSocketTargetTest",
+    defaults: [
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalBluetoothSocketTargetTest.cpp"],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libcutils",
+        "liblog",
+        "libutils",
+    ],
+    static_libs: [
+        "android.hardware.bluetooth.socket-V1-ndk",
+        "android.hardware.contexthub-V4-ndk",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+    require_root: true,
+}
diff --git a/bluetooth/socket/aidl/vts/VtsHalBluetoothSocketTargetTest.cpp b/bluetooth/socket/aidl/vts/VtsHalBluetoothSocketTargetTest.cpp
new file mode 100644
index 0000000..1069207
--- /dev/null
+++ b/bluetooth/socket/aidl/vts/VtsHalBluetoothSocketTargetTest.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/bluetooth/socket/BnBluetoothSocketCallback.h>
+#include <aidl/android/hardware/bluetooth/socket/IBluetoothSocket.h>
+#include <aidl/android/hardware/bluetooth/socket/IBluetoothSocketCallback.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+
+#include <future>
+
+using ::aidl::android::hardware::bluetooth::socket::BnBluetoothSocketCallback;
+using ::aidl::android::hardware::bluetooth::socket::IBluetoothSocket;
+using ::aidl::android::hardware::bluetooth::socket::SocketCapabilities;
+using ::aidl::android::hardware::bluetooth::socket::SocketContext;
+using ::ndk::ScopedAStatus;
+
+namespace {
+constexpr static int kCallbackTimeoutMs = 250;
+constexpr static int kOpenedCallbackTimeoutMs = 5000;
+}  // namespace
+
+class BluetoothSocketCallback : public BnBluetoothSocketCallback {
+ public:
+  BluetoothSocketCallback(
+      const std::function<
+          void(int64_t in_socketId,
+               ::aidl::android::hardware::bluetooth::socket::Status in_status,
+               const std::string& in_reason)>& on_hal_opened_complete_cb)
+      : on_hal_opened_complete_cb_(on_hal_opened_complete_cb) {}
+
+  ScopedAStatus openedComplete(
+      int64_t in_socketId,
+      ::aidl::android::hardware::bluetooth::socket::Status in_status,
+      const std::string& in_reason) override {
+    on_hal_opened_complete_cb_(in_socketId, in_status, in_reason);
+    return ::ndk::ScopedAStatus::ok();
+  }
+
+  ScopedAStatus close(int64_t /* in_socketId */,
+                      const std::string& /* in_reason */) override {
+    return ::ndk::ScopedAStatus::ok();
+  }
+
+ private:
+  std::function<void(
+      int64_t in_socketId,
+      ::aidl::android::hardware::bluetooth::socket::Status in_status,
+      const std::string& in_reason)>
+      on_hal_opened_complete_cb_;
+};
+
+class BluetoothSocketTest : public ::testing::TestWithParam<std::string> {
+ public:
+  virtual void SetUp() override {
+    ALOGI("SetUp Socket Test");
+    bluetooth_socket_ = IBluetoothSocket::fromBinder(
+        ndk::SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+    ASSERT_NE(bluetooth_socket_, nullptr);
+  }
+
+  virtual void TearDown() override {
+    ALOGI("TearDown Socket Test");
+    bluetooth_socket_ = nullptr;
+    ASSERT_EQ(bluetooth_socket_, nullptr);
+  }
+
+  std::shared_ptr<IBluetoothSocket> bluetooth_socket_;
+};
+
+TEST_P(BluetoothSocketTest, registerCallback) {
+  std::promise<void> open_cb_promise;
+  std::future<void> open_cb_future{open_cb_promise.get_future()};
+  std::shared_ptr<BluetoothSocketCallback> callback =
+      ndk::SharedRefBase::make<BluetoothSocketCallback>(
+          [&open_cb_promise](auto /* socket_id */, auto /* status */,
+                             auto /* reason */) {
+            open_cb_promise.set_value();
+          });
+  ScopedAStatus status = bluetooth_socket_->registerCallback(callback);
+  ASSERT_TRUE(status.isOk());
+}
+
+TEST_P(BluetoothSocketTest, GetSocketCapabilities) {
+  SocketCapabilities socket_capabilities;
+  ScopedAStatus status =
+      bluetooth_socket_->getSocketCapabilities(&socket_capabilities);
+  ASSERT_TRUE(status.isOk());
+  ASSERT_TRUE(socket_capabilities.leCocCapabilities.numberOfSupportedSockets >=
+              0);
+  if (socket_capabilities.leCocCapabilities.numberOfSupportedSockets) {
+    // When LE COC is supported, the local MTU must be configured within the
+    // valid range defined in the L2CAP specification.
+    ASSERT_TRUE(socket_capabilities.leCocCapabilities.mtu >= 23 &&
+                socket_capabilities.leCocCapabilities.mtu <= 65535);
+  }
+  ASSERT_TRUE(socket_capabilities.rfcommCapabilities.numberOfSupportedSockets >=
+              0);
+  if (socket_capabilities.rfcommCapabilities.numberOfSupportedSockets) {
+    // When RFCOMM is supported, the maximum frame size must be configured
+    // within the valid range defined in the RFCOMM specification.
+    ASSERT_TRUE(socket_capabilities.rfcommCapabilities.maxFrameSize >= 23 &&
+                socket_capabilities.rfcommCapabilities.maxFrameSize <= 32767);
+  }
+}
+
+TEST_P(BluetoothSocketTest, Opened) {
+  std::promise<void> open_cb_promise;
+  std::future<void> open_cb_future{open_cb_promise.get_future()};
+  std::shared_ptr<BluetoothSocketCallback> callback =
+      ndk::SharedRefBase::make<BluetoothSocketCallback>(
+          [&open_cb_promise](auto /* socket_id */, auto /* status */,
+                             auto /* reason */) {
+            open_cb_promise.set_value();
+          });
+  bluetooth_socket_->registerCallback(callback);
+  SocketCapabilities socket_capabilities;
+  bluetooth_socket_->getSocketCapabilities(&socket_capabilities);
+
+  SocketContext socket_context;
+  ScopedAStatus status = bluetooth_socket_->opened(socket_context);
+  std::chrono::milliseconds timeout{kOpenedCallbackTimeoutMs};
+  if (status.isOk()) {
+    // If IBluetoothSocket.opened() returns success, the callback
+    // BluetoothSocketCallback.openedComplete() must be called within the
+    // timeout.
+    EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready);
+  } else {
+    // If IBluetoothSocket.opened() returns failure, the callback
+    // BluetoothSocketCallback.openedComplete() must not be called.
+    EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::timeout);
+  }
+}
+
+TEST_P(BluetoothSocketTest, Closed) {
+  std::promise<void> open_cb_promise;
+  std::future<void> open_cb_future{open_cb_promise.get_future()};
+  std::shared_ptr<BluetoothSocketCallback> callback =
+      ndk::SharedRefBase::make<BluetoothSocketCallback>(
+          [&open_cb_promise](auto /* socket_id */, auto /* status */,
+                             auto /* reason */) {
+            open_cb_promise.set_value();
+          });
+  bluetooth_socket_->registerCallback(callback);
+  SocketCapabilities socket_capabilities;
+  bluetooth_socket_->getSocketCapabilities(&socket_capabilities);
+
+  long socket_id = 1;
+  bluetooth_socket_->closed(socket_id);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BluetoothSocketTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothSocketTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             IBluetoothSocket::descriptor)),
+                         android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  ABinderProcess_startThreadPool();
+  int status = RUN_ALL_TESTS();
+  ALOGI("Test result = %d", status);
+  return status;
+}
diff --git a/broadcastradio/aidl/default/fuzzer.cpp b/broadcastradio/aidl/default/fuzzer.cpp
index d535432..2492d47 100644
--- a/broadcastradio/aidl/default/fuzzer.cpp
+++ b/broadcastradio/aidl/default/fuzzer.cpp
@@ -24,6 +24,8 @@
 using ::android::fuzzService;
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    // TODO(b/183141167): need to rewrite 'dump' to avoid SIGPIPE.
+    signal(SIGPIPE, SIG_IGN);
     const VirtualRadio& amFmRadioMock = VirtualRadio::getAmFmRadio();
     std::shared_ptr<BroadcastRadio> amFmRadio =
             ::ndk::SharedRefBase::make<BroadcastRadio>(amFmRadioMock);
diff --git a/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp b/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp
index ee0c639..4627ec9 100644
--- a/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp
+++ b/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp
@@ -736,6 +736,7 @@
     }
 
     // try tuning
+    mCallback->reset();
     auto result = mModule->tune(hdSel);
 
     // expect a failure if it's not supported
@@ -782,12 +783,13 @@
     }
 
     ProgramSelector sel = {};
-    uint64_t freq = 0;
+    uint64_t dabSidExt = 0;
     bool dabStationPresent = false;
     for (auto&& programInfo : *programList) {
         if (!utils::hasId(programInfo.selector, IdentifierType::DAB_FREQUENCY_KHZ)) {
             continue;
         }
+        uint64_t freq = 0;
         for (auto&& config_entry : config) {
             if (config_entry.frequencyKhz ==
                 utils::getId(programInfo.selector, IdentifierType::DAB_FREQUENCY_KHZ, 0)) {
@@ -800,7 +802,7 @@
         if (freq == 0) {
             continue;
         }
-        int64_t dabSidExt = utils::getId(programInfo.selector, IdentifierType::DAB_SID_EXT, 0);
+        dabSidExt = utils::getId(programInfo.selector, IdentifierType::DAB_SID_EXT, 0);
         int64_t dabEns = utils::getId(programInfo.selector, IdentifierType::DAB_ENSEMBLE, 0);
         sel = makeSelectorDab(dabSidExt, (int32_t)dabEns, freq);
         dabStationPresent = true;
@@ -812,7 +814,7 @@
     }
 
     // try tuning
-
+    mCallback->reset();
     auto result = mModule->tune(sel);
 
     // expect a failure if it's not supported
@@ -829,9 +831,9 @@
     LOG(DEBUG) << "Current program info: " << infoCb.toString();
 
     // it should tune exactly to what was requested
-    vector<int64_t> freqs = bcutils::getAllIds(infoCb.selector, IdentifierType::DAB_FREQUENCY_KHZ);
-    EXPECT_NE(freqs.end(), find(freqs.begin(), freqs.end(), freq))
-            << "DAB freq " << freq << " kHz is not sent back by callback.";
+    vector<int64_t> sidExts = bcutils::getAllIds(infoCb.selector, IdentifierType::DAB_SID_EXT);
+    EXPECT_NE(sidExts.end(), find(sidExts.begin(), sidExts.end(), dabSidExt))
+            << "DAB SID ext " << std::hex << dabSidExt << " is not sent back by callback.";
 }
 
 /**
diff --git a/camera/common/aidl/Android.bp b/camera/common/aidl/Android.bp
index 8f7d19d..b59c92e 100644
--- a/camera/common/aidl/Android.bp
+++ b/camera/common/aidl/Android.bp
@@ -10,6 +10,7 @@
 
 aidl_interface {
     name: "android.hardware.camera.common",
+    host_supported: true,
     vendor_available: true,
     srcs: ["android/hardware/camera/common/*.aidl"],
     frozen: true,
diff --git a/camera/device/aidl/Android.bp b/camera/device/aidl/Android.bp
index 31c2dbe..291ed0d 100644
--- a/camera/device/aidl/Android.bp
+++ b/camera/device/aidl/Android.bp
@@ -10,6 +10,7 @@
 
 aidl_interface {
     name: "android.hardware.camera.device",
+    host_supported: true,
     vendor_available: true,
     srcs: ["android/hardware/camera/device/*.aidl"],
     frozen: true,
@@ -31,6 +32,9 @@
             sdk_version: "module_current",
             enabled: false,
         },
+        rust: {
+            enabled: true,
+        },
     },
     versions_with_info: [
         {
@@ -40,7 +44,7 @@
                 "android.hardware.common.fmq-V1",
                 "android.hardware.camera.common-V1",
                 "android.hardware.camera.metadata-V1",
-                "android.hardware.graphics.common-V5",
+                "android.hardware.graphics.common-V6",
             ],
         },
         {
@@ -50,7 +54,7 @@
                 "android.hardware.common.fmq-V1",
                 "android.hardware.camera.common-V1",
                 "android.hardware.camera.metadata-V2",
-                "android.hardware.graphics.common-V5",
+                "android.hardware.graphics.common-V6",
             ],
         },
         {
@@ -60,7 +64,7 @@
                 "android.hardware.common.fmq-V1",
                 "android.hardware.camera.common-V1",
                 "android.hardware.camera.metadata-V3",
-                "android.hardware.graphics.common-V5",
+                "android.hardware.graphics.common-V6",
             ],
         },
 
diff --git a/camera/device/aidl/android/hardware/camera/device/ICameraDeviceSession.aidl b/camera/device/aidl/android/hardware/camera/device/ICameraDeviceSession.aidl
index 62a19cf..63ae320 100644
--- a/camera/device/aidl/android/hardware/camera/device/ICameraDeviceSession.aidl
+++ b/camera/device/aidl/android/hardware/camera/device/ICameraDeviceSession.aidl
@@ -575,6 +575,11 @@
      * This can be called at any point after 'processCaptureRequest' in response
      * to camera clients disabling an active repeating request.
      *
+     * Note: The frame number parameter is the latest possible frame number at which the
+     * ongoing repeating request will end. It is possible that the repeating request may end
+     * before the specified frame number due to reasons such as the camera client abandoning
+     * buffers, which is timing dependent.
+     *
      * Performance requirements:
      * The call must not be blocked for extensive periods and should be extremely lightweight. There
      * must be no frame rate degradation or frame jitter introduced.
diff --git a/camera/metadata/aidl/Android.bp b/camera/metadata/aidl/Android.bp
index ae8ba14..a9c1a1a 100644
--- a/camera/metadata/aidl/Android.bp
+++ b/camera/metadata/aidl/Android.bp
@@ -10,6 +10,7 @@
 
 aidl_interface {
     name: "android.hardware.camera.metadata",
+    host_supported: true,
     vendor_available: true,
     srcs: ["android/hardware/camera/metadata/*.aidl"],
     frozen: true,
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 82666ae..49c8410 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -52,6 +52,7 @@
 #include <android/hardware/camera/provider/2.7/ICameraProvider.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <binder/MemoryHeapBase.h>
+#include <com_android_graphics_libgui_flags.h>
 #include <cutils/properties.h>
 #include <fmq/MessageQueue.h>
 #include <grallocusage/GrallocUsageConversion.h>
@@ -8714,16 +8715,25 @@
     ASSERT_NE(nullptr, bufferItemConsumer);
     ASSERT_NE(nullptr, bufferHandler);
 
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
+    *bufferItemConsumer = new BufferItemConsumer(
+            GraphicBuffer::USAGE_HW_TEXTURE);  // Use GLConsumer default usage flags
+#else
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
     *bufferItemConsumer = new BufferItemConsumer(consumer,
             GraphicBuffer::USAGE_HW_TEXTURE); //Use GLConsumer default usage flags
+#endif  // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
     ASSERT_NE(nullptr, (*bufferItemConsumer).get());
     *bufferHandler = new BufferItemHander(*bufferItemConsumer);
     ASSERT_NE(nullptr, (*bufferHandler).get());
     (*bufferItemConsumer)->setFrameAvailableListener(*bufferHandler);
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
+    sp<Surface> surface = (*bufferItemConsumer)->getSurface();
+#else
     sp<Surface> surface = new Surface(producer);
+#endif  // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
     sp<PreviewWindowCb> previewCb = new PreviewWindowCb(surface);
 
     auto rc = device->setPreviewWindow(previewCb);
diff --git a/camera/provider/aidl/Android.bp b/camera/provider/aidl/Android.bp
index 38a8936..faad35a 100644
--- a/camera/provider/aidl/Android.bp
+++ b/camera/provider/aidl/Android.bp
@@ -10,6 +10,7 @@
 
 aidl_interface {
     name: "android.hardware.camera.provider",
+    host_supported: true,
     vendor_available: true,
     srcs: [
         "android/hardware/camera/provider/*.aidl",
@@ -27,6 +28,9 @@
         cpp: {
             enabled: false,
         },
+        rust: {
+            enabled: true,
+        },
     },
     versions_with_info: [
         {
diff --git a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
index ad8d4c8..9fa4df2 100644
--- a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
+++ b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
@@ -165,26 +165,21 @@
 
 // Validate the integrity of manual flash strength control metadata
 TEST_P(CameraAidlTest, validateManualFlashStrengthControlKeys) {
-    if (flags::camera_manual_flash_strength_control()) {
-        std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
-        for (const auto& name : cameraDeviceNames) {
-            ALOGI("validateManualFlashStrengthControlKeys: Testing camera device %s", name.c_str());
-            CameraMetadata meta;
-            std::shared_ptr<ICameraDevice> cameraDevice;
-            openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
-                    &cameraDevice /*out*/);
-            ndk::ScopedAStatus ret = cameraDevice->getCameraCharacteristics(&meta);
-            ASSERT_TRUE(ret.isOk());
-            const camera_metadata_t* staticMeta =
-                    reinterpret_cast<const camera_metadata_t*>(meta.metadata.data());
-            verifyManualFlashStrengthControlCharacteristics(staticMeta);
-            ret = mSession->close();
-            mSession = nullptr;
-            ASSERT_TRUE(ret.isOk());
-        }
-    } else {
-        ALOGI("validateManualFlashStrengthControlKeys: Test skipped.\n");
-        GTEST_SKIP();
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    for (const auto& name : cameraDeviceNames) {
+        ALOGI("validateManualFlashStrengthControlKeys: Testing camera device %s", name.c_str());
+        CameraMetadata meta;
+        std::shared_ptr<ICameraDevice> cameraDevice;
+        openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
+                &cameraDevice /*out*/);
+        ndk::ScopedAStatus ret = cameraDevice->getCameraCharacteristics(&meta);
+        ASSERT_TRUE(ret.isOk());
+        const camera_metadata_t* staticMeta =
+                reinterpret_cast<const camera_metadata_t*>(meta.metadata.data());
+        verifyManualFlashStrengthControlCharacteristics(staticMeta);
+        ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
     }
 }
 
@@ -288,77 +283,70 @@
 }
 
 TEST_P(CameraAidlTest, getSessionCharacteristics) {
-    if (flags::feature_combination_query()) {
-        std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
 
-        for (const auto& name : cameraDeviceNames) {
-            std::shared_ptr<ICameraDevice> device;
-            ALOGI("getSessionCharacteristics: Testing camera device %s", name.c_str());
-            ndk::ScopedAStatus ret = mProvider->getCameraDeviceInterface(name, &device);
-            ALOGI("getCameraDeviceInterface returns: %d:%d", ret.getExceptionCode(),
-                  ret.getServiceSpecificError());
-            ASSERT_TRUE(ret.isOk());
-            ASSERT_NE(device, nullptr);
+    for (const auto& name : cameraDeviceNames) {
+        std::shared_ptr<ICameraDevice> device;
+        ALOGI("getSessionCharacteristics: Testing camera device %s", name.c_str());
+        ndk::ScopedAStatus ret = mProvider->getCameraDeviceInterface(name, &device);
+        ALOGI("getCameraDeviceInterface returns: %d:%d", ret.getExceptionCode(),
+              ret.getServiceSpecificError());
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_NE(device, nullptr);
 
-            int32_t interfaceVersion = -1;
-            ret = device->getInterfaceVersion(&interfaceVersion);
-            ASSERT_TRUE(ret.isOk());
-            bool supportSessionCharacteristics =
-                    (interfaceVersion >= CAMERA_DEVICE_API_MINOR_VERSION_3);
-            if (!supportSessionCharacteristics) {
-                continue;
-            }
-
-            CameraMetadata meta;
-            openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
-                                   &device /*out*/);
-
-            std::vector<AvailableStream> outputStreams;
-            camera_metadata_t* staticMeta =
-                    reinterpret_cast<camera_metadata_t*>(meta.metadata.data());
-            outputStreams.clear();
-            ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
-            ASSERT_NE(0u, outputStreams.size());
-
-            AvailableStream sampleStream = outputStreams[0];
-
-            int32_t streamId = 0;
-            Stream stream = {streamId,
-                             StreamType::OUTPUT,
-                             sampleStream.width,
-                             sampleStream.height,
-                             static_cast<PixelFormat>(sampleStream.format),
-                             static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
-                                     GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER),
-                             Dataspace::UNKNOWN,
-                             StreamRotation::ROTATION_0,
-                             std::string(),
-                             /*bufferSize*/ 0,
-                             /*groupId*/ -1,
-                             {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
-                             RequestAvailableDynamicRangeProfilesMap::
-                                     ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
-
-            std::vector<Stream> streams = {stream};
-            StreamConfiguration config;
-            createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &config);
-
-            CameraMetadata camera_chars;
-            ret = device->getCameraCharacteristics(&camera_chars);
-            ASSERT_TRUE(ret.isOk());
-
-            CameraMetadata session_chars;
-            ret = device->getSessionCharacteristics(config, &session_chars);
-            ASSERT_TRUE(ret.isOk());
-            verifySessionCharacteristics(session_chars, camera_chars);
-
-            ret = mSession->close();
-            mSession = nullptr;
-            ASSERT_TRUE(ret.isOk());
+        int32_t interfaceVersion = -1;
+        ret = device->getInterfaceVersion(&interfaceVersion);
+        ASSERT_TRUE(ret.isOk());
+        bool supportSessionCharacteristics =
+                (interfaceVersion >= CAMERA_DEVICE_API_MINOR_VERSION_3);
+        if (!supportSessionCharacteristics) {
+            continue;
         }
-    } else {
-        ALOGI("getSessionCharacteristics: Test skipped.\n");
-        GTEST_SKIP();
+
+        CameraMetadata meta;
+        openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/, &device /*out*/);
+
+        std::vector<AvailableStream> outputStreams;
+        camera_metadata_t* staticMeta = reinterpret_cast<camera_metadata_t*>(meta.metadata.data());
+        outputStreams.clear();
+        ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
+        ASSERT_NE(0u, outputStreams.size());
+
+        AvailableStream sampleStream = outputStreams[0];
+
+        int32_t streamId = 0;
+        Stream stream = {streamId,
+                         StreamType::OUTPUT,
+                         sampleStream.width,
+                         sampleStream.height,
+                         static_cast<PixelFormat>(sampleStream.format),
+                         static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                                 GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER),
+                         Dataspace::UNKNOWN,
+                         StreamRotation::ROTATION_0,
+                         std::string(),
+                         /*bufferSize*/ 0,
+                         /*groupId*/ -1,
+                         {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                         RequestAvailableDynamicRangeProfilesMap::
+                                 ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+
+        std::vector<Stream> streams = {stream};
+        StreamConfiguration config;
+        createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &config);
+
+        CameraMetadata camera_chars;
+        ret = device->getCameraCharacteristics(&camera_chars);
+        ASSERT_TRUE(ret.isOk());
+
+        CameraMetadata session_chars;
+        ret = device->getSessionCharacteristics(config, &session_chars);
+        ASSERT_TRUE(ret.isOk());
+        verifySessionCharacteristics(session_chars, camera_chars);
+
+        ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
     }
 }
 
@@ -615,19 +603,17 @@
                 ASSERT_EQ(0u, rawMetadata.metadata.size());
             }
 
-            if (flags::feature_combination_query()) {
-                if (supportFeatureCombinationQuery) {
-                    CameraMetadata rawMetadata2;
-                    ndk::ScopedAStatus ret2 =
-                            device->constructDefaultRequestSettings(reqTemplate, &rawMetadata2);
+            if (supportFeatureCombinationQuery) {
+                CameraMetadata rawMetadata2;
+                ndk::ScopedAStatus ret2 =
+                        device->constructDefaultRequestSettings(reqTemplate, &rawMetadata2);
 
-                    ASSERT_EQ(ret.isOk(), ret2.isOk());
-                    ASSERT_EQ(ret.getStatus(), ret2.getStatus());
+                ASSERT_EQ(ret.isOk(), ret2.isOk());
+                ASSERT_EQ(ret.getStatus(), ret2.getStatus());
 
-                    ASSERT_EQ(rawMetadata.metadata.size(), rawMetadata2.metadata.size());
-                    if (ret2.isOk()) {
-                        validateDefaultRequestMetadata(reqTemplate, rawMetadata2);
-                    }
+                ASSERT_EQ(rawMetadata.metadata.size(), rawMetadata2.metadata.size());
+                if (ret2.isOk()) {
+                    validateDefaultRequestMetadata(reqTemplate, rawMetadata2);
                 }
             }
         }
diff --git a/camera/provider/aidl/vts/camera_aidl_test.cpp b/camera/provider/aidl/vts/camera_aidl_test.cpp
index f905011..6ecd451 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.cpp
+++ b/camera/provider/aidl/vts/camera_aidl_test.cpp
@@ -1920,28 +1920,22 @@
         ASSERT_TRUE(ret.isOk());
         ASSERT_EQ(expectedStatus, streamCombinationSupported);
 
-        if (flags::feature_combination_query()) {
-            int32_t interfaceVersion;
-            ret = device->getInterfaceVersion(&interfaceVersion);
+        int32_t interfaceVersion;
+        ret = device->getInterfaceVersion(&interfaceVersion);
+        ASSERT_TRUE(ret.isOk());
+        bool supportFeatureCombinationQuery =
+                (interfaceVersion >= CAMERA_DEVICE_API_MINOR_VERSION_3);
+        if (supportFeatureCombinationQuery) {
+            ret = device->isStreamCombinationWithSettingsSupported(config,
+                                                                   &streamCombinationSupported);
             ASSERT_TRUE(ret.isOk());
-            bool supportFeatureCombinationQuery =
-                    (interfaceVersion >= CAMERA_DEVICE_API_MINOR_VERSION_3);
-            if (supportFeatureCombinationQuery) {
-                ret = device->isStreamCombinationWithSettingsSupported(config,
-                                                                       &streamCombinationSupported);
-                ASSERT_TRUE(ret.isOk());
-                ASSERT_EQ(expectedStatus, streamCombinationSupported);
-            }
+            ASSERT_EQ(expectedStatus, streamCombinationSupported);
         }
     }
 }
 
 void CameraAidlTest::verifySessionCharacteristics(const CameraMetadata& session_chars,
                                                   const CameraMetadata& camera_chars) {
-    if (!flags::feature_combination_query()) {
-        return;
-    }
-
     const camera_metadata_t* session_metadata =
             reinterpret_cast<const camera_metadata_t*>(session_chars.metadata.data());
 
diff --git a/compatibility_matrices/compatibility_matrix.202504.xml b/compatibility_matrices/compatibility_matrix.202504.xml
index e019902..8338e13 100644
--- a/compatibility_matrices/compatibility_matrix.202504.xml
+++ b/compatibility_matrices/compatibility_matrix.202504.xml
@@ -139,6 +139,14 @@
         </interface>
     </hal>
     <hal format="aidl">
+        <name>android.hardware.bluetooth.socket</name>
+        <version>1</version>
+        <interface>
+            <name>IBluetoothSocket</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
         <name>android.hardware.bluetooth.finder</name>
         <version>1</version>
         <interface>
@@ -241,7 +249,7 @@
     </hal>
     <hal format="aidl">
         <name>android.hardware.graphics.composer3</name>
-        <version>3</version>
+        <version>4</version>
         <interface>
             <name>IComposer</name>
             <instance>default</instance>
@@ -304,7 +312,7 @@
     </hal>
     <hal format="aidl">
         <name>android.hardware.security.secretkeeper</name>
-        <version>1</version>
+        <version>1-2</version>
         <interface>
             <name>ISecretkeeper</name>
             <instance>default</instance>
@@ -507,6 +515,14 @@
             <instance>nonsecure</instance>
         </interface>
     </hal>
+    <hal format="aidl">
+        <name>android.hardware.security.see.hwcrypto</name>
+        <version>1</version>
+        <interface>
+            <name>IHwCryptoKey</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
     <hal format="aidl" updatable-via-apex="true">
         <name>android.hardware.security.secureclock</name>
         <version>1</version>
@@ -622,7 +638,7 @@
     </hal>
     <hal format="aidl">
         <name>android.hardware.vibrator</name>
-        <version>1-2</version>
+        <version>1-3</version>
         <interface>
             <name>IVibrator</name>
             <instance>default</instance>
@@ -630,13 +646,22 @@
     </hal>
     <hal format="aidl">
         <name>android.hardware.vibrator</name>
-        <version>1-2</version>
+        <version>1-3</version>
         <interface>
             <name>IVibratorManager</name>
             <instance>default</instance>
         </interface>
     </hal>
     <hal format="aidl">
+      <name>android.hardware.virtualization.capabilities</name>
+        <version>1</version>
+        <interface>
+            <name>IVmCapabilitiesService</name>
+            <instance>default</instance>
+            <instance>noop</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
         <name>android.hardware.weaver</name>
         <version>2</version>
         <interface>
@@ -662,7 +687,7 @@
     </hal>
     <hal format="aidl">
         <name>android.hardware.wifi.hostapd</name>
-        <version>1-2</version>
+        <version>2-3</version>
         <interface>
             <name>IHostapd</name>
             <instance>default</instance>
@@ -670,7 +695,7 @@
     </hal>
     <hal format="aidl">
         <name>android.hardware.wifi.supplicant</name>
-        <version>2-3</version>
+        <version>3-4</version>
         <interface>
             <name>ISupplicant</name>
             <instance>default</instance>
diff --git a/compatibility_matrices/exclude/fcm_exclude.cpp b/compatibility_matrices/exclude/fcm_exclude.cpp
index 79dd0bb..1d5b2bd 100644
--- a/compatibility_matrices/exclude/fcm_exclude.cpp
+++ b/compatibility_matrices/exclude/fcm_exclude.cpp
@@ -149,6 +149,7 @@
             "android.hardware.radio@",
             "android.hardware.uwb.fira_android@",
             "android.hardware.wifi.common@",
+            "android.hardware.biometrics.fingerprint.virtualhal@",
 
             // Test packages are exempted.
             "android.hardware.tests.",
@@ -156,6 +157,7 @@
             // Fastboot HAL is only used by recovery. Recovery is owned by OEM. Framework
             // does not depend on this HAL, hence it is not declared in any manifests or matrices.
             "android.hardware.fastboot@",
+            "android.hardware.security.see.hwcrypto.types",
             "android.hardware.security.see.storage",
     };
 
@@ -168,6 +170,7 @@
             "android.hardware.audio.core.sounddose@3",
             // This is only used by a trusty VM
             "android.hardware.security.see.authmgr@1",
+            "android.hardware.security.see.hdcp@1",
 
             // Deprecated HALs.
             "android.hardware.audio.sounddose@3",
diff --git a/configstore/1.1/default/Android.bp b/configstore/1.1/default/Android.bp
new file mode 100644
index 0000000..34470ad
--- /dev/null
+++ b/configstore/1.1/default/Android.bp
@@ -0,0 +1,142 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//###############################################################################
+package {
+    // See: http://go/android-license-faq
+    default_applicable_licenses: [
+        "hardware_interfaces_license",
+    ],
+}
+
+soong_config_module_type {
+    name: "surfaceflinger_cc_defaults_type",
+    module_type: "cc_defaults",
+    config_namespace: "surfaceflinger",
+    value_variables: [
+        "vsync_event_phase_offset_ns",
+        "sf_vsync_event_phase_offset_ns",
+        "present_time_offset_from_vsync_ns",
+        "max_virtual_displat_dimension",
+        "num_framebuffer_surface_buffers",
+        "sf_primary_display_orientation",
+    ],
+    bool_variables: [
+        "use_context_priority",
+        "has_wide_color_display",
+        "has_hdr_display",
+        "force_hwc_copy_for_virtual_displays",
+        "running_without_sync_framework",
+        "use_vr_flinger",
+        "sf_start_graphics_allocator_service",
+    ],
+    properties: [
+        "cflags",
+    ],
+}
+
+surfaceflinger_cc_defaults_type {
+    name: "surfaceflinger_cc_defaults",
+    srcs: [
+        "SurfaceFlingerConfigs.cpp",
+    ],
+    soong_config_variables: {
+        vsync_event_phase_offset_ns: {
+            cflags: ["-DVSYNC_EVENT_PHASE_OFFSET_NS=%s"],
+        },
+        sf_vsync_event_phase_offset_ns: {
+            cflags: ["-DSF_VSYNC_EVENT_PHASE_OFFSET_NS=%s"],
+        },
+        present_time_offset_from_vsync_ns: {
+            cflags: ["-DPRESENT_TIME_OFFSET_FROM_VSYNC_NS=%s"],
+        },
+        max_virtual_displat_dimension: {
+            cflags: ["-DMAX_VIRTUAL_DISPLAY_DIMENSION=%s"],
+        },
+        num_framebuffer_surface_buffers: {
+            cflags: ["-DNUM_FRAMEBUFFER_SURFACE_BUFFERS=%s"],
+        },
+        sf_primary_display_orientation: {
+            cflags: ["-DPRIMARY_DISPLAY_ORIENTATION=%s"],
+        },
+        use_context_priority: {
+            cflags: ["-DUSE_CONTEXT_PRIORITY=1"],
+        },
+        has_wide_color_display: {
+            cflags: ["-DHAS_WIDE_COLOR_DISPLAY"],
+        },
+        has_hdr_display: {
+            cflags: ["-DHAS_HDR_DISPLAY"],
+        },
+        force_hwc_copy_for_virtual_displays: {
+            cflags: ["-DFORCE_HWC_COPY_FOR_VIRTUAL_DISPLAYS"],
+        },
+        running_without_sync_framework: {
+            cflags: ["-DRUNNING_WITHOUT_SYNC_FRAMEWORK"],
+        },
+        use_vr_flinger: {
+            cflags: ["-DUSE_VR_FLINGER"],
+        },
+        sf_start_graphics_allocator_service: {
+            cflags: ["-DSTART_GRAPHICS_ALLOCATOR_SERVICE"],
+        },
+    },
+}
+
+cc_binary {
+    name: "android.hardware.configstore@1.1-service",
+    srcs: ["service.cpp"],
+    vendor: true,
+    relative_install_path: "hw",
+    init_rc: ["android.hardware.configstore@1.1-service.rc"],
+    shared_libs: [
+        "libhidlbase",
+        "libbase",
+        "libhwminijail",
+        "liblog",
+        "libutils",
+        "android.hardware.configstore@1.0",
+        "android.hardware.configstore@1.1",
+    ],
+    defaults: [
+        "surfaceflinger_cc_defaults",
+    ],
+    required: select((arch(), soong_config_variable("ANDROID", "GCOV_COVERAGE")), {
+        ("arm64", false): ["configstore@1.1.policy"],
+        (default, default): [],
+    }),
+}
+
+// Only build for arm64
+prebuilt_etc {
+    name: "configstore@1.1.policy",
+    relative_install_path: "seccomp_policy",
+    proprietary: true,
+    enabled: false,
+    arch: {
+        arm64: {
+            src: "seccomp_policy/configstore@1.1-arm64.policy",
+            enabled: true,
+        },
+    },
+}
+
+// disable configstore
+cc_binary {
+    name: "disable_configstore",
+    installable: false,
+    srcs: ["disable_configstore.cpp"],
+    overrides: ["android.hardware.configstore@1.1-service"],
+    vendor: true,
+}
diff --git a/configstore/1.1/default/Android.mk b/configstore/1.1/default/Android.mk
deleted file mode 100644
index 9a6f0fc..0000000
--- a/configstore/1.1/default/Android.mk
+++ /dev/null
@@ -1,57 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-################################################################################
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.configstore@1.1-service
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../NOTICE
-# seccomp is not required for coverage build.
-ifneq ($(NATIVE_COVERAGE),true)
-LOCAL_REQUIRED_MODULES_arm64 := configstore@1.1.policy
-endif
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_INIT_RC := android.hardware.configstore@1.1-service.rc
-LOCAL_SRC_FILES:= service.cpp
-
-include $(LOCAL_PATH)/surfaceflinger.mk
-
-LOCAL_SHARED_LIBRARIES := \
-    libhidlbase \
-    libbase \
-    libhwminijail \
-    liblog \
-    libutils \
-    android.hardware.configstore@1.0 \
-    android.hardware.configstore@1.1
-
-include $(BUILD_EXECUTABLE)
-
-# seccomp filter for configstore
-ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), arm64))
-include $(CLEAR_VARS)
-LOCAL_MODULE := configstore@1.1.policy
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../NOTICE
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/etc/seccomp_policy
-LOCAL_SRC_FILES := seccomp_policy/configstore@1.1-$(TARGET_ARCH).policy
-include $(BUILD_PREBUILT)
-endif
-
-# disable configstore
-include $(CLEAR_VARS)
-LOCAL_MODULE := disable_configstore
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../NOTICE
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_SRC_FILES:= disable_configstore.cpp
-LOCAL_OVERRIDES_MODULES := android.hardware.configstore@1.1-service
-LOCAL_VENDOR_MODULE := true
-LOCAL_UNINSTALLABLE_MODULE := true
-
-include $(BUILD_EXECUTABLE)
diff --git a/configstore/1.1/default/surfaceflinger.mk b/configstore/1.1/default/surfaceflinger.mk
index 35922eb..462fe85 100644
--- a/configstore/1.1/default/surfaceflinger.mk
+++ b/configstore/1.1/default/surfaceflinger.mk
@@ -2,55 +2,69 @@
 LOCAL_SRC_FILES += SurfaceFlingerConfigs.cpp
 
 ifneq ($(VSYNC_EVENT_PHASE_OFFSET_NS),)
+    $(call soong_config_set,surfaceflinger,vsync_event_phase_offset_ns,$(VSYNC_EVENT_PHASE_OFFSET_NS))
     LOCAL_CFLAGS += -DVSYNC_EVENT_PHASE_OFFSET_NS=$(VSYNC_EVENT_PHASE_OFFSET_NS)
 endif
 
 ifneq ($(SF_VSYNC_EVENT_PHASE_OFFSET_NS),)
+    $(call soong_config_set,surfaceflinger,sf_vsync_event_phase_offset_ns,$(SF_VSYNC_EVENT_PHASE_OFFSET_NS))
     LOCAL_CFLAGS += -DSF_VSYNC_EVENT_PHASE_OFFSET_NS=$(SF_VSYNC_EVENT_PHASE_OFFSET_NS)
 endif
 
 ifeq ($(TARGET_USE_CONTEXT_PRIORITY),true)
+    $(call soong_config_set_bool,surfaceflinger,use_context_priority,true)
     LOCAL_CFLAGS += -DUSE_CONTEXT_PRIORITY=1
 endif
 
 ifeq ($(TARGET_HAS_WIDE_COLOR_DISPLAY),true)
+    $(call soong_config_set_bool,surfaceflinger,has_wide_color_display,true)
     LOCAL_CFLAGS += -DHAS_WIDE_COLOR_DISPLAY
 endif
 
 ifeq ($(TARGET_HAS_HDR_DISPLAY),true)
+    $(call soong_config_set_bool,surfaceflinger,has_hdr_display,true)
     LOCAL_CFLAGS += -DHAS_HDR_DISPLAY
 endif
 
 ifneq ($(PRESENT_TIME_OFFSET_FROM_VSYNC_NS),)
+    $(call soong_config_set,surfaceflinger,present_time_offset_from_vsync_ns,$(PRESENT_TIME_OFFSET_FROM_VSYNC_NS))
     LOCAL_CFLAGS += -DPRESENT_TIME_OFFSET_FROM_VSYNC_NS=$(PRESENT_TIME_OFFSET_FROM_VSYNC_NS)
 else
+    $(call soong_config_set,surfaceflinger,present_time_offset_from_vsync_ns,0)
     LOCAL_CFLAGS += -DPRESENT_TIME_OFFSET_FROM_VSYNC_NS=0
 endif
 
 ifeq ($(TARGET_FORCE_HWC_FOR_VIRTUAL_DISPLAYS),true)
+    $(call soong_config_set_bool,surfaceflinger,force_hwc_copy_for_virtual_displays,true)
     LOCAL_CFLAGS += -DFORCE_HWC_COPY_FOR_VIRTUAL_DISPLAYS
 endif
 
 ifneq ($(MAX_VIRTUAL_DISPLAY_DIMENSION),)
+    $(call soong_config_set,surfaceflinger,max_virtual_displat_dimension,$(MAX_VIRTUAL_DISPLAY_DIMENSION))
     LOCAL_CFLAGS += -DMAX_VIRTUAL_DISPLAY_DIMENSION=$(MAX_VIRTUAL_DISPLAY_DIMENSION)
 endif
 
 ifeq ($(TARGET_RUNNING_WITHOUT_SYNC_FRAMEWORK),true)
+    $(call soong_config_set_bool,surfaceflinger,running_without_sync_framework,true)
     LOCAL_CFLAGS += -DRUNNING_WITHOUT_SYNC_FRAMEWORK
 endif
 
 ifneq ($(USE_VR_FLINGER),)
+    $(call soong_config_set_bool,surfaceflinger,use_vr_flinger,true)
     LOCAL_CFLAGS += -DUSE_VR_FLINGER
 endif
 
 ifneq ($(NUM_FRAMEBUFFER_SURFACE_BUFFERS),)
+    $(call soong_config_set,surfaceflinger,num_framebuffer_surface_buffers,$(NUM_FRAMEBUFFER_SURFACE_BUFFERS))
     LOCAL_CFLAGS += -DNUM_FRAMEBUFFER_SURFACE_BUFFERS=$(NUM_FRAMEBUFFER_SURFACE_BUFFERS)
 endif
 
 ifneq ($(SF_START_GRAPHICS_ALLOCATOR_SERVICE),)
+    $(call soong_config_set_bool,surfaceflinger,sf_start_graphics_allocator_service,true)
     LOCAL_CFLAGS += -DSTART_GRAPHICS_ALLOCATOR_SERVICE
 endif
 
 ifneq ($(SF_PRIMARY_DISPLAY_ORIENTATION),)
+    $(call soong_config_set,surfaceflinger,sf_primary_display_orientation,$(SF_PRIMARY_DISPLAY_ORIENTATION))
     LOCAL_CFLAGS += -DPRIMARY_DISPLAY_ORIENTATION=$(SF_PRIMARY_DISPLAY_ORIENTATION)
 endif
diff --git a/contexthub/aidl/Android.bp b/contexthub/aidl/Android.bp
index eaa47c6..674f8af 100644
--- a/contexthub/aidl/Android.bp
+++ b/contexthub/aidl/Android.bp
@@ -33,7 +33,12 @@
             sdk_version: "module_current",
         },
         ndk: {
-            apps_enabled: false,
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.btservices",
+            ],
+            min_sdk_version: "33",
+            apps_enabled: true,
         },
         rust: {
             enabled: true,
diff --git a/drm/Android.bp b/drm/Android.bp
new file mode 100644
index 0000000..35c1b03
--- /dev/null
+++ b/drm/Android.bp
@@ -0,0 +1,5 @@
+dirgroup {
+    name: "trusty_dirgroup_hardware_interfaces_drm",
+    dirs: ["."],
+    visibility: ["//trusty/vendor/google/aosp/scripts"],
+}
diff --git a/drm/aidl/Android.bp b/drm/aidl/Android.bp
index c42e723..7ee8c34 100644
--- a/drm/aidl/Android.bp
+++ b/drm/aidl/Android.bp
@@ -15,6 +15,7 @@
     frozen: true,
     imports: [
         "android.hardware.common-V2",
+        "android.hardware.drm.common-V1",
     ],
     backend: {
         cpp: {
@@ -26,12 +27,18 @@
         ndk: {
             min_sdk_version: "34",
         },
+        rust: {
+            enabled: true,
+        },
     },
     double_loadable: true,
     versions_with_info: [
         {
             version: "1",
-            imports: ["android.hardware.common-V2"],
+            imports: [
+                "android.hardware.common-V2",
+                "android.hardware.drm.common-V1",
+            ],
         },
     ],
 
diff --git a/drm/aidl/aidl_api/android.hardware.drm/1/.hash b/drm/aidl/aidl_api/android.hardware.drm/1/.hash
index 886e28c..9a735e9 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/1/.hash
+++ b/drm/aidl/aidl_api/android.hardware.drm/1/.hash
@@ -1 +1,2 @@
 7b4b0a0f36a7a6bb22d2016375e4a9d4a033592f
+3a0197fb44863256da9034c26e721b1eee12d1be
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/EventType.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/EventType.aidl
index 80ebb28..f09eadd 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/EventType.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/EventType.aidl
@@ -34,9 +34,9 @@
 package android.hardware.drm;
 @Backing(type="int") @VintfStability
 enum EventType {
-  PROVISION_REQUIRED = 0,
-  KEY_NEEDED = 1,
-  KEY_EXPIRED = 2,
-  VENDOR_DEFINED = 3,
-  SESSION_RECLAIMED = 4,
+  PROVISION_REQUIRED,
+  KEY_NEEDED,
+  KEY_EXPIRED,
+  VENDOR_DEFINED,
+  SESSION_RECLAIMED,
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/HdcpLevel.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/HdcpLevel.aidl
deleted file mode 100644
index 5704fb0..0000000
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/HdcpLevel.aidl
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file built
-// with the aidl_interface module type with versions property set. The module
-// type is used to build AIDL files in a way that they can be used across
-// independently updatable components of the system. If a device is shipped
-// with such a backward incompatible change, it has a high risk of breaking
-// later when a module using the interface is updated, e.g., Mainline modules.
-
-package android.hardware.drm;
-@Backing(type="int") @VintfStability
-enum HdcpLevel {
-  HDCP_UNKNOWN = 0,
-  HDCP_NONE = 1,
-  HDCP_V1 = 2,
-  HDCP_V2 = 3,
-  HDCP_V2_1 = 4,
-  HDCP_V2_2 = 5,
-  HDCP_NO_OUTPUT = 6,
-  HDCP_V2_3 = 7,
-}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyRequestType.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyRequestType.aidl
index 34b9615..556ee38 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyRequestType.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyRequestType.aidl
@@ -34,10 +34,10 @@
 package android.hardware.drm;
 @Backing(type="int") @VintfStability
 enum KeyRequestType {
-  INITIAL = 0,
-  RENEWAL = 1,
-  RELEASE = 2,
-  UNKNOWN = 3,
-  NONE = 4,
-  UPDATE = 5,
+  INITIAL,
+  RENEWAL,
+  RELEASE,
+  UNKNOWN,
+  NONE,
+  UPDATE,
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyStatusType.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyStatusType.aidl
index 261516f..5a46552 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyStatusType.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyStatusType.aidl
@@ -34,10 +34,10 @@
 package android.hardware.drm;
 @Backing(type="int") @VintfStability
 enum KeyStatusType {
-  USABLE = 0,
-  EXPIRED = 1,
-  OUTPUT_NOT_ALLOWED = 2,
-  STATUS_PENDING = 3,
-  INTERNAL_ERROR = 4,
-  USABLE_IN_FUTURE = 5,
+  USABLE,
+  EXPIRED,
+  OUTPUT_NOT_ALLOWED,
+  STATUS_PENDING,
+  INTERNAL_ERROR,
+  USABLE_IN_FUTURE,
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyType.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyType.aidl
index 7a9d633..e677c86 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyType.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyType.aidl
@@ -34,7 +34,7 @@
 package android.hardware.drm;
 @Backing(type="int") @VintfStability
 enum KeyType {
-  OFFLINE = 0,
-  STREAMING = 1,
-  RELEASE = 2,
+  OFFLINE,
+  STREAMING,
+  RELEASE,
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/LogPriority.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/LogPriority.aidl
index 83362c3..b77ddf6 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/LogPriority.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/LogPriority.aidl
@@ -34,12 +34,12 @@
 package android.hardware.drm;
 @Backing(type="int") @VintfStability
 enum LogPriority {
-  UNKNOWN = 0,
-  DEFAULT = 1,
-  VERBOSE = 2,
-  DEBUG = 3,
-  INFO = 4,
-  WARN = 5,
-  ERROR = 6,
-  FATAL = 7,
+  UNKNOWN,
+  DEFAULT,
+  VERBOSE,
+  DEBUG,
+  INFO,
+  WARN,
+  ERROR,
+  FATAL,
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/OfflineLicenseState.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/OfflineLicenseState.aidl
index 629564d..be0e822 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/OfflineLicenseState.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/OfflineLicenseState.aidl
@@ -34,7 +34,7 @@
 package android.hardware.drm;
 @Backing(type="int") @VintfStability
 enum OfflineLicenseState {
-  UNKNOWN = 0,
-  USABLE = 1,
-  INACTIVE = 2,
+  UNKNOWN,
+  USABLE,
+  INACTIVE,
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SecurityLevel.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SecurityLevel.aidl
index 65b2b9d..87b3641 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SecurityLevel.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SecurityLevel.aidl
@@ -34,11 +34,11 @@
 package android.hardware.drm;
 @Backing(type="int") @VintfStability
 enum SecurityLevel {
-  UNKNOWN = 0,
-  SW_SECURE_CRYPTO = 1,
-  SW_SECURE_DECODE = 2,
-  HW_SECURE_CRYPTO = 3,
-  HW_SECURE_DECODE = 4,
-  HW_SECURE_ALL = 5,
-  DEFAULT = 6,
+  UNKNOWN,
+  SW_SECURE_CRYPTO,
+  SW_SECURE_DECODE,
+  HW_SECURE_CRYPTO,
+  HW_SECURE_DECODE,
+  HW_SECURE_ALL,
+  DEFAULT,
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Status.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Status.aidl
index c640689..a3ba6c3 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Status.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Status.aidl
@@ -34,44 +34,44 @@
 package android.hardware.drm;
 @Backing(type="int") @VintfStability
 enum Status {
-  OK = 0,
-  ERROR_DRM_NO_LICENSE = 1,
-  ERROR_DRM_LICENSE_EXPIRED = 2,
-  ERROR_DRM_SESSION_NOT_OPENED = 3,
-  ERROR_DRM_CANNOT_HANDLE = 4,
-  ERROR_DRM_INVALID_STATE = 5,
-  BAD_VALUE = 6,
-  ERROR_DRM_NOT_PROVISIONED = 7,
-  ERROR_DRM_RESOURCE_BUSY = 8,
-  ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION = 9,
-  ERROR_DRM_DEVICE_REVOKED = 10,
-  ERROR_DRM_DECRYPT = 11,
-  ERROR_DRM_UNKNOWN = 12,
-  ERROR_DRM_INSUFFICIENT_SECURITY = 13,
-  ERROR_DRM_FRAME_TOO_LARGE = 14,
-  ERROR_DRM_SESSION_LOST_STATE = 15,
-  ERROR_DRM_RESOURCE_CONTENTION = 16,
-  CANNOT_DECRYPT_ZERO_SUBSAMPLES = 17,
-  CRYPTO_LIBRARY_ERROR = 18,
-  GENERAL_OEM_ERROR = 19,
-  GENERAL_PLUGIN_ERROR = 20,
-  INIT_DATA_INVALID = 21,
-  KEY_NOT_LOADED = 22,
-  LICENSE_PARSE_ERROR = 23,
-  LICENSE_POLICY_ERROR = 24,
-  LICENSE_RELEASE_ERROR = 25,
-  LICENSE_REQUEST_REJECTED = 26,
-  LICENSE_RESTORE_ERROR = 27,
-  LICENSE_STATE_ERROR = 28,
-  MALFORMED_CERTIFICATE = 29,
-  MEDIA_FRAMEWORK_ERROR = 30,
-  MISSING_CERTIFICATE = 31,
-  PROVISIONING_CERTIFICATE_ERROR = 32,
-  PROVISIONING_CONFIGURATION_ERROR = 33,
-  PROVISIONING_PARSE_ERROR = 34,
-  PROVISIONING_REQUEST_REJECTED = 35,
-  RETRYABLE_PROVISIONING_ERROR = 36,
-  SECURE_STOP_RELEASE_ERROR = 37,
-  STORAGE_READ_FAILURE = 38,
-  STORAGE_WRITE_FAILURE = 39,
+  OK,
+  ERROR_DRM_NO_LICENSE,
+  ERROR_DRM_LICENSE_EXPIRED,
+  ERROR_DRM_SESSION_NOT_OPENED,
+  ERROR_DRM_CANNOT_HANDLE,
+  ERROR_DRM_INVALID_STATE,
+  BAD_VALUE,
+  ERROR_DRM_NOT_PROVISIONED,
+  ERROR_DRM_RESOURCE_BUSY,
+  ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION,
+  ERROR_DRM_DEVICE_REVOKED,
+  ERROR_DRM_DECRYPT,
+  ERROR_DRM_UNKNOWN,
+  ERROR_DRM_INSUFFICIENT_SECURITY,
+  ERROR_DRM_FRAME_TOO_LARGE,
+  ERROR_DRM_SESSION_LOST_STATE,
+  ERROR_DRM_RESOURCE_CONTENTION,
+  CANNOT_DECRYPT_ZERO_SUBSAMPLES,
+  CRYPTO_LIBRARY_ERROR,
+  GENERAL_OEM_ERROR,
+  GENERAL_PLUGIN_ERROR,
+  INIT_DATA_INVALID,
+  KEY_NOT_LOADED,
+  LICENSE_PARSE_ERROR,
+  LICENSE_POLICY_ERROR,
+  LICENSE_RELEASE_ERROR,
+  LICENSE_REQUEST_REJECTED,
+  LICENSE_RESTORE_ERROR,
+  LICENSE_STATE_ERROR,
+  MALFORMED_CERTIFICATE,
+  MEDIA_FRAMEWORK_ERROR,
+  MISSING_CERTIFICATE,
+  PROVISIONING_CERTIFICATE_ERROR,
+  PROVISIONING_CONFIGURATION_ERROR,
+  PROVISIONING_PARSE_ERROR,
+  PROVISIONING_REQUEST_REJECTED,
+  RETRYABLE_PROVISIONING_ERROR,
+  SECURE_STOP_RELEASE_ERROR,
+  STORAGE_READ_FAILURE,
+  STORAGE_WRITE_FAILURE,
 }
diff --git a/drm/aidl/vts/Android.bp b/drm/aidl/vts/Android.bp
index e813bd1..1fe0972 100644
--- a/drm/aidl/vts/Android.bp
+++ b/drm/aidl/vts/Android.bp
@@ -48,6 +48,7 @@
     ],
     static_libs: [
         "android.hardware.drm@1.0-helper",
+        "android.hardware.drm.common-V1-ndk",
         "android.hardware.drm-V1-ndk",
         "android.hardware.common-V2-ndk",
         "libaidlcommonsupport",
@@ -60,13 +61,19 @@
             data: [":libvtswidevine-arm-prebuilts"],
         },
         arm64: {
-            data: [":libvtswidevine-arm64-prebuilts", ":libvtswidevine-arm-prebuilts"],
+            data: [
+                ":libvtswidevine-arm64-prebuilts",
+                ":libvtswidevine-arm-prebuilts",
+            ],
         },
         x86: {
             data: [":libvtswidevine-x86-prebuilts"],
         },
         x86_64: {
-            data: [":libvtswidevine-x86_64-prebuilts", ":libvtswidevine-x86-prebuilts"],
+            data: [
+                ":libvtswidevine-x86_64-prebuilts",
+                ":libvtswidevine-x86-prebuilts",
+            ],
         },
     },
     test_suites: [
diff --git a/drm/common/aidl/Android.bp b/drm/common/aidl/Android.bp
new file mode 100644
index 0000000..c5cb441
--- /dev/null
+++ b/drm/common/aidl/Android.bp
@@ -0,0 +1,39 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.drm.common",
+    host_supported: true,
+    vendor_available: true,
+    srcs: ["android/hardware/drm/*.aidl"],
+    stability: "vintf",
+    backend: {
+        cpp: {
+            enabled: false,
+        },
+        java: {
+            sdk_version: "module_current",
+        },
+        ndk: {
+            min_sdk_version: "34",
+        },
+        rust: {
+            enabled: true,
+        },
+    },
+    double_loadable: true,
+    versions_with_info: [
+        {
+            version: "1",
+            imports: [],
+        },
+    ],
+    frozen: true,
+
+}
diff --git a/drm/common/aidl/aidl_api/android.hardware.drm.common/1/.hash b/drm/common/aidl/aidl_api/android.hardware.drm.common/1/.hash
new file mode 100644
index 0000000..66690e1
--- /dev/null
+++ b/drm/common/aidl/aidl_api/android.hardware.drm.common/1/.hash
@@ -0,0 +1 @@
+1b5e9159609b3aa05e2c7158f3a1488fda2250d1
diff --git a/drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevel.aidl b/drm/common/aidl/aidl_api/android.hardware.drm.common/1/android/hardware/drm/HdcpLevel.aidl
similarity index 92%
rename from drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevel.aidl
rename to drm/common/aidl/aidl_api/android.hardware.drm.common/1/android/hardware/drm/HdcpLevel.aidl
index 5704fb0..118bef6 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevel.aidl
+++ b/drm/common/aidl/aidl_api/android.hardware.drm.common/1/android/hardware/drm/HdcpLevel.aidl
@@ -34,12 +34,12 @@
 package android.hardware.drm;
 @Backing(type="int") @VintfStability
 enum HdcpLevel {
-  HDCP_UNKNOWN = 0,
-  HDCP_NONE = 1,
-  HDCP_V1 = 2,
-  HDCP_V2 = 3,
-  HDCP_V2_1 = 4,
-  HDCP_V2_2 = 5,
-  HDCP_NO_OUTPUT = 6,
-  HDCP_V2_3 = 7,
+  HDCP_UNKNOWN,
+  HDCP_NONE,
+  HDCP_V1,
+  HDCP_V2,
+  HDCP_V2_1,
+  HDCP_V2_2,
+  HDCP_NO_OUTPUT,
+  HDCP_V2_3,
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevels.aidl b/drm/common/aidl/aidl_api/android.hardware.drm.common/1/android/hardware/drm/HdcpLevels.aidl
similarity index 100%
rename from drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevels.aidl
rename to drm/common/aidl/aidl_api/android.hardware.drm.common/1/android/hardware/drm/HdcpLevels.aidl
diff --git a/drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevel.aidl b/drm/common/aidl/aidl_api/android.hardware.drm.common/current/android/hardware/drm/HdcpLevel.aidl
similarity index 92%
copy from drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevel.aidl
copy to drm/common/aidl/aidl_api/android.hardware.drm.common/current/android/hardware/drm/HdcpLevel.aidl
index 5704fb0..118bef6 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevel.aidl
+++ b/drm/common/aidl/aidl_api/android.hardware.drm.common/current/android/hardware/drm/HdcpLevel.aidl
@@ -34,12 +34,12 @@
 package android.hardware.drm;
 @Backing(type="int") @VintfStability
 enum HdcpLevel {
-  HDCP_UNKNOWN = 0,
-  HDCP_NONE = 1,
-  HDCP_V1 = 2,
-  HDCP_V2 = 3,
-  HDCP_V2_1 = 4,
-  HDCP_V2_2 = 5,
-  HDCP_NO_OUTPUT = 6,
-  HDCP_V2_3 = 7,
+  HDCP_UNKNOWN,
+  HDCP_NONE,
+  HDCP_V1,
+  HDCP_V2,
+  HDCP_V2_1,
+  HDCP_V2_2,
+  HDCP_NO_OUTPUT,
+  HDCP_V2_3,
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/HdcpLevels.aidl b/drm/common/aidl/aidl_api/android.hardware.drm.common/current/android/hardware/drm/HdcpLevels.aidl
similarity index 100%
rename from drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/HdcpLevels.aidl
rename to drm/common/aidl/aidl_api/android.hardware.drm.common/current/android/hardware/drm/HdcpLevels.aidl
diff --git a/drm/aidl/android/hardware/drm/HdcpLevel.aidl b/drm/common/aidl/android/hardware/drm/HdcpLevel.aidl
similarity index 100%
rename from drm/aidl/android/hardware/drm/HdcpLevel.aidl
rename to drm/common/aidl/android/hardware/drm/HdcpLevel.aidl
diff --git a/drm/aidl/android/hardware/drm/HdcpLevels.aidl b/drm/common/aidl/android/hardware/drm/HdcpLevels.aidl
similarity index 100%
rename from drm/aidl/android/hardware/drm/HdcpLevels.aidl
rename to drm/common/aidl/android/hardware/drm/HdcpLevels.aidl
diff --git a/gnss/aidl/android/hardware/gnss/IGnss.aidl b/gnss/aidl/android/hardware/gnss/IGnss.aidl
index 8a22d6e..aaafe7f 100644
--- a/gnss/aidl/android/hardware/gnss/IGnss.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnss.aidl
@@ -217,10 +217,6 @@
      * Starts a location output stream using the IGnssCallback gnssLocationCb(), following the
      * settings from the most recent call to setPositionMode().
      *
-     * When a location output stream is in progress, calling setPositionMode() does not change the
-     * settings of the current location output stream. stop() and start() must be called to make the
-     * new settings effective.
-     *
      * This output must operate independently of any GNSS location batching operations,
      * see the IGnssBatching for details.
      */
@@ -310,10 +306,6 @@
     /**
      * Sets the GnssPositionMode parameter, its associated recurrence value, the time between fixes,
      * requested fix accuracy, time to first fix.
-     *
-     * If a location output stream is in progress, calling this method does not affect the settings
-     * of current location output stream. stop() and start() must be called to make the new settings
-     * effective.
      */
     void setPositionMode(in PositionModeOptions options);
 
diff --git a/graphics/Android.bp b/graphics/Android.bp
index ac5c17f..cdeb2e6 100644
--- a/graphics/Android.bp
+++ b/graphics/Android.bp
@@ -56,28 +56,28 @@
 aidl_interface_defaults {
     name: "android.hardware.graphics.common-latest",
     imports: [
-        "android.hardware.graphics.common-V5",
+        "android.hardware.graphics.common-V6",
     ],
 }
 
 rust_defaults {
     name: "android.hardware.graphics.common-latest-rust",
     rustlibs: [
-        "android.hardware.graphics.common-V5-rust",
+        "android.hardware.graphics.common-V6-rust",
     ],
 }
 
 cc_defaults {
     name: "android.hardware.graphics.common-ndk_static",
     static_libs: [
-        "android.hardware.graphics.common-V5-ndk",
+        "android.hardware.graphics.common-V6-ndk",
     ],
 }
 
 cc_defaults {
     name: "android.hardware.graphics.common-ndk_shared",
     shared_libs: [
-        "android.hardware.graphics.common-V5-ndk",
+        "android.hardware.graphics.common-V6-ndk",
     ],
 }
 
@@ -91,13 +91,15 @@
 cc_defaults {
     name: "android.hardware.graphics.composer3-ndk_static",
     static_libs: [
-        "android.hardware.graphics.composer3-V3-ndk",
+        "android.hardware.drm.common-V1-ndk",
+        "android.hardware.graphics.composer3-V4-ndk",
     ],
 }
 
 cc_defaults {
     name: "android.hardware.graphics.composer3-ndk_shared",
     shared_libs: [
-        "android.hardware.graphics.composer3-V3-ndk",
+        "android.hardware.drm.common-V1-ndk",
+        "android.hardware.graphics.composer3-V4-ndk",
     ],
 }
diff --git a/graphics/allocator/aidl/Android.bp b/graphics/allocator/aidl/Android.bp
index 30b341c..3f74b23 100644
--- a/graphics/allocator/aidl/Android.bp
+++ b/graphics/allocator/aidl/Android.bp
@@ -45,7 +45,7 @@
             version: "2",
             imports: [
                 "android.hardware.common-V2",
-                "android.hardware.graphics.common-V5",
+                "android.hardware.graphics.common-V6",
             ],
         },
 
diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp
index 7157862..3b0a597 100644
--- a/graphics/composer/2.2/utils/vts/Android.bp
+++ b/graphics/composer/2.2/utils/vts/Android.bp
@@ -39,6 +39,7 @@
     shared_libs: [
         "libui",
         "server_configurable_flags",
+        "libtracing_perfetto",
     ],
     static_libs: [
         "android.hardware.graphics.composer@2.1-vts",
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index bda4198..431b1b6 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -55,6 +55,7 @@
         "libui",
         "android.hardware.common-V2-ndk",
         "server_configurable_flags",
+        "libtracing_perfetto",
     ],
     static_libs: [
         "android.hardware.graphics.common@1.1",
diff --git a/graphics/composer/aidl/Android.bp b/graphics/composer/aidl/Android.bp
index ace940a..719318a 100644
--- a/graphics/composer/aidl/Android.bp
+++ b/graphics/composer/aidl/Android.bp
@@ -29,7 +29,7 @@
     host_supported: true,
     vendor_available: true,
     double_loadable: true,
-    frozen: true,
+    frozen: false,
     srcs: [
         "android/hardware/graphics/composer3/*.aidl",
     ],
@@ -39,6 +39,7 @@
     ],
     imports: [
         "android.hardware.common-V2",
+        "android.hardware.drm.common-V1",
     ],
     backend: {
         cpp: {
@@ -58,21 +59,21 @@
         {
             version: "1",
             imports: [
-                "android.hardware.graphics.common-V5",
+                "android.hardware.graphics.common-V6",
                 "android.hardware.common-V2",
             ],
         },
         {
             version: "2",
             imports: [
-                "android.hardware.graphics.common-V5",
+                "android.hardware.graphics.common-V6",
                 "android.hardware.common-V2",
             ],
         },
         {
             version: "3",
             imports: [
-                "android.hardware.graphics.common-V5",
+                "android.hardware.graphics.common-V6",
                 "android.hardware.common-V2",
             ],
         },
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/CommandResultPayload.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/CommandResultPayload.aidl
index 6892f06..0fff523 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/CommandResultPayload.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/CommandResultPayload.aidl
@@ -41,4 +41,5 @@
   android.hardware.graphics.composer3.ReleaseFences releaseFences;
   android.hardware.graphics.composer3.PresentOrValidate presentOrValidateResult;
   android.hardware.graphics.composer3.ClientTargetPropertyWithBrightness clientTargetProperty;
+  android.hardware.graphics.composer3.DisplayLuts displayLuts;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/NextEnrollment.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayLuts.aidl
similarity index 84%
rename from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/NextEnrollment.aidl
rename to graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayLuts.aidl
index 75ed070..327e84c 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/NextEnrollment.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayLuts.aidl
@@ -5,7 +5,7 @@
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -31,11 +31,13 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
+package android.hardware.graphics.composer3;
 @VintfStability
-parcelable NextEnrollment {
-  int id;
-  android.hardware.biometrics.fingerprint.EnrollmentProgressStep[] progressSteps;
-  boolean result = true;
+parcelable DisplayLuts {
+  long display;
+  android.hardware.graphics.composer3.DisplayLuts.LayerLut[] layerLuts;
+  parcelable LayerLut {
+    long layer;
+    android.hardware.graphics.composer3.Lut lut;
+  }
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerCallback.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerCallback.aidl
index e64bd52..cd27360 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerCallback.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerCallback.aidl
@@ -45,4 +45,5 @@
   oneway void onVsyncIdle(long display);
   oneway void onRefreshRateChangedDebug(in android.hardware.graphics.composer3.RefreshRateChangedDebugData data);
   void onHotplugEvent(long display, android.hardware.graphics.common.DisplayHotplugEvent event);
+  oneway void onHdcpLevelsChanged(long display, in android.hardware.drm.HdcpLevels levels);
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl
index 87c8c18..8b2b13c 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl
@@ -57,4 +57,5 @@
   @nullable int[] bufferSlotsToClear;
   android.hardware.graphics.composer3.LayerLifecycleBatchCommandType layerLifecycleBatchCommandType;
   int newBufferSlotCount;
+  @nullable android.hardware.graphics.composer3.Lut[] luts;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Lut.aidl
similarity index 85%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Lut.aidl
index 173ac17..5fae35b 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Lut.aidl
@@ -5,7 +5,7 @@
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -31,10 +31,9 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
+package android.hardware.graphics.composer3;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable Lut {
+  @nullable ParcelFileDescriptor pfd;
+  android.hardware.graphics.composer3.LutProperties lutProperties;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/NextEnrollment.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LutProperties.aidl
similarity index 79%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/NextEnrollment.aidl
copy to graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LutProperties.aidl
index 75ed070..5edceb5 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/NextEnrollment.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LutProperties.aidl
@@ -5,7 +5,7 @@
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -31,11 +31,20 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
+package android.hardware.graphics.composer3;
 @VintfStability
-parcelable NextEnrollment {
-  int id;
-  android.hardware.biometrics.fingerprint.EnrollmentProgressStep[] progressSteps;
-  boolean result = true;
+parcelable LutProperties {
+  android.hardware.graphics.composer3.LutProperties.Dimension dimension;
+  long size;
+  android.hardware.graphics.composer3.LutProperties.SamplingKey[] samplingKeys;
+  @VintfStability
+  enum Dimension {
+    ONE_D = 1,
+    THREE_D = 3,
+  }
+  @VintfStability
+  enum SamplingKey {
+    RGB,
+    MAX_RGB,
+  }
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/OverlayProperties.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/OverlayProperties.aidl
index 7d31ea3..dae78fd 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/OverlayProperties.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/OverlayProperties.aidl
@@ -36,6 +36,7 @@
 parcelable OverlayProperties {
   android.hardware.graphics.composer3.OverlayProperties.SupportedBufferCombinations[] combinations;
   boolean supportMixedColorSpaces;
+  @nullable android.hardware.graphics.composer3.LutProperties[] lutProperties;
   parcelable SupportedBufferCombinations {
     android.hardware.graphics.common.PixelFormat[] pixelFormats;
     android.hardware.graphics.common.Dataspace[] standards;
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/CommandResultPayload.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/CommandResultPayload.aidl
index 99c91aa..94fc3d0 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/CommandResultPayload.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/CommandResultPayload.aidl
@@ -19,6 +19,7 @@
 import android.hardware.graphics.composer3.ChangedCompositionTypes;
 import android.hardware.graphics.composer3.ClientTargetPropertyWithBrightness;
 import android.hardware.graphics.composer3.CommandError;
+import android.hardware.graphics.composer3.DisplayLuts;
 import android.hardware.graphics.composer3.DisplayRequest;
 import android.hardware.graphics.composer3.PresentFence;
 import android.hardware.graphics.composer3.PresentOrValidate;
@@ -96,4 +97,13 @@
      * the SDR buffers when an HDR layer is simultaneously device-composited.
      */
     ClientTargetPropertyWithBrightness clientTargetProperty;
+
+    /**
+     * Sets the Lut(s) for the layers.
+     *
+     * HWC should only request Lut(s) if SurfaceFlinger does not send the Lut(s) to the HWC.
+     * The main use-case is like HDR10+ or Dolby Vision where there is no Lut to send from
+     * SurfaceFlinger.
+     */
+    DisplayLuts displayLuts;
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayLuts.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayLuts.aidl
new file mode 100644
index 0000000..ac0a606
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayLuts.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+import android.hardware.graphics.composer3.Lut;
+
+/**
+ * LUT (Look-Up Table) Interface for Color Transformation.
+ *
+ * This interface allows the HWC (Hardware Composer) to define and communicate Luts
+ * to SurfaceFlinger.
+ */
+@VintfStability
+parcelable DisplayLuts {
+    /**
+     * The display which the layerLuts list is for.
+     */
+    long display;
+
+    parcelable LayerLut {
+        /**
+         * The layer that the HWC is requesting a LUT to be applied during GPU composition.
+         */
+        long layer;
+        /**
+         * A Lut specified by the HWC for given HDR layers that don't have Luts provided.
+         */
+        Lut lut;
+    }
+
+    LayerLut[] layerLuts;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerCallback.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerCallback.aidl
index 96eccd7..a1d61fd 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerCallback.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerCallback.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.graphics.composer3;
 
+import android.hardware.drm.HdcpLevels;
 import android.hardware.graphics.common.DisplayHotplugEvent;
 import android.hardware.graphics.composer3.RefreshRateChangedDebugData;
 import android.hardware.graphics.composer3.VsyncPeriodChangeTimeline;
@@ -139,4 +140,12 @@
      * @param event is the type of event that occurred.
      */
     void onHotplugEvent(long display, DisplayHotplugEvent event);
+
+    /**
+     * Notify the client the HDCP levels of the display changed.
+     *
+     * @param display is the display whose HDCP levels have changed.
+     * @param levels is the new HDCP levels.
+     */
+    oneway void onHdcpLevelsChanged(long display, in HdcpLevels levels);
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl
index e961c48..bf4f504 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl
@@ -24,6 +24,7 @@
 import android.hardware.graphics.composer3.Color;
 import android.hardware.graphics.composer3.LayerBrightness;
 import android.hardware.graphics.composer3.LayerLifecycleBatchCommandType;
+import android.hardware.graphics.composer3.Lut;
 import android.hardware.graphics.composer3.ParcelableBlendMode;
 import android.hardware.graphics.composer3.ParcelableComposition;
 import android.hardware.graphics.composer3.ParcelableDataspace;
@@ -279,4 +280,9 @@
      * Specifies the number of buffer slot to be reserved.
      */
     int newBufferSlotCount;
+
+    /**
+     * Sets the lut(s) for the layer.
+     */
+    @nullable Lut[] luts;
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/Lut.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/Lut.aidl
new file mode 100644
index 0000000..abfeb14
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/Lut.aidl
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+import android.hardware.graphics.composer3.LutProperties;
+
+/**
+ * LUT (Look-Up Table) Interface for Color Transformation.
+ *
+ * This interface allows the HWC (Hardware Composer) to define and communicate LUTs
+ * with SurfaceFlinger.
+ */
+
+@VintfStability
+parcelable Lut {
+    /**
+     * A handle to a memory region.
+     * If the file descriptor is not set, this means that the HWC doesn't specify a Lut.
+     *
+     * When specifying a Lut, the HWC is required to follow the instructions as below:
+     * 1. use `memfd_create` to create a shared memory segment
+     *    with the size specified in lutProperties.
+     * 2. use `mmap` to map the shared memory segment into its own virtual address space.
+     *    PROT_READ/PROT_WRITE recommended for prot argument.
+     *
+     * For data precision, 32-bit float is used to specify a Lut by both the HWC and
+     * the platform.
+     *
+     * For unflattening/flattening 3D Lut(s), the algorithm below should be observed
+     * by both the HWC and the platform.
+     * Assuming that we have a 3D array `ORIGINAL[WIDTH, HEIGHT, DEPTH]`, we would turn it into
+     * `FLAT[WIDTH * HEIGHT * DEPTH]` by
+     *
+     * `FLAT[z + DEPTH * (y + HEIGHT * x)] = ORIGINAL[x, y, z]`
+     */
+    @nullable ParcelFileDescriptor pfd;
+
+    /**
+     * The properties of the Lut.
+     */
+    LutProperties lutProperties;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/LutProperties.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/LutProperties.aidl
new file mode 100644
index 0000000..47ec390
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/LutProperties.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+/**
+ * The properties of the LUT (Look-Up Table).
+ */
+@VintfStability
+parcelable LutProperties {
+    /**
+     * The dimension of the Lut.
+     * Either 1d or 3d.
+     */
+    @VintfStability enum Dimension { ONE_D = 1, THREE_D = 3 }
+    Dimension dimension;
+
+    /**
+     * The size of the Lut.
+     * This refers to the length of a 1D Lut, or the grid size of a 3D one.
+     */
+    long size;
+
+    /**
+     * SamplingKey is about how a Lut can be sampled.
+     * A Lut can be sampled in more than one way,
+     * but only one sampling method is used at one time.
+     *
+     * The implementations should use a sampling strategy
+     * at least as good as linear sampling.
+     */
+    // TODO(b/358422255): add sampling ways
+    @VintfStability enum SamplingKey { RGB, MAX_RGB }
+    SamplingKey[] samplingKeys;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/OverlayProperties.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/OverlayProperties.aidl
index c25eea4..b97cdcc 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/OverlayProperties.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/OverlayProperties.aidl
@@ -16,6 +16,8 @@
 
 package android.hardware.graphics.composer3;
 
+import android.hardware.graphics.composer3.LutProperties;
+
 @VintfStability
 parcelable OverlayProperties {
     parcelable SupportedBufferCombinations {
@@ -42,4 +44,8 @@
     // True if the DPU is able to color manage at least two overlays
     // with different input colorspaces, false otherwise.
     boolean supportMixedColorSpaces;
+
+    // Array of lut properties in order that the HWC supports.
+    // The list accepts 1D lut(s) and 3D lut(s).
+    @nullable LutProperties[] lutProperties;
 }
diff --git a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h
index 76ba24b..331d717 100644
--- a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h
+++ b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h
@@ -27,9 +27,8 @@
 #include <string.h>
 
 #include <aidl/android/hardware/graphics/composer3/ClientTargetProperty.h>
-#include <aidl/android/hardware/graphics/composer3/Composition.h>
 #include <aidl/android/hardware/graphics/composer3/CommandResultPayload.h>
-
+#include <aidl/android/hardware/graphics/composer3/Composition.h>
 
 #include <log/log.h>
 #include <sync/sync.h>
@@ -84,6 +83,10 @@
                     parseSetClientTargetProperty(std::move(
                             result.get<CommandResultPayload::Tag::clientTargetProperty>()));
                     break;
+                case CommandResultPayload::Tag::displayLuts:
+                    parseSetDisplayLuts(
+                            std::move(result.get<CommandResultPayload::Tag::displayLuts>()));
+                    break;
             }
         }
     }
@@ -182,6 +185,20 @@
         return std::move(data.clientTargetProperty);
     }
 
+    // Get the lut(s) requested by hardware composer.
+    std::vector<DisplayLuts::LayerLut> takeDisplayLuts(int64_t display) {
+        LOG_ALWAYS_FATAL_IF(mDisplay && display != *mDisplay);
+        auto found = mReturnData.find(display);
+
+        // If not found, return the empty vector
+        if (found == mReturnData.end()) {
+            return {};
+        }
+
+        ReturnData& data = found->second;
+        return std::move(data.layerLuts);
+    }
+
   private:
     void resetData() {
         mErrors.clear();
@@ -227,6 +244,18 @@
         data.clientTargetProperty = std::move(clientTargetProperty);
     }
 
+    void parseSetDisplayLuts(DisplayLuts&& displayLuts) {
+        LOG_ALWAYS_FATAL_IF(mDisplay && displayLuts.display != *mDisplay);
+        auto& data = mReturnData[displayLuts.display];
+        for (auto& layerLut : displayLuts.layerLuts) {
+            if (layerLut.lut.pfd.get() >= 0) {
+                data.layerLuts.push_back(
+                        {layerLut.layer, Lut{ndk::ScopedFileDescriptor(layerLut.lut.pfd.release()),
+                                             layerLut.lut.lutProperties}});
+            }
+        }
+    }
+
     struct ReturnData {
         DisplayRequest displayRequests;
         std::vector<ChangedCompositionLayer> changedLayers;
@@ -238,6 +267,7 @@
                 .clientTargetProperty = {common::PixelFormat::RGBA_8888, Dataspace::UNKNOWN},
                 .brightness = 1.f,
         };
+        std::vector<DisplayLuts::LayerLut> layerLuts;
     };
 
     std::vector<CommandError> mErrors;
diff --git a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
index a1ccbfe..02fb3aa 100644
--- a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
+++ b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
@@ -30,6 +30,7 @@
 #include <aidl/android/hardware/graphics/composer3/DisplayBrightness.h>
 #include <aidl/android/hardware/graphics/composer3/LayerBrightness.h>
 #include <aidl/android/hardware/graphics/composer3/LayerLifecycleBatchCommandType.h>
+#include <aidl/android/hardware/graphics/composer3/Lut.h>
 #include <aidl/android/hardware/graphics/composer3/PerFrameMetadata.h>
 #include <aidl/android/hardware/graphics/composer3/PerFrameMetadataBlob.h>
 
@@ -245,6 +246,15 @@
         getLayerCommand(display, layer).blockingRegion.emplace(blocking.begin(), blocking.end());
     }
 
+    void setLayerLuts(int64_t display, int64_t layer, std::vector<Lut>& luts) {
+        std::vector<std::optional<Lut>> currentLuts;
+        for (auto& lut : luts) {
+            currentLuts.push_back(std::make_optional<Lut>(
+                    {ndk::ScopedFileDescriptor(lut.pfd.release()), lut.lutProperties}));
+        }
+        getLayerCommand(display, layer).luts.emplace(std::move(currentLuts));
+    }
+
     std::vector<DisplayCommand> takePendingCommands() {
         flushLayerCommand();
         flushDisplayCommand();
diff --git a/graphics/composer/aidl/vts/Android.bp b/graphics/composer/aidl/vts/Android.bp
index 3464fe9..894ca52 100644
--- a/graphics/composer/aidl/vts/Android.bp
+++ b/graphics/composer/aidl/vts/Android.bp
@@ -57,6 +57,7 @@
         "libprocessgroup",
         "libvndksupport",
         "server_configurable_flags",
+        "libtracing_perfetto",
     ],
     header_libs: [
         "android.hardware.graphics.composer3-command-buffer",
@@ -65,6 +66,7 @@
         "android.hardware.graphics.common@1.2",
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
+        "android.hardware.drm.common-V1-ndk",
         "libaidlcommonsupport",
         "libarect",
         "libbase",
diff --git a/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp b/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp
index 544f692..1f7972c 100644
--- a/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp
+++ b/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp
@@ -208,4 +208,15 @@
     }
 }
 
+::ndk::ScopedAStatus GraphicsComposerCallback::onHdcpLevelsChanged(
+        int64_t in_display, const ::aidl::android::hardware::drm::HdcpLevels&) {
+    std::scoped_lock lock(mMutex);
+
+    const auto it = std::find(mDisplays.begin(), mDisplays.end(), in_display);
+    if (it != mDisplays.end()) {
+        mHdcpLevelChangedCount++;
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
 }  // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/vts/GraphicsComposerCallback.h b/graphics/composer/aidl/vts/GraphicsComposerCallback.h
index 7a8d4a3..97f8e2b 100644
--- a/graphics/composer/aidl/vts/GraphicsComposerCallback.h
+++ b/graphics/composer/aidl/vts/GraphicsComposerCallback.h
@@ -65,6 +65,8 @@
             const RefreshRateChangedDebugData&) override;
     virtual ::ndk::ScopedAStatus onHotplugEvent(int64_t in_display,
                                                 common::DisplayHotplugEvent) override;
+    virtual ::ndk::ScopedAStatus onHdcpLevelsChanged(
+            int64_t in_display, const ::aidl::android::hardware::drm::HdcpLevels&) override;
 
     mutable std::mutex mMutex;
     // the set of all currently connected displays
@@ -88,6 +90,7 @@
     int32_t mInvalidVsyncPeriodChangeCount GUARDED_BY(mMutex) = 0;
     int32_t mInvalidSeamlessPossibleCount GUARDED_BY(mMutex) = 0;
     int32_t mInvalidRefreshRateDebugEnabledCallbackCount GUARDED_BY(mMutex) = 0;
+    int32_t mHdcpLevelChangedCount GUARDED_BY(mMutex) = 0;
 };
 
 }  // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/vts/ReadbackVts.cpp b/graphics/composer/aidl/vts/ReadbackVts.cpp
index 283b8ce..9d5928d 100644
--- a/graphics/composer/aidl/vts/ReadbackVts.cpp
+++ b/graphics/composer/aidl/vts/ReadbackVts.cpp
@@ -16,6 +16,7 @@
 
 #include "ReadbackVts.h"
 #include <aidl/android/hardware/graphics/common/BufferUsage.h>
+#include <cmath>
 #include "RenderEngineVts.h"
 #include "renderengine/ExternalTexture.h"
 #include "renderengine/impl/ExternalTexture.h"
@@ -106,37 +107,72 @@
     return layerSettings;
 }
 
-int32_t ReadbackHelper::GetBytesPerPixel(common::PixelFormat pixelFormat) {
+int32_t ReadbackHelper::GetBitsPerChannel(common::PixelFormat pixelFormat) {
     switch (pixelFormat) {
+        case common::PixelFormat::RGBA_1010102:
+            return 10;
         case common::PixelFormat::RGBA_8888:
-            return 4;
         case common::PixelFormat::RGB_888:
-            return 3;
+            return 8;
         default:
             return -1;
     }
 }
 
-void ReadbackHelper::fillBuffer(uint32_t width, uint32_t height, uint32_t stride, void* bufferData,
+int32_t ReadbackHelper::GetAlphaBits(common::PixelFormat pixelFormat) {
+    switch (pixelFormat) {
+        case common::PixelFormat::RGBA_8888:
+            return 8;
+        case common::PixelFormat::RGBA_1010102:
+            return 2;
+        case common::PixelFormat::RGB_888:
+            return 0;
+        default:
+            return -1;
+    }
+}
+
+void ReadbackHelper::fillBuffer(uint32_t width, uint32_t height, uint32_t stride,
+                                int32_t bytesPerPixel, void* bufferData,
                                 common::PixelFormat pixelFormat,
                                 std::vector<Color> desiredPixelColors) {
     ASSERT_TRUE(pixelFormat == common::PixelFormat::RGB_888 ||
-                pixelFormat == common::PixelFormat::RGBA_8888);
-    int32_t bytesPerPixel = GetBytesPerPixel(pixelFormat);
+                pixelFormat == common::PixelFormat::RGBA_8888 ||
+                pixelFormat == common::PixelFormat::RGBA_1010102);
+    int32_t bitsPerChannel = GetBitsPerChannel(pixelFormat);
+    int32_t alphaBits = GetAlphaBits(pixelFormat);
+    ASSERT_NE(-1, alphaBits);
+    ASSERT_NE(-1, bitsPerChannel);
     ASSERT_NE(-1, bytesPerPixel);
-    for (int row = 0; row < height; row++) {
-        for (int col = 0; col < width; col++) {
-            auto pixel = row * static_cast<int32_t>(width) + col;
+
+    uint32_t maxValue = (1 << bitsPerChannel) - 1;
+    uint32_t maxAlphaValue = (1 << alphaBits) - 1;
+    for (uint32_t row = 0; row < height; row++) {
+        for (uint32_t col = 0; col < width; col++) {
+            auto pixel = row * width + col;
             Color srcColor = desiredPixelColors[static_cast<size_t>(pixel)];
 
-            int offset = (row * static_cast<int32_t>(stride) + col) * bytesPerPixel;
-            uint8_t* pixelColor = (uint8_t*)bufferData + offset;
-            pixelColor[0] = static_cast<uint8_t>(std::round(255.0f * srcColor.r));
-            pixelColor[1] = static_cast<uint8_t>(std::round(255.0f * srcColor.g));
-            pixelColor[2] = static_cast<uint8_t>(std::round(255.0f * srcColor.b));
+            uint32_t offset = (row * stride + col) * static_cast<uint32_t>(bytesPerPixel);
 
-            if (bytesPerPixel == 4) {
-                pixelColor[3] = static_cast<uint8_t>(std::round(255.0f * srcColor.a));
+            uint32_t* pixelStart = (uint32_t*)((uint8_t*)bufferData + offset);
+
+            uint32_t red = static_cast<uint32_t>(std::round(maxValue * srcColor.r));
+            uint32_t green = static_cast<uint32_t>(std::round(maxValue * srcColor.g));
+            uint32_t blue = static_cast<uint32_t>(std::round(maxValue * srcColor.b));
+
+            // Boo we're not word aligned so special case this.
+            if (pixelFormat == common::PixelFormat::RGB_888) {
+                uint8_t* pixelColor = (uint8_t*)pixelStart;
+                pixelColor[0] = static_cast<uint8_t>(red);
+                pixelColor[1] = static_cast<uint8_t>(green);
+                pixelColor[2] = static_cast<uint8_t>(blue);
+            } else {
+                uint32_t alpha = static_cast<uint32_t>(std::round(maxAlphaValue * srcColor.a));
+                uint32_t color = (alpha << (32 - alphaBits)) |
+                                 (blue << (32 - alphaBits - bitsPerChannel)) |
+                                 (green << (32 - alphaBits - bitsPerChannel * 2)) |
+                                 (red << (32 - alphaBits - bitsPerChannel * 3));
+                *pixelStart = color;
             }
         }
     }
@@ -165,7 +201,8 @@
 bool ReadbackHelper::readbackSupported(const common::PixelFormat& pixelFormat,
                                        const common::Dataspace& dataspace) {
     if (pixelFormat != common::PixelFormat::RGB_888 &&
-        pixelFormat != common::PixelFormat::RGBA_8888) {
+        pixelFormat != common::PixelFormat::RGBA_8888 &&
+        pixelFormat != common::PixelFormat::RGBA_1010102) {
         return false;
     }
     if (std::find(dataspaces.begin(), dataspaces.end(), dataspace) == dataspaces.end()) {
@@ -175,36 +212,110 @@
 }
 
 void ReadbackHelper::compareColorBuffers(const std::vector<Color>& expectedColors, void* bufferData,
-                                         const uint32_t stride, const uint32_t width,
-                                         const uint32_t height, common::PixelFormat pixelFormat) {
-    const int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(pixelFormat);
-    ASSERT_NE(-1, bytesPerPixel);
-    for (int row = 0; row < height; row++) {
-        for (int col = 0; col < width; col++) {
-            auto pixel = row * static_cast<int32_t>(width) + col;
-            int offset = (row * static_cast<int32_t>(stride) + col) * bytesPerPixel;
-            uint8_t* pixelColor = (uint8_t*)bufferData + offset;
+                                         const uint32_t stride, int32_t bytesPerPixel,
+                                         const uint32_t width, const uint32_t height,
+                                         common::PixelFormat pixelFormat) {
+    int32_t bitsPerChannel = GetBitsPerChannel(pixelFormat);
+    int32_t alphaBits = GetAlphaBits(pixelFormat);
+    ASSERT_GT(bytesPerPixel, 0);
+    ASSERT_NE(-1, alphaBits);
+    ASSERT_NE(-1, bitsPerChannel);
+    uint32_t maxValue = (1 << bitsPerChannel) - 1;
+    uint32_t maxAlphaValue = (1 << alphaBits) - 1;
+    for (uint32_t row = 0; row < height; row++) {
+        for (uint32_t col = 0; col < width; col++) {
+            auto pixel = row * width + col;
             const Color expectedColor = expectedColors[static_cast<size_t>(pixel)];
-            ASSERT_EQ(std::round(255.0f * expectedColor.r), pixelColor[0]);
-            ASSERT_EQ(std::round(255.0f * expectedColor.g), pixelColor[1]);
-            ASSERT_EQ(std::round(255.0f * expectedColor.b), pixelColor[2]);
+
+            uint32_t offset = (row * stride + col) * static_cast<uint32_t>(bytesPerPixel);
+            uint32_t* pixelStart = (uint32_t*)((uint8_t*)bufferData + offset);
+
+            uint32_t expectedRed = static_cast<uint32_t>(std::round(maxValue * expectedColor.r));
+            uint32_t expectedGreen = static_cast<uint32_t>(std::round(maxValue * expectedColor.g));
+            uint32_t expectedBlue = static_cast<uint32_t>(std::round(maxValue * expectedColor.b));
+
+            // Boo we're not word aligned so special case this.
+            if (pixelFormat == common::PixelFormat::RGB_888) {
+                uint8_t* pixelColor = (uint8_t*)pixelStart;
+                ASSERT_EQ(pixelColor[0], static_cast<uint8_t>(expectedRed))
+                        << "Red channel mismatch at (" << row << ", " << col << ")";
+                ASSERT_EQ(pixelColor[1], static_cast<uint8_t>(expectedGreen))
+                        << "Green channel mismatch at (" << row << ", " << col << ")";
+                ASSERT_EQ(pixelColor[2], static_cast<uint8_t>(expectedBlue))
+                        << "Blue channel mismatch at (" << row << ", " << col << ")";
+            } else {
+                uint32_t expectedAlpha =
+                        static_cast<uint32_t>(std::round(maxAlphaValue * expectedColor.a));
+
+                uint32_t actualRed =
+                        (*pixelStart >> (32 - alphaBits - bitsPerChannel * 3)) & maxValue;
+                uint32_t actualGreen =
+                        (*pixelStart >> (32 - alphaBits - bitsPerChannel * 2)) & maxValue;
+                uint32_t actualBlue = (*pixelStart >> (32 - alphaBits - bitsPerChannel)) & maxValue;
+                uint32_t actualAlpha = (*pixelStart >> (32 - alphaBits)) & maxAlphaValue;
+
+                ASSERT_EQ(expectedRed, actualRed)
+                        << "Red channel mismatch at (" << row << ", " << col << ")";
+                ASSERT_EQ(expectedGreen, actualGreen)
+                        << "Green channel mismatch at (" << row << ", " << col << ")";
+                ASSERT_EQ(expectedBlue, actualBlue)
+                        << "Blue channel mismatch at (" << row << ", " << col << ")";
+            }
         }
     }
 }
 
 void ReadbackHelper::compareColorBuffers(void* expectedBuffer, void* actualBuffer,
-                                         const uint32_t stride, const uint32_t width,
-                                         const uint32_t height, common::PixelFormat pixelFormat) {
-    const int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(pixelFormat);
-    ASSERT_NE(-1, bytesPerPixel);
-    for (int row = 0; row < height; row++) {
-        for (int col = 0; col < width; col++) {
-            int offset = (row * static_cast<int32_t>(stride) + col) * bytesPerPixel;
-            uint8_t* expectedColor = (uint8_t*)expectedBuffer + offset;
-            uint8_t* actualColor = (uint8_t*)actualBuffer + offset;
-            ASSERT_EQ(expectedColor[0], actualColor[0]);
-            ASSERT_EQ(expectedColor[1], actualColor[1]);
-            ASSERT_EQ(expectedColor[2], actualColor[2]);
+                                         const uint32_t stride, int32_t bytesPerPixel,
+                                         const uint32_t width, const uint32_t height,
+                                         common::PixelFormat pixelFormat) {
+    int32_t bitsPerChannel = GetBitsPerChannel(pixelFormat);
+    int32_t alphaBits = GetAlphaBits(pixelFormat);
+    ASSERT_GT(bytesPerPixel, 0);
+    ASSERT_NE(-1, alphaBits);
+    ASSERT_NE(-1, bitsPerChannel);
+    uint32_t maxValue = (1 << bitsPerChannel) - 1;
+    uint32_t maxAlphaValue = (1 << alphaBits) - 1;
+    for (uint32_t row = 0; row < height; row++) {
+        for (uint32_t col = 0; col < width; col++) {
+            uint32_t offset = (row * stride + col) * static_cast<uint32_t>(bytesPerPixel);
+            uint32_t* expectedStart = (uint32_t*)((uint8_t*)expectedBuffer + offset);
+            uint32_t* actualStart = (uint32_t*)((uint8_t*)actualBuffer + offset);
+
+            // Boo we're not word aligned so special case this.
+            if (pixelFormat == common::PixelFormat::RGB_888) {
+                uint8_t* expectedPixel = (uint8_t*)expectedStart;
+                uint8_t* actualPixel = (uint8_t*)actualStart;
+                ASSERT_EQ(actualPixel[0], expectedPixel[0])
+                        << "Red channel mismatch at (" << row << ", " << col << ")";
+                ASSERT_EQ(actualPixel[1], expectedPixel[1])
+                        << "Green channel mismatch at (" << row << ", " << col << ")";
+                ASSERT_EQ(actualPixel[2], expectedPixel[2])
+                        << "Blue channel mismatch at (" << row << ", " << col << ")";
+            } else {
+                uint32_t expectedRed =
+                        (*expectedStart >> (32 - alphaBits - bitsPerChannel * 3)) & maxValue;
+                uint32_t expectedGreen =
+                        (*expectedStart >> (32 - alphaBits - bitsPerChannel * 2)) & maxValue;
+                uint32_t expectedBlue =
+                        (*expectedStart >> (32 - alphaBits - bitsPerChannel)) & maxValue;
+                uint32_t expectedAlpha = (*expectedStart >> (32 - alphaBits)) & maxAlphaValue;
+
+                uint32_t actualRed =
+                        (*actualStart >> (32 - alphaBits - bitsPerChannel * 3)) & maxValue;
+                uint32_t actualGreen =
+                        (*actualStart >> (32 - alphaBits - bitsPerChannel * 2)) & maxValue;
+                uint32_t actualBlue =
+                        (*actualStart >> (32 - alphaBits - bitsPerChannel)) & maxValue;
+                uint32_t actualAlpha = (*actualStart >> (32 - alphaBits)) & maxAlphaValue;
+
+                ASSERT_EQ(expectedRed, actualRed)
+                        << "Red channel mismatch at (" << row << ", " << col << ")";
+                ASSERT_EQ(expectedGreen, actualGreen)
+                        << "Green channel mismatch at (" << row << ", " << col << ")";
+                ASSERT_EQ(expectedBlue, actualBlue)
+                        << "Blue channel mismatch at (" << row << ", " << col << ")";
+            }
         }
     }
 }
@@ -258,12 +369,13 @@
     auto status = mGraphicBuffer->lockAsync(mUsage, mAccessRegion, &bufData, dup(bufferFence.get()),
                                             &bytesPerPixel, &bytesPerStride);
     EXPECT_EQ(::android::OK, status);
-    ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888);
+    ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888 ||
+                mPixelFormat == PixelFormat::RGBA_1010102);
     const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
                                     ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
                                     : mGraphicBuffer->getStride();
-    ReadbackHelper::compareColorBuffers(expectedColors, bufData, stride, mWidth, mHeight,
-                                        mPixelFormat);
+    ReadbackHelper::compareColorBuffers(expectedColors, bufData, stride, bytesPerPixel, mWidth,
+                                        mHeight, mPixelFormat);
     status = mGraphicBuffer->unlock();
     EXPECT_EQ(::android::OK, status);
 }
@@ -353,8 +465,8 @@
                                     ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
                                     : mGraphicBuffer->getStride();
     EXPECT_EQ(::android::OK, status);
-    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mWidth, mHeight, stride, bufData,
-                                                       mPixelFormat, expectedColors));
+    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mWidth, mHeight, stride, bytesPerPixel,
+                                                       bufData, mPixelFormat, expectedColors));
 
     const auto unlockStatus = mGraphicBuffer->unlockAsync(&mFillFence);
     ASSERT_EQ(::android::OK, unlockStatus);
diff --git a/graphics/composer/aidl/vts/ReadbackVts.h b/graphics/composer/aidl/vts/ReadbackVts.h
index 8ac0f4b..e3b2384 100644
--- a/graphics/composer/aidl/vts/ReadbackVts.h
+++ b/graphics/composer/aidl/vts/ReadbackVts.h
@@ -172,10 +172,12 @@
 
     static Dataspace getDataspaceForColorMode(ColorMode mode);
 
-    static int32_t GetBytesPerPixel(PixelFormat pixelFormat);
+    static int32_t GetBitsPerChannel(PixelFormat pixelFormat);
+    static int32_t GetAlphaBits(PixelFormat pixelFormat);
 
-    static void fillBuffer(uint32_t width, uint32_t height, uint32_t stride, void* bufferData,
-                           PixelFormat pixelFormat, std::vector<Color> desiredPixelColors);
+    static void fillBuffer(uint32_t width, uint32_t height, uint32_t stride, int32_t bytesPerPixel,
+                           void* bufferData, PixelFormat pixelFormat,
+                           std::vector<Color> desiredPixelColors);
 
     static void clearColors(std::vector<Color>& expectedColors, int32_t width, int32_t height,
                             int32_t displayWidth);
@@ -189,11 +191,12 @@
     static const std::vector<Dataspace> dataspaces;
 
     static void compareColorBuffers(const std::vector<Color>& expectedColors, void* bufferData,
-                                    const uint32_t stride, const uint32_t width,
-                                    const uint32_t height, PixelFormat pixelFormat);
-    static void compareColorBuffers(void* expectedBuffer, void* actualBuffer, const uint32_t stride,
+                                    const uint32_t stride, int32_t bytesPerPixel,
                                     const uint32_t width, const uint32_t height,
                                     PixelFormat pixelFormat);
+    static void compareColorBuffers(void* expectedBuffer, void* actualBuffer, const uint32_t stride,
+                                    int32_t bytesPerPixel, const uint32_t width,
+                                    const uint32_t height, PixelFormat pixelFormat);
 };
 
 class ReadbackBuffer {
diff --git a/graphics/composer/aidl/vts/RenderEngineVts.cpp b/graphics/composer/aidl/vts/RenderEngineVts.cpp
index bc5eb6f..8f8b5fd 100644
--- a/graphics/composer/aidl/vts/RenderEngineVts.cpp
+++ b/graphics/composer/aidl/vts/RenderEngineVts.cpp
@@ -81,7 +81,7 @@
     const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
                                     ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
                                     : mGraphicBuffer->getStride();
-    ReadbackHelper::compareColorBuffers(expectedColors, bufferData, stride,
+    ReadbackHelper::compareColorBuffers(expectedColors, bufferData, stride, bytesPerPixel,
                                         mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight(),
                                         mFormat);
     ASSERT_EQ(::android::OK, mGraphicBuffer->unlock());
@@ -108,7 +108,7 @@
 
     ASSERT_EQ(renderedStride, bufferStride);
 
-    ReadbackHelper::compareColorBuffers(renderedBufferData, bufferData, bufferStride,
+    ReadbackHelper::compareColorBuffers(renderedBufferData, bufferData, bufferStride, bytesPerPixel,
                                         mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight(),
                                         mFormat);
     ASSERT_EQ(::android::OK, buffer->unlock());
diff --git a/graphics/composer/aidl/vts/RenderEngineVts.h b/graphics/composer/aidl/vts/RenderEngineVts.h
index bbe508f..6553720 100644
--- a/graphics/composer/aidl/vts/RenderEngineVts.h
+++ b/graphics/composer/aidl/vts/RenderEngineVts.h
@@ -51,9 +51,10 @@
 
   private:
     common::PixelFormat mFormat;
-    std::vector<::android::renderengine::LayerSettings> mCompositionLayers;
     std::unique_ptr<::android::renderengine::RenderEngine> mRenderEngine;
-    std::vector<::android::renderengine::LayerSettings> mRenderLayers;
+    // Delete RenderEngine layers before RenderEngine -- ExternalTexture holds a reference to
+    // RenderEngine.
+    std::vector<::android::renderengine::LayerSettings> mCompositionLayers;
     ::android::sp<::android::GraphicBuffer> mGraphicBuffer;
 
     DisplaySettings mDisplaySettings;
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
index 3d9253f..9db8794 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
@@ -496,11 +496,14 @@
             const auto& buffer = graphicBuffer->handle;
             void* clientBufData;
             const auto stride = static_cast<uint32_t>(graphicBuffer->stride);
-            graphicBuffer->lock(clientUsage, layer->getAccessRegion(), &clientBufData);
+            int bytesPerPixel = -1;
+            int bytesPerStride = -1;
+            graphicBuffer->lock(clientUsage, layer->getAccessRegion(), &clientBufData,
+                                &bytesPerPixel, &bytesPerStride);
 
-            ASSERT_NO_FATAL_FAILURE(
-                    ReadbackHelper::fillBuffer(layer->getWidth(), layer->getHeight(), stride,
-                                               clientBufData, clientFormat, expectedColors));
+            ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(
+                    layer->getWidth(), layer->getHeight(), stride, bytesPerPixel, clientBufData,
+                    clientFormat, expectedColors));
             int32_t clientFence;
             const auto unlockStatus = graphicBuffer->unlockAsync(&clientFence);
             ASSERT_EQ(::android::OK, unlockStatus);
@@ -677,15 +680,18 @@
         const auto& buffer = graphicBuffer->handle;
 
         void* clientBufData;
+        int bytesPerPixel = -1;
+        int bytesPerStride = -1;
         graphicBuffer->lock(clientUsage, {0, 0, getDisplayWidth(), getDisplayHeight()},
-                            &clientBufData);
+                            &clientBufData, &bytesPerPixel, &bytesPerStride);
 
         std::vector<Color> clientColors(
                 static_cast<size_t>(getDisplayWidth() * getDisplayHeight()));
         ReadbackHelper::fillColorsArea(clientColors, getDisplayWidth(), clientFrame, RED);
         ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(
                 static_cast<uint32_t>(getDisplayWidth()), static_cast<uint32_t>(getDisplayHeight()),
-                graphicBuffer->getStride(), clientBufData, clientFormat, clientColors));
+                graphicBuffer->getStride(), bytesPerPixel, clientBufData, clientFormat,
+                clientColors));
         int32_t clientFence;
         const auto unlockStatus = graphicBuffer->unlockAsync(&clientFence);
         ASSERT_EQ(::android::OK, unlockStatus);
diff --git a/graphics/mapper/4.0/utils/vts/Android.bp b/graphics/mapper/4.0/utils/vts/Android.bp
index c5f124c..1be460e 100644
--- a/graphics/mapper/4.0/utils/vts/Android.bp
+++ b/graphics/mapper/4.0/utils/vts/Android.bp
@@ -48,7 +48,7 @@
     ],
     export_static_lib_headers: [
         "android.hardware.graphics.allocator@4.0",
-        "android.hardware.graphics.common-V5-ndk",
+        "android.hardware.graphics.common-V6-ndk",
         "android.hardware.graphics.mapper@4.0",
     ],
     export_include_dirs: ["include"],
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index bae362f..f398c53 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -719,6 +719,38 @@
 }
 
 /**
+ * Test IMapper::lock and IMapper::unlock with no CPU usage requested.
+ */
+TEST_P(GraphicsMapperHidlTest, LockUnlockNoCPUUsage) {
+    const auto& info = mDummyDescriptorInfo;
+
+    const native_handle_t* bufferHandle;
+    uint32_t stride;
+    ASSERT_NO_FATAL_FAILURE(
+            bufferHandle = mGralloc->allocate(info, true, Tolerance::kToleranceStrict, &stride));
+
+    // lock buffer with 0 usage
+    const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+                               static_cast<int32_t>(info.height)};
+
+    hidl_handle acquireFenceHandle;
+
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+    mGralloc->getMapper()->lock(buffer, 0, region, acquireFenceHandle,
+                                [&](const auto& tmpError, const auto& /*tmpData*/) {
+                                    EXPECT_EQ(Error::BAD_VALUE, tmpError)
+                                            << "Locking with 0 access succeeded";
+                                });
+
+    mGralloc->getMapper()->unlock(buffer, [&](const auto& tmpError, const auto&) {
+        EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+                << "Unlocking not locked buffer succeeded";
+    });
+
+    mGralloc->freeBuffer(bufferHandle);
+}
+
+/**
  *  Test multiple operations associated with different color formats
  */
 TEST_P(GraphicsMapperHidlTest, Lock_YCRCB_420_SP) {
diff --git a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
index 1e0c427..cfd3173 100644
--- a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
+++ b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
@@ -460,8 +460,8 @@
         ASSERT_NE(nullptr, outYCbCr->cr);
     }
 
-    YCbCr getAndroidYCbCr_P010(const native_handle_t* bufferHandle, uint8_t* data) {
-        YCbCr yCbCr_P010;
+    YCbCr getAndroidYCbCr_10bit(const native_handle_t* bufferHandle, uint8_t* data) {
+        YCbCr yCbCr_10bit;
         auto decodeResult = getStandardMetadata<StandardMetadataType::PLANE_LAYOUTS>(bufferHandle);
         if (!decodeResult.has_value()) {
             ADD_FAILURE() << "failed to get plane layout";
@@ -472,12 +472,12 @@
         EXPECT_EQ(1, planeLayouts[0].components.size());
         EXPECT_EQ(2, planeLayouts[1].components.size());
 
-        yCbCr_P010.yCbCr.y = nullptr;
-        yCbCr_P010.yCbCr.cb = nullptr;
-        yCbCr_P010.yCbCr.cr = nullptr;
-        yCbCr_P010.yCbCr.ystride = 0;
-        yCbCr_P010.yCbCr.cstride = 0;
-        yCbCr_P010.yCbCr.chroma_step = 0;
+        yCbCr_10bit.yCbCr.y = nullptr;
+        yCbCr_10bit.yCbCr.cb = nullptr;
+        yCbCr_10bit.yCbCr.cr = nullptr;
+        yCbCr_10bit.yCbCr.ystride = 0;
+        yCbCr_10bit.yCbCr.cstride = 0;
+        yCbCr_10bit.yCbCr.chroma_step = 0;
         int64_t cb_offset = 0;
         int64_t cr_offset = 0;
 
@@ -493,15 +493,15 @@
                 auto type = static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value);
                 switch (type) {
                     case PlaneLayoutComponentType::Y:
-                        // For specs refer:
+                        // For specs refer to:
                         // https://docs.microsoft.com/en-us/windows/win32/medfound/10-bit-and-16-bit-yuv-video-formats
                         EXPECT_EQ(6, planeLayoutComponent.offsetInBits);
-                        EXPECT_EQ(nullptr, yCbCr_P010.yCbCr.y);
+                        EXPECT_EQ(nullptr, yCbCr_10bit.yCbCr.y);
                         EXPECT_EQ(10, planeLayoutComponent.sizeInBits);
                         EXPECT_EQ(16, planeLayout.sampleIncrementInBits);
 
-                        yCbCr_P010.yCbCr.y = tmpData;
-                        yCbCr_P010.yCbCr.ystride = planeLayout.strideInBytes;
+                        yCbCr_10bit.yCbCr.y = tmpData;
+                        yCbCr_10bit.yCbCr.ystride = planeLayout.strideInBytes;
                         break;
 
                     case PlaneLayoutComponentType::CB:
@@ -509,46 +509,46 @@
                         sampleIncrementInBytes = bitsToBytes(planeLayout.sampleIncrementInBits);
                         EXPECT_EQ(4, sampleIncrementInBytes);
 
-                        if (yCbCr_P010.yCbCr.cstride == 0 && yCbCr_P010.yCbCr.chroma_step == 0) {
-                            yCbCr_P010.yCbCr.cstride = planeLayout.strideInBytes;
-                            yCbCr_P010.yCbCr.chroma_step = sampleIncrementInBytes;
+                        if (yCbCr_10bit.yCbCr.cstride == 0 && yCbCr_10bit.yCbCr.chroma_step == 0) {
+                            yCbCr_10bit.yCbCr.cstride = planeLayout.strideInBytes;
+                            yCbCr_10bit.yCbCr.chroma_step = sampleIncrementInBytes;
                         } else {
-                            EXPECT_EQ(yCbCr_P010.yCbCr.cstride, planeLayout.strideInBytes);
-                            EXPECT_EQ(yCbCr_P010.yCbCr.chroma_step, sampleIncrementInBytes);
+                            EXPECT_EQ(yCbCr_10bit.yCbCr.cstride, planeLayout.strideInBytes);
+                            EXPECT_EQ(yCbCr_10bit.yCbCr.chroma_step, sampleIncrementInBytes);
                         }
 
-                        if (yCbCr_P010.horizontalSubSampling == 0 &&
-                            yCbCr_P010.verticalSubSampling == 0) {
-                            yCbCr_P010.horizontalSubSampling = planeLayout.horizontalSubsampling;
-                            yCbCr_P010.verticalSubSampling = planeLayout.verticalSubsampling;
+                        if (yCbCr_10bit.horizontalSubSampling == 0 &&
+                            yCbCr_10bit.verticalSubSampling == 0) {
+                            yCbCr_10bit.horizontalSubSampling = planeLayout.horizontalSubsampling;
+                            yCbCr_10bit.verticalSubSampling = planeLayout.verticalSubsampling;
                         } else {
-                            EXPECT_EQ(yCbCr_P010.horizontalSubSampling,
+                            EXPECT_EQ(yCbCr_10bit.horizontalSubSampling,
                                       planeLayout.horizontalSubsampling);
-                            EXPECT_EQ(yCbCr_P010.verticalSubSampling,
+                            EXPECT_EQ(yCbCr_10bit.verticalSubSampling,
                                       planeLayout.verticalSubsampling);
                         }
 
                         if (type == PlaneLayoutComponentType::CB) {
-                            EXPECT_EQ(nullptr, yCbCr_P010.yCbCr.cb);
-                            yCbCr_P010.yCbCr.cb = tmpData;
+                            EXPECT_EQ(nullptr, yCbCr_10bit.yCbCr.cb);
+                            yCbCr_10bit.yCbCr.cb = tmpData;
                             cb_offset = planeLayoutComponent.offsetInBits;
                         } else {
-                            EXPECT_EQ(nullptr, yCbCr_P010.yCbCr.cr);
-                            yCbCr_P010.yCbCr.cr = tmpData;
+                            EXPECT_EQ(nullptr, yCbCr_10bit.yCbCr.cr);
+                            yCbCr_10bit.yCbCr.cr = tmpData;
                             cr_offset = planeLayoutComponent.offsetInBits;
                         }
                         break;
                     default:
                         break;
-                };
+                }
             }
         }
 
         EXPECT_EQ(cb_offset + bytesToBits(2), cr_offset);
-        EXPECT_NE(nullptr, yCbCr_P010.yCbCr.y);
-        EXPECT_NE(nullptr, yCbCr_P010.yCbCr.cb);
-        EXPECT_NE(nullptr, yCbCr_P010.yCbCr.cr);
-        return yCbCr_P010;
+        EXPECT_NE(nullptr, yCbCr_10bit.yCbCr.y);
+        EXPECT_NE(nullptr, yCbCr_10bit.yCbCr.cb);
+        EXPECT_NE(nullptr, yCbCr_10bit.yCbCr.cr);
+        return yCbCr_10bit;
     }
 };
 
@@ -750,6 +750,39 @@
 }
 
 /**
+ * Test IMapper::lock and IMapper::unlock with no CPU usage requested.
+ */
+TEST_P(GraphicsMapperStableCTests, LockUnlockNoCPUUsage) {
+    constexpr auto usage = BufferUsage::CPU_READ_RARELY | BufferUsage::CPU_WRITE_NEVER;
+    auto buffer = allocate({
+            .name = {"VTS_TEMP"},
+            .width = 64,
+            .height = 64,
+            .layerCount = 1,
+            .format = PixelFormat::RGBA_8888,
+            .usage = usage,
+            .reservedSize = 0,
+    });
+    ASSERT_NE(nullptr, buffer.get());
+
+    // lock buffer for writing
+    const auto& info = buffer->info();
+    const ARect region{0, 0, info.width, info.height};
+    auto handle = buffer->import();
+    uint8_t* data = nullptr;
+
+    EXPECT_EQ(AIMAPPER_ERROR_BAD_VALUE, mapper()->v5.lock(*handle, 0, region, -1, (void**)&data))
+            << "Locking with 0 access succeeded";
+
+    int releaseFence = -1;
+    EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.unlock(*handle, &releaseFence))
+            << "Unlocking not locked buffer succeeded";
+    if (releaseFence != -1) {
+        close(releaseFence);
+    }
+}
+
+/**
  *  Test multiple operations associated with different color formats
  */
 TEST_P(GraphicsMapperStableCTests, Lock_YCRCB_420_SP) {
@@ -1098,7 +1131,7 @@
                                                      region, -1, (void**)&data));
 
     YCbCr yCbCr;
-    ASSERT_NO_FATAL_FAILURE(yCbCr = getAndroidYCbCr_P010(*handle, data));
+    ASSERT_NO_FATAL_FAILURE(yCbCr = getAndroidYCbCr_10bit(*handle, data));
 
     constexpr uint32_t kCbCrSubSampleFactor = 2;
     ASSERT_EQ(kCbCrSubSampleFactor, yCbCr.horizontalSubSampling);
@@ -1120,6 +1153,54 @@
     }
 }
 
+TEST_P(GraphicsMapperStableCTests, Lock_YCBCR_P210) {
+    BufferDescriptorInfo info{
+        .name = {"VTS_TEMP"},
+        .width = 64,
+        .height = 64,
+        .layerCount = 1,
+        .format = PixelFormat::YCBCR_P210,
+        .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+        .reservedSize = 0,
+    };
+    auto buffer = allocate(info);
+    if (!buffer) {
+        ASSERT_FALSE(isSupported(info));
+        GTEST_SUCCEED() << "YCBCR_P210 format is unsupported";
+        return;
+    }
+
+    // lock buffer for writing
+    const ARect region{0, 0, info.width, info.height};
+    auto handle = buffer->import();
+    uint8_t *data = nullptr;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE,
+              mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage), region,
+                                -1, (void **)&data));
+
+    YCbCr yCbCr;
+    ASSERT_NO_FATAL_FAILURE(yCbCr = getAndroidYCbCr_10bit(*handle, data));
+
+    constexpr uint32_t kCbCrSubSampleFactor = 2;
+    ASSERT_EQ(kCbCrSubSampleFactor, yCbCr.horizontalSubSampling);
+    ASSERT_EQ(1, yCbCr.verticalSubSampling);
+
+    ASSERT_EQ(0, info.height % 2);
+
+    // fill the data
+    fillYCbCrData(yCbCr.yCbCr, info.width, info.height,
+                  yCbCr.horizontalSubSampling, yCbCr.verticalSubSampling);
+    // verify the YCbCr data
+    verifyYCbCrData(yCbCr.yCbCr, info.width, info.height,
+                    yCbCr.horizontalSubSampling, yCbCr.verticalSubSampling);
+
+    int releaseFence = -1;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+    if (releaseFence != -1) {
+        close(releaseFence);
+    }
+}
+
 TEST_P(GraphicsMapperStableCTests, LockBadAccessRegion) {
     auto buffer = allocateGeneric();
     ASSERT_NE(nullptr, buffer);
diff --git a/keymaster/aidl/Android.bp b/keymaster/aidl/Android.bp
index 56997a9..c101f56 100644
--- a/keymaster/aidl/Android.bp
+++ b/keymaster/aidl/Android.bp
@@ -18,6 +18,13 @@
         java: {
             platform_apis: true,
         },
+        ndk: {
+            apex_available: [
+                "com.android.hardware.biometrics.face.virtual",
+                "com.android.hardware.biometrics.fingerprint.virtual",
+                "//apex_available:platform",
+            ],
+        },
         rust: {
             enabled: true,
         },
diff --git a/neuralnetworks/1.2/utils/test/DeviceTest.cpp b/neuralnetworks/1.2/utils/test/DeviceTest.cpp
index 0e855c4..0d8c141 100644
--- a/neuralnetworks/1.2/utils/test/DeviceTest.cpp
+++ b/neuralnetworks/1.2/utils/test/DeviceTest.cpp
@@ -54,10 +54,6 @@
         .execTime = std::numeric_limits<float>::max(),
         .powerUsage = std::numeric_limits<float>::max()};
 
-// FIXME: This function causes Clang to hang indefinitely when building with
-// -O1. Turn off optimization as a temporary workaround.
-// http://b/296850773
-#pragma clang optimize off
 template <typename... Args>
 auto makeCallbackReturn(Args&&... args) {
     return [argPack = std::make_tuple(std::forward<Args>(args)...)](const auto& cb) {
@@ -65,7 +61,6 @@
         return Void();
     };
 }
-#pragma clang optimize on
 
 sp<MockDevice> createMockDevice() {
     const auto mockDevice = MockDevice::create();
diff --git a/neuralnetworks/aidl/Android.bp b/neuralnetworks/aidl/Android.bp
index 9589750..e7583aa 100644
--- a/neuralnetworks/aidl/Android.bp
+++ b/neuralnetworks/aidl/Android.bp
@@ -33,7 +33,6 @@
             apex_available: [
                 "//apex_available:platform",
                 "com.android.neuralnetworks",
-                "test_com.android.neuralnetworks",
             ],
             min_sdk_version: "30",
         },
@@ -43,28 +42,28 @@
             version: "1",
             imports: [
                 "android.hardware.common-V2",
-                "android.hardware.graphics.common-V5",
+                "android.hardware.graphics.common-V6",
             ],
         },
         {
             version: "2",
             imports: [
                 "android.hardware.common-V2",
-                "android.hardware.graphics.common-V5",
+                "android.hardware.graphics.common-V6",
             ],
         },
         {
             version: "3",
             imports: [
                 "android.hardware.common-V2",
-                "android.hardware.graphics.common-V5",
+                "android.hardware.graphics.common-V6",
             ],
         },
         {
             version: "4",
             imports: [
                 "android.hardware.common-V2",
-                "android.hardware.graphics.common-V5",
+                "android.hardware.graphics.common-V6",
             ],
         },
 
diff --git a/nfc/aidl/Android.bp b/nfc/aidl/Android.bp
index b34e4f2..1ffd274 100644
--- a/nfc/aidl/Android.bp
+++ b/nfc/aidl/Android.bp
@@ -33,8 +33,9 @@
             enabled: false,
         },
         java: {
-            sdk_version: "module_current",
             enabled: false,
+            sdk_version: "module_current",
+            min_sdk_version: "35",
         },
         ndk: {
             enabled: true,
@@ -42,6 +43,7 @@
                 "//apex_available:platform",
                 "com.android.nfcservices",
             ],
+            min_sdk_version: "35",
         },
         rust: {
             enabled: true,
diff --git a/power/OWNERS b/power/OWNERS
index 95778a4..13895bd 100644
--- a/power/OWNERS
+++ b/power/OWNERS
@@ -1,6 +1,3 @@
 # Bug component: 826709
-
-# ADPF virtual team
-lpy@google.com
-wvw@google.com
 file:platform/frameworks/base:/ADPF_OWNERS
+wvw@google.com
diff --git a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
index 9f530b3..f909676 100644
--- a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
@@ -239,18 +239,13 @@
     EXPECT_EQ(std::cv_status::no_timeout, wait());
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
-    if (getRadioHalCapabilities()) {
-        ASSERT_TRUE(CheckAnyOfErrors(
-                radioRsp_v1_6->rspInfo.error,
-                {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED}));
-    } else {
-        ASSERT_TRUE(
-                CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
-                                 {::android::hardware::radio::V1_6::RadioError::NONE,
-                                  ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
-                                  ::android::hardware::radio::V1_6::RadioError::INTERNAL_ERR,
-                                  ::android::hardware::radio::V1_6::RadioError::MODEM_ERR}));
-    }
+    ASSERT_TRUE(CheckAnyOfErrors(
+            radioRsp_v1_6->rspInfo.error,
+            {::android::hardware::radio::V1_6::RadioError::NONE,
+             ::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED,
+             ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+             ::android::hardware::radio::V1_6::RadioError::INTERNAL_ERR,
+             ::android::hardware::radio::V1_6::RadioError::MODEM_ERR}));
 }
 
 /*
diff --git a/radio/aidl/android/hardware/radio/modem/HardwareConfigModem.aidl b/radio/aidl/android/hardware/radio/modem/HardwareConfigModem.aidl
index 4818c9e..0389170 100644
--- a/radio/aidl/android/hardware/radio/modem/HardwareConfigModem.aidl
+++ b/radio/aidl/android/hardware/radio/modem/HardwareConfigModem.aidl
@@ -32,9 +32,12 @@
      */
     int rilModel;
     /**
-     * Bitset value, based on RadioTechnology.
+     * All supported radio technologies.
+     *
+     * Despite the stated type, this is an int bitset: a mask where each bit position represents a
+     * radio technology.
      */
-    RadioTechnology rat = RadioTechnology.UNKNOWN;
+    RadioTechnology rat = RadioTechnology.UNKNOWN; // it's really an empty bitmask
     /**
      * Maximum number of concurrent active voice calls.
      */
diff --git a/radio/aidl/vts/radio_sim_test.cpp b/radio/aidl/vts/radio_sim_test.cpp
index ec1facc..2823977 100644
--- a/radio/aidl/vts/radio_sim_test.cpp
+++ b/radio/aidl/vts/radio_sim_test.cpp
@@ -533,7 +533,7 @@
         EXPECT_EQ(RadioError::NONE, radioRsp_sim->rspInfo.error);
 
         if (aidl_version <= 2) {
-            EXPECT_EQ(1, radioRsp_sim->carrierRestrictionsResp.allowedCarriers.size());
+            ASSERT_EQ(1, radioRsp_sim->carrierRestrictionsResp.allowedCarriers.size());
             EXPECT_EQ(0, radioRsp_sim->carrierRestrictionsResp.excludedCarriers.size());
 
             ASSERT_TRUE(std::string("123") ==
@@ -545,7 +545,7 @@
             ASSERT_TRUE(radioRsp_sim->carrierRestrictionsResp.allowedCarriersPrioritized);
             EXPECT_EQ(SimLockMultiSimPolicy::NO_MULTISIM_POLICY, radioRsp_sim->multiSimPolicyResp);
         } else {
-            EXPECT_EQ(1, radioRsp_sim->carrierRestrictionsResp.allowedCarrierInfoList.size());
+            ASSERT_EQ(1, radioRsp_sim->carrierRestrictionsResp.allowedCarrierInfoList.size());
             EXPECT_EQ(0, radioRsp_sim->carrierRestrictionsResp.excludedCarrierInfoList.size());
             ASSERT_EQ(std::string("123"),
                       radioRsp_sim->carrierRestrictionsResp.allowedCarrierInfoList[0].mcc);
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index e8eed71..b57dd8a 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -548,10 +548,8 @@
     void deleteKey(in byte[] keyBlob);
 
     /**
-     * Deletes all keys in the hardware keystore.  Used when keystore is reset completely.  After
-     * this function is called all keys with Tag::ROLLBACK_RESISTANCE in their hardware-enforced
-     * authorization lists must be rendered permanently unusable.  Keys without
-     * Tag::ROLLBACK_RESISTANCE may or may not be rendered unusable.
+     * Deletes all keys in the hardware keystore. Used when keystore is reset completely. After
+     * this function is called all keys created previously must be rendered permanently unusable.
      */
     void deleteAllKeys();
 
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
index 4fe3bd9..2d2f307 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
@@ -125,14 +125,25 @@
      * straightforward translation of the KeyMint tag/value parameter lists to ASN.1.
      *
      * KeyDescription ::= SEQUENCE {
-     *     attestationVersion         INTEGER, # Value 400
-     *     attestationSecurityLevel   SecurityLevel, # See below
-     *     keyMintVersion             INTEGER, # Value 400
-     *     keymintSecurityLevel       SecurityLevel, # See below
-     *     attestationChallenge       OCTET_STRING, # Tag::ATTESTATION_CHALLENGE from attestParams
-     *     uniqueId                   OCTET_STRING, # Empty unless key has Tag::INCLUDE_UNIQUE_ID
-     *     softwareEnforced           AuthorizationList, # See below
-     *     hardwareEnforced           AuthorizationList, # See below
+     *     -- attestationVersion must be 400.
+     *     attestationVersion         INTEGER,
+     *     -- attestationSecurityLevel is the SecurityLevel of the location where the attested
+     *     -- key is stored. Must match keymintSecurityLevel.
+     *     attestationSecurityLevel   SecurityLevel,
+     *     -- keyMintVersion must be 400.
+     *     keyMintVersion             INTEGER,
+     *     -- keyMintSecurityLevel is the SecurityLevel of the IKeyMintDevice. Must match
+     *     -- attestationSecurityLevel.
+     *     keyMintSecurityLevel       SecurityLevel,
+     *     -- attestationChallenge contains Tag::ATTESTATION_CHALLENGE from attestParams.
+     *     attestationChallenge       OCTET_STRING,
+     *     -- uniqueId is empty unless the key has Tag::INCLUDE_UNIQUE_ID.
+     *     uniqueId                   OCTET_STRING,
+     *     -- softwareEnforced contains the authorization tags enforced by the Android system.
+     *     softwareEnforced           AuthorizationList,
+     *     -- hardwareEnforced contains the authorization tags enforced by a secure environment
+     *     -- (TEE or StrongBox).
+     *     hardwareEnforced           AuthorizationList,
      * }
      *
      * SecurityLevel ::= ENUMERATED {
@@ -142,12 +153,15 @@
      * }
      *
      * RootOfTrust ::= SEQUENCE {
+     *     -- verifiedBootKey must contain a SHA-256 digest of the public key embedded in the
+     *     -- "vbmeta" partition if the device's bootloader is locked, or 32 bytes of zeroes if the
+     *     -- device's bootloader is unlocked.
      *     verifiedBootKey            OCTET_STRING,
      *     deviceLocked               BOOLEAN,
      *     verifiedBootState          VerifiedBootState,
-     *     # verifiedBootHash must contain a SHA-256 digest of all binaries and components validated
-     *     # by Verified Boot. Updating any verified binary or component must cause this value to
-     *     # change.
+     *     -- verifiedBootHash must contain a SHA-256 digest of all binaries and components
+     *     -- validated by Verified Boot. Updating any verified binary or component must cause this
+     *     -- value to change.
      *     verifiedBootHash           OCTET_STRING,
      * }
      *
@@ -158,15 +172,15 @@
      *     Failed                     (3),
      * }
      *
-     * # Modules contains version information for APEX modules.
-     * # Note that the Modules information is DER-encoded before being hashed, which requires a
-     * # specific ordering (lexicographic by encoded value) for the constituent Module entries. This
-     * # ensures that the ordering of Module entries is predictable and that the resulting SHA-256
-     * # hash value is identical for the same set of modules.
+     * -- Modules contains version information for APEX modules.
+     * -- Note that the Modules information is DER-encoded before being hashed, which requires a
+     * -- specific ordering (lexicographic by encoded value) for the constituent Module entries.
+     * -- This ensures that the ordering of Module entries is predictable and that the resulting
+     * -- SHA-256 hash value is identical for the same set of modules.
      * Modules ::= SET OF Module
      * Module ::= SEQUENCE {
      *     packageName                OCTET_STRING,
-     *     version                    INTEGER, # As determined at boot time
+     *     version                    INTEGER, -- As determined at boot time
      * }
      *
      * -- Note that the AuthorizationList SEQUENCE is also used in IKeyMintDevice::importWrappedKey
@@ -181,11 +195,11 @@
      *     purpose                    [1] EXPLICIT SET OF INTEGER OPTIONAL,
      *     algorithm                  [2] EXPLICIT INTEGER OPTIONAL,
      *     keySize                    [3] EXPLICIT INTEGER OPTIONAL,
-     *     blockMode                  [4] EXPLICIT SET OF INTEGER OPTIONAL, -- symmetric only
+     *     blockMode                  [4] EXPLICIT SET OF INTEGER OPTIONAL, -- Symmetric keys only
      *     digest                     [5] EXPLICIT SET OF INTEGER OPTIONAL,
      *     padding                    [6] EXPLICIT SET OF INTEGER OPTIONAL,
-     *     callerNonce                [7] EXPLICIT NULL OPTIONAL, -- symmetric only
-     *     minMacLength               [8] EXPLICIT INTEGER OPTIONAL, -- symmetric only
+     *     callerNonce                [7] EXPLICIT NULL OPTIONAL, -- Symmetric keys only
+     *     minMacLength               [8] EXPLICIT INTEGER OPTIONAL, -- Symmetric keys only
      *     ecCurve                    [10] EXPLICIT INTEGER OPTIONAL,
      *     rsaPublicExponent          [200] EXPLICIT INTEGER OPTIONAL,
      *     mgfDigest                  [203] EXPLICIT SET OF INTEGER OPTIONAL,
@@ -195,7 +209,7 @@
      *     originationExpireDateTime  [401] EXPLICIT INTEGER OPTIONAL,
      *     usageExpireDateTime        [402] EXPLICIT INTEGER OPTIONAL,
      *     usageCountLimit            [405] EXPLICIT INTEGER OPTIONAL,
-     *     userSecureId               [502] EXPLICIT INTEGER OPTIONAL, -- only used on import
+     *     userSecureId               [502] EXPLICIT INTEGER OPTIONAL, -- Only used on key import
      *     noAuthRequired             [503] EXPLICIT NULL OPTIONAL,
      *     userAuthType               [504] EXPLICIT INTEGER OPTIONAL,
      *     authTimeout                [505] EXPLICIT INTEGER OPTIONAL,
@@ -221,7 +235,8 @@
      *     bootPatchLevel             [719] EXPLICIT INTEGER OPTIONAL,
      *     deviceUniqueAttestation    [720] EXPLICIT NULL OPTIONAL,
      *     attestationIdSecondImei    [723] EXPLICIT OCTET_STRING OPTIONAL,
-     *     moduleHash                 [724] EXPLICIT OCTET_STRING OPTIONAL, -- SHA-256 hash of DER-encoded `Modules`
+     *     -- moduleHash contains a SHA-256 hash of DER-encoded `Modules`
+     *     moduleHash                 [724] EXPLICIT OCTET_STRING OPTIONAL,
      * }
      */
     Certificate[] certificateChain;
diff --git a/security/keymint/aidl/default/Android.bp b/security/keymint/aidl/default/Android.bp
index ff2393c..0197141 100644
--- a/security/keymint/aidl/default/Android.bp
+++ b/security/keymint/aidl/default/Android.bp
@@ -104,6 +104,7 @@
     ],
 }
 
+// The following target declares the latest version of KeyMint.
 prebuilt_etc {
     name: "android.hardware.hardware_keystore.xml",
     sub_dir: "permissions",
@@ -111,6 +112,24 @@
     src: "android.hardware.hardware_keystore.xml",
 }
 
+// The following targets (and underlying XML files) declare specific
+// versions of KeyMint.  Vendors should use the version that matches the
+// version of the KeyMint HAL that the device implements.
+
+prebuilt_etc {
+    name: "android.hardware.hardware_keystore_V1.xml",
+    sub_dir: "permissions",
+    vendor: true,
+    src: "android.hardware.hardware_keystore_V1.xml",
+}
+
+prebuilt_etc {
+    name: "android.hardware.hardware_keystore_V2.xml",
+    sub_dir: "permissions",
+    vendor: true,
+    src: "android.hardware.hardware_keystore_V2.xml",
+}
+
 prebuilt_etc {
     name: "android.hardware.hardware_keystore_V3.xml",
     sub_dir: "permissions",
@@ -118,6 +137,13 @@
     src: "android.hardware.hardware_keystore_V3.xml",
 }
 
+prebuilt_etc {
+    name: "android.hardware.hardware_keystore_V4.xml",
+    sub_dir: "permissions",
+    vendor: true,
+    src: "android.hardware.hardware_keystore_V4.xml",
+}
+
 rust_library {
     name: "libkmr_hal_nonsecure",
     crate_name: "kmr_hal_nonsecure",
diff --git a/security/keymint/aidl/default/android.hardware.hardware_keystore_V1.xml b/security/keymint/aidl/default/android.hardware.hardware_keystore_V1.xml
new file mode 100644
index 0000000..e5a9345
--- /dev/null
+++ b/security/keymint/aidl/default/android.hardware.hardware_keystore_V1.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<permissions>
+  <feature name="android.hardware.hardware_keystore" version="100" />
+</permissions>
diff --git a/security/keymint/aidl/default/android.hardware.hardware_keystore_V2.xml b/security/keymint/aidl/default/android.hardware.hardware_keystore_V2.xml
new file mode 100644
index 0000000..2ebf1fe
--- /dev/null
+++ b/security/keymint/aidl/default/android.hardware.hardware_keystore_V2.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<permissions>
+  <feature name="android.hardware.hardware_keystore" version="200" />
+</permissions>
diff --git a/security/keymint/aidl/default/android.hardware.hardware_keystore_V4.xml b/security/keymint/aidl/default/android.hardware.hardware_keystore_V4.xml
new file mode 100644
index 0000000..1ab2133
--- /dev/null
+++ b/security/keymint/aidl/default/android.hardware.hardware_keystore_V4.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<permissions>
+  <feature name="android.hardware.hardware_keystore" version="400" />
+</permissions>
diff --git a/security/keymint/aidl/default/hal/lib.rs b/security/keymint/aidl/default/hal/lib.rs
index 621f077..fad807f 100644
--- a/security/keymint/aidl/default/hal/lib.rs
+++ b/security/keymint/aidl/default/hal/lib.rs
@@ -47,11 +47,9 @@
 
 /// Get boot information based on system properties.
 pub fn get_boot_info() -> kmr_wire::SetBootInfoRequest {
-    // No access to a verified boot key.
-    let verified_boot_key = vec![0; 32];
     let vbmeta_digest = get_property("ro.boot.vbmeta.digest").unwrap_or_else(|_| "00".repeat(32));
     let verified_boot_hash = hex::decode(&vbmeta_digest).unwrap_or_else(|_e| {
-        error!("failed to parse hex data in '{}'", vbmeta_digest);
+        error!("failed to parse VBMeta digest hex data in '{vbmeta_digest}': {_e:?}");
         vec![0; 32]
     });
     let device_boot_locked = match get_property("ro.boot.vbmeta.device_state")
@@ -65,6 +63,18 @@
             false
         }
     };
+    let verified_boot_key_digest =
+        get_property("ro.boot.vbmeta.public_key_digest").unwrap_or_else(|_| "00".repeat(32));
+    let verified_boot_key = match device_boot_locked {
+        true => hex::decode(&verified_boot_key_digest).unwrap_or_else(|_e| {
+            error!("Failed to parse Verified Boot key hex data in '{verified_boot_key_digest}': {_e:?}");
+            vec![0; 32]
+        }),
+        // VTS-16+ requires the attested Verified Boot key to be 32 bytes of zeroes when the
+        // bootloader is unlocked, so we ignore the property's value in that case. Behaviour
+        // prior to VTS-16 is unspecified, so it's fine to return the same.
+        false => vec![0; 32],
+    };
     let verified_boot_state = match get_property("ro.boot.verifiedbootstate")
         .unwrap_or_else(|_| "no-prop".to_string())
         .as_str()
diff --git a/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp
index 1414220..da3427a 100644
--- a/security/keymint/aidl/vts/functional/Android.bp
+++ b/security/keymint/aidl/vts/functional/Android.bp
@@ -37,6 +37,7 @@
         "libcrypto",
         "libbase",
         "libgatekeeper",
+        "libvendorsupport",
         "packagemanager_aidl-cpp",
     ],
     static_libs: [
diff --git a/security/keymint/aidl/vts/functional/BootloaderStateTest.cpp b/security/keymint/aidl/vts/functional/BootloaderStateTest.cpp
index 083a9aa..a799ab1 100644
--- a/security/keymint/aidl/vts/functional/BootloaderStateTest.cpp
+++ b/security/keymint/aidl/vts/functional/BootloaderStateTest.cpp
@@ -27,6 +27,7 @@
 #include <libavb/libavb.h>
 #include <libavb_user/avb_ops_user.h>
 #include <remote_prov/remote_prov_utils.h>
+#include <vendorsupport/api_level.h>
 
 #include "KeyMintAidlTestBase.h"
 
@@ -95,6 +96,18 @@
             << "Verified boot state must be \"UNVERIFIED\" aka \"orange\".";
 }
 
+// Check that the attested Verified Boot key is 32 bytes of zeroes since the bootloader is unlocked.
+TEST_P(BootloaderStateTest, VerifiedBootKeyAllZeroes) {
+    // Gate this test to avoid waiver issues.
+    if (get_vendor_api_level() <= AVendorSupport_getVendorApiLevelOf(__ANDROID_API_V__)) {
+        return;
+    }
+
+    std::vector<uint8_t> expectedVbKey(32, 0);
+    ASSERT_EQ(attestedVbKey_, expectedVbKey) << "Verified Boot key digest must be 32 bytes of "
+                                                "zeroes since the bootloader is unlocked.";
+}
+
 // Following error codes from avb_slot_data() mean that slot data was loaded
 // (even if verification failed).
 static inline bool avb_slot_data_loaded(AvbSlotVerifyResult result) {
@@ -129,13 +142,13 @@
     avb_slot_verify_data_calculate_vbmeta_digest(avbSlotData, AVB_DIGEST_TYPE_SHA256,
                                                  sha256Digest.data());
 
-    if (get_vsr_api_level() >= __ANDROID_API_V__) {
+    if (get_vendor_api_level() >= AVendorSupport_getVendorApiLevelOf(__ANDROID_API_V__)) {
         ASSERT_TRUE(attestedVbmetaDigest_ == sha256Digest)
                 << "Attested VBMeta digest (" << bin2hex(attestedVbmetaDigest_)
                 << ") does not match the expected SHA-256 digest (" << bin2hex(sha256Digest)
                 << ").";
     } else {
-        // Prior to VSR-V, there was no MUST requirement for the algorithm used by the bootloader
+        // Prior to VSR-15, there was no MUST requirement for the algorithm used by the bootloader
         // to calculate the VBMeta digest. However, the only two supported options are SHA-256 and
         // SHA-512, so we expect the attested VBMeta digest to match one of these.
         vector<uint8_t> sha512Digest(AVB_SHA512_DIGEST_SIZE);
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 3aa5d76..06e0f58 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -35,6 +35,7 @@
 #include <openssl/evp.h>
 #include <openssl/mem.h>
 #include <remote_prov/remote_prov_utils.h>
+#include <vendorsupport/api_level.h>
 
 #include <keymaster/cppcose/cppcose.h>
 #include <keymint_support/key_param_output.h>
@@ -1434,12 +1435,11 @@
 }
 
 bool KeyMintAidlTestBase::IsRkpSupportRequired() const {
-    // This is technically not a match to the requirements for S chipsets,
-    // however when S shipped there was a bug in the test that skipped the
-    // tests if KeyMint 2 was not on the system. So we allowed many chipests
-    // to ship without RKP support. In T we hardened the requirements around
-    // support for RKP, so relax the test to match.
-    return get_vsr_api_level() >= __ANDROID_API_T__;
+    // This is technically weaker than the VSR-12 requirements, but when
+    // Android 12 shipped, there was a bug that skipped the tests if KeyMint
+    // 2 was not present. As a result, many chipsets were allowed to ship
+    // without RKP support. The RKP requirements were hardened in VSR-13.
+    return get_vendor_api_level() >= __ANDROID_API_T__;
 }
 
 vector<uint32_t> KeyMintAidlTestBase::ValidKeySizes(Algorithm algorithm) {
@@ -1690,11 +1690,11 @@
                                                  vector<uint8_t>* key_blob,
                                                  vector<KeyCharacteristics>* key_characteristics,
                                                  vector<Certificate>* cert_chain) {
-    // The original specification for KeyMint v1 required ATTEST_KEY not be combined
-    // with any other key purpose, but the original VTS tests incorrectly did exactly that.
-    // This means that a device that launched prior to Android T (API level 33) may
-    // accept or even require KeyPurpose::SIGN too.
-    if (get_vsr_api_level() < __ANDROID_API_T__) {
+    // The original specification for KeyMint v1 (introduced in Android 12) required ATTEST_KEY not
+    // be combined with any other key purpose, but the original VTS-12 tests incorrectly did exactly
+    // that. The tests were fixed in VTS-13 (vendor API level 33). This means that devices with
+    // vendor API level < 33 may accept or even require KeyPurpose::SIGN too.
+    if (get_vendor_api_level() < __ANDROID_API_T__) {
         AuthorizationSet key_desc_plus_sign = key_desc;
         key_desc_plus_sign.push_back(TAG_PURPOSE, KeyPurpose::SIGN);
 
@@ -1819,13 +1819,19 @@
     OPENSSL_free(cert_issuer);
 }
 
-int get_vsr_api_level() {
+int get_vendor_api_level() {
+    // Android 13+ builds have the `ro.vendor.api_level` system property. See
+    // https://source.android.com/docs/core/architecture/api-flags#determine_vendor_api_level_android_13.
     int vendor_api_level = ::android::base::GetIntProperty("ro.vendor.api_level", -1);
     if (vendor_api_level != -1) {
         return vendor_api_level;
     }
 
-    // Android S and older devices do not define ro.vendor.api_level
+    // Android 12 builds have the `ro.board.api_level` and `ro.board.first_api_level` system
+    // properties, which are only expected to be populated for GRF SoCs on Android 12 builds. Note
+    // that they are populated automatically by the build system starting in Android 15, but we use
+    // `ro.vendor.api_level` on such builds (see above). For details, see
+    // https://docs.partner.android.com/gms/building/integrating/extending-os-upgrade-support-windows#new-system-properties.
     vendor_api_level = ::android::base::GetIntProperty("ro.board.api_level", -1);
     if (vendor_api_level == -1) {
         vendor_api_level = ::android::base::GetIntProperty("ro.board.first_api_level", -1);
@@ -1837,11 +1843,12 @@
         EXPECT_NE(product_api_level, -1) << "Could not find ro.build.version.sdk";
     }
 
-    // VSR API level is the minimum of vendor_api_level and product_api_level.
-    if (vendor_api_level == -1 || vendor_api_level > product_api_level) {
+    // If the `ro.board.api_level` and `ro.board.first_api_level` properties aren't populated, it
+    // means the build doesn't have a GRF SoC, so the product API level should be used.
+    if (vendor_api_level == -1) {
         return product_api_level;
     }
-    return vendor_api_level;
+    return std::min(product_api_level, vendor_api_level);
 }
 
 bool is_gsi_image() {
@@ -1908,16 +1915,29 @@
         }
     }
 
+    if (get_vendor_api_level() > AVendorSupport_getVendorApiLevelOf(__ANDROID_API_V__)) {
+        // The Verified Boot key field should be exactly 32 bytes since it
+        // contains the SHA-256 hash of the key on locked devices or 32 bytes
+        // of zeroes on unlocked devices. This wasn't checked for earlier
+        // versions of the KeyMint HAL, so we version-gate the strict check.
+        EXPECT_EQ(verified_boot_key.size(), 32);
+    } else if (get_vendor_api_level() == AVendorSupport_getVendorApiLevelOf(__ANDROID_API_V__)) {
+        // The Verified Boot key field should be:
+        //   - Exactly 32 bytes on locked devices since it should contain
+        //     the SHA-256 hash of the key, or
+        //   - Up to 32 bytes of zeroes on unlocked devices (behaviour on
+        //     unlocked devices isn't specified in the HAL interface
+        //     specification).
+        // Thus, we can't check for strict equality in case unlocked devices
+        // report values with less than 32 bytes. This wasn't checked for
+        // earlier versions of the KeyMint HAL, so we version-gate the check.
+        EXPECT_LE(verified_boot_key.size(), 32);
+    }
+
     // Verified Boot key should be all zeroes if the boot state is "orange".
     std::string empty_boot_key(32, '\0');
     std::string verified_boot_key_str((const char*)verified_boot_key.data(),
                                       verified_boot_key.size());
-    if (get_vsr_api_level() >= __ANDROID_API_V__) {
-        // The attestation should contain the SHA-256 hash of the verified boot
-        // key.  However, this was not checked for earlier versions of the KeyMint
-        // HAL so only be strict for VSR-V and above.
-        EXPECT_LE(verified_boot_key.size(), 32);
-    }
     EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0);
     if (!strcmp(property_value, "green")) {
         EXPECT_EQ(verified_boot_state, VerifiedBoot::VERIFIED);
@@ -2232,6 +2252,33 @@
 
 namespace {
 
+std::optional<std::string> validateP256Point(const std::vector<uint8_t>& x_buffer,
+                                             const std::vector<uint8_t>& y_buffer) {
+    auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+    if (group.get() == nullptr) {
+        return "Error creating EC group by curve name for prime256v1";
+    }
+
+    auto point = EC_POINT_Ptr(EC_POINT_new(group.get()));
+    BIGNUM_Ptr x(BN_bin2bn(x_buffer.data(), x_buffer.size(), nullptr));
+    BIGNUM_Ptr y(BN_bin2bn(y_buffer.data(), y_buffer.size(), nullptr));
+    if (!EC_POINT_set_affine_coordinates_GFp(group.get(), point.get(), x.get(), y.get(), nullptr)) {
+        return "Failed to set affine coordinates.";
+    }
+    if (!EC_POINT_is_on_curve(group.get(), point.get(), nullptr)) {
+        return "Point is not on curve.";
+    }
+    if (EC_POINT_is_at_infinity(group.get(), point.get())) {
+        return "Point is at infinity.";
+    }
+    const auto* generator = EC_GROUP_get0_generator(group.get());
+    if (!EC_POINT_cmp(group.get(), generator, point.get(), nullptr)) {
+        return "Point is equal to generator.";
+    }
+
+    return std::nullopt;
+}
+
 void check_cose_key(const vector<uint8_t>& data, bool testMode) {
     auto [parsedPayload, __, payloadParseErr] = cppbor::parse(data);
     ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
@@ -2265,6 +2312,24 @@
                              "  -3 : \\{(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}\\},\n"  // pub_y: data
                              "\\}"));
     }
+
+    ASSERT_TRUE(parsedPayload->asMap()) << "CBOR item was not a map";
+
+    ASSERT_TRUE(parsedPayload->asMap()->get(CoseKey::Label::PUBKEY_X))
+            << "CBOR map did not contain x coordinate of public key";
+    ASSERT_TRUE(parsedPayload->asMap()->get(CoseKey::Label::PUBKEY_X)->asBstr())
+            << "x coordinate of public key was not a bstr";
+    const auto& x = parsedPayload->asMap()->get(CoseKey::Label::PUBKEY_X)->asBstr()->value();
+
+    ASSERT_TRUE(parsedPayload->asMap()->get(CoseKey::Label::PUBKEY_Y))
+            << "CBOR map did not contain y coordinate of public key";
+    ASSERT_TRUE(parsedPayload->asMap()->get(CoseKey::Label::PUBKEY_Y)->asBstr())
+            << "y coordinate of public key was not a bstr";
+    const auto& y = parsedPayload->asMap()->get(CoseKey::Label::PUBKEY_Y)->asBstr()->value();
+
+    auto errorMessage = validateP256Point(x, y);
+    EXPECT_EQ(errorMessage, std::nullopt)
+            << *errorMessage << " x: " << bin2hex(x) << " y: " << bin2hex(y);
 }
 
 }  // namespace
@@ -2357,7 +2422,7 @@
     } else if (result == ErrorCode::INVALID_TAG) {
         // Depending on the situation, other error codes may be acceptable.  First, allow older
         // implementations to use INVALID_TAG.
-        ASSERT_FALSE(get_vsr_api_level() > __ANDROID_API_T__)
+        ASSERT_FALSE(get_vendor_api_level() > __ANDROID_API_T__)
                 << "It is a specification violation for INVALID_TAG to be returned due to ID "
                 << "mismatch in a Device ID Attestation call. INVALID_TAG is only intended to "
                 << "be used for a case where updateAad() is called after update(). As of "
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index 1c12136..6c327bb 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -406,8 +406,8 @@
     add_tag(tags, ttag, ::android::base::GetProperty(prop, /* default= */ ""));
 }
 
-// Return the VSR API level for this device.
-int get_vsr_api_level();
+// Return the vendor API level for this device.
+int get_vendor_api_level();
 
 // Indicate whether the test is running on a GSI image.
 bool is_gsi_image();
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 067db78..743928e 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -42,6 +42,8 @@
 #include <keymint_support/key_param_output.h>
 #include <keymint_support/openssl_utils.h>
 
+#include <vendorsupport/api_level.h>
+
 #include "KeyMintAidlTestBase.h"
 
 using aidl::android::hardware::security::keymint::AuthorizationSet;
@@ -4156,13 +4158,15 @@
  * when the EC_CURVE is not explicitly specified.
  */
 TEST_P(ImportKeyTest, EcdsaSuccessCurveNotSpecified) {
-    if (get_vsr_api_level() < __ANDROID_API_V__) {
+    int vendor_api_level = get_vendor_api_level();
+    if (vendor_api_level < AVendorSupport_getVendorApiLevelOf(__ANDROID_API_V__)) {
         /*
          * The KeyMint spec was previously not clear as to whether EC_CURVE was optional on import
-         * of EC keys. However, this was not checked at the time so we can only be strict about
-         * checking this for implementations at VSR-V or later.
+         * of EC keys. However, this was not checked at the time, so we version-gate the strict
+         * check.
          */
-        GTEST_SKIP() << "Skipping EC_CURVE on import only strict >= VSR-V";
+        GTEST_SKIP() << "Applies only to vendor API level >= 202404, but this device is: "
+                     << vendor_api_level;
     }
 
     ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
@@ -5314,15 +5318,15 @@
         "8564");
 
 TEST_P(ImportWrappedKeyTest, RsaKey) {
-    int vsr_api_level = get_vsr_api_level();
-    if (vsr_api_level < __ANDROID_API_V__) {
+    int vendor_api_level = get_vendor_api_level();
+    if (vendor_api_level < AVendorSupport_getVendorApiLevelOf(__ANDROID_API_V__)) {
         /*
          * The Keymaster v4 spec introduced `importWrappedKey()` and did not restrict it to
          * just symmetric keys.  However, the import of asymmetric wrapped keys was not tested
-         * at the time, so we can only be strict about checking this for implementations claiming
-         * support for VSR API level 35 and above.
+         * at the time, so we version-gate the strict check.
          */
-        GTEST_SKIP() << "Applies only to VSR API level 35, this device is: " << vsr_api_level;
+        GTEST_SKIP() << "Applies only to vendor API level >= 202404, but this device is: "
+                     << vendor_api_level;
     }
 
     auto wrapping_key_desc = AuthorizationSetBuilder()
@@ -5345,15 +5349,15 @@
 }
 
 TEST_P(ImportWrappedKeyTest, EcKey) {
-    int vsr_api_level = get_vsr_api_level();
-    if (vsr_api_level < __ANDROID_API_V__) {
+    int vendor_api_level = get_vendor_api_level();
+    if (vendor_api_level < AVendorSupport_getVendorApiLevelOf(__ANDROID_API_V__)) {
         /*
          * The Keymaster v4 spec introduced `importWrappedKey()` and did not restrict it to
          * just symmetric keys.  However, the import of asymmetric wrapped keys was not tested
-         * at the time, so we can only be strict about checking this for implementations claiming
-         * support for VSR API level 35 and above.
+         * at the time, so we version-gate the strict check.
          */
-        GTEST_SKIP() << "Applies only to VSR API level 35, this device is: " << vsr_api_level;
+        GTEST_SKIP() << "Applies only to vendor API level >= 202404, but this device is: "
+                     << vendor_api_level;
     }
 
     auto wrapping_key_desc = AuthorizationSetBuilder()
@@ -8305,21 +8309,15 @@
         GTEST_SKIP() << "Option --arm_deleteAllKeys not set";
         return;
     }
+    // This test was introduced in API level 36, but is not version guarded because it requires a
+    // manual opt-in anyway. This makes it easier to run on older devices.
     auto error = GenerateKey(AuthorizationSetBuilder()
                                      .RsaSigningKey(2048, 65537)
                                      .Digest(Digest::NONE)
                                      .Padding(PaddingMode::NONE)
                                      .Authorization(TAG_NO_AUTH_REQUIRED)
-                                     .Authorization(TAG_ROLLBACK_RESISTANCE)
                                      .SetDefaultValidity());
-    if (error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE) {
-        GTEST_SKIP() << "Rollback resistance not supported";
-    }
-
-    // Delete must work if rollback protection is implemented
     ASSERT_EQ(ErrorCode::OK, error);
-    AuthorizationSet hardwareEnforced(SecLevelAuthorizations());
-    ASSERT_TRUE(hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE));
 
     ASSERT_EQ(ErrorCode::OK, DeleteAllKeys());
 
@@ -8949,27 +8947,30 @@
 
 // @VsrTest = VSR-3.10-008
 TEST_P(VsrRequirementTest, Vsr13Test) {
-    int vsr_api_level = get_vsr_api_level();
-    if (vsr_api_level < __ANDROID_API_T__) {
-        GTEST_SKIP() << "Applies only to VSR API level 33, this device is: " << vsr_api_level;
+    int vendor_api_level = get_vendor_api_level();
+    if (vendor_api_level < __ANDROID_API_T__) {
+        GTEST_SKIP() << "Applies only to vendor API level >= 33, but this device is: "
+                     << vendor_api_level;
     }
     EXPECT_GE(AidlVersion(), 2) << "VSR 13+ requires KeyMint version 2";
 }
 
 // @VsrTest = VSR-3.10-013.001
 TEST_P(VsrRequirementTest, Vsr14Test) {
-    int vsr_api_level = get_vsr_api_level();
-    if (vsr_api_level < __ANDROID_API_U__) {
-        GTEST_SKIP() << "Applies only to VSR API level 34, this device is: " << vsr_api_level;
+    int vendor_api_level = get_vendor_api_level();
+    if (vendor_api_level < __ANDROID_API_U__) {
+        GTEST_SKIP() << "Applies only to vendor API level >= 34, but this device is: "
+                     << vendor_api_level;
     }
     EXPECT_GE(AidlVersion(), 3) << "VSR 14+ requires KeyMint version 3";
 }
 
 // @VsrTest = GMS-VSR-3.10-019
 TEST_P(VsrRequirementTest, Vsr16Test) {
-    int vsr_api_level = get_vsr_api_level();
-    if (vsr_api_level <= __ANDROID_API_V__) {
-        GTEST_SKIP() << "Applies only to VSR API level > 35, this device is: " << vsr_api_level;
+    int vendor_api_level = get_vendor_api_level();
+    if (vendor_api_level <= AVendorSupport_getVendorApiLevelOf(__ANDROID_API_V__)) {
+        GTEST_SKIP() << "Applies only to vendor API level > 202404, but this device is: "
+                     << vendor_api_level;
     }
     if (SecLevel() == SecurityLevel::STRONGBOX) {
         GTEST_SKIP() << "Applies only to TEE KeyMint, not StrongBox KeyMint";
diff --git a/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
index 9f7322a..5888644 100644
--- a/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
+++ b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
@@ -26,6 +26,7 @@
 #include <cppbor_parse.h>
 #include <keymaster/cppcose/cppcose.h>
 #include <keymint_support/key_param_output.h>
+#include <vendorsupport/api_level.h>
 
 #include "KeyMintAidlTestBase.h"
 
@@ -114,10 +115,23 @@
         const auto& vbKey = rot->asArray()->get(pos++);
         ASSERT_TRUE(vbKey);
         ASSERT_TRUE(vbKey->asBstr());
-        if (get_vsr_api_level() >= __ANDROID_API_V__) {
-            // The attestation should contain the SHA-256 hash of the verified boot
-            // key.  However, this not was checked for earlier versions of the KeyMint
-            // HAL so only be strict for VSR-V and above.
+        if (get_vendor_api_level() > AVendorSupport_getVendorApiLevelOf(__ANDROID_API_V__)) {
+            // The Verified Boot key field should be exactly 32 bytes since it
+            // contains the SHA-256 hash of the key on locked devices or 32 bytes
+            // of zeroes on unlocked devices. This wasn't checked for earlier
+            // versions of the KeyMint HAL, so we version-gate the strict check.
+            ASSERT_EQ(vbKey->asBstr()->value().size(), 32);
+        } else if (get_vendor_api_level() ==
+                   AVendorSupport_getVendorApiLevelOf(__ANDROID_API_V__)) {
+            // The Verified Boot key field should be:
+            //   - Exactly 32 bytes on locked devices since it should contain
+            //     the SHA-256 hash of the key, or
+            //   - Up to 32 bytes of zeroes on unlocked devices (behaviour on
+            //     unlocked devices isn't specified in the HAL interface
+            //     specification).
+            // Thus, we can't check for strict equality in case unlocked devices
+            // report values with less than 32 bytes. This wasn't checked for
+            // earlier versions of the KeyMint HAL, so we version-gate the check.
             ASSERT_LE(vbKey->asBstr()->value().size(), 32);
         }
 
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 6cb00f2..4e0ce29 100644
--- a/security/keymint/support/include/remote_prov/remote_prov_utils.h
+++ b/security/keymint/support/include/remote_prov/remote_prov_utils.h
@@ -29,6 +29,11 @@
 using bytevec = std::vector<uint8_t>;
 using namespace cppcose;
 
+constexpr std::string_view kErrorChallengeMismatch = "challenges do not match";
+constexpr std::string_view kErrorUdsCertsAreRequired = "UdsCerts are required";
+constexpr std::string_view kErrorKeysToSignMismatch = "KeysToSign do not match";
+constexpr std::string_view kErrorDiceChainIsDegenerate = "DICE chain is degenerate";
+
 extern bytevec kTestMacKey;
 
 // The Google root key for the Endpoint Encryption Key chain, encoded as COSE_Sign1
@@ -209,6 +214,23 @@
 ErrMsgOr<bool> isCsrWithProperDiceChain(const std::vector<uint8_t>& csr,
                                         const std::string& instanceName);
 
+/** Checks whether the CSRs contain DICE certificate chains that have root certificates
+ * with the same public key.
+ */
+ErrMsgOr<bool> compareRootPublicKeysInDiceChains(const std::vector<uint8_t>& csr1,
+                                                 std::string_view instanceName1,
+                                                 const std::vector<uint8_t>& csr2,
+                                                 std::string_view instanceName2);
+
+/** Checks whether the component name in the configuration descriptor in the leaf certificate
+ * of the primary KeyMint instance's DICE certificate chain contains "keymint"
+ */
+ErrMsgOr<bool> verifyComponentNameInKeyMintDiceChain(const std::vector<uint8_t>& csr);
+
+/** Checks whether the DICE chain in the CSR has a certificate with a non-normal mode. */
+ErrMsgOr<bool> hasNonNormalModeInDiceChain(const std::vector<uint8_t>& csr,
+                                           std::string_view instanceName);
+
 /** Verify the DICE chain. */
 ErrMsgOr<std::vector<BccEntryData>> validateBcc(const cppbor::Array* bcc,
                                                 hwtrust::DiceChain::Kind kind, bool allowAnyMode,
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
index e11f021..eaeec32 100644
--- a/security/keymint/support/remote_prov_utils.cpp
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -45,6 +45,7 @@
 constexpr int32_t kBccPayloadKeyUsage = -4670553;
 constexpr int kP256AffinePointSize = 32;
 constexpr uint32_t kNumTeeDeviceInfoEntries = 14;
+constexpr std::string_view kKeyMintComponentName = "keymint";
 
 using EC_KEY_Ptr = bssl::UniquePtr<EC_KEY>;
 using EVP_PKEY_Ptr = bssl::UniquePtr<EVP_PKEY>;
@@ -123,37 +124,6 @@
     return std::make_tuple(std::move(pubX), std::move(pubY));
 }
 
-ErrMsgOr<bytevec> getRawPublicKey(const EVP_PKEY_Ptr& pubKey) {
-    if (pubKey.get() == nullptr) {
-        return "pkey is null.";
-    }
-    int keyType = EVP_PKEY_base_id(pubKey.get());
-    switch (keyType) {
-        case EVP_PKEY_EC: {
-            int nid = EVP_PKEY_bits(pubKey.get()) == 384 ? NID_secp384r1 : NID_X9_62_prime256v1;
-            auto ecKey = EC_KEY_Ptr(EVP_PKEY_get1_EC_KEY(pubKey.get()));
-            if (ecKey.get() == nullptr) {
-                return "Failed to get ec key";
-          }
-          return ecKeyGetPublicKey(ecKey.get(), nid);
-        }
-        case EVP_PKEY_ED25519: {
-            bytevec rawPubKey;
-            size_t rawKeySize = 0;
-            if (!EVP_PKEY_get_raw_public_key(pubKey.get(), NULL, &rawKeySize)) {
-                return "Failed to get raw public key.";
-            }
-            rawPubKey.resize(rawKeySize);
-            if (!EVP_PKEY_get_raw_public_key(pubKey.get(), rawPubKey.data(), &rawKeySize)) {
-                return "Failed to get raw public key.";
-            }
-            return rawPubKey;
-        }
-        default:
-            return "Unknown key type.";
-    }
-}
-
 ErrMsgOr<std::tuple<bytevec, bytevec>> generateEc256KeyPair() {
     auto ec_key = EC_KEY_Ptr(EC_KEY_new());
     if (ec_key.get() == nullptr) {
@@ -166,7 +136,7 @@
     }
 
     if (EC_KEY_set_group(ec_key.get(), group.get()) != 1 ||
-        EC_KEY_generate_key(ec_key.get()) != 1 || EC_KEY_check_key(ec_key.get()) < 0) {
+        EC_KEY_generate_key(ec_key.get()) != 1 || EC_KEY_check_key(ec_key.get()) != 1) {
         return "Error generating key";
     }
 
@@ -331,17 +301,22 @@
     return chain.encode();
 }
 
+bool maybeOverrideAllowAnyMode(bool allowAnyMode) {
+    // Use ro.build.type instead of ro.debuggable because ro.debuggable=1 for VTS testing
+    std::string build_type = ::android::base::GetProperty("ro.build.type", "");
+    if (!build_type.empty() && build_type != "user") {
+        return true;
+    }
+    return allowAnyMode;
+}
+
 ErrMsgOr<std::vector<BccEntryData>> validateBcc(const cppbor::Array* bcc,
                                                 hwtrust::DiceChain::Kind kind, bool allowAnyMode,
                                                 bool allowDegenerate,
                                                 const std::string& instanceName) {
     auto encodedBcc = bcc->encode();
 
-    // Use ro.build.type instead of ro.debuggable because ro.debuggable=1 for VTS testing
-    std::string build_type = ::android::base::GetProperty("ro.build.type", "");
-    if (!build_type.empty() && build_type != "user") {
-        allowAnyMode = true;
-    }
+    allowAnyMode = maybeOverrideAllowAnyMode(allowAnyMode);
 
     auto chain =
             hwtrust::DiceChain::Verify(encodedBcc, kind, allowAnyMode, deviceSuffix(instanceName));
@@ -779,233 +754,9 @@
                                /*isFactory=*/false, allowAnyMode);
 }
 
-ErrMsgOr<X509_Ptr> parseX509Cert(const std::vector<uint8_t>& cert) {
-    CRYPTO_BUFFER_Ptr certBuf(CRYPTO_BUFFER_new(cert.data(), cert.size(), nullptr));
-    if (!certBuf.get()) {
-        return "Failed to create crypto buffer.";
-    }
-    X509_Ptr result(X509_parse_from_buffer(certBuf.get()));
-    if (!result.get()) {
-        return "Failed to parse certificate.";
-    }
-    return result;
-}
-
-std::string getX509IssuerName(const X509_Ptr& cert) {
-    char* name = X509_NAME_oneline(X509_get_issuer_name(cert.get()), nullptr, 0);
-    std::string result(name);
-    OPENSSL_free(name);
-    return result;
-}
-
-std::string getX509SubjectName(const X509_Ptr& cert) {
-    char* name = X509_NAME_oneline(X509_get_subject_name(cert.get()), nullptr, 0);
-    std::string result(name);
-    OPENSSL_free(name);
-    return result;
-}
-
-// Validates the certificate chain and returns the leaf public key.
-ErrMsgOr<bytevec> validateCertChain(const cppbor::Array& chain) {
-    bytevec rawPubKey;
-    for (size_t i = 0; i < chain.size(); ++i) {
-        // Root must be self-signed.
-        size_t signingCertIndex = (i > 0) ? i - 1 : i;
-        auto& keyCertItem = chain[i];
-        auto& signingCertItem = chain[signingCertIndex];
-        if (!keyCertItem || !keyCertItem->asBstr()) {
-            return "Key certificate must be a Bstr.";
-        }
-        if (!signingCertItem || !signingCertItem->asBstr()) {
-            return "Signing certificate must be a Bstr.";
-        }
-
-        auto keyCert = parseX509Cert(keyCertItem->asBstr()->value());
-        if (!keyCert) {
-            return keyCert.message();
-        }
-        auto signingCert = parseX509Cert(signingCertItem->asBstr()->value());
-        if (!signingCert) {
-            return signingCert.message();
-        }
-
-        EVP_PKEY_Ptr pubKey(X509_get_pubkey(keyCert->get()));
-        if (!pubKey.get()) {
-            return "Failed to get public key.";
-        }
-        EVP_PKEY_Ptr signingPubKey(X509_get_pubkey(signingCert->get()));
-        if (!signingPubKey.get()) {
-            return "Failed to get signing public key.";
-        }
-
-        if (!X509_verify(keyCert->get(), signingPubKey.get())) {
-            return "Verification of certificate " + std::to_string(i) +
-                   " faile. OpenSSL error string: " + ERR_error_string(ERR_get_error(), NULL);
-        }
-
-        auto certIssuer = getX509IssuerName(*keyCert);
-        auto signerSubj = getX509SubjectName(*signingCert);
-        if (certIssuer != signerSubj) {
-            return "Certificate " + std::to_string(i) + " has wrong issuer. Signer subject is " +
-                   signerSubj + " Issuer subject is " + certIssuer;
-        }
-        if (i == chain.size() - 1) {
-            auto key = getRawPublicKey(pubKey);
-            if (!key) return key.moveMessage();
-            rawPubKey = key.moveValue();
-        }
-    }
-    return rawPubKey;
-}
-
-std::optional<std::string> validateUdsCerts(const cppbor::Map& udsCerts,
-                                            const bytevec& udsCoseKeyBytes) {
-    for (const auto& [signerName, udsCertChain] : udsCerts) {
-        if (!signerName || !signerName->asTstr()) {
-            return "Signer Name must be a Tstr.";
-        }
-        if (!udsCertChain || !udsCertChain->asArray()) {
-            return "UDS certificate chain must be an Array.";
-        }
-        if (udsCertChain->asArray()->size() < 2) {
-            return "UDS certificate chain must have at least two entries: root and leaf.";
-        }
-
-        auto leafPubKey = validateCertChain(*udsCertChain->asArray());
-        if (!leafPubKey) {
-            return leafPubKey.message();
-        }
-        auto coseKey = CoseKey::parse(udsCoseKeyBytes);
-        if (!coseKey) {
-            return coseKey.moveMessage();
-        }
-        auto curve = coseKey->getIntValue(CoseKey::CURVE);
-        if (!curve) {
-            return "CoseKey must contain curve.";
-        }
-        bytevec udsPub;
-        if (curve == CoseKeyCurve::P256 || curve == CoseKeyCurve::P384) {
-            auto pubKey = coseKey->getEcPublicKey();
-            if (!pubKey) {
-                return pubKey.moveMessage();
-            }
-            // convert public key to uncompressed form by prepending 0x04 at begin.
-            pubKey->insert(pubKey->begin(), 0x04);
-            udsPub = pubKey.moveValue();
-        } else if (curve == CoseKeyCurve::ED25519) {
-            auto& pubkey = coseKey->getMap().get(cppcose::CoseKey::PUBKEY_X);
-            if (!pubkey || !pubkey->asBstr()) {
-                return "Invalid public key.";
-            }
-            udsPub = pubkey->asBstr()->value();
-        } else {
-            return "Unknown curve.";
-        }
-        if (*leafPubKey != udsPub) {
-            return "Leaf public key in UDS certificate chain doesn't match UDS public key.";
-        }
-    }
-    return std::nullopt;
-}
-
-ErrMsgOr<std::unique_ptr<cppbor::Array>> parseAndValidateCsrPayload(
-        const cppbor::Array& keysToSign, const std::vector<uint8_t>& csrPayload,
-        const RpcHardwareInfo& rpcHardwareInfo, bool isFactory) {
-    auto [parsedCsrPayload, _, errMsg] = cppbor::parse(csrPayload);
-    if (!parsedCsrPayload) {
-        return errMsg;
-    }
-
-    std::unique_ptr<cppbor::Array> parsed(parsedCsrPayload.release()->asArray());
-    if (!parsed) {
-        return "CSR payload is not a CBOR array.";
-    }
-
-    if (parsed->size() != 4U) {
-        return "CSR payload must contain version, certificate type, device info, keys. "
-               "However, the parsed CSR payload has " +
-               std::to_string(parsed->size()) + " entries.";
-    }
-
-    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->value() != 3U) {
-        return "CSR payload version must be an unsigned integer and must be equal to 3.";
-    }
-    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) {
-        return "Device info must be an Map.";
-    }
-    if (!signedKeys) {
-        return "Keys must be an Array.";
-    }
-
-    auto result =
-            parseAndValidateDeviceInfo(signedDeviceInfo->encode(), rpcHardwareInfo, 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() > 64) {
-        return "Challenge size must be between 0 and 64 bytes inclusive. "
-               "However, challenge is " +
-               std::to_string(challenge.size()) + " bytes long.";
-    }
-
-    auto challengeBstr = cppbor::Bstr(challenge);
-    if (*signedChallenge != challengeBstr) {
-        return "Signed challenge does not match."
-               "\n  Actual: " +
-               cppbor::prettyPrint(signedChallenge->asBstr(), 64 /* maxBStrSize */) +
-               "\nExpected: " + cppbor::prettyPrint(&challengeBstr, 64 /* maxBStrSize */);
-    }
-
-    if (!signedRequest) {
-        return "Request must be a Bstr.";
-    }
-
-    return signedRequest->value();
-}
-
 ErrMsgOr<hwtrust::DiceChain::Kind> getDiceChainKind() {
     int vendor_api_level = ::android::base::GetIntProperty("ro.vendor.api_level", -1);
-    if (vendor_api_level == __ANDROID_API_T__) {
+    if (vendor_api_level <= __ANDROID_API_T__) {
         return hwtrust::DiceChain::Kind::kVsr13;
     } else if (vendor_api_level == __ANDROID_API_U__) {
         return hwtrust::DiceChain::Kind::kVsr14;
@@ -1018,87 +769,8 @@
     }
 }
 
-ErrMsgOr<bytevec> parseAndValidateAuthenticatedRequest(const std::vector<uint8_t>& request,
-                                                       const std::vector<uint8_t>& challenge,
-                                                       const std::string& instanceName,
-                                                       bool allowAnyMode = false,
-                                                       bool allowDegenerate = true,
-                                                       bool requireUdsCerts = false) {
-    auto [parsedRequest, _, csrErrMsg] = cppbor::parse(request);
-    if (!parsedRequest) {
-        return csrErrMsg;
-    }
-    if (!parsedRequest->asArray()) {
-        return "AuthenticatedRequest is not a CBOR array.";
-    }
-    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 = 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->value() != 1U) {
-        return "AuthenticatedRequest version must be an unsigned integer and must be equal to 1.";
-    }
-
-    if (!udsCerts) {
-        return "AuthenticatedRequest UdsCerts must be a Map.";
-    }
-    if (requireUdsCerts && udsCerts->size() == 0) {
-        return "AuthenticatedRequest UdsCerts must not be empty.";
-    }
-    if (!diceCertChain) {
-        return "AuthenticatedRequest DiceCertChain must be an Array.";
-    }
-    if (!signedData) {
-        return "AuthenticatedRequest SignedData must be an Array.";
-    }
-
-    // DICE chain is [ pubkey, + DiceChainEntry ].
-    auto diceChainKind = getDiceChainKind();
-    if (!diceChainKind) {
-        return diceChainKind.message();
-    }
-
-    auto diceContents =
-            validateBcc(diceCertChain, *diceChainKind, allowAnyMode, allowDegenerate, instanceName);
-    if (!diceContents) {
-        return diceContents.message() + "\n" + prettyPrint(diceCertChain);
-    }
-
-    if (!diceCertChain->get(0)->asMap()) {
-        return "AuthenticatedRequest The first entry in DiceCertChain must be a Map.";
-    }
-    auto udsPub = diceCertChain->get(0)->asMap()->encode();
-    auto error = validateUdsCerts(*udsCerts, udsPub);
-    if (error) {
-        return *error;
-    }
-
-    if (diceContents->empty()) {
-        return "AuthenticatedRequest DiceContents must not be empty.";
-    }
-    auto& kmDiceKey = diceContents->back().pubKey;
-    auto signedPayload = verifyAndParseCoseSign1(signedData, kmDiceKey, /*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,
+        const cppbor::Array& keysToSign, const std::vector<uint8_t>& encodedCsr,
         const RpcHardwareInfo& rpcHardwareInfo, const std::string& instanceName,
         const std::vector<uint8_t>& challenge, bool isFactory, bool allowAnyMode = false,
         bool allowDegenerate = true, bool requireUdsCerts = false) {
@@ -1108,14 +780,68 @@
                ") does not match expected version (3).";
     }
 
-    auto csrPayload = parseAndValidateAuthenticatedRequest(
-            csr, challenge, instanceName, allowAnyMode, allowDegenerate, requireUdsCerts);
-
-    if (!csrPayload) {
-        return csrPayload.message();
+    auto diceChainKind = getDiceChainKind();
+    if (!diceChainKind) {
+        return diceChainKind.message();
     }
 
-    return parseAndValidateCsrPayload(keysToSign, *csrPayload, rpcHardwareInfo, isFactory);
+    allowAnyMode = maybeOverrideAllowAnyMode(allowAnyMode);
+
+    auto csr = hwtrust::Csr::validate(encodedCsr, *diceChainKind, isFactory, allowAnyMode,
+                                      deviceSuffix(instanceName));
+
+    if (!csr.ok()) {
+        return csr.error().message();
+    }
+
+    if (!allowDegenerate) {
+        auto diceChain = csr->getDiceChain();
+        if (!diceChain.ok()) {
+            return diceChain.error().message();
+        }
+
+        if (!diceChain->IsProper()) {
+            return kErrorDiceChainIsDegenerate;
+        }
+    }
+
+    if (requireUdsCerts && !csr->hasUdsCerts()) {
+        return kErrorUdsCertsAreRequired;
+    }
+
+    auto equalChallenges = csr->compareChallenge(challenge);
+    if (!equalChallenges.ok()) {
+        return equalChallenges.error().message();
+    }
+
+    if (!*equalChallenges) {
+        return kErrorChallengeMismatch;
+    }
+
+    auto equalKeysToSign = csr->compareKeysToSign(keysToSign.encode());
+    if (!equalKeysToSign.ok()) {
+        return equalKeysToSign.error().message();
+    }
+
+    if (!*equalKeysToSign) {
+        return kErrorKeysToSignMismatch;
+    }
+
+    auto csrPayload = csr->getCsrPayload();
+    if (!csrPayload) {
+        return csrPayload.error().message();
+    }
+
+    auto [csrPayloadDecoded, _, errMsg] = cppbor::parse(*csrPayload);
+    if (!csrPayloadDecoded) {
+        return errMsg;
+    }
+
+    if (!csrPayloadDecoded->asArray()) {
+        return "CSR payload is not an array.";
+    }
+
+    return std::unique_ptr<cppbor::Array>(csrPayloadDecoded.release()->asArray());
 }
 
 ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyFactoryCsr(
@@ -1143,8 +869,8 @@
         return diceChainKind.message();
     }
 
-    auto csr = hwtrust::Csr::validate(encodedCsr, *diceChainKind, false /*allowAnyMode*/,
-                                      deviceSuffix(instanceName));
+    auto csr = hwtrust::Csr::validate(encodedCsr, *diceChainKind, false /*isFactory*/,
+                                      false /*allowAnyMode*/, deviceSuffix(instanceName));
     if (!csr.ok()) {
         return csr.error().message();
     }
@@ -1157,4 +883,117 @@
     return diceChain->IsProper();
 }
 
+std::string hexlify(const std::vector<uint8_t>& bytes) {
+    std::stringstream ss;
+    ss << std::hex << std::setfill('0');
+
+    for (const auto& byte : bytes) {
+        ss << std::setw(2) << static_cast<int>(byte);
+    }
+
+    return ss.str();
+}
+
+ErrMsgOr<bool> compareRootPublicKeysInDiceChains(const std::vector<uint8_t>& encodedCsr1,
+                                                 std::string_view instanceName1,
+                                                 const std::vector<uint8_t>& encodedCsr2,
+                                                 std::string_view instanceName2) {
+    auto diceChainKind = getDiceChainKind();
+    if (!diceChainKind) {
+        return diceChainKind.message();
+    }
+
+    auto csr1 = hwtrust::Csr::validate(encodedCsr1, *diceChainKind, false /*isFactory*/,
+                                       false /*allowAnyMode*/, deviceSuffix(instanceName1));
+    if (!csr1.ok()) {
+        return csr1.error().message();
+    }
+
+    auto diceChain1 = csr1->getDiceChain();
+    if (!diceChain1.ok()) {
+        return diceChain1.error().message();
+    }
+
+    auto proper1 = diceChain1->IsProper();
+    if (!proper1) {
+        return std::string(instanceName1) + " has a degenerate DICE chain:\n" +
+               hexlify(encodedCsr1);
+    }
+
+    auto csr2 = hwtrust::Csr::validate(encodedCsr2, *diceChainKind, false /*isFactory*/,
+                                       false /*allowAnyMode*/, deviceSuffix(instanceName2));
+    if (!csr2.ok()) {
+        return csr2.error().message();
+    }
+
+    auto diceChain2 = csr2->getDiceChain();
+    if (!diceChain2.ok()) {
+        return diceChain2.error().message();
+    }
+
+    auto proper2 = diceChain2->IsProper();
+    if (!proper2) {
+        return std::string(instanceName2) + " has a degenerate DICE chain:\n" +
+               hexlify(encodedCsr2);
+    }
+
+    auto result = diceChain1->compareRootPublicKey(*diceChain2);
+    if (!result.ok()) {
+        return result.error().message();
+    }
+
+    return *result;
+}
+
+ErrMsgOr<bool> verifyComponentNameInKeyMintDiceChain(const std::vector<uint8_t>& encodedCsr) {
+    auto diceChainKind = getDiceChainKind();
+    if (!diceChainKind) {
+        return diceChainKind.message();
+    }
+
+    auto csr = hwtrust::Csr::validate(encodedCsr, *diceChainKind, false /*isFactory*/,
+                                      false /*allowAnyMode*/, deviceSuffix(DEFAULT_INSTANCE_NAME));
+    if (!csr.ok()) {
+        return csr.error().message();
+    }
+
+    auto diceChain = csr->getDiceChain();
+    if (!diceChain.ok()) {
+        return diceChain.error().message();
+    }
+
+    auto satisfied = diceChain->componentNameContains(kKeyMintComponentName);
+    if (!satisfied.ok()) {
+        return satisfied.error().message();
+    }
+
+    return *satisfied;
+}
+
+ErrMsgOr<bool> hasNonNormalModeInDiceChain(const std::vector<uint8_t>& encodedCsr,
+                                           std::string_view instanceName) {
+    auto diceChainKind = getDiceChainKind();
+    if (!diceChainKind) {
+        return diceChainKind.message();
+    }
+
+    auto csr = hwtrust::Csr::validate(encodedCsr, *diceChainKind, false /*isFactory*/,
+                                      true /*allowAnyMode*/, deviceSuffix(instanceName));
+    if (!csr.ok()) {
+        return csr.error().message();
+    }
+
+    auto diceChain = csr->getDiceChain();
+    if (!diceChain.ok()) {
+        return diceChain.error().message();
+    }
+
+    auto hasNonNormalModeInDiceChain = diceChain->hasNonNormalMode();
+    if (!hasNonNormalModeInDiceChain.ok()) {
+        return hasNonNormalModeInDiceChain.error().message();
+    }
+
+    return *hasNonNormalModeInDiceChain;
+}
+
 }  // namespace aidl::android::hardware::security::keymint::remote_prov
diff --git a/security/keymint/support/remote_prov_utils_test.cpp b/security/keymint/support/remote_prov_utils_test.cpp
index 6f6a2d6..e3c1e58 100644
--- a/security/keymint/support/remote_prov_utils_test.cpp
+++ b/security/keymint/support/remote_prov_utils_test.cpp
@@ -81,30 +81,423 @@
         0x50, 0x12, 0x82, 0x37, 0xfe, 0xa4, 0x07, 0xc3, 0xd5, 0xc3, 0x78, 0xcc, 0xf9, 0xef, 0xe1,
         0x95, 0x38, 0x9f, 0xb0, 0x79, 0x16, 0x4c, 0x4a, 0x23, 0xc4, 0xdc, 0x35, 0x4e, 0x0f};
 
+inline const std::vector<uint8_t> kKeysToSignForCsrWithDegenerateDiceChain{
+        0x82, 0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x1d, 0x94, 0xf2, 0x27,
+        0xc3, 0x70, 0x01, 0xde, 0x3c, 0xaf, 0x6f, 0xfd, 0x78, 0x08, 0x37, 0x39, 0x21, 0xdd, 0x46,
+        0x6f, 0x08, 0x4f, 0x77, 0xf7, 0x80, 0x34, 0x30, 0x74, 0x78, 0x69, 0xeb, 0xb1, 0x22, 0x58,
+        0x20, 0x6b, 0x71, 0xd7, 0x7f, 0x0e, 0x51, 0xb2, 0xc9, 0x3d, 0x1a, 0xa0, 0xe8, 0x7a, 0x0d,
+        0x57, 0xfc, 0x91, 0xd0, 0x68, 0xf9, 0x33, 0x5f, 0x80, 0x29, 0x00, 0x80, 0x98, 0x78, 0x63,
+        0x5b, 0x30, 0x24, 0x23, 0x58, 0x20, 0x09, 0x83, 0xa6, 0x5a, 0xbb, 0x3a, 0xf8, 0x90, 0x88,
+        0x87, 0x16, 0x37, 0xb4, 0xe7, 0x11, 0x9b, 0xcc, 0xbb, 0x15, 0x82, 0xa9, 0x97, 0xa5, 0xad,
+        0xa9, 0x85, 0x39, 0x30, 0x55, 0x46, 0x99, 0xc6, 0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01,
+        0x21, 0x58, 0x20, 0xa8, 0xaa, 0x4b, 0x63, 0x86, 0xf6, 0x5c, 0xe4, 0x28, 0xda, 0x26, 0x3f,
+        0x9a, 0x42, 0x6e, 0xb9, 0x2b, 0x4d, 0x5a, 0x49, 0x4c, 0x5f, 0x1a, 0xa2, 0x5f, 0xd4, 0x8f,
+        0x84, 0xd7, 0x25, 0xe4, 0x6c, 0x22, 0x58, 0x20, 0x6b, 0xef, 0xde, 0xd6, 0x04, 0x58, 0x12,
+        0xdb, 0xf8, 0x90, 0x2c, 0x9c, 0xe0, 0x5e, 0x43, 0xbc, 0xcf, 0x22, 0x01, 0x4d, 0x5c, 0x0c,
+        0x86, 0x7b, 0x66, 0xd2, 0xa1, 0xfc, 0x69, 0x8a, 0x91, 0xfc, 0x23, 0x58, 0x20, 0x31, 0xaf,
+        0x30, 0x85, 0x1f, 0x2a, 0x82, 0xe1, 0x9c, 0xda, 0xe5, 0x68, 0xed, 0x79, 0xc1, 0x35, 0x1a,
+        0x02, 0xb4, 0x8a, 0xd2, 0x4c, 0xc4, 0x70, 0x6b, 0x88, 0x98, 0x23, 0x9e, 0xb3, 0x52, 0xb1};
+
 inline const std::vector<uint8_t> kCsrWithDegenerateDiceChain{
-        0x85, 0x01, 0xa0, 0x82, 0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x65,
-        0xe0, 0x51, 0x62, 0x45, 0x17, 0xcc, 0xa8, 0x40, 0x41, 0x6d, 0xc0, 0x86, 0x7a, 0x15, 0x6e,
-        0xee, 0x04, 0xae, 0xbd, 0x05, 0x13, 0x36, 0xcb, 0xd2, 0x8d, 0xd8, 0x80, 0x16, 0xc1, 0x69,
-        0x0d, 0x22, 0x58, 0x20, 0xea, 0xa1, 0x37, 0xd5, 0x01, 0xbd, 0xe0, 0x25, 0x6a, 0x3d, 0x4c,
-        0xcd, 0x31, 0xa1, 0x4d, 0xa6, 0x80, 0x82, 0x03, 0x40, 0xe2, 0x88, 0x81, 0x53, 0xc3, 0xb3,
-        0x6d, 0xf7, 0xf4, 0x10, 0xde, 0x96, 0x23, 0x58, 0x20, 0x24, 0x69, 0x44, 0x6e, 0xf5, 0xcc,
-        0x18, 0xfe, 0x63, 0xac, 0x5e, 0x85, 0x9c, 0xfc, 0x9d, 0xfa, 0x90, 0xee, 0x6c, 0xc2, 0x22,
-        0x49, 0x02, 0xc7, 0x93, 0xf4, 0x30, 0xf1, 0x51, 0x11, 0x20, 0x33, 0x84, 0x43, 0xa1, 0x01,
-        0x26, 0xa0, 0x58, 0x97, 0xa5, 0x01, 0x66, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x02, 0x67,
-        0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a,
-        0x00, 0x47, 0x44, 0x57, 0x58, 0x70, 0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58,
-        0x20, 0x65, 0xe0, 0x51, 0x62, 0x45, 0x17, 0xcc, 0xa8, 0x40, 0x41, 0x6d, 0xc0, 0x86, 0x7a,
-        0x15, 0x6e, 0xee, 0x04, 0xae, 0xbd, 0x05, 0x13, 0x36, 0xcb, 0xd2, 0x8d, 0xd8, 0x80, 0x16,
-        0xc1, 0x69, 0x0d, 0x22, 0x58, 0x20, 0xea, 0xa1, 0x37, 0xd5, 0x01, 0xbd, 0xe0, 0x25, 0x6a,
-        0x3d, 0x4c, 0xcd, 0x31, 0xa1, 0x4d, 0xa6, 0x80, 0x82, 0x03, 0x40, 0xe2, 0x88, 0x81, 0x53,
-        0xc3, 0xb3, 0x6d, 0xf7, 0xf4, 0x10, 0xde, 0x96, 0x23, 0x58, 0x20, 0x24, 0x69, 0x44, 0x6e,
-        0xf5, 0xcc, 0x18, 0xfe, 0x63, 0xac, 0x5e, 0x85, 0x9c, 0xfc, 0x9d, 0xfa, 0x90, 0xee, 0x6c,
-        0xc2, 0x22, 0x49, 0x02, 0xc7, 0x93, 0xf4, 0x30, 0xf1, 0x51, 0x11, 0x20, 0x33, 0x3a, 0x00,
-        0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40, 0x16, 0xb9, 0x51, 0xdf, 0x31, 0xad, 0xa0, 0x3d,
-        0x98, 0x40, 0x85, 0xdf, 0xd9, 0xbe, 0xf6, 0x79, 0x62, 0x36, 0x8b, 0x60, 0xaa, 0x79, 0x8e,
-        0x52, 0x04, 0xdd, 0xba, 0x39, 0xa2, 0x58, 0x9c, 0x60, 0xd5, 0x96, 0x51, 0x42, 0xe2, 0xa5,
-        0x57, 0x58, 0xb4, 0x89, 0x2c, 0x94, 0xb9, 0xda, 0xe7, 0x93, 0x85, 0xda, 0x64, 0xa0, 0x52,
-        0xfc, 0x6b, 0xb1, 0x0a, 0xa8, 0x13, 0xd9, 0x84, 0xfb, 0x34, 0x77, 0x84, 0x43, 0xa1, 0x01,
+        0x84, 0x01, 0xa0, 0x82, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xf2,
+        0xc6, 0x50, 0xd2, 0x42, 0x59, 0xe0, 0x4e, 0x7b, 0xc0, 0x75, 0x41, 0xa2, 0xe9, 0xd0, 0xe8,
+        0x18, 0xd7, 0xd7, 0x63, 0x7e, 0x41, 0x04, 0x7e, 0x52, 0x1a, 0xb1, 0xb7, 0xdc, 0x13, 0xb3,
+        0x0f, 0x22, 0x58, 0x20, 0x1a, 0xf3, 0x8b, 0x0f, 0x7a, 0xc6, 0xf2, 0xb8, 0x31, 0x0b, 0x40,
+        0x9b, 0x7e, 0xb6, 0xd6, 0xec, 0x9c, 0x21, 0xad, 0xde, 0xd1, 0x6c, 0x52, 0xfc, 0x06, 0xf1,
+        0x39, 0x31, 0xa0, 0x22, 0x65, 0x86, 0x84, 0x43, 0xa1, 0x01, 0x26, 0xa0, 0x58, 0x74, 0xa5,
+        0x01, 0x66, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x02, 0x67, 0x73, 0x75, 0x62, 0x6a, 0x65,
+        0x63, 0x74, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58,
+        0x4d, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xf2, 0xc6, 0x50, 0xd2,
+        0x42, 0x59, 0xe0, 0x4e, 0x7b, 0xc0, 0x75, 0x41, 0xa2, 0xe9, 0xd0, 0xe8, 0x18, 0xd7, 0xd7,
+        0x63, 0x7e, 0x41, 0x04, 0x7e, 0x52, 0x1a, 0xb1, 0xb7, 0xdc, 0x13, 0xb3, 0x0f, 0x22, 0x58,
+        0x20, 0x1a, 0xf3, 0x8b, 0x0f, 0x7a, 0xc6, 0xf2, 0xb8, 0x31, 0x0b, 0x40, 0x9b, 0x7e, 0xb6,
+        0xd6, 0xec, 0x9c, 0x21, 0xad, 0xde, 0xd1, 0x6c, 0x52, 0xfc, 0x06, 0xf1, 0x39, 0x31, 0xa0,
+        0x22, 0x65, 0x86, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40, 0x1e, 0xdf, 0xe0,
+        0x1c, 0xca, 0xbb, 0xb2, 0x13, 0xae, 0xe2, 0x49, 0x32, 0x3c, 0x6e, 0x9c, 0x6e, 0xf4, 0x23,
+        0x87, 0x41, 0x60, 0x04, 0x34, 0xe6, 0x32, 0xe2, 0xf1, 0x22, 0x55, 0xcc, 0x89, 0x4b, 0x4f,
+        0xdb, 0x05, 0x89, 0x8a, 0x3c, 0x2f, 0x8a, 0x52, 0x84, 0x43, 0xdc, 0x43, 0x62, 0x7e, 0x85,
+        0xb3, 0xea, 0x49, 0x3b, 0x0b, 0x4a, 0xf0, 0x64, 0xfe, 0x8f, 0x41, 0xb6, 0xd1, 0xcc, 0xe3,
+        0xf6, 0x84, 0x43, 0xa1, 0x01, 0x26, 0xa0, 0x59, 0x02, 0x0e, 0x82, 0x58, 0x20, 0x01, 0x02,
+        0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
+        0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+        0x59, 0x01, 0xe8, 0x84, 0x03, 0x67, 0x6b, 0x65, 0x79, 0x6d, 0x69, 0x6e, 0x74, 0xae, 0x65,
+        0x62, 0x72, 0x61, 0x6e, 0x64, 0x66, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x65, 0x66, 0x75,
+        0x73, 0x65, 0x64, 0x01, 0x65, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x65, 0x6d, 0x6f, 0x64, 0x65,
+        0x6c, 0x66, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x66, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
+        0x67, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x65, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x68,
+        0x76, 0x62, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x65, 0x67, 0x72, 0x65, 0x65, 0x6e, 0x6a,
+        0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x62, 0x31, 0x32, 0x6c, 0x6d,
+        0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x66, 0x47, 0x6f, 0x6f,
+        0x67, 0x6c, 0x65, 0x6d, 0x76, 0x62, 0x6d, 0x65, 0x74, 0x61, 0x5f, 0x64, 0x69, 0x67, 0x65,
+        0x73, 0x74, 0x4f, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc,
+        0xdd, 0xee, 0xff, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x6c, 0x65,
+        0x76, 0x65, 0x6c, 0x63, 0x74, 0x65, 0x65, 0x70, 0x62, 0x6f, 0x6f, 0x74, 0x5f, 0x70, 0x61,
+        0x74, 0x63, 0x68, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x1a, 0x01, 0x34, 0x8c, 0x62, 0x70,
+        0x62, 0x6f, 0x6f, 0x74, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x74,
+        0x65, 0x66, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x72, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d,
+        0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x1a, 0x01, 0x34,
+        0x8c, 0x61, 0x72, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x74, 0x63, 0x68,
+        0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x1a, 0x01, 0x34, 0x8c, 0x63, 0x82, 0xa6, 0x01, 0x02,
+        0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x1d, 0x94, 0xf2, 0x27, 0xc3, 0x70, 0x01, 0xde,
+        0x3c, 0xaf, 0x6f, 0xfd, 0x78, 0x08, 0x37, 0x39, 0x21, 0xdd, 0x46, 0x6f, 0x08, 0x4f, 0x77,
+        0xf7, 0x80, 0x34, 0x30, 0x74, 0x78, 0x69, 0xeb, 0xb1, 0x22, 0x58, 0x20, 0x6b, 0x71, 0xd7,
+        0x7f, 0x0e, 0x51, 0xb2, 0xc9, 0x3d, 0x1a, 0xa0, 0xe8, 0x7a, 0x0d, 0x57, 0xfc, 0x91, 0xd0,
+        0x68, 0xf9, 0x33, 0x5f, 0x80, 0x29, 0x00, 0x80, 0x98, 0x78, 0x63, 0x5b, 0x30, 0x24, 0x23,
+        0x58, 0x20, 0x09, 0x83, 0xa6, 0x5a, 0xbb, 0x3a, 0xf8, 0x90, 0x88, 0x87, 0x16, 0x37, 0xb4,
+        0xe7, 0x11, 0x9b, 0xcc, 0xbb, 0x15, 0x82, 0xa9, 0x97, 0xa5, 0xad, 0xa9, 0x85, 0x39, 0x30,
+        0x55, 0x46, 0x99, 0xc6, 0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xa8,
+        0xaa, 0x4b, 0x63, 0x86, 0xf6, 0x5c, 0xe4, 0x28, 0xda, 0x26, 0x3f, 0x9a, 0x42, 0x6e, 0xb9,
+        0x2b, 0x4d, 0x5a, 0x49, 0x4c, 0x5f, 0x1a, 0xa2, 0x5f, 0xd4, 0x8f, 0x84, 0xd7, 0x25, 0xe4,
+        0x6c, 0x22, 0x58, 0x20, 0x6b, 0xef, 0xde, 0xd6, 0x04, 0x58, 0x12, 0xdb, 0xf8, 0x90, 0x2c,
+        0x9c, 0xe0, 0x5e, 0x43, 0xbc, 0xcf, 0x22, 0x01, 0x4d, 0x5c, 0x0c, 0x86, 0x7b, 0x66, 0xd2,
+        0xa1, 0xfc, 0x69, 0x8a, 0x91, 0xfc, 0x23, 0x58, 0x20, 0x31, 0xaf, 0x30, 0x85, 0x1f, 0x2a,
+        0x82, 0xe1, 0x9c, 0xda, 0xe5, 0x68, 0xed, 0x79, 0xc1, 0x35, 0x1a, 0x02, 0xb4, 0x8a, 0xd2,
+        0x4c, 0xc4, 0x70, 0x6b, 0x88, 0x98, 0x23, 0x9e, 0xb3, 0x52, 0xb1, 0x58, 0x40, 0x8e, 0x7e,
+        0xdf, 0x77, 0x13, 0xdb, 0x51, 0xf6, 0xc1, 0x67, 0x52, 0x48, 0x48, 0x79, 0xe6, 0xbc, 0x89,
+        0xe2, 0xfe, 0x7c, 0x0d, 0x2c, 0x88, 0x3b, 0x23, 0x66, 0x93, 0x7b, 0x94, 0x59, 0xc4, 0x87,
+        0x16, 0xc4, 0x3a, 0x85, 0x60, 0xe3, 0x62, 0x45, 0x53, 0xa8, 0x1d, 0x4e, 0xa4, 0x2b, 0x61,
+        0x33, 0x17, 0x71, 0xb6, 0x40, 0x11, 0x7d, 0x23, 0x64, 0xe6, 0x49, 0xbe, 0xa6, 0x85, 0x32,
+        0x1a, 0x89};
+
+// The challenge that is in kKeysToSignForCsrWithUdsCerts and kCsrWithUdsCerts
+inline const std::vector<uint8_t> kChallenge{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+                                             0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+                                             0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+                                             0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20};
+
+inline const std::vector<uint8_t> kKeysToSignForCsrWithUdsCerts{
+        0x82, 0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xd5, 0x0b, 0x27, 0x39,
+        0xa3, 0xd5, 0xfd, 0xd9, 0x4f, 0x87, 0x4a, 0x97, 0x17, 0x60, 0x6c, 0x63, 0x55, 0x13, 0xa0,
+        0xf5, 0x1c, 0x2b, 0xe7, 0x0e, 0x8e, 0xdb, 0x76, 0x82, 0x69, 0x5a, 0x46, 0xec, 0x22, 0x58,
+        0x20, 0xa6, 0x08, 0xb3, 0x57, 0xaa, 0x5f, 0x72, 0x2b, 0xb1, 0xf0, 0x43, 0x52, 0xf4, 0xcb,
+        0x97, 0x39, 0xfd, 0x54, 0x79, 0xa3, 0xaf, 0x07, 0xb7, 0xbe, 0xbc, 0x93, 0xc1, 0xb6, 0x9b,
+        0x2f, 0x75, 0x1b, 0x23, 0x58, 0x21, 0x00, 0xb4, 0x59, 0xe3, 0x78, 0x6f, 0x3f, 0xbd, 0xdc,
+        0x38, 0x8a, 0xa5, 0x7d, 0xbe, 0xe0, 0xce, 0xf9, 0x2e, 0x9a, 0x5b, 0xfc, 0xbd, 0x4d, 0x27,
+        0x7b, 0xa7, 0xc8, 0xda, 0xaa, 0xe4, 0xcd, 0xf3, 0xd2, 0xa6, 0x01, 0x02, 0x03, 0x26, 0x20,
+        0x01, 0x21, 0x58, 0x20, 0x10, 0x6c, 0xe8, 0x71, 0xa8, 0x78, 0x9d, 0x29, 0xbe, 0xf8, 0x84,
+        0x39, 0xd4, 0xa2, 0xf5, 0x3e, 0x09, 0xf1, 0xd4, 0x81, 0x59, 0x24, 0x63, 0x07, 0xae, 0x25,
+        0xad, 0x24, 0x72, 0x0f, 0x8b, 0xd0, 0x22, 0x58, 0x20, 0xe8, 0xba, 0x76, 0x49, 0x7b, 0x97,
+        0x98, 0xcf, 0xbb, 0x90, 0xfa, 0x30, 0x3a, 0x2d, 0x88, 0xfe, 0x3f, 0xc6, 0x75, 0x05, 0x7b,
+        0x59, 0xdf, 0x14, 0xd8, 0xde, 0x4d, 0x51, 0x8b, 0x2f, 0x5a, 0xc7, 0x23, 0x58, 0x20, 0x76,
+        0x11, 0x2f, 0x31, 0xe5, 0xc2, 0xbb, 0xa7, 0x2c, 0x2b, 0x2f, 0x73, 0x16, 0x29, 0xf8, 0x67,
+        0x66, 0x44, 0x7f, 0x3f, 0x22, 0xa2, 0x40, 0x45, 0x12, 0xac, 0x97, 0x06, 0xc8, 0x66, 0x08,
+        0xc9, 0x0a};
+
+inline const std::vector<uint8_t> kCsrWithUdsCerts{
+        0x84, 0x01, 0xa1, 0x70, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72,
+        0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0x59, 0x01, 0x6c, 0x30, 0x82, 0x01, 0x68, 0x30, 0x82,
+        0x01, 0x1a, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x7b, 0x30, 0x05, 0x06, 0x03, 0x2b,
+        0x65, 0x70, 0x30, 0x2b, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c,
+        0x46, 0x61, 0x6b, 0x65, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x31, 0x12, 0x30,
+        0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x09, 0x46, 0x61, 0x6b, 0x65, 0x20, 0x52, 0x6f,
+        0x6f, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x34, 0x31, 0x31, 0x31, 0x34, 0x30, 0x39, 0x35,
+        0x32, 0x30, 0x37, 0x5a, 0x17, 0x0d, 0x34, 0x39, 0x31, 0x31, 0x30, 0x38, 0x30, 0x39, 0x35,
+        0x32, 0x30, 0x37, 0x5a, 0x30, 0x2b, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a,
+        0x13, 0x0c, 0x46, 0x61, 0x6b, 0x65, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x31,
+        0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x09, 0x46, 0x61, 0x6b, 0x65, 0x20,
+        0x52, 0x6f, 0x6f, 0x74, 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21,
+        0x00, 0x54, 0x40, 0x8c, 0x1b, 0x60, 0x39, 0x81, 0xe7, 0x38, 0x87, 0xb9, 0x75, 0x10, 0x30,
+        0x6a, 0x1b, 0x9b, 0x38, 0x61, 0xa0, 0x94, 0x49, 0xb0, 0xf3, 0xae, 0x39, 0x53, 0x2d, 0x61,
+        0x8d, 0x6e, 0x59, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
+        0x16, 0x04, 0x14, 0x6d, 0xd5, 0xea, 0x8c, 0xe0, 0x5a, 0x50, 0xd9, 0x36, 0xf3, 0x28, 0xc2,
+        0x54, 0x1d, 0xfa, 0x9d, 0x94, 0x19, 0x98, 0x76, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23,
+        0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x6d, 0xd5, 0xea, 0x8c, 0xe0, 0x5a, 0x50, 0xd9, 0x36,
+        0xf3, 0x28, 0xc2, 0x54, 0x1d, 0xfa, 0x9d, 0x94, 0x19, 0x98, 0x76, 0x30, 0x0f, 0x06, 0x03,
+        0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e,
+        0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30,
+        0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x41, 0x00, 0x1e, 0x27, 0x99, 0xd3, 0x05, 0xa7,
+        0xd2, 0xc6, 0xad, 0x1f, 0x2c, 0xbd, 0xef, 0x34, 0x18, 0xbd, 0x37, 0xb9, 0x96, 0x57, 0x63,
+        0x72, 0x7e, 0xf8, 0xe5, 0xa2, 0xb5, 0x9a, 0x20, 0x42, 0x1d, 0x9c, 0x8e, 0xdc, 0x97, 0xd4,
+        0x3b, 0x65, 0xe0, 0x52, 0xb4, 0x0d, 0x95, 0x59, 0x94, 0x94, 0x7a, 0x31, 0x9e, 0x45, 0x4b,
+        0x93, 0x3d, 0x5d, 0x88, 0x98, 0xb1, 0x52, 0xf5, 0x46, 0x1c, 0x2a, 0x0b, 0x05, 0x59, 0x01,
+        0x9f, 0x30, 0x82, 0x01, 0x9b, 0x30, 0x82, 0x01, 0x4d, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
+        0x02, 0x01, 0xc8, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x30, 0x2b, 0x31, 0x15, 0x30,
+        0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x46, 0x61, 0x6b, 0x65, 0x20, 0x43, 0x6f,
+        0x6d, 0x70, 0x61, 0x6e, 0x79, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+        0x09, 0x46, 0x61, 0x6b, 0x65, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x32,
+        0x34, 0x31, 0x31, 0x31, 0x34, 0x30, 0x39, 0x35, 0x32, 0x30, 0x37, 0x5a, 0x17, 0x0d, 0x34,
+        0x39, 0x31, 0x31, 0x30, 0x38, 0x30, 0x39, 0x35, 0x32, 0x30, 0x37, 0x5a, 0x30, 0x2e, 0x31,
+        0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x46, 0x61, 0x6b, 0x65, 0x20,
+        0x43, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04,
+        0x03, 0x13, 0x0c, 0x46, 0x61, 0x6b, 0x65, 0x20, 0x43, 0x68, 0x69, 0x70, 0x73, 0x65, 0x74,
+        0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08,
+        0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xc9, 0x35, 0xf7,
+        0x7e, 0x71, 0xc9, 0xa4, 0xd2, 0x13, 0x58, 0x5a, 0xc1, 0x0c, 0x17, 0xa8, 0x2c, 0x28, 0x99,
+        0x32, 0x8e, 0x01, 0x45, 0xb8, 0xf1, 0xf4, 0xf8, 0x37, 0x25, 0x4a, 0x25, 0x1f, 0xbf, 0x8f,
+        0xd8, 0xdf, 0x53, 0xdd, 0x95, 0x7a, 0x90, 0xff, 0xe3, 0x40, 0xbf, 0xda, 0x19, 0x0c, 0x14,
+        0x41, 0x1c, 0x76, 0x73, 0x4e, 0x86, 0x94, 0x7d, 0x2c, 0x21, 0x5f, 0x5e, 0x05, 0x26, 0x15,
+        0x4f, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
+        0x14, 0x12, 0x84, 0xe1, 0x31, 0xef, 0xa8, 0xfd, 0xcc, 0xbb, 0x35, 0x22, 0xb9, 0x99, 0xd1,
+        0xca, 0x64, 0x19, 0x09, 0x54, 0x4c, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18,
+        0x30, 0x16, 0x80, 0x14, 0x6d, 0xd5, 0xea, 0x8c, 0xe0, 0x5a, 0x50, 0xd9, 0x36, 0xf3, 0x28,
+        0xc2, 0x54, 0x1d, 0xfa, 0x9d, 0x94, 0x19, 0x98, 0x76, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d,
+        0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03,
+        0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x05, 0x06,
+        0x03, 0x2b, 0x65, 0x70, 0x03, 0x41, 0x00, 0xc7, 0x93, 0x86, 0x58, 0xb2, 0x31, 0x30, 0x4f,
+        0x1a, 0x53, 0x06, 0x87, 0x0e, 0xdf, 0xc4, 0xd8, 0x03, 0xf4, 0xaf, 0xa3, 0x2d, 0xfb, 0x7d,
+        0xab, 0x08, 0x70, 0x47, 0x38, 0x10, 0xc5, 0xa8, 0x5e, 0x67, 0x64, 0xc7, 0xdc, 0x28, 0xe8,
+        0x63, 0x3c, 0xa7, 0xb8, 0xf9, 0xbe, 0x3e, 0x75, 0xa7, 0x1c, 0xac, 0xc4, 0x81, 0x82, 0x4a,
+        0x21, 0xf0, 0x89, 0x8e, 0x99, 0xf4, 0x52, 0x23, 0x30, 0x6d, 0x04, 0x82, 0xa5, 0x01, 0x02,
+        0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xc9, 0x35, 0xf7, 0x7e, 0x71, 0xc9, 0xa4, 0xd2,
+        0x13, 0x58, 0x5a, 0xc1, 0x0c, 0x17, 0xa8, 0x2c, 0x28, 0x99, 0x32, 0x8e, 0x01, 0x45, 0xb8,
+        0xf1, 0xf4, 0xf8, 0x37, 0x25, 0x4a, 0x25, 0x1f, 0xbf, 0x22, 0x58, 0x20, 0x8f, 0xd8, 0xdf,
+        0x53, 0xdd, 0x95, 0x7a, 0x90, 0xff, 0xe3, 0x40, 0xbf, 0xda, 0x19, 0x0c, 0x14, 0x41, 0x1c,
+        0x76, 0x73, 0x4e, 0x86, 0x94, 0x7d, 0x2c, 0x21, 0x5f, 0x5e, 0x05, 0x26, 0x15, 0x4f, 0x84,
+        0x43, 0xa1, 0x01, 0x26, 0xa0, 0x59, 0x01, 0x04, 0xa9, 0x01, 0x66, 0x69, 0x73, 0x73, 0x75,
+        0x65, 0x72, 0x02, 0x67, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x00, 0x47, 0x44,
+        0x50, 0x58, 0x20, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+        0x55, 0x55, 0x55, 0x55, 0x55, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x20, 0xb8, 0x96, 0x54,
+        0xe2, 0x2c, 0xa4, 0xd2, 0x4a, 0x9c, 0x0e, 0x45, 0x11, 0xc8, 0xf2, 0x63, 0xf0, 0x66, 0x0d,
+        0x2e, 0x20, 0x48, 0x96, 0x90, 0x14, 0xf4, 0x54, 0x63, 0xc4, 0xf4, 0x39, 0x30, 0x38, 0x3a,
+        0x00, 0x47, 0x44, 0x53, 0x55, 0xa1, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x6e, 0x63, 0x6f, 0x6d,
+        0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x00, 0x47, 0x44,
+        0x54, 0x58, 0x20, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+        0x55, 0x55, 0x55, 0x55, 0x55, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47,
+        0x44, 0x57, 0x58, 0x4d, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xb8,
+        0x42, 0x01, 0xd7, 0xf0, 0xb7, 0x57, 0x98, 0xe3, 0x05, 0xf5, 0xcf, 0xef, 0x7b, 0x38, 0x39,
+        0x6d, 0x55, 0x68, 0x72, 0xa6, 0x46, 0xd3, 0x16, 0x89, 0x1a, 0x3a, 0x9b, 0xc8, 0xce, 0xc0,
+        0x1c, 0x22, 0x58, 0x20, 0xd1, 0xd5, 0x0e, 0xb8, 0xd0, 0x99, 0x09, 0x41, 0x63, 0x93, 0x33,
+        0x20, 0xef, 0x84, 0xbb, 0xf5, 0xc9, 0x27, 0x4b, 0x52, 0x33, 0xa9, 0x07, 0xcc, 0x5d, 0x22,
+        0xab, 0xf6, 0x8f, 0x2d, 0x15, 0x41, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40,
+        0xd0, 0x6d, 0xb0, 0xd2, 0x49, 0xc8, 0xd3, 0x81, 0xdd, 0x10, 0x4b, 0xd9, 0x49, 0x45, 0x93,
+        0x10, 0xd5, 0x1b, 0xc7, 0x59, 0x66, 0x6f, 0x6c, 0x06, 0xb5, 0x72, 0x98, 0x51, 0x2d, 0xed,
+        0xa0, 0xd9, 0xbb, 0x4a, 0xe6, 0x9b, 0x67, 0x31, 0xd9, 0x27, 0xd0, 0x9c, 0xf8, 0x3d, 0xfc,
+        0x61, 0x8d, 0x53, 0x13, 0x53, 0x68, 0xb4, 0xb5, 0x41, 0x4c, 0xea, 0x6a, 0x28, 0xbb, 0xcb,
+        0x63, 0x4d, 0xd0, 0x20, 0x84, 0x43, 0xa1, 0x01, 0x26, 0xa0, 0x59, 0x02, 0x0f, 0x82, 0x58,
+        0x20, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+        0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+        0x1e, 0x1f, 0x20, 0x59, 0x01, 0xe9, 0x84, 0x03, 0x67, 0x6b, 0x65, 0x79, 0x6d, 0x69, 0x6e,
+        0x74, 0xae, 0x65, 0x62, 0x72, 0x61, 0x6e, 0x64, 0x66, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+        0x65, 0x66, 0x75, 0x73, 0x65, 0x64, 0x01, 0x65, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x65, 0x6d,
+        0x6f, 0x64, 0x65, 0x6c, 0x66, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x66, 0x64, 0x65, 0x76,
+        0x69, 0x63, 0x65, 0x67, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x65, 0x70, 0x69, 0x78,
+        0x65, 0x6c, 0x68, 0x76, 0x62, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x65, 0x67, 0x72, 0x65,
+        0x65, 0x6e, 0x6a, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x62, 0x31,
+        0x32, 0x6c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x66,
+        0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x6d, 0x76, 0x62, 0x6d, 0x65, 0x74, 0x61, 0x5f, 0x64,
+        0x69, 0x67, 0x65, 0x73, 0x74, 0x4f, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99,
+        0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79,
+        0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x63, 0x74, 0x65, 0x65, 0x70, 0x62, 0x6f, 0x6f, 0x74,
+        0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x1a, 0x01, 0x34,
+        0x8c, 0x62, 0x70, 0x62, 0x6f, 0x6f, 0x74, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x73,
+        0x74, 0x61, 0x74, 0x65, 0x66, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x72, 0x73, 0x79, 0x73,
+        0x74, 0x65, 0x6d, 0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c,
+        0x1a, 0x01, 0x34, 0x8c, 0x61, 0x72, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x70, 0x61,
+        0x74, 0x63, 0x68, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x1a, 0x01, 0x34, 0x8c, 0x63, 0x82,
+        0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xd5, 0x0b, 0x27, 0x39, 0xa3,
+        0xd5, 0xfd, 0xd9, 0x4f, 0x87, 0x4a, 0x97, 0x17, 0x60, 0x6c, 0x63, 0x55, 0x13, 0xa0, 0xf5,
+        0x1c, 0x2b, 0xe7, 0x0e, 0x8e, 0xdb, 0x76, 0x82, 0x69, 0x5a, 0x46, 0xec, 0x22, 0x58, 0x20,
+        0xa6, 0x08, 0xb3, 0x57, 0xaa, 0x5f, 0x72, 0x2b, 0xb1, 0xf0, 0x43, 0x52, 0xf4, 0xcb, 0x97,
+        0x39, 0xfd, 0x54, 0x79, 0xa3, 0xaf, 0x07, 0xb7, 0xbe, 0xbc, 0x93, 0xc1, 0xb6, 0x9b, 0x2f,
+        0x75, 0x1b, 0x23, 0x58, 0x21, 0x00, 0xb4, 0x59, 0xe3, 0x78, 0x6f, 0x3f, 0xbd, 0xdc, 0x38,
+        0x8a, 0xa5, 0x7d, 0xbe, 0xe0, 0xce, 0xf9, 0x2e, 0x9a, 0x5b, 0xfc, 0xbd, 0x4d, 0x27, 0x7b,
+        0xa7, 0xc8, 0xda, 0xaa, 0xe4, 0xcd, 0xf3, 0xd2, 0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01,
+        0x21, 0x58, 0x20, 0x10, 0x6c, 0xe8, 0x71, 0xa8, 0x78, 0x9d, 0x29, 0xbe, 0xf8, 0x84, 0x39,
+        0xd4, 0xa2, 0xf5, 0x3e, 0x09, 0xf1, 0xd4, 0x81, 0x59, 0x24, 0x63, 0x07, 0xae, 0x25, 0xad,
+        0x24, 0x72, 0x0f, 0x8b, 0xd0, 0x22, 0x58, 0x20, 0xe8, 0xba, 0x76, 0x49, 0x7b, 0x97, 0x98,
+        0xcf, 0xbb, 0x90, 0xfa, 0x30, 0x3a, 0x2d, 0x88, 0xfe, 0x3f, 0xc6, 0x75, 0x05, 0x7b, 0x59,
+        0xdf, 0x14, 0xd8, 0xde, 0x4d, 0x51, 0x8b, 0x2f, 0x5a, 0xc7, 0x23, 0x58, 0x20, 0x76, 0x11,
+        0x2f, 0x31, 0xe5, 0xc2, 0xbb, 0xa7, 0x2c, 0x2b, 0x2f, 0x73, 0x16, 0x29, 0xf8, 0x67, 0x66,
+        0x44, 0x7f, 0x3f, 0x22, 0xa2, 0x40, 0x45, 0x12, 0xac, 0x97, 0x06, 0xc8, 0x66, 0x08, 0xc9,
+        0x58, 0x40, 0x11, 0x65, 0x46, 0xfa, 0xbd, 0xe3, 0xd3, 0x1b, 0x0d, 0x78, 0x23, 0x2e, 0x5d,
+        0x48, 0x3c, 0xab, 0xd3, 0x74, 0xf8, 0x41, 0x88, 0x9b, 0x48, 0xf3, 0x93, 0x06, 0x40, 0x1b,
+        0x5f, 0x60, 0x7b, 0xbe, 0xd8, 0xa6, 0x65, 0xff, 0x6a, 0x89, 0x24, 0x12, 0x1b, 0xac, 0xa3,
+        0xd5, 0x37, 0x85, 0x6e, 0x53, 0x8d, 0xa5, 0x07, 0xe7, 0xe7, 0x44, 0x2c, 0xba, 0xa0, 0xbe,
+        0x1a, 0x43, 0xde, 0x28, 0x59, 0x65};
+
+inline const std::vector<uint8_t> kKeysToSignForCsrWithoutUdsCerts = {
+        0x82, 0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x11, 0x29, 0x11, 0x96,
+        0x98, 0x26, 0xb2, 0x3a, 0xf2, 0xf9, 0x95, 0xb7, 0x46, 0xb9, 0x38, 0x6e, 0x5e, 0x3d, 0x5e,
+        0xb2, 0x19, 0x90, 0xc7, 0xd3, 0xbd, 0x49, 0x47, 0x55, 0xcb, 0xef, 0xeb, 0x89, 0x22, 0x58,
+        0x20, 0x42, 0x87, 0xea, 0x75, 0x27, 0x42, 0x34, 0xeb, 0xe8, 0xb5, 0x50, 0xdf, 0xb0, 0xbf,
+        0xef, 0x6b, 0x62, 0x90, 0x5c, 0xd1, 0xe8, 0x2b, 0x4d, 0x02, 0x58, 0xe6, 0xca, 0xda, 0xe6,
+        0x33, 0x97, 0xff, 0x23, 0x58, 0x21, 0x00, 0x9b, 0x34, 0xdb, 0x1e, 0xe6, 0x53, 0x72, 0xaf,
+        0x67, 0xb5, 0x5e, 0x9a, 0xee, 0x07, 0x31, 0x77, 0xa3, 0x8b, 0x6a, 0xe9, 0x58, 0x97, 0x04,
+        0xe2, 0xa2, 0x48, 0x0f, 0xdf, 0x26, 0x4d, 0xe5, 0xbb, 0xa6, 0x01, 0x02, 0x03, 0x26, 0x20,
+        0x01, 0x21, 0x58, 0x20, 0xf9, 0xd7, 0x37, 0x75, 0x6b, 0x55, 0xc7, 0x64, 0xf9, 0xe2, 0x59,
+        0x8f, 0x11, 0x48, 0xa1, 0xac, 0x95, 0xb1, 0xe3, 0x60, 0xe5, 0xa8, 0xa4, 0x2f, 0xb5, 0xcb,
+        0x90, 0x1e, 0x9e, 0xcb, 0x4c, 0xab, 0x22, 0x58, 0x20, 0x20, 0xad, 0x7b, 0xeb, 0xba, 0x5d,
+        0x3c, 0xd5, 0xa3, 0x6d, 0x86, 0x6e, 0x3f, 0x38, 0xb8, 0x44, 0x32, 0x4b, 0xe7, 0x97, 0xea,
+        0xf8, 0x3d, 0xc2, 0xc0, 0x7c, 0x1b, 0x49, 0xe4, 0x22, 0x23, 0xc7, 0x23, 0x58, 0x20, 0x5f,
+        0x1f, 0x80, 0xe2, 0xcf, 0x59, 0x1d, 0x7e, 0x98, 0x51, 0x78, 0xbe, 0xf8, 0x88, 0x0b, 0x64,
+        0x1b, 0xc8, 0xf2, 0x7b, 0x12, 0x22, 0x53, 0xd9, 0xd5, 0x8d, 0x32, 0xe7, 0x7f, 0x0e, 0x97,
+        0x09};
+
+inline const std::vector<uint8_t> kCsrWithoutUdsCerts{
+        0x84, 0x01, 0xa0, 0x82, 0xa4, 0x01, 0x01, 0x03, 0x27, 0x20, 0x06, 0x21, 0x58, 0x20, 0xca,
+        0x73, 0xd6, 0x09, 0x91, 0xec, 0x92, 0x63, 0xee, 0x9f, 0x7c, 0x79, 0x3e, 0x80, 0xa9, 0xc9,
+        0x4e, 0xf7, 0x3b, 0x5b, 0x41, 0xa4, 0x56, 0xc1, 0x9e, 0xf3, 0x80, 0x16, 0x6d, 0xfe, 0x14,
+        0x98, 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01, 0x04, 0xa9, 0x01, 0x66, 0x69, 0x73,
+        0x73, 0x75, 0x65, 0x72, 0x02, 0x67, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x00,
+        0x47, 0x44, 0x50, 0x58, 0x20, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x20, 0xb8,
+        0x96, 0x54, 0xe2, 0x2c, 0xa4, 0xd2, 0x4a, 0x9c, 0x0e, 0x45, 0x11, 0xc8, 0xf2, 0x63, 0xf0,
+        0x66, 0x0d, 0x2e, 0x20, 0x48, 0x96, 0x90, 0x14, 0xf4, 0x54, 0x63, 0xc4, 0xf4, 0x39, 0x30,
+        0x38, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x55, 0xa1, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x6e, 0x63,
+        0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x00,
+        0x47, 0x44, 0x54, 0x58, 0x20, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a,
+        0x00, 0x47, 0x44, 0x57, 0x58, 0x4d, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58,
+        0x20, 0x45, 0x71, 0x10, 0x9a, 0x1b, 0x9c, 0x9f, 0x3c, 0x6e, 0x29, 0xf9, 0x6d, 0xb9, 0x93,
+        0x4a, 0xf2, 0x88, 0xf1, 0x3a, 0xf7, 0x69, 0xf9, 0xf3, 0x54, 0x91, 0x3a, 0x12, 0x4f, 0xd0,
+        0xbb, 0xb7, 0x0d, 0x22, 0x58, 0x20, 0x56, 0x8b, 0xb0, 0x0e, 0xd3, 0x8d, 0x12, 0xf5, 0x17,
+        0xd2, 0x6b, 0x21, 0xdf, 0x4d, 0xb8, 0xaa, 0x17, 0x65, 0x02, 0x4e, 0x5c, 0x0a, 0x77, 0x93,
+        0x64, 0x1e, 0x8d, 0xbc, 0x6a, 0xa1, 0x26, 0xe7, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20,
+        0x58, 0x40, 0xb0, 0x7b, 0xdd, 0xa5, 0x8e, 0xcb, 0xce, 0xf9, 0x89, 0xfb, 0x21, 0x4b, 0x29,
+        0x34, 0xff, 0x6b, 0x0e, 0xc1, 0xff, 0x51, 0xba, 0x12, 0x12, 0xa0, 0x93, 0x2c, 0x09, 0xca,
+        0x3a, 0x02, 0x81, 0x2a, 0x5b, 0x6f, 0x8d, 0x58, 0x21, 0x94, 0x30, 0xde, 0x99, 0x8b, 0x36,
+        0x69, 0x45, 0xa1, 0x52, 0x5c, 0x7b, 0x36, 0x4f, 0xec, 0x4f, 0x40, 0x5f, 0x10, 0xdf, 0x26,
+        0x18, 0xea, 0x4b, 0x72, 0x9f, 0x05, 0x84, 0x43, 0xa1, 0x01, 0x26, 0xa0, 0x59, 0x02, 0x0f,
+        0x82, 0x58, 0x20, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+        0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
+        0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x59, 0x01, 0xe9, 0x84, 0x03, 0x67, 0x6b, 0x65, 0x79, 0x6d,
+        0x69, 0x6e, 0x74, 0xae, 0x65, 0x62, 0x72, 0x61, 0x6e, 0x64, 0x66, 0x47, 0x6f, 0x6f, 0x67,
+        0x6c, 0x65, 0x65, 0x66, 0x75, 0x73, 0x65, 0x64, 0x01, 0x65, 0x6d, 0x6f, 0x64, 0x65, 0x6c,
+        0x65, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x66, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x66, 0x64,
+        0x65, 0x76, 0x69, 0x63, 0x65, 0x67, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x65, 0x70,
+        0x69, 0x78, 0x65, 0x6c, 0x68, 0x76, 0x62, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x65, 0x67,
+        0x72, 0x65, 0x65, 0x6e, 0x6a, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
+        0x62, 0x31, 0x32, 0x6c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65,
+        0x72, 0x66, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x6d, 0x76, 0x62, 0x6d, 0x65, 0x74, 0x61,
+        0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x4f, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69,
+        0x74, 0x79, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x63, 0x74, 0x65, 0x65, 0x70, 0x62, 0x6f,
+        0x6f, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x1a,
+        0x01, 0x34, 0x8c, 0x62, 0x70, 0x62, 0x6f, 0x6f, 0x74, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72,
+        0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x66, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x72, 0x73,
+        0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6c, 0x65, 0x76,
+        0x65, 0x6c, 0x1a, 0x01, 0x34, 0x8c, 0x61, 0x72, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f,
+        0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x1a, 0x01, 0x34, 0x8c,
+        0x63, 0x82, 0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x11, 0x29, 0x11,
+        0x96, 0x98, 0x26, 0xb2, 0x3a, 0xf2, 0xf9, 0x95, 0xb7, 0x46, 0xb9, 0x38, 0x6e, 0x5e, 0x3d,
+        0x5e, 0xb2, 0x19, 0x90, 0xc7, 0xd3, 0xbd, 0x49, 0x47, 0x55, 0xcb, 0xef, 0xeb, 0x89, 0x22,
+        0x58, 0x20, 0x42, 0x87, 0xea, 0x75, 0x27, 0x42, 0x34, 0xeb, 0xe8, 0xb5, 0x50, 0xdf, 0xb0,
+        0xbf, 0xef, 0x6b, 0x62, 0x90, 0x5c, 0xd1, 0xe8, 0x2b, 0x4d, 0x02, 0x58, 0xe6, 0xca, 0xda,
+        0xe6, 0x33, 0x97, 0xff, 0x23, 0x58, 0x21, 0x00, 0x9b, 0x34, 0xdb, 0x1e, 0xe6, 0x53, 0x72,
+        0xaf, 0x67, 0xb5, 0x5e, 0x9a, 0xee, 0x07, 0x31, 0x77, 0xa3, 0x8b, 0x6a, 0xe9, 0x58, 0x97,
+        0x04, 0xe2, 0xa2, 0x48, 0x0f, 0xdf, 0x26, 0x4d, 0xe5, 0xbb, 0xa6, 0x01, 0x02, 0x03, 0x26,
+        0x20, 0x01, 0x21, 0x58, 0x20, 0xf9, 0xd7, 0x37, 0x75, 0x6b, 0x55, 0xc7, 0x64, 0xf9, 0xe2,
+        0x59, 0x8f, 0x11, 0x48, 0xa1, 0xac, 0x95, 0xb1, 0xe3, 0x60, 0xe5, 0xa8, 0xa4, 0x2f, 0xb5,
+        0xcb, 0x90, 0x1e, 0x9e, 0xcb, 0x4c, 0xab, 0x22, 0x58, 0x20, 0x20, 0xad, 0x7b, 0xeb, 0xba,
+        0x5d, 0x3c, 0xd5, 0xa3, 0x6d, 0x86, 0x6e, 0x3f, 0x38, 0xb8, 0x44, 0x32, 0x4b, 0xe7, 0x97,
+        0xea, 0xf8, 0x3d, 0xc2, 0xc0, 0x7c, 0x1b, 0x49, 0xe4, 0x22, 0x23, 0xc7, 0x23, 0x58, 0x20,
+        0x5f, 0x1f, 0x80, 0xe2, 0xcf, 0x59, 0x1d, 0x7e, 0x98, 0x51, 0x78, 0xbe, 0xf8, 0x88, 0x0b,
+        0x64, 0x1b, 0xc8, 0xf2, 0x7b, 0x12, 0x22, 0x53, 0xd9, 0xd5, 0x8d, 0x32, 0xe7, 0x7f, 0x0e,
+        0x97, 0x09, 0x58, 0x40, 0xe1, 0x9a, 0x3f, 0x36, 0x65, 0x7a, 0xfe, 0x1b, 0x99, 0xc9, 0x35,
+        0x8f, 0xb5, 0x5c, 0xfe, 0x12, 0x9c, 0x6f, 0x0e, 0x97, 0x12, 0xbd, 0x26, 0x32, 0x46, 0xd9,
+        0x08, 0x6b, 0x7c, 0xa1, 0xd3, 0x47, 0xd6, 0xba, 0xf0, 0x9c, 0xe0, 0x12, 0x37, 0x39, 0x75,
+        0x88, 0xb5, 0xbe, 0xd8, 0x37, 0x33, 0x9b, 0x26, 0xfc, 0x38, 0x14, 0x28, 0xea, 0x47, 0xcc,
+        0x1f, 0xf3, 0xfe, 0x44, 0x0c, 0x1e, 0x6f, 0x2b, 0xa1, 0x6b, 0x66, 0x69, 0x6e, 0x67, 0x65,
+        0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x78, 0x3b, 0x62, 0x72, 0x61, 0x6e, 0x64, 0x31, 0x2f,
+        0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x31, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
+        0x31, 0x3a, 0x31, 0x31, 0x2f, 0x69, 0x64, 0x2f, 0x32, 0x30, 0x32, 0x31, 0x30, 0x38, 0x30,
+        0x35, 0x2e, 0x34, 0x32, 0x3a, 0x75, 0x73, 0x65, 0x72, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61,
+        0x73, 0x65, 0x2d, 0x6b, 0x65, 0x79, 0x73};
+
+inline const std::vector<uint8_t> kCsrWithKeyMintInComponentName{
+        0x84, 0x01, 0xa0, 0x82, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x44,
+        0xfd, 0xdd, 0xf1, 0x8a, 0x78, 0xa0, 0xbe, 0x37, 0x49, 0x51, 0x85, 0xfb, 0x7a, 0x16, 0xca,
+        0xc1, 0x00, 0xb3, 0x78, 0x13, 0x4a, 0x90, 0x4c, 0x5a, 0xa1, 0x3b, 0xfc, 0xea, 0xb6, 0xf3,
+        0x16, 0x22, 0x58, 0x20, 0x12, 0x7f, 0xf5, 0xe2, 0x14, 0xbd, 0x5d, 0x51, 0xd3, 0x7f, 0x2f,
+        0x1f, 0x9c, 0xc2, 0x18, 0x31, 0x94, 0x13, 0x52, 0x31, 0x3d, 0x43, 0xc9, 0x39, 0xbc, 0xc9,
+        0x06, 0xb0, 0xb2, 0xa9, 0x0e, 0x59, 0x84, 0x43, 0xa1, 0x01, 0x26, 0xa0, 0x59, 0x01, 0x0e,
+        0xa9, 0x01, 0x66, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x02, 0x67, 0x73, 0x75, 0x62, 0x6a,
+        0x65, 0x63, 0x74, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x20, 0x55, 0x55, 0x55, 0x55, 0x55,
+        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x3a, 0x00, 0x47,
+        0x44, 0x52, 0x58, 0x20, 0x88, 0x44, 0x82, 0xb6, 0x6c, 0x9c, 0xcb, 0x2e, 0xe8, 0xdc, 0xb4,
+        0xe9, 0xd3, 0xf7, 0x87, 0x63, 0x03, 0xaa, 0x90, 0x9d, 0xd9, 0xcb, 0xc3, 0x81, 0x03, 0x5b,
+        0xa9, 0xa2, 0x75, 0xe8, 0xfa, 0x50, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x58, 0x1e, 0xa1, 0x3a,
+        0x00, 0x01, 0x11, 0x71, 0x77, 0x4d, 0x6f, 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20,
+        0x6a, 0x75, 0x73, 0x74, 0x20, 0x6b, 0x65, 0x79, 0x6d, 0x69, 0x6e, 0x74, 0x3f, 0x3a, 0x00,
+        0x47, 0x44, 0x54, 0x58, 0x20, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a,
+        0x00, 0x47, 0x44, 0x57, 0x58, 0x4d, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58,
+        0x20, 0xe7, 0x0e, 0x4b, 0xcb, 0x8d, 0x4a, 0xd0, 0x36, 0x7f, 0xbf, 0x19, 0xdd, 0x9a, 0xd9,
+        0x43, 0x62, 0xab, 0x29, 0x13, 0x1e, 0x14, 0x98, 0x68, 0xee, 0x5d, 0xae, 0xfa, 0x2f, 0x49,
+        0x99, 0xfa, 0x0b, 0x22, 0x58, 0x20, 0xfb, 0x9f, 0xd3, 0xd8, 0x67, 0x86, 0x81, 0x5f, 0xb3,
+        0x84, 0x00, 0x32, 0xc4, 0xe8, 0x7e, 0x9b, 0xb2, 0x4c, 0x1d, 0xd7, 0x71, 0x0d, 0x8f, 0xe0,
+        0x26, 0xc6, 0x73, 0xb1, 0x8f, 0x2d, 0x02, 0xf8, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20,
+        0x58, 0x40, 0x8f, 0xb9, 0x41, 0x5f, 0xa7, 0x48, 0xe4, 0xe3, 0xfb, 0x80, 0xbf, 0x2e, 0x30,
+        0xb8, 0xc9, 0x2c, 0xe4, 0x74, 0x4f, 0x4c, 0xb1, 0x79, 0xfb, 0x42, 0x43, 0x1e, 0xb4, 0x6c,
+        0x6a, 0x37, 0xaf, 0x3a, 0x76, 0x15, 0x16, 0x1f, 0x25, 0x26, 0x27, 0x1b, 0x9c, 0x5c, 0xcf,
+        0x9a, 0xfd, 0xb0, 0x82, 0xad, 0xe4, 0xd1, 0xd9, 0x04, 0x80, 0x80, 0x1a, 0x21, 0x12, 0x3e,
+        0x81, 0xff, 0x0c, 0x23, 0x3d, 0x0a, 0x84, 0x43, 0xa1, 0x01, 0x26, 0xa0, 0x59, 0x02, 0x10,
+        0x82, 0x58, 0x20, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+        0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
+        0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x59, 0x01, 0xea, 0x84, 0x03, 0x67, 0x6b, 0x65, 0x79, 0x6d,
+        0x69, 0x6e, 0x74, 0xae, 0x65, 0x62, 0x72, 0x61, 0x6e, 0x64, 0x66, 0x47, 0x6f, 0x6f, 0x67,
+        0x6c, 0x65, 0x65, 0x66, 0x75, 0x73, 0x65, 0x64, 0x01, 0x65, 0x6d, 0x6f, 0x64, 0x65, 0x6c,
+        0x65, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x66, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x66, 0x64,
+        0x65, 0x76, 0x69, 0x63, 0x65, 0x67, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x65, 0x70,
+        0x69, 0x78, 0x65, 0x6c, 0x68, 0x76, 0x62, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x65, 0x67,
+        0x72, 0x65, 0x65, 0x6e, 0x6a, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
+        0x62, 0x31, 0x32, 0x6c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65,
+        0x72, 0x66, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x6d, 0x76, 0x62, 0x6d, 0x65, 0x74, 0x61,
+        0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x4f, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69,
+        0x74, 0x79, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x63, 0x74, 0x65, 0x65, 0x70, 0x62, 0x6f,
+        0x6f, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x1a,
+        0x01, 0x34, 0x8c, 0x62, 0x70, 0x62, 0x6f, 0x6f, 0x74, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72,
+        0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x66, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x72, 0x73,
+        0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6c, 0x65, 0x76,
+        0x65, 0x6c, 0x1a, 0x01, 0x34, 0x8c, 0x61, 0x72, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f,
+        0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x1a, 0x01, 0x34, 0x8c,
+        0x63, 0x82, 0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x40, 0x9a, 0x39,
+        0x4d, 0xe2, 0xc5, 0x48, 0x58, 0x6e, 0xaa, 0x17, 0x81, 0x8a, 0xba, 0xc4, 0xea, 0x20, 0x23,
+        0xc4, 0xf3, 0xdc, 0xfa, 0x78, 0x9f, 0x5b, 0x7d, 0x30, 0xd2, 0x3d, 0x6f, 0x42, 0xa8, 0x22,
+        0x58, 0x20, 0x3e, 0x85, 0x73, 0xe5, 0x86, 0x57, 0x45, 0x72, 0xcd, 0xf2, 0xe8, 0x62, 0x93,
+        0xf3, 0xea, 0xbf, 0x21, 0x57, 0xa9, 0x25, 0xe7, 0xa8, 0x2a, 0xa0, 0xd0, 0x0a, 0x1d, 0xa5,
+        0x81, 0x22, 0xd0, 0xe1, 0x23, 0x58, 0x21, 0x00, 0x95, 0x00, 0xea, 0x43, 0x32, 0x8d, 0x2e,
+        0x1c, 0x18, 0x6d, 0x73, 0x34, 0xa2, 0xe4, 0x53, 0x64, 0x20, 0x95, 0x25, 0x8d, 0x4b, 0x97,
+        0x71, 0x13, 0xdf, 0xa6, 0x0e, 0xdc, 0x5b, 0x66, 0x66, 0x0b, 0xa6, 0x01, 0x02, 0x03, 0x26,
+        0x20, 0x01, 0x21, 0x58, 0x20, 0xa4, 0x81, 0xd9, 0xa0, 0x37, 0x89, 0xb1, 0x5d, 0x22, 0xf1,
+        0x22, 0x7e, 0x19, 0x00, 0xf1, 0x87, 0xdf, 0x10, 0x88, 0x1f, 0x64, 0xc5, 0x46, 0x6d, 0x91,
+        0x9d, 0x6c, 0x86, 0x3b, 0x67, 0x07, 0x14, 0x22, 0x58, 0x20, 0x3c, 0x42, 0x1f, 0x47, 0x62,
+        0x2c, 0x4f, 0x08, 0x29, 0xe9, 0xc6, 0x0c, 0x7c, 0xe5, 0x11, 0xc6, 0x39, 0x69, 0xc9, 0x9d,
+        0xdf, 0x69, 0x18, 0x8e, 0xdb, 0x99, 0x87, 0x52, 0x2f, 0x6b, 0xb4, 0x6a, 0x23, 0x58, 0x21,
+        0x00, 0x83, 0xa2, 0x6f, 0x5b, 0x3a, 0x71, 0x7c, 0x66, 0x3c, 0x96, 0x3f, 0x4e, 0x42, 0x6f,
+        0x98, 0x45, 0x1f, 0x59, 0x50, 0x03, 0x48, 0x9b, 0x57, 0xf5, 0x0e, 0x0f, 0x96, 0x30, 0xa4,
+        0xd6, 0xc3, 0x45, 0x58, 0x40, 0x8b, 0xdf, 0xc8, 0xc7, 0x6d, 0xa4, 0x02, 0xec, 0x3c, 0x5d,
+        0x90, 0x73, 0x0f, 0x8c, 0x10, 0x0f, 0x99, 0xd2, 0x85, 0x6e, 0x03, 0x45, 0x55, 0x28, 0xf7,
+        0x64, 0x0b, 0xbd, 0x7c, 0x3a, 0x69, 0xf1, 0x80, 0x1a, 0xf3, 0x93, 0x7e, 0x82, 0xfc, 0xa5,
+        0x3b, 0x69, 0x98, 0xf1, 0xde, 0x06, 0xb6, 0x72, 0x78, 0x0b, 0xdb, 0xbb, 0x97, 0x20, 0x04,
+        0x98, 0xb0, 0xd4, 0x07, 0x83, 0x65, 0xfb, 0xf8, 0x9c};
+
+inline std::vector<uint8_t> kCsrWithDebugMode{
+        0x84, 0x01, 0xa0, 0x82, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x03,
+        0x09, 0xad, 0x0d, 0x07, 0xec, 0x59, 0xfc, 0x14, 0x31, 0x21, 0x1f, 0xbc, 0x8e, 0x44, 0xe7,
+        0x0f, 0xa9, 0xb7, 0x5a, 0x57, 0x38, 0x5f, 0x76, 0x8a, 0xa3, 0x38, 0x2c, 0xf0, 0x1b, 0x37,
+        0x15, 0x22, 0x58, 0x20, 0x82, 0xae, 0x09, 0x76, 0x9c, 0x1d, 0x18, 0x39, 0x5d, 0x09, 0xf8,
+        0x19, 0x86, 0x70, 0x60, 0x12, 0x1e, 0x06, 0xb3, 0x68, 0x4a, 0x27, 0x2c, 0x79, 0xd3, 0x83,
+        0xb8, 0x54, 0x5b, 0x9f, 0xc0, 0x9f, 0x84, 0x43, 0xa1, 0x01, 0x26, 0xa0, 0x59, 0x01, 0x04,
+        0xa9, 0x01, 0x66, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x02, 0x67, 0x73, 0x75, 0x62, 0x6a,
+        0x65, 0x63, 0x74, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x20, 0x55, 0x55, 0x55, 0x55, 0x55,
+        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x3a, 0x00, 0x47,
+        0x44, 0x52, 0x58, 0x20, 0xb8, 0x96, 0x54, 0xe2, 0x2c, 0xa4, 0xd2, 0x4a, 0x9c, 0x0e, 0x45,
+        0x11, 0xc8, 0xf2, 0x63, 0xf0, 0x66, 0x0d, 0x2e, 0x20, 0x48, 0x96, 0x90, 0x14, 0xf4, 0x54,
+        0x63, 0xc4, 0xf4, 0x39, 0x30, 0x38, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x55, 0xa1, 0x3a, 0x00,
+        0x01, 0x11, 0x71, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x6e,
+        0x61, 0x6d, 0x65, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x20, 0x55, 0x55, 0x55, 0x55, 0x55,
+        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x3a, 0x00, 0x47,
+        0x44, 0x56, 0x41, 0x02, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x4d, 0xa5, 0x01, 0x02, 0x03,
+        0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x5f, 0xcf, 0x63, 0xcc, 0x24, 0x16, 0x66, 0x11, 0x6c,
+        0xaf, 0xed, 0xf4, 0x02, 0x8f, 0xc9, 0x14, 0xc7, 0x32, 0xa5, 0xdb, 0x41, 0x53, 0x54, 0x34,
+        0xcf, 0xcd, 0x6b, 0x4c, 0xb2, 0x22, 0x89, 0x96, 0x22, 0x58, 0x20, 0x4c, 0xed, 0xe3, 0x92,
+        0x94, 0x8f, 0x04, 0xd6, 0x04, 0x3a, 0x6c, 0x15, 0x5f, 0xbb, 0x52, 0x4a, 0x7d, 0x94, 0xcf,
+        0x31, 0x49, 0x31, 0x28, 0x66, 0x38, 0xe2, 0x40, 0x3e, 0xd0, 0xc1, 0x2b, 0xf4, 0x3a, 0x00,
+        0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40, 0xb6, 0x0b, 0xa7, 0x9c, 0x02, 0x6d, 0x64, 0x98,
+        0x9d, 0x73, 0x1b, 0x74, 0x21, 0x32, 0xf6, 0xb6, 0x1e, 0x6d, 0x07, 0x56, 0x0f, 0x5f, 0x14,
+        0x60, 0xf9, 0x68, 0xb5, 0xee, 0xa5, 0xf9, 0x9b, 0xa9, 0x88, 0x4c, 0x55, 0x75, 0x26, 0xa7,
+        0x84, 0xee, 0x07, 0x8a, 0xdc, 0xeb, 0x6d, 0xfe, 0x53, 0xe4, 0x38, 0xa8, 0x11, 0x1f, 0x57,
+        0xbe, 0x77, 0x51, 0xc7, 0xbe, 0x4b, 0xd5, 0x2f, 0x9c, 0x2a, 0xcd, 0x84, 0x43, 0xa1, 0x01,
         0x26, 0xa0, 0x59, 0x02, 0x0f, 0x82, 0x58, 0x20, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
         0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
         0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x59, 0x01, 0xe9, 0x84, 0x03,
@@ -126,276 +519,165 @@
         0x68, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x1a, 0x01, 0x34, 0x8c, 0x61, 0x72, 0x76, 0x65,
         0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6c, 0x65, 0x76, 0x65,
         0x6c, 0x1a, 0x01, 0x34, 0x8c, 0x63, 0x82, 0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21,
-        0x58, 0x20, 0x46, 0xbd, 0xfc, 0xed, 0xa6, 0x94, 0x9a, 0xc4, 0x5e, 0x27, 0xcf, 0x24, 0x25,
-        0xc5, 0x0c, 0x7d, 0xed, 0x8f, 0x21, 0xe0, 0x47, 0x81, 0x5a, 0xdc, 0x3b, 0xd4, 0x9e, 0x13,
-        0xb6, 0x06, 0x36, 0x70, 0x22, 0x58, 0x20, 0x0a, 0xbd, 0xbc, 0x0d, 0x19, 0xba, 0xcc, 0xdc,
-        0x00, 0x64, 0x31, 0x4c, 0x84, 0x66, 0x1d, 0xfb, 0x50, 0xd0, 0xe3, 0xf8, 0x78, 0x9d, 0xf9,
-        0x77, 0x2b, 0x40, 0x6b, 0xb5, 0x8e, 0xd3, 0xf8, 0xa9, 0x23, 0x58, 0x21, 0x00, 0x9c, 0x42,
-        0x3f, 0x79, 0x76, 0xa0, 0xd1, 0x98, 0x58, 0xbb, 0x9b, 0x9e, 0xfb, 0x3b, 0x08, 0xf2, 0xe1,
-        0xa3, 0xfe, 0xf4, 0x21, 0x5b, 0x97, 0x2d, 0xcb, 0x9a, 0x55, 0x1a, 0x7f, 0xa7, 0xc1, 0xa8,
-        0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xef, 0xd3, 0x88, 0xc4, 0xbc,
-        0xce, 0x51, 0x4d, 0x4b, 0xd3, 0x81, 0x26, 0xc6, 0xcc, 0x66, 0x3b, 0x12, 0x38, 0xbf, 0x23,
-        0x7a, 0x2e, 0x7f, 0x82, 0xa7, 0x81, 0x74, 0x21, 0xc0, 0x12, 0x79, 0xf4, 0x22, 0x58, 0x20,
-        0xdc, 0x85, 0x6c, 0x1c, 0xcc, 0xf9, 0xf3, 0xe8, 0xff, 0x90, 0xfd, 0x89, 0x03, 0xf5, 0xaf,
-        0x75, 0xa0, 0x79, 0xbb, 0x53, 0x9a, 0x1f, 0x2b, 0x34, 0x86, 0x47, 0x3d, 0x66, 0x2a, 0x07,
-        0x3b, 0x1e, 0x23, 0x58, 0x20, 0x34, 0x7b, 0x15, 0xcc, 0xbf, 0x26, 0xc9, 0x28, 0x0e, 0xee,
-        0xc5, 0x47, 0xac, 0x00, 0xc4, 0x4d, 0x81, 0x2b, 0x1e, 0xac, 0x31, 0xd2, 0x6f, 0x36, 0x85,
-        0xe6, 0xa8, 0xf0, 0x46, 0xfc, 0xd2, 0x83, 0x58, 0x40, 0x55, 0x4c, 0x38, 0xdf, 0xfe, 0x49,
-        0xa8, 0xa0, 0xa5, 0x08, 0xce, 0x2f, 0xe5, 0xf6, 0x6e, 0x2b, 0xc2, 0x95, 0x39, 0xc8, 0xca,
-        0x77, 0xd6, 0xf6, 0x67, 0x24, 0x6b, 0x0e, 0x63, 0x5d, 0x11, 0x97, 0x26, 0x52, 0x30, 0xbc,
-        0x28, 0x1d, 0xbf, 0x2a, 0x3e, 0x8c, 0x90, 0x54, 0xaa, 0xaa, 0xd1, 0x7c, 0x53, 0x7b, 0x48,
-        0x1f, 0x51, 0x50, 0x6c, 0x32, 0xe1, 0x0f, 0x57, 0xea, 0x47, 0x76, 0x85, 0x0c, 0xa1, 0x6b,
-        0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x78, 0x3b, 0x62, 0x72,
-        0x61, 0x6e, 0x64, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x31, 0x2f, 0x64,
-        0x65, 0x76, 0x69, 0x63, 0x65, 0x31, 0x3a, 0x31, 0x31, 0x2f, 0x69, 0x64, 0x2f, 0x32, 0x30,
-        0x32, 0x31, 0x30, 0x38, 0x30, 0x35, 0x2e, 0x34, 0x32, 0x3a, 0x75, 0x73, 0x65, 0x72, 0x2f,
-        0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x6b, 0x65, 0x79, 0x73};
+        0x58, 0x20, 0x78, 0xa9, 0x66, 0xc0, 0xc1, 0x92, 0xc9, 0x0d, 0x74, 0xbf, 0x81, 0x99, 0xe6,
+        0x7c, 0x61, 0xb2, 0xc3, 0x41, 0x27, 0x4e, 0x92, 0xd8, 0xd8, 0xf8, 0x34, 0x43, 0x81, 0xe1,
+        0x9c, 0x5f, 0xed, 0xbb, 0x22, 0x58, 0x20, 0x80, 0x05, 0x96, 0xe5, 0x65, 0x7e, 0xa8, 0x5b,
+        0x58, 0xf7, 0x2c, 0xb8, 0x28, 0x95, 0x34, 0x7a, 0x88, 0xd5, 0xe2, 0x1c, 0x20, 0x01, 0xd7,
+        0x60, 0xfe, 0xec, 0xf1, 0x3f, 0x69, 0xfc, 0xc0, 0xa4, 0x23, 0x58, 0x21, 0x00, 0x99, 0xad,
+        0x34, 0x13, 0xf0, 0x7f, 0xaa, 0xf7, 0xda, 0xe9, 0x95, 0xfe, 0x2a, 0x36, 0xf5, 0xac, 0xbb,
+        0xad, 0x39, 0x8f, 0x3f, 0x86, 0x10, 0x39, 0x2c, 0xa9, 0x4c, 0xb9, 0xbb, 0x79, 0x10, 0x45,
+        0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xd2, 0x94, 0xcb, 0x74, 0x5f,
+        0x9c, 0xc2, 0x1e, 0x47, 0x28, 0x69, 0x85, 0x6e, 0xf2, 0x34, 0x0a, 0x62, 0x90, 0xc3, 0xb0,
+        0xc9, 0x3a, 0xb2, 0x32, 0xdc, 0x99, 0x19, 0x9b, 0x36, 0xde, 0x78, 0xed, 0x22, 0x58, 0x20,
+        0xd9, 0x81, 0x04, 0x83, 0xbb, 0x85, 0x3e, 0x3b, 0x46, 0xe8, 0xe1, 0xa3, 0x8a, 0x04, 0xb9,
+        0x3f, 0x74, 0x4e, 0x5c, 0x96, 0x21, 0x5c, 0x79, 0x0b, 0x8e, 0x4e, 0x7d, 0x61, 0x1b, 0x69,
+        0xb2, 0x46, 0x23, 0x58, 0x20, 0x2f, 0x79, 0xf7, 0xbb, 0xbb, 0x7e, 0xee, 0x15, 0x61, 0xa2,
+        0x78, 0x5f, 0x9c, 0x8c, 0xaf, 0x52, 0xcb, 0xbe, 0x24, 0x31, 0xa8, 0x95, 0x86, 0x8d, 0xed,
+        0x98, 0x80, 0x71, 0x53, 0x91, 0xb3, 0x87, 0x58, 0x40, 0x19, 0xc9, 0xc4, 0x4e, 0x8b, 0xae,
+        0x26, 0x7f, 0xdd, 0x9c, 0xac, 0xe2, 0xbf, 0xe2, 0xfb, 0x3c, 0x3f, 0xd6, 0x6f, 0x9a, 0x97,
+        0xc3, 0x2a, 0x60, 0xfe, 0x0e, 0x9f, 0x11, 0xc9, 0x04, 0xa7, 0xdf, 0xe1, 0x21, 0x1e, 0xc1,
+        0x10, 0x10, 0x64, 0xf7, 0xeb, 0xcc, 0x3a, 0x4c, 0xa6, 0xdf, 0xd8, 0xf5, 0xcc, 0x0d, 0x34,
+        0xa4, 0x32, 0xf4, 0x0a, 0xd7, 0x83, 0x1e, 0x30, 0x0d, 0x68, 0x6a, 0xb4, 0xc1};
 
-// The challenge that is in kKeysToSignForCsrWithUdsCerts and kCsrWithUdsCerts
-inline const std::vector<uint8_t> kChallenge{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
-                                             0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
-                                             0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
-                                             0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20};
-
-inline const std::vector<uint8_t> kKeysToSignForCsrWithUdsCerts{
-        0x82, 0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x35, 0xeb, 0x56, 0xed,
-        0x62, 0x13, 0x6a, 0x41, 0x89, 0xf6, 0x72, 0xa6, 0xf1, 0x5c, 0xd1, 0xf6, 0x34, 0xbd, 0x81,
-        0xdb, 0x2e, 0x0b, 0x4d, 0xf6, 0x69, 0x6f, 0xa6, 0xf3, 0xce, 0x27, 0x2c, 0x78, 0x22, 0x58,
-        0x20, 0xac, 0xa9, 0x9f, 0x62, 0x81, 0x58, 0xc7, 0x10, 0xd7, 0xb5, 0xa8, 0xa0, 0x7b, 0x11,
-        0xf5, 0x75, 0xdb, 0xd9, 0xa2, 0x1d, 0x86, 0x34, 0xc6, 0xf4, 0x23, 0x79, 0xcc, 0x8a, 0x87,
-        0x3c, 0xb2, 0xd0, 0x23, 0x58, 0x20, 0x0f, 0x2c, 0x5a, 0xb7, 0xe1, 0x3b, 0x24, 0xa3, 0x4f,
-        0xaa, 0x49, 0x51, 0xfc, 0x8c, 0xd0, 0x35, 0x43, 0x7c, 0x21, 0xfa, 0x7d, 0x56, 0x97, 0x69,
-        0xe1, 0x81, 0xf5, 0x88, 0x15, 0x33, 0xa0, 0x7f, 0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01,
-        0x21, 0x58, 0x20, 0xb5, 0xcc, 0xd9, 0x4f, 0x7a, 0xe2, 0xca, 0xac, 0xfe, 0xa5, 0x65, 0x0c,
-        0x6a, 0xa8, 0x16, 0x45, 0x40, 0x41, 0x1c, 0xb2, 0x64, 0xcd, 0x34, 0xe8, 0x37, 0x88, 0xb9,
-        0x9a, 0xb3, 0xc3, 0xfd, 0x6a, 0x22, 0x58, 0x20, 0x5e, 0xbe, 0xff, 0x98, 0x60, 0x6e, 0x1d,
-        0x6b, 0x42, 0x60, 0x59, 0xe9, 0x42, 0x95, 0xc8, 0x2e, 0xc5, 0xb6, 0x66, 0x4a, 0x53, 0xf1,
-        0x73, 0x02, 0xcb, 0x89, 0x8a, 0x2a, 0xc9, 0xa5, 0xa3, 0x39, 0x23, 0x58, 0x21, 0x00, 0xdb,
-        0xda, 0x3c, 0x3e, 0x27, 0x71, 0x5e, 0xd0, 0x2b, 0x09, 0xb8, 0x6f, 0xe2, 0x2c, 0xdd, 0x0a,
-        0xbf, 0x1d, 0x94, 0x36, 0xd2, 0x33, 0x88, 0x6e, 0x66, 0x05, 0x21, 0x92, 0x64, 0x79, 0xa9,
-        0x10};
-
-inline const std::vector<uint8_t> kCsrWithUdsCerts{
-        0x84, 0x01, 0xa1, 0x70, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72,
-        0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0x59, 0x01, 0x6c, 0x30, 0x82, 0x01, 0x68, 0x30, 0x82,
-        0x01, 0x1a, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x7b, 0x30, 0x05, 0x06, 0x03, 0x2b,
-        0x65, 0x70, 0x30, 0x2b, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c,
-        0x46, 0x61, 0x6b, 0x65, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x31, 0x12, 0x30,
-        0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x09, 0x46, 0x61, 0x6b, 0x65, 0x20, 0x52, 0x6f,
-        0x6f, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x34, 0x31, 0x30, 0x31, 0x37, 0x31, 0x39, 0x32,
-        0x33, 0x30, 0x39, 0x5a, 0x17, 0x0d, 0x32, 0x34, 0x31, 0x31, 0x31, 0x36, 0x31, 0x39, 0x32,
-        0x33, 0x30, 0x39, 0x5a, 0x30, 0x2b, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a,
-        0x13, 0x0c, 0x46, 0x61, 0x6b, 0x65, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x31,
-        0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x09, 0x46, 0x61, 0x6b, 0x65, 0x20,
-        0x52, 0x6f, 0x6f, 0x74, 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21,
-        0x00, 0x20, 0xc5, 0xfa, 0x42, 0xe9, 0x23, 0xd3, 0x72, 0x83, 0x96, 0xc5, 0x73, 0x1e, 0xec,
-        0x07, 0x39, 0x4f, 0xc8, 0xb7, 0xd1, 0x9f, 0x77, 0xb6, 0x0b, 0x59, 0x9e, 0x62, 0xc0, 0xec,
-        0x06, 0x06, 0xad, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
-        0x16, 0x04, 0x14, 0xec, 0x36, 0x07, 0x83, 0xf0, 0xda, 0x23, 0xfc, 0x0f, 0xb1, 0x08, 0xd0,
-        0x60, 0x97, 0xc1, 0x9a, 0x14, 0x54, 0xbf, 0x63, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23,
-        0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xec, 0x36, 0x07, 0x83, 0xf0, 0xda, 0x23, 0xfc, 0x0f,
-        0xb1, 0x08, 0xd0, 0x60, 0x97, 0xc1, 0x9a, 0x14, 0x54, 0xbf, 0x63, 0x30, 0x0f, 0x06, 0x03,
-        0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e,
-        0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30,
-        0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x41, 0x00, 0x41, 0xfa, 0x27, 0xfd, 0xe3, 0x42,
-        0x89, 0x43, 0x68, 0x92, 0x48, 0x39, 0xb1, 0x93, 0x93, 0x8b, 0x69, 0x16, 0x50, 0xbe, 0xc0,
-        0xc5, 0x83, 0xd6, 0x1e, 0x4b, 0x2f, 0x6e, 0x18, 0x32, 0x78, 0xfe, 0x35, 0x78, 0xed, 0x6d,
-        0xc8, 0x36, 0xb2, 0x4e, 0x0d, 0x10, 0x23, 0xab, 0x28, 0x32, 0xa1, 0xfc, 0x83, 0x2a, 0xa3,
-        0xca, 0xe1, 0xca, 0x82, 0xd2, 0x5f, 0xf1, 0x7f, 0xf2, 0xba, 0xbe, 0x86, 0x0b, 0x59, 0x01,
-        0x70, 0x30, 0x82, 0x01, 0x6c, 0x30, 0x82, 0x01, 0x1e, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
-        0x02, 0x01, 0xc8, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x30, 0x2b, 0x31, 0x15, 0x30,
-        0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x46, 0x61, 0x6b, 0x65, 0x20, 0x43, 0x6f,
-        0x6d, 0x70, 0x61, 0x6e, 0x79, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
-        0x09, 0x46, 0x61, 0x6b, 0x65, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x32,
-        0x34, 0x31, 0x30, 0x31, 0x37, 0x31, 0x39, 0x32, 0x33, 0x30, 0x39, 0x5a, 0x17, 0x0d, 0x32,
-        0x34, 0x31, 0x31, 0x31, 0x36, 0x31, 0x39, 0x32, 0x33, 0x30, 0x39, 0x5a, 0x30, 0x2e, 0x31,
-        0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x46, 0x61, 0x6b, 0x65, 0x20,
-        0x43, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04,
-        0x03, 0x13, 0x0c, 0x46, 0x61, 0x6b, 0x65, 0x20, 0x43, 0x68, 0x69, 0x70, 0x73, 0x65, 0x74,
-        0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00, 0x14, 0xf4, 0x4a,
-        0x88, 0x56, 0x9f, 0xc0, 0xf5, 0x1f, 0xe5, 0xef, 0xfb, 0xf4, 0x06, 0xbc, 0xb1, 0xe4, 0x4a,
-        0x37, 0xe5, 0x07, 0xf8, 0x65, 0x95, 0x55, 0x54, 0xfd, 0x90, 0xf9, 0x8b, 0xa7, 0xc6, 0xa3,
-        0x63, 0x30, 0x61, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xef,
-        0x05, 0x40, 0x0a, 0x1b, 0x74, 0x3e, 0x4d, 0x2e, 0x22, 0xf5, 0x66, 0x0c, 0xd7, 0xf9, 0xb8,
-        0x8e, 0x81, 0x3d, 0xab, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
-        0x80, 0x14, 0xec, 0x36, 0x07, 0x83, 0xf0, 0xda, 0x23, 0xfc, 0x0f, 0xb1, 0x08, 0xd0, 0x60,
-        0x97, 0xc1, 0x9a, 0x14, 0x54, 0xbf, 0x63, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
-        0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
-        0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x05, 0x06, 0x03, 0x2b,
-        0x65, 0x70, 0x03, 0x41, 0x00, 0x64, 0x32, 0x42, 0x06, 0xa7, 0x11, 0xb0, 0x67, 0x81, 0x73,
-        0x19, 0x70, 0xb6, 0x60, 0x1c, 0xd2, 0x43, 0xde, 0x42, 0xec, 0x71, 0x4d, 0x6e, 0xa8, 0xed,
-        0x6f, 0xe2, 0x59, 0x3e, 0xa3, 0x45, 0x82, 0x8b, 0x25, 0x25, 0xf9, 0xc6, 0xb3, 0xf5, 0xb5,
-        0x3d, 0x11, 0x7d, 0xcf, 0xf2, 0x50, 0x22, 0xff, 0x2b, 0xc5, 0x14, 0x94, 0x64, 0xbf, 0xbf,
-        0x52, 0x69, 0xb1, 0xfe, 0x07, 0x81, 0x83, 0xb3, 0x0d, 0x82, 0xa5, 0x01, 0x01, 0x03, 0x27,
-        0x20, 0x06, 0x21, 0x58, 0x20, 0x14, 0xf4, 0x4a, 0x88, 0x56, 0x9f, 0xc0, 0xf5, 0x1f, 0xe5,
-        0xef, 0xfb, 0xf4, 0x06, 0xbc, 0xb1, 0xe4, 0x4a, 0x37, 0xe5, 0x07, 0xf8, 0x65, 0x95, 0x55,
-        0x54, 0xfd, 0x90, 0xf9, 0x8b, 0xa7, 0xc6, 0x23, 0x58, 0x20, 0x8d, 0x38, 0x0d, 0x38, 0xcb,
-        0x76, 0x73, 0xef, 0x13, 0xd1, 0x08, 0x02, 0xa5, 0x0e, 0xd2, 0x16, 0xd4, 0x0f, 0x2c, 0x29,
-        0xf8, 0xd0, 0x20, 0xb8, 0x6a, 0x7f, 0xa2, 0xd1, 0x1e, 0xeb, 0xd1, 0x5c, 0x84, 0x43, 0xa1,
-        0x01, 0x27, 0xa0, 0x59, 0x01, 0x27, 0xa9, 0x01, 0x66, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72,
-        0x02, 0x67, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58,
-        0x20, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+inline const std::vector<uint8_t> kCsrWithSharedUdsRoot1{
+        0x84, 0x01, 0xa0, 0x82, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x96,
+        0xf9, 0xf7, 0x16, 0xa7, 0xe2, 0x20, 0xe3, 0x6e, 0x19, 0x8e, 0xc0, 0xc4, 0x82, 0xc5, 0xca,
+        0x8d, 0x1d, 0xb4, 0xda, 0x94, 0x6d, 0xf8, 0xbc, 0x0b, 0x0e, 0xc7, 0x90, 0x83, 0x5b, 0xc3,
+        0x4b, 0x22, 0x58, 0x20, 0xed, 0xe0, 0xa1, 0x56, 0x46, 0x5b, 0xe0, 0x67, 0x2d, 0xbc, 0x08,
+        0x84, 0x6f, 0x43, 0xd0, 0x10, 0xf3, 0x70, 0x90, 0xc2, 0xbf, 0xe3, 0x6b, 0x32, 0x9f, 0xf3,
+        0xca, 0x57, 0x0f, 0xa8, 0xb9, 0xdd, 0x84, 0x43, 0xa1, 0x01, 0x26, 0xa0, 0x59, 0x01, 0x04,
+        0xa9, 0x01, 0x66, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x02, 0x67, 0x73, 0x75, 0x62, 0x6a,
+        0x65, 0x63, 0x74, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x20, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
-        0x55, 0x55, 0x55, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x20, 0xb8, 0x96, 0x54, 0xe2, 0x2c,
-        0xa4, 0xd2, 0x4a, 0x9c, 0x0e, 0x45, 0x11, 0xc8, 0xf2, 0x63, 0xf0, 0x66, 0x0d, 0x2e, 0x20,
-        0x48, 0x96, 0x90, 0x14, 0xf4, 0x54, 0x63, 0xc4, 0xf4, 0x39, 0x30, 0x38, 0x3a, 0x00, 0x47,
-        0x44, 0x53, 0x55, 0xa1, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x6f,
-        0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58,
-        0x20, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x3a, 0x00, 0x47,
+        0x44, 0x52, 0x58, 0x20, 0xb8, 0x96, 0x54, 0xe2, 0x2c, 0xa4, 0xd2, 0x4a, 0x9c, 0x0e, 0x45,
+        0x11, 0xc8, 0xf2, 0x63, 0xf0, 0x66, 0x0d, 0x2e, 0x20, 0x48, 0x96, 0x90, 0x14, 0xf4, 0x54,
+        0x63, 0xc4, 0xf4, 0x39, 0x30, 0x38, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x55, 0xa1, 0x3a, 0x00,
+        0x01, 0x11, 0x71, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x6e,
+        0x61, 0x6d, 0x65, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x20, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
-        0x55, 0x55, 0x55, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57,
-        0x58, 0x70, 0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x76, 0x82, 0x58,
-        0xce, 0x99, 0x1c, 0x29, 0xa1, 0x81, 0x3e, 0x22, 0xe3, 0x02, 0x13, 0xea, 0x2a, 0x25, 0x2e,
-        0x20, 0x14, 0xeb, 0x45, 0x0d, 0xb8, 0xdb, 0x8c, 0x38, 0xef, 0xeb, 0x25, 0xd6, 0x31, 0x22,
-        0x58, 0x20, 0xbe, 0x55, 0xba, 0x87, 0x17, 0xc2, 0x5b, 0xb6, 0x56, 0xff, 0x4b, 0xf0, 0x8a,
-        0x98, 0x57, 0x86, 0xa4, 0x36, 0x0a, 0x90, 0x38, 0xce, 0x66, 0xec, 0xcb, 0x25, 0x30, 0x29,
-        0x83, 0x02, 0x02, 0xc0, 0x23, 0x58, 0x20, 0x73, 0xdf, 0xc3, 0x4a, 0xe4, 0x2e, 0xbd, 0x04,
-        0x09, 0xec, 0x91, 0xc7, 0xe7, 0xf1, 0xec, 0x55, 0x10, 0x7e, 0xd1, 0x36, 0x5e, 0x9d, 0x11,
-        0x71, 0x27, 0xee, 0x30, 0x7b, 0x04, 0x45, 0x5f, 0x95, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41,
-        0x20, 0x58, 0x40, 0x44, 0x7f, 0x1a, 0x67, 0x16, 0xa0, 0x49, 0xfe, 0x2c, 0xde, 0x87, 0x38,
-        0xef, 0xb9, 0xe0, 0x19, 0x25, 0x7d, 0xcc, 0x39, 0x53, 0x27, 0xbd, 0x2c, 0x04, 0x6c, 0xe3,
-        0x5c, 0x5e, 0xd6, 0x27, 0x09, 0xb9, 0xf7, 0x8c, 0x2b, 0xd2, 0x68, 0xc3, 0xf1, 0x23, 0xcf,
-        0xc6, 0xfc, 0x21, 0xb3, 0x52, 0x48, 0xe6, 0x8a, 0x89, 0x3e, 0x37, 0x24, 0x13, 0x23, 0x80,
-        0xb2, 0xc7, 0xa7, 0xc6, 0xf1, 0xec, 0x04, 0x84, 0x43, 0xa1, 0x01, 0x26, 0xa0, 0x59, 0x02,
-        0x0f, 0x82, 0x58, 0x20, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
-        0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a,
-        0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x59, 0x01, 0xe9, 0x84, 0x03, 0x67, 0x6b, 0x65, 0x79,
-        0x6d, 0x69, 0x6e, 0x74, 0xae, 0x65, 0x62, 0x72, 0x61, 0x6e, 0x64, 0x66, 0x47, 0x6f, 0x6f,
-        0x67, 0x6c, 0x65, 0x65, 0x66, 0x75, 0x73, 0x65, 0x64, 0x01, 0x65, 0x6d, 0x6f, 0x64, 0x65,
-        0x6c, 0x65, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x66, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x66,
-        0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x67, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x65,
-        0x70, 0x69, 0x78, 0x65, 0x6c, 0x68, 0x76, 0x62, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x65,
-        0x67, 0x72, 0x65, 0x65, 0x6e, 0x6a, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
-        0x6e, 0x62, 0x31, 0x32, 0x6c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72,
-        0x65, 0x72, 0x66, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x6d, 0x76, 0x62, 0x6d, 0x65, 0x74,
-        0x61, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x4f, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
-        0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72,
-        0x69, 0x74, 0x79, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x63, 0x74, 0x65, 0x65, 0x70, 0x62,
-        0x6f, 0x6f, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c,
-        0x1a, 0x01, 0x34, 0x8c, 0x62, 0x70, 0x62, 0x6f, 0x6f, 0x74, 0x6c, 0x6f, 0x61, 0x64, 0x65,
-        0x72, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x66, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x72,
-        0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6c, 0x65,
-        0x76, 0x65, 0x6c, 0x1a, 0x01, 0x34, 0x8c, 0x61, 0x72, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72,
-        0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x1a, 0x01, 0x34,
-        0x8c, 0x63, 0x82, 0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x35, 0xeb,
-        0x56, 0xed, 0x62, 0x13, 0x6a, 0x41, 0x89, 0xf6, 0x72, 0xa6, 0xf1, 0x5c, 0xd1, 0xf6, 0x34,
-        0xbd, 0x81, 0xdb, 0x2e, 0x0b, 0x4d, 0xf6, 0x69, 0x6f, 0xa6, 0xf3, 0xce, 0x27, 0x2c, 0x78,
-        0x22, 0x58, 0x20, 0xac, 0xa9, 0x9f, 0x62, 0x81, 0x58, 0xc7, 0x10, 0xd7, 0xb5, 0xa8, 0xa0,
-        0x7b, 0x11, 0xf5, 0x75, 0xdb, 0xd9, 0xa2, 0x1d, 0x86, 0x34, 0xc6, 0xf4, 0x23, 0x79, 0xcc,
-        0x8a, 0x87, 0x3c, 0xb2, 0xd0, 0x23, 0x58, 0x20, 0x0f, 0x2c, 0x5a, 0xb7, 0xe1, 0x3b, 0x24,
-        0xa3, 0x4f, 0xaa, 0x49, 0x51, 0xfc, 0x8c, 0xd0, 0x35, 0x43, 0x7c, 0x21, 0xfa, 0x7d, 0x56,
-        0x97, 0x69, 0xe1, 0x81, 0xf5, 0x88, 0x15, 0x33, 0xa0, 0x7f, 0xa6, 0x01, 0x02, 0x03, 0x26,
-        0x20, 0x01, 0x21, 0x58, 0x20, 0xb5, 0xcc, 0xd9, 0x4f, 0x7a, 0xe2, 0xca, 0xac, 0xfe, 0xa5,
-        0x65, 0x0c, 0x6a, 0xa8, 0x16, 0x45, 0x40, 0x41, 0x1c, 0xb2, 0x64, 0xcd, 0x34, 0xe8, 0x37,
-        0x88, 0xb9, 0x9a, 0xb3, 0xc3, 0xfd, 0x6a, 0x22, 0x58, 0x20, 0x5e, 0xbe, 0xff, 0x98, 0x60,
-        0x6e, 0x1d, 0x6b, 0x42, 0x60, 0x59, 0xe9, 0x42, 0x95, 0xc8, 0x2e, 0xc5, 0xb6, 0x66, 0x4a,
-        0x53, 0xf1, 0x73, 0x02, 0xcb, 0x89, 0x8a, 0x2a, 0xc9, 0xa5, 0xa3, 0x39, 0x23, 0x58, 0x21,
-        0x00, 0xdb, 0xda, 0x3c, 0x3e, 0x27, 0x71, 0x5e, 0xd0, 0x2b, 0x09, 0xb8, 0x6f, 0xe2, 0x2c,
-        0xdd, 0x0a, 0xbf, 0x1d, 0x94, 0x36, 0xd2, 0x33, 0x88, 0x6e, 0x66, 0x05, 0x21, 0x92, 0x64,
-        0x79, 0xa9, 0x10, 0x58, 0x40, 0x87, 0xcf, 0xaa, 0x82, 0x6a, 0xba, 0x25, 0x8b, 0x81, 0xd8,
-        0x14, 0xca, 0xbd, 0xf4, 0x67, 0xdf, 0xc8, 0x2c, 0xa1, 0x04, 0x57, 0x99, 0xa0, 0x54, 0xe7,
-        0x9b, 0xb2, 0xd0, 0xaf, 0xdd, 0x07, 0x46, 0x0a, 0xd7, 0xbd, 0xa7, 0xf9, 0xa8, 0x0c, 0x08,
-        0x1e, 0x9c, 0xae, 0x73, 0x4c, 0x22, 0x6e, 0x56, 0x8b, 0xe4, 0x91, 0x54, 0xa4, 0x7a, 0xb0,
-        0xf5, 0xe4, 0x5d, 0xa9, 0x8f, 0xae, 0x43, 0x95, 0x7a};
+        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x3a, 0x00, 0x47,
+        0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x4d, 0xa5, 0x01, 0x02, 0x03,
+        0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x04, 0x25, 0x41, 0x6f, 0x6a, 0xdc, 0x88, 0x56, 0x9a,
+        0xd4, 0x39, 0x82, 0xde, 0xd1, 0xe6, 0x65, 0xd4, 0x09, 0xb8, 0x9f, 0xde, 0xbf, 0x09, 0x03,
+        0xe3, 0x9a, 0x48, 0xd4, 0x4f, 0x13, 0xaa, 0x5b, 0x22, 0x58, 0x20, 0x3a, 0xfb, 0x46, 0x2d,
+        0xe1, 0xdf, 0x34, 0x76, 0x03, 0x37, 0x1e, 0xcf, 0xea, 0xd5, 0xf6, 0xd3, 0x99, 0x3e, 0x55,
+        0x2a, 0xd1, 0x9d, 0x10, 0x21, 0xb1, 0xc8, 0x4f, 0xbd, 0xec, 0xb6, 0x67, 0x82, 0x3a, 0x00,
+        0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40, 0x10, 0xda, 0xc8, 0x8d, 0x83, 0x6d, 0xdd, 0x85,
+        0x48, 0x92, 0xdc, 0xc0, 0xc8, 0xde, 0xe4, 0x61, 0x03, 0x04, 0xfb, 0x77, 0xdf, 0xc1, 0xce,
+        0xb7, 0x9b, 0x74, 0x9a, 0x31, 0x7a, 0xca, 0xcb, 0x7c, 0x45, 0x65, 0xf5, 0xc1, 0x3b, 0x29,
+        0x53, 0x22, 0xbc, 0xda, 0xa9, 0xfa, 0x97, 0x84, 0x42, 0xfc, 0xcb, 0x36, 0xae, 0xe9, 0x67,
+        0x1c, 0xb1, 0x19, 0x42, 0x74, 0x01, 0xb1, 0x11, 0xc9, 0x7b, 0x58, 0x84, 0x43, 0xa1, 0x01,
+        0x26, 0xa0, 0x59, 0x02, 0x0f, 0x82, 0x58, 0x20, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+        0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x59, 0x01, 0xe9, 0x84, 0x03,
+        0x67, 0x6b, 0x65, 0x79, 0x6d, 0x69, 0x6e, 0x74, 0xae, 0x65, 0x62, 0x72, 0x61, 0x6e, 0x64,
+        0x66, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x65, 0x66, 0x75, 0x73, 0x65, 0x64, 0x01, 0x65,
+        0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x65, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x66, 0x64, 0x65, 0x76,
+        0x69, 0x63, 0x65, 0x66, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x67, 0x70, 0x72, 0x6f, 0x64,
+        0x75, 0x63, 0x74, 0x65, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x68, 0x76, 0x62, 0x5f, 0x73, 0x74,
+        0x61, 0x74, 0x65, 0x65, 0x67, 0x72, 0x65, 0x65, 0x6e, 0x6a, 0x6f, 0x73, 0x5f, 0x76, 0x65,
+        0x72, 0x73, 0x69, 0x6f, 0x6e, 0x62, 0x31, 0x32, 0x6c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61,
+        0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x66, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x6d, 0x76,
+        0x62, 0x6d, 0x65, 0x74, 0x61, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x4f, 0x11, 0x22,
+        0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x6e, 0x73,
+        0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x63, 0x74,
+        0x65, 0x65, 0x70, 0x62, 0x6f, 0x6f, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6c,
+        0x65, 0x76, 0x65, 0x6c, 0x1a, 0x01, 0x34, 0x8c, 0x62, 0x70, 0x62, 0x6f, 0x6f, 0x74, 0x6c,
+        0x6f, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x66, 0x6c, 0x6f, 0x63,
+        0x6b, 0x65, 0x64, 0x72, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x70, 0x61, 0x74, 0x63,
+        0x68, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x1a, 0x01, 0x34, 0x8c, 0x61, 0x72, 0x76, 0x65,
+        0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6c, 0x65, 0x76, 0x65,
+        0x6c, 0x1a, 0x01, 0x34, 0x8c, 0x63, 0x82, 0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21,
+        0x58, 0x20, 0xf6, 0x86, 0x74, 0x7d, 0x1a, 0x83, 0x75, 0xec, 0x8c, 0xf9, 0x3a, 0xa9, 0x20,
+        0x88, 0xe5, 0xca, 0x24, 0x34, 0x24, 0xbf, 0x89, 0xe7, 0xdb, 0x44, 0xc3, 0x6e, 0xdd, 0x5d,
+        0x1a, 0xe1, 0xf0, 0xd8, 0x22, 0x58, 0x20, 0xae, 0xcb, 0x01, 0x2e, 0x73, 0xac, 0xb5, 0x52,
+        0x0e, 0x73, 0x15, 0xd8, 0x9d, 0x78, 0x64, 0x10, 0x35, 0x41, 0x0e, 0xc9, 0x7d, 0x9a, 0x11,
+        0xa3, 0xed, 0x7f, 0x53, 0xa6, 0xff, 0xc4, 0xad, 0x61, 0x23, 0x58, 0x20, 0x5a, 0xd2, 0xc5,
+        0xd0, 0x58, 0x2e, 0x94, 0x93, 0xd7, 0xa4, 0x2d, 0x5b, 0x12, 0x43, 0x52, 0x93, 0xc3, 0x95,
+        0x91, 0xac, 0x6a, 0xa3, 0x31, 0x08, 0xda, 0x33, 0x6a, 0xce, 0x7e, 0x8e, 0xae, 0xb1, 0xa6,
+        0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x8f, 0xb1, 0x85, 0xa5, 0xf5, 0x68,
+        0x74, 0xfc, 0x8a, 0x87, 0x2b, 0x13, 0xea, 0xf7, 0xff, 0x82, 0x6d, 0xcf, 0xc3, 0xea, 0x04,
+        0x80, 0x40, 0xe5, 0xcb, 0x80, 0xdb, 0x07, 0x8b, 0x36, 0x8c, 0x29, 0x22, 0x58, 0x20, 0x6a,
+        0x8c, 0x52, 0x3f, 0xf7, 0x26, 0xb3, 0xf9, 0xa8, 0x91, 0x08, 0x4e, 0xec, 0x7a, 0x03, 0x16,
+        0x1c, 0xab, 0x12, 0xcd, 0x8b, 0x05, 0x77, 0x33, 0x16, 0x1c, 0x80, 0x99, 0x79, 0x14, 0x6a,
+        0x5c, 0x23, 0x58, 0x21, 0x00, 0xd0, 0x0a, 0xa2, 0xaa, 0x27, 0x62, 0x10, 0x24, 0x0c, 0x74,
+        0x34, 0xe7, 0x06, 0xb3, 0x4d, 0x33, 0x9c, 0x86, 0xa6, 0x62, 0xb9, 0x0f, 0x1a, 0x4b, 0xe2,
+        0x8b, 0x45, 0x0a, 0xc9, 0xe3, 0x43, 0x28, 0x58, 0x40, 0xea, 0xe3, 0xd3, 0xd9, 0x7f, 0x4e,
+        0x08, 0x8a, 0x5b, 0xb9, 0xef, 0x28, 0x5a, 0xe0, 0x02, 0x40, 0xf5, 0x68, 0x49, 0x8b, 0xa7,
+        0xf7, 0x9d, 0xa3, 0xb3, 0x37, 0x72, 0x79, 0xa9, 0x32, 0x47, 0xf6, 0x8d, 0x5d, 0x08, 0xe7,
+        0xec, 0x00, 0x19, 0x09, 0x6f, 0x0a, 0x4d, 0x7c, 0x62, 0x6c, 0x2b, 0xaa, 0x33, 0x61, 0xe5,
+        0xa5, 0x3f, 0x2a, 0xfe, 0xcc, 0xdf, 0x8e, 0x62, 0x1c, 0x31, 0xe1, 0x56, 0x6b};
 
-inline const std::vector<uint8_t> kKeysToSignForCsrWithoutUdsCerts = {
-        0x82, 0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x50, 0x43, 0xb4, 0xf1,
-        0xc1, 0x7f, 0x17, 0xc6, 0x3b, 0x56, 0x27, 0x63, 0x03, 0x18, 0x78, 0x9d, 0x63, 0x93, 0x3b,
-        0x98, 0xed, 0x55, 0x8c, 0x87, 0x1b, 0xd7, 0x89, 0xb6, 0x81, 0x92, 0x5f, 0x24, 0x22, 0x58,
-        0x20, 0xd5, 0x24, 0x93, 0xda, 0x3e, 0x32, 0x17, 0xfa, 0xe8, 0x8d, 0x1e, 0xa9, 0xe0, 0x84,
-        0x4e, 0x1c, 0x6a, 0xef, 0x9a, 0xe3, 0xbe, 0x1d, 0xf1, 0x14, 0xe0, 0x9e, 0x82, 0xc8, 0x92,
-        0x1a, 0x3a, 0x69, 0x23, 0x58, 0x20, 0x29, 0xcb, 0x16, 0x78, 0x61, 0x35, 0x92, 0x3f, 0x71,
-        0xc4, 0x66, 0x61, 0xd4, 0xd4, 0x20, 0x8a, 0x86, 0x1e, 0xb0, 0x2b, 0x2f, 0x4f, 0x13, 0xb4,
-        0x0d, 0x89, 0x60, 0x87, 0x77, 0xac, 0x1a, 0x0f, 0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01,
-        0x21, 0x58, 0x20, 0x4b, 0xcc, 0x7a, 0x09, 0x99, 0x76, 0xe7, 0xfa, 0x06, 0xb9, 0x19, 0x22,
-        0x15, 0x3b, 0x9f, 0xa8, 0x34, 0x77, 0x24, 0x27, 0x8c, 0x8a, 0x97, 0x61, 0xf3, 0x6f, 0x29,
-        0x74, 0x4e, 0x9a, 0x66, 0x23, 0x22, 0x58, 0x20, 0x8f, 0xa8, 0xaf, 0x2b, 0x02, 0x3a, 0xd4,
-        0x8a, 0xa2, 0x9d, 0x25, 0xa8, 0x01, 0xe7, 0xbd, 0x61, 0x25, 0x88, 0xb4, 0xc9, 0xce, 0x05,
-        0x43, 0xcc, 0x0d, 0x38, 0x7d, 0xe2, 0xda, 0x03, 0xb3, 0x33, 0x23, 0x58, 0x21, 0x00, 0xc8,
-        0x67, 0xb8, 0xbe, 0xc4, 0x1c, 0xca, 0x3c, 0x73, 0x3c, 0xbf, 0x52, 0xb2, 0x5a, 0x64, 0x9e,
-        0x9f, 0xae, 0xc6, 0x9f, 0x02, 0x2f, 0xee, 0x92, 0x1d, 0xdb, 0x01, 0x77, 0x27, 0x12, 0x84,
-        0x14};
-
-inline const std::vector<uint8_t> kCsrWithoutUdsCerts{
-        0x84, 0x01, 0xa0, 0x82, 0xa6, 0x01, 0x02, 0x03, 0x38, 0x22, 0x20, 0x02, 0x21, 0x58, 0x30,
-        0x21, 0x09, 0x81, 0xb2, 0x4c, 0x8e, 0x23, 0x63, 0x46, 0xe5, 0x32, 0x1e, 0x1b, 0xa3, 0x39,
-        0x47, 0xd1, 0x19, 0x91, 0xc5, 0xe1, 0xd0, 0x51, 0xa4, 0x4e, 0x6d, 0xfd, 0x21, 0x46, 0xf3,
-        0x65, 0x6b, 0xd3, 0xec, 0x20, 0x21, 0xf8, 0xef, 0x39, 0x50, 0x0a, 0xfc, 0x6d, 0x18, 0xf8,
-        0x90, 0x1c, 0xc8, 0x22, 0x58, 0x30, 0x80, 0x1f, 0xd8, 0xe3, 0x64, 0x51, 0x48, 0x66, 0xa5,
-        0xad, 0x05, 0xcb, 0xe4, 0xee, 0x0f, 0x20, 0xc1, 0xca, 0x84, 0xc2, 0xe0, 0xcc, 0x22, 0x06,
-        0x7c, 0x5e, 0x2c, 0xb3, 0x3b, 0x52, 0xd4, 0xe7, 0xc1, 0xe2, 0x57, 0x9d, 0x8a, 0xa6, 0x5c,
-        0x08, 0xbb, 0x77, 0x07, 0xa8, 0x39, 0xba, 0x9f, 0x5f, 0x23, 0x58, 0x31, 0x00, 0xff, 0x5f,
-        0xa3, 0x03, 0x87, 0x70, 0xe5, 0xf0, 0x69, 0xcd, 0x0a, 0x32, 0x9e, 0x4a, 0xe8, 0x07, 0x1f,
-        0x26, 0xb9, 0x8a, 0x01, 0x83, 0xfe, 0xb9, 0x21, 0x22, 0x49, 0x9d, 0x9f, 0x78, 0x48, 0xf4,
-        0x24, 0x87, 0xe8, 0x4d, 0xab, 0xd5, 0xe9, 0xd6, 0x90, 0x49, 0x4b, 0x42, 0xb4, 0x68, 0xac,
-        0xf1, 0x84, 0x44, 0xa1, 0x01, 0x38, 0x22, 0xa0, 0x59, 0x01, 0x28, 0xa9, 0x01, 0x66, 0x69,
-        0x73, 0x73, 0x75, 0x65, 0x72, 0x02, 0x67, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a,
-        0x00, 0x47, 0x44, 0x50, 0x58, 0x20, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+inline const std::vector<uint8_t> kCsrWithSharedUdsRoot2{
+        0x84, 0x01, 0xa0, 0x82, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x96,
+        0xf9, 0xf7, 0x16, 0xa7, 0xe2, 0x20, 0xe3, 0x6e, 0x19, 0x8e, 0xc0, 0xc4, 0x82, 0xc5, 0xca,
+        0x8d, 0x1d, 0xb4, 0xda, 0x94, 0x6d, 0xf8, 0xbc, 0x0b, 0x0e, 0xc7, 0x90, 0x83, 0x5b, 0xc3,
+        0x4b, 0x22, 0x58, 0x20, 0xed, 0xe0, 0xa1, 0x56, 0x46, 0x5b, 0xe0, 0x67, 0x2d, 0xbc, 0x08,
+        0x84, 0x6f, 0x43, 0xd0, 0x10, 0xf3, 0x70, 0x90, 0xc2, 0xbf, 0xe3, 0x6b, 0x32, 0x9f, 0xf3,
+        0xca, 0x57, 0x0f, 0xa8, 0xb9, 0xdd, 0x84, 0x43, 0xa1, 0x01, 0x26, 0xa0, 0x59, 0x01, 0x04,
+        0xa9, 0x01, 0x66, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x02, 0x67, 0x73, 0x75, 0x62, 0x6a,
+        0x65, 0x63, 0x74, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x20, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
-        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x20,
-        0xb8, 0x96, 0x54, 0xe2, 0x2c, 0xa4, 0xd2, 0x4a, 0x9c, 0x0e, 0x45, 0x11, 0xc8, 0xf2, 0x63,
-        0xf0, 0x66, 0x0d, 0x2e, 0x20, 0x48, 0x96, 0x90, 0x14, 0xf4, 0x54, 0x63, 0xc4, 0xf4, 0x39,
-        0x30, 0x38, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x55, 0xa1, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x6e,
-        0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x3a,
-        0x00, 0x47, 0x44, 0x54, 0x58, 0x20, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x3a, 0x00, 0x47,
+        0x44, 0x52, 0x58, 0x20, 0xb8, 0x96, 0x54, 0xe2, 0x2c, 0xa4, 0xd2, 0x4a, 0x9c, 0x0e, 0x45,
+        0x11, 0xc8, 0xf2, 0x63, 0xf0, 0x66, 0x0d, 0x2e, 0x20, 0x48, 0x96, 0x90, 0x14, 0xf4, 0x54,
+        0x63, 0xc4, 0xf4, 0x39, 0x30, 0x38, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x55, 0xa1, 0x3a, 0x00,
+        0x01, 0x11, 0x71, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x6e,
+        0x61, 0x6d, 0x65, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x20, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
-        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01,
-        0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x71, 0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21,
-        0x58, 0x20, 0x2d, 0x41, 0x43, 0x19, 0xf2, 0x91, 0x58, 0x12, 0x65, 0x2e, 0x96, 0xb5, 0x9d,
-        0x12, 0x18, 0x58, 0x54, 0x11, 0xed, 0x41, 0x30, 0xef, 0xa4, 0xee, 0x69, 0x8f, 0x0c, 0x6e,
-        0xe6, 0x27, 0xc5, 0x20, 0x22, 0x58, 0x20, 0x21, 0x0e, 0x8f, 0x83, 0xe5, 0xeb, 0x40, 0x89,
-        0xc2, 0x0a, 0x43, 0x6c, 0x9f, 0xa8, 0x4e, 0xe0, 0xba, 0x9e, 0xba, 0x4f, 0xe3, 0x27, 0xc4,
-        0xbd, 0x41, 0xa0, 0xd6, 0xe9, 0x55, 0x54, 0x17, 0x78, 0x23, 0x58, 0x21, 0x00, 0xb6, 0x33,
-        0x44, 0x98, 0xa7, 0x1c, 0x90, 0x13, 0xcc, 0x42, 0x71, 0x43, 0x29, 0xe5, 0xe1, 0x57, 0x89,
-        0x7a, 0x39, 0x17, 0x7c, 0xcc, 0x03, 0xac, 0xd3, 0x1b, 0xd2, 0xae, 0x29, 0x5f, 0xd6, 0xf8,
-        0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x60, 0xc4, 0x54, 0xad, 0x40, 0xa2, 0x07,
-        0xc7, 0x80, 0xbd, 0x41, 0x77, 0x5d, 0xa7, 0xa2, 0xef, 0xef, 0x92, 0x67, 0x24, 0xab, 0xa1,
-        0x4a, 0x5e, 0x4f, 0x73, 0xfb, 0x5c, 0x1f, 0xe6, 0x46, 0x2f, 0xb9, 0x1b, 0x71, 0x86, 0x87,
-        0x29, 0xc4, 0x66, 0xb7, 0x3e, 0x85, 0x13, 0x9a, 0xa3, 0xf8, 0xfc, 0x63, 0x26, 0xe0, 0xba,
-        0x0b, 0xe0, 0x9b, 0x2e, 0x7d, 0x06, 0x06, 0xb8, 0x2f, 0xdd, 0x0c, 0xa5, 0x90, 0x1c, 0x10,
-        0x1c, 0x55, 0xf9, 0x65, 0xf6, 0x26, 0x40, 0x41, 0xaf, 0x5c, 0x16, 0x03, 0xf3, 0xee, 0x8d,
-        0x72, 0x2c, 0x6b, 0x1e, 0xb3, 0x1f, 0x96, 0x97, 0x34, 0x61, 0x0d, 0x5c, 0xe4, 0x94, 0x6a,
-        0x84, 0x43, 0xa1, 0x01, 0x26, 0xa0, 0x59, 0x02, 0x0f, 0x82, 0x58, 0x20, 0x01, 0x02, 0x03,
-        0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
-        0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x59,
-        0x01, 0xe9, 0x84, 0x03, 0x67, 0x6b, 0x65, 0x79, 0x6d, 0x69, 0x6e, 0x74, 0xae, 0x65, 0x62,
-        0x72, 0x61, 0x6e, 0x64, 0x66, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x65, 0x66, 0x75, 0x73,
-        0x65, 0x64, 0x01, 0x65, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x65, 0x6d, 0x6f, 0x64, 0x65, 0x6c,
-        0x66, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x66, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x67,
-        0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x65, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x68, 0x76,
-        0x62, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x65, 0x67, 0x72, 0x65, 0x65, 0x6e, 0x6a, 0x6f,
-        0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x62, 0x31, 0x32, 0x6c, 0x6d, 0x61,
-        0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x66, 0x47, 0x6f, 0x6f, 0x67,
-        0x6c, 0x65, 0x6d, 0x76, 0x62, 0x6d, 0x65, 0x74, 0x61, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73,
-        0x74, 0x4f, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
-        0xee, 0xff, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x6c, 0x65, 0x76,
-        0x65, 0x6c, 0x63, 0x74, 0x65, 0x65, 0x70, 0x62, 0x6f, 0x6f, 0x74, 0x5f, 0x70, 0x61, 0x74,
-        0x63, 0x68, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x1a, 0x01, 0x34, 0x8c, 0x62, 0x70, 0x62,
-        0x6f, 0x6f, 0x74, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65,
-        0x66, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x72, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f,
-        0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x1a, 0x01, 0x34, 0x8c,
-        0x61, 0x72, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f,
-        0x6c, 0x65, 0x76, 0x65, 0x6c, 0x1a, 0x01, 0x34, 0x8c, 0x63, 0x82, 0xa6, 0x01, 0x02, 0x03,
-        0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x50, 0x43, 0xb4, 0xf1, 0xc1, 0x7f, 0x17, 0xc6, 0x3b,
-        0x56, 0x27, 0x63, 0x03, 0x18, 0x78, 0x9d, 0x63, 0x93, 0x3b, 0x98, 0xed, 0x55, 0x8c, 0x87,
-        0x1b, 0xd7, 0x89, 0xb6, 0x81, 0x92, 0x5f, 0x24, 0x22, 0x58, 0x20, 0xd5, 0x24, 0x93, 0xda,
-        0x3e, 0x32, 0x17, 0xfa, 0xe8, 0x8d, 0x1e, 0xa9, 0xe0, 0x84, 0x4e, 0x1c, 0x6a, 0xef, 0x9a,
-        0xe3, 0xbe, 0x1d, 0xf1, 0x14, 0xe0, 0x9e, 0x82, 0xc8, 0x92, 0x1a, 0x3a, 0x69, 0x23, 0x58,
-        0x20, 0x29, 0xcb, 0x16, 0x78, 0x61, 0x35, 0x92, 0x3f, 0x71, 0xc4, 0x66, 0x61, 0xd4, 0xd4,
-        0x20, 0x8a, 0x86, 0x1e, 0xb0, 0x2b, 0x2f, 0x4f, 0x13, 0xb4, 0x0d, 0x89, 0x60, 0x87, 0x77,
-        0xac, 0x1a, 0x0f, 0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x4b, 0xcc,
-        0x7a, 0x09, 0x99, 0x76, 0xe7, 0xfa, 0x06, 0xb9, 0x19, 0x22, 0x15, 0x3b, 0x9f, 0xa8, 0x34,
-        0x77, 0x24, 0x27, 0x8c, 0x8a, 0x97, 0x61, 0xf3, 0x6f, 0x29, 0x74, 0x4e, 0x9a, 0x66, 0x23,
-        0x22, 0x58, 0x20, 0x8f, 0xa8, 0xaf, 0x2b, 0x02, 0x3a, 0xd4, 0x8a, 0xa2, 0x9d, 0x25, 0xa8,
-        0x01, 0xe7, 0xbd, 0x61, 0x25, 0x88, 0xb4, 0xc9, 0xce, 0x05, 0x43, 0xcc, 0x0d, 0x38, 0x7d,
-        0xe2, 0xda, 0x03, 0xb3, 0x33, 0x23, 0x58, 0x21, 0x00, 0xc8, 0x67, 0xb8, 0xbe, 0xc4, 0x1c,
-        0xca, 0x3c, 0x73, 0x3c, 0xbf, 0x52, 0xb2, 0x5a, 0x64, 0x9e, 0x9f, 0xae, 0xc6, 0x9f, 0x02,
-        0x2f, 0xee, 0x92, 0x1d, 0xdb, 0x01, 0x77, 0x27, 0x12, 0x84, 0x14, 0x58, 0x40, 0x6c, 0xd5,
-        0x66, 0x0a, 0x99, 0xdd, 0x32, 0x47, 0x50, 0x1f, 0x5d, 0x46, 0x40, 0x8a, 0x60, 0x25, 0xa0,
-        0x1b, 0x3c, 0x2a, 0xcf, 0xa1, 0x92, 0x1a, 0xdc, 0x81, 0xaa, 0xb0, 0x0f, 0xf2, 0xe6, 0x94,
-        0xce, 0x3d, 0xff, 0xac, 0x25, 0x44, 0xea, 0xf7, 0x0a, 0x89, 0x9d, 0xc4, 0x7e, 0xe5, 0x02,
-        0xa7, 0xb6, 0xc2, 0x40, 0x06, 0x65, 0xc5, 0xff, 0x19, 0xc5, 0xcd, 0x1c, 0xd5, 0x78, 0x01,
-        0xd4, 0xb8};
+        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x3a, 0x00, 0x47,
+        0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x4d, 0xa5, 0x01, 0x02, 0x03,
+        0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x2d, 0xbd, 0x92, 0x58, 0xc8, 0xcd, 0xc3, 0xc5, 0x14,
+        0xe3, 0x6e, 0x5f, 0xab, 0x71, 0x41, 0x46, 0x83, 0xb4, 0x3e, 0x82, 0xdb, 0xe7, 0x7d, 0x27,
+        0xe5, 0x26, 0x36, 0x94, 0xcb, 0x4c, 0x72, 0x8f, 0x22, 0x58, 0x20, 0xbf, 0xa2, 0xa7, 0x15,
+        0x46, 0x5a, 0xea, 0xa8, 0xc7, 0xad, 0x22, 0x61, 0x9c, 0xba, 0x87, 0x70, 0x65, 0x64, 0x11,
+        0x05, 0x8a, 0x58, 0x8c, 0x0c, 0x25, 0xc7, 0xf8, 0x5f, 0xfc, 0x4a, 0xee, 0xa1, 0x3a, 0x00,
+        0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40, 0x43, 0xba, 0xff, 0xdb, 0xbb, 0xa9, 0x9e, 0x8f,
+        0x06, 0xdf, 0x33, 0xa0, 0x3f, 0x30, 0xc3, 0x64, 0x84, 0x32, 0xb5, 0x2a, 0x06, 0x53, 0x13,
+        0x70, 0xbe, 0xa3, 0x0b, 0x4d, 0xbe, 0x8d, 0x8c, 0x90, 0xde, 0x6c, 0x1d, 0xa8, 0xea, 0x40,
+        0xd5, 0x17, 0xa1, 0xea, 0x62, 0x95, 0x37, 0x64, 0x92, 0xc3, 0xc4, 0xef, 0xd7, 0xcf, 0x87,
+        0x0c, 0x9a, 0xd2, 0x5c, 0x10, 0x1d, 0x00, 0x2e, 0xe4, 0xe9, 0x1f, 0x84, 0x43, 0xa1, 0x01,
+        0x26, 0xa0, 0x59, 0x02, 0x10, 0x82, 0x58, 0x20, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+        0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x59, 0x01, 0xea, 0x84, 0x03,
+        0x67, 0x6b, 0x65, 0x79, 0x6d, 0x69, 0x6e, 0x74, 0xae, 0x65, 0x62, 0x72, 0x61, 0x6e, 0x64,
+        0x66, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x65, 0x66, 0x75, 0x73, 0x65, 0x64, 0x01, 0x65,
+        0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x65, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x66, 0x64, 0x65, 0x76,
+        0x69, 0x63, 0x65, 0x66, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x67, 0x70, 0x72, 0x6f, 0x64,
+        0x75, 0x63, 0x74, 0x65, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x68, 0x76, 0x62, 0x5f, 0x73, 0x74,
+        0x61, 0x74, 0x65, 0x65, 0x67, 0x72, 0x65, 0x65, 0x6e, 0x6a, 0x6f, 0x73, 0x5f, 0x76, 0x65,
+        0x72, 0x73, 0x69, 0x6f, 0x6e, 0x62, 0x31, 0x32, 0x6c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61,
+        0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x66, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x6d, 0x76,
+        0x62, 0x6d, 0x65, 0x74, 0x61, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x4f, 0x11, 0x22,
+        0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x6e, 0x73,
+        0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x63, 0x74,
+        0x65, 0x65, 0x70, 0x62, 0x6f, 0x6f, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6c,
+        0x65, 0x76, 0x65, 0x6c, 0x1a, 0x01, 0x34, 0x8c, 0x62, 0x70, 0x62, 0x6f, 0x6f, 0x74, 0x6c,
+        0x6f, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x66, 0x6c, 0x6f, 0x63,
+        0x6b, 0x65, 0x64, 0x72, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x70, 0x61, 0x74, 0x63,
+        0x68, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x1a, 0x01, 0x34, 0x8c, 0x61, 0x72, 0x76, 0x65,
+        0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6c, 0x65, 0x76, 0x65,
+        0x6c, 0x1a, 0x01, 0x34, 0x8c, 0x63, 0x82, 0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21,
+        0x58, 0x20, 0xad, 0xd2, 0x8c, 0xcc, 0xfb, 0x22, 0xd8, 0x5a, 0x3b, 0x9d, 0x22, 0x58, 0xb3,
+        0x7c, 0xcc, 0xa5, 0x22, 0x46, 0x86, 0x2b, 0x29, 0x87, 0x49, 0xdd, 0xe4, 0x2c, 0xb4, 0x3f,
+        0xf2, 0x4e, 0x6a, 0xed, 0x22, 0x58, 0x20, 0xe9, 0x34, 0x28, 0x54, 0x21, 0x7e, 0x88, 0x34,
+        0x82, 0x0d, 0x0f, 0x14, 0x5b, 0xec, 0x61, 0xc4, 0xf2, 0xa4, 0xef, 0xf8, 0x17, 0xeb, 0xeb,
+        0x05, 0x01, 0x36, 0x14, 0x52, 0xc7, 0xc2, 0xd8, 0xd3, 0x23, 0x58, 0x21, 0x00, 0xd9, 0xb4,
+        0x13, 0xd0, 0x86, 0x31, 0x5e, 0x97, 0xc2, 0x54, 0x03, 0x72, 0x80, 0x6f, 0x14, 0x53, 0xbe,
+        0x2e, 0xe5, 0x1b, 0x02, 0x1a, 0x62, 0x1a, 0x88, 0xe8, 0xa2, 0xde, 0xd0, 0x7d, 0xf6, 0x53,
+        0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xca, 0x7d, 0x6e, 0xb5, 0x78,
+        0x99, 0x9e, 0x66, 0xf4, 0x5d, 0xfe, 0xd5, 0x92, 0xe3, 0x30, 0xf5, 0xd5, 0xc2, 0x82, 0xf2,
+        0x6d, 0x58, 0x16, 0x26, 0xa5, 0xe7, 0xfc, 0x62, 0x8f, 0xf3, 0x61, 0x56, 0x22, 0x58, 0x20,
+        0x9f, 0x42, 0x22, 0x11, 0x1c, 0x45, 0x5c, 0x3a, 0x30, 0x95, 0xb4, 0xb3, 0x63, 0x26, 0x09,
+        0xfc, 0x2e, 0x6e, 0x99, 0xdd, 0x44, 0x37, 0x34, 0xa9, 0x68, 0x42, 0xf5, 0x91, 0x40, 0xae,
+        0xfa, 0x52, 0x23, 0x58, 0x21, 0x00, 0xe2, 0x3b, 0xaa, 0x88, 0xfc, 0xec, 0x23, 0xe7, 0x93,
+        0x91, 0x04, 0x8e, 0xae, 0xa7, 0x44, 0xb4, 0x5e, 0x46, 0xe8, 0x91, 0x59, 0x3e, 0x43, 0x13,
+        0x82, 0x8e, 0xa1, 0xee, 0x47, 0xbd, 0x13, 0x27, 0x58, 0x40, 0x43, 0x1d, 0xc8, 0x35, 0x44,
+        0xbf, 0xd5, 0x06, 0x2c, 0xac, 0x18, 0x3c, 0xbb, 0xc6, 0x77, 0x99, 0x2f, 0x4e, 0x71, 0xcd,
+        0x7a, 0x9b, 0x93, 0xc7, 0x08, 0xa3, 0x71, 0x89, 0xb5, 0xb2, 0x04, 0xbe, 0x69, 0x22, 0xf3,
+        0x66, 0xb8, 0xa9, 0xc6, 0x5e, 0x7c, 0x45, 0xf6, 0x2f, 0x8a, 0xa9, 0x3e, 0xee, 0x6f, 0x92,
+        0x2a, 0x9c, 0x91, 0xe2, 0x1d, 0x4a, 0x4e, 0x4a, 0xb4, 0xcc, 0x87, 0xd2, 0x85, 0x5f};
 
 const RpcHardwareInfo kRpcHardwareInfo = {.versionNumber = 3};
 
@@ -640,14 +922,87 @@
     ASSERT_FALSE(*result) << "DICE Chain is proper";
 }
 
+TEST(RemoteProvUtils, csrHasUdsCerts) {
+    auto csr = hwtrust::Csr::validate(kCsrWithUdsCerts, hwtrust::DiceChain::Kind::kVsr16,
+                                      false /*isFactory*/, false /*allowAnyMode*/,
+                                      deviceSuffix(DEFAULT_INSTANCE_NAME));
+    ASSERT_TRUE(csr.ok()) << csr.error().message();
+    ASSERT_TRUE(csr->hasUdsCerts());
+}
+
+TEST(RemoteProvUtils, csrDoesntHaveUdsCerts) {
+    auto csr = hwtrust::Csr::validate(kCsrWithoutUdsCerts, hwtrust::DiceChain::Kind::kVsr16,
+                                      false /*isFactory*/, false /*allowAnyMode*/,
+                                      deviceSuffix(DEFAULT_INSTANCE_NAME));
+    ASSERT_TRUE(csr.ok()) << csr.error().message();
+    ASSERT_FALSE(csr->hasUdsCerts());
+}
+
+TEST(RemoteProvUtils, csrHasCorrectChallenge) {
+    auto csr = hwtrust::Csr::validate(kCsrWithoutUdsCerts, hwtrust::DiceChain::Kind::kVsr16,
+                                      false /*isFactory*/, false /*allowAnyMode*/,
+                                      deviceSuffix(DEFAULT_INSTANCE_NAME));
+    ASSERT_TRUE(csr.ok()) << csr.error().message();
+
+    auto equal = csr->compareChallenge(kChallenge);
+    ASSERT_TRUE(equal.ok()) << equal.error().message();
+
+    ASSERT_TRUE(*equal) << kErrorChallengeMismatch;
+
+    auto zeroes = std::vector<uint8_t>(32, 0);
+    auto notEqual = csr->compareChallenge(zeroes);
+    ASSERT_TRUE(notEqual.ok()) << notEqual.error().message();
+
+    ASSERT_FALSE(*notEqual) << "ERROR: challenges are not different";
+}
+
+TEST(RemoteProvUtils, csrHasCorrectKeysToSign) {
+    auto csr = hwtrust::Csr::validate(kCsrWithoutUdsCerts, hwtrust::DiceChain::Kind::kVsr16,
+                                      false /*isFactory*/, false /*allowAnyMode*/,
+                                      deviceSuffix(DEFAULT_INSTANCE_NAME));
+    ASSERT_TRUE(csr.ok()) << csr.error().message();
+
+    auto equal = csr->compareKeysToSign(kKeysToSignForCsrWithoutUdsCerts);
+    ASSERT_TRUE(equal.ok()) << equal.error().message();
+    ASSERT_TRUE(*equal) << kErrorKeysToSignMismatch;
+
+    auto zeroes = std::vector<uint8_t>(kKeysToSignForCsrWithoutUdsCerts.size(), 0);
+    auto notEqual = csr->compareKeysToSign(zeroes);
+    ASSERT_TRUE(notEqual.ok()) << notEqual.error().message();
+    ASSERT_FALSE(*notEqual) << kErrorKeysToSignMismatch;
+}
+
+TEST(RemoteProvUtilsTest, allowDegenerateDiceChainWhenDegenerate) {
+    auto [keysToSignPtr, _, errMsg] = cppbor::parse(kKeysToSignForCsrWithDegenerateDiceChain);
+    ASSERT_TRUE(keysToSignPtr) << "Error: " << errMsg;
+
+    const auto keysToSign = keysToSignPtr->asArray();
+    auto csr = verifyFactoryCsr(*keysToSign, kCsrWithDegenerateDiceChain, kRpcHardwareInfo,
+                                DEFAULT_INSTANCE_NAME, kChallenge,
+                                /*allowDegenerate=*/true, /*requireUdsCerts=*/false);
+    ASSERT_TRUE(csr) << csr.message();
+}
+
+TEST(RemoteProvUtilsTest, disallowDegenerateDiceChainWhenDegenerate) {
+    auto [keysToSignPtr, _, errMsg] = cppbor::parse(kKeysToSignForCsrWithDegenerateDiceChain);
+    ASSERT_TRUE(keysToSignPtr) << "Error: " << errMsg;
+
+    const auto keysToSign = keysToSignPtr->asArray();
+    auto csr = verifyFactoryCsr(*keysToSign, kCsrWithDegenerateDiceChain, kRpcHardwareInfo,
+                                DEFAULT_INSTANCE_NAME, kChallenge,
+                                /*allowDegenerate=*/false, /*requireUdsCerts=*/false);
+    ASSERT_FALSE(csr);
+    ASSERT_THAT(csr.message(), testing::HasSubstr(kErrorDiceChainIsDegenerate));
+}
+
 TEST(RemoteProvUtilsTest, requireUdsCertsWhenPresent) {
     auto [keysToSignPtr, _, errMsg] = cppbor::parse(kKeysToSignForCsrWithUdsCerts);
     ASSERT_TRUE(keysToSignPtr) << "Error: " << errMsg;
 
     const auto keysToSign = keysToSignPtr->asArray();
-    auto csr =
-            verifyFactoryCsr(*keysToSign, kCsrWithUdsCerts, kRpcHardwareInfo, "default", kChallenge,
-                             /*allowDegenerate=*/false, /*requireUdsCerts=*/true);
+    auto csr = verifyFactoryCsr(*keysToSign, kCsrWithUdsCerts, kRpcHardwareInfo,
+                                DEFAULT_INSTANCE_NAME, kChallenge,
+                                /*allowDegenerate=*/false, /*requireUdsCerts=*/true);
     ASSERT_TRUE(csr) << csr.message();
 }
 
@@ -667,13 +1022,11 @@
                                 DEFAULT_INSTANCE_NAME, kChallenge, /*allowDegenerate=*/false,
                                 /*requireUdsCerts=*/true);
     ASSERT_FALSE(csr);
-    ASSERT_THAT(csr.message(), testing::HasSubstr("UdsCerts must not be empty"));
+    ASSERT_THAT(csr.message(), testing::HasSubstr(kErrorUdsCertsAreRequired));
 }
 
 TEST(RemoteProvUtilsTest, dontRequireUdsCertsWhenNotPresent) {
-    auto [keysToSignPtr, _, errMsg] = cppbor::parse(
-            kKeysToSignForCsrWithoutUdsCerts.data(),
-            kKeysToSignForCsrWithoutUdsCerts.data() + kKeysToSignForCsrWithoutUdsCerts.size());
+    auto [keysToSignPtr, _, errMsg] = cppbor::parse(kKeysToSignForCsrWithoutUdsCerts);
     ASSERT_TRUE(keysToSignPtr) << "Error: " << errMsg;
 
     const auto* keysToSign = keysToSignPtr->asArray();
@@ -683,6 +1036,42 @@
     ASSERT_TRUE(csr) << csr.message();
 }
 
+TEST(RemoteProvUtilsTest, compareRootPublicKeysInDiceChains) {
+    ASSERT_NE(kCsrWithSharedUdsRoot1, kCsrWithSharedUdsRoot2);
+    ASSERT_NE(kCsrWithUdsCerts, kCsrWithSharedUdsRoot1);
+
+    auto equal = compareRootPublicKeysInDiceChains(kCsrWithSharedUdsRoot1, DEFAULT_INSTANCE_NAME,
+                                                   kCsrWithSharedUdsRoot2, DEFAULT_INSTANCE_NAME);
+    ASSERT_TRUE(equal) << equal.message();
+    ASSERT_TRUE(*equal) << "Root public keys in DICE chains do not match.";
+
+    auto notEqual = compareRootPublicKeysInDiceChains(kCsrWithSharedUdsRoot1, DEFAULT_INSTANCE_NAME,
+                                                      kCsrWithUdsCerts, DEFAULT_INSTANCE_NAME);
+    ASSERT_TRUE(notEqual) << notEqual.message();
+    ASSERT_FALSE(*notEqual) << "Root public keys in DICE chains match.";
+}
+
+TEST(RemoteProvUtilsTest, componentNameInLeafCertificateOfDiceChainContainsKeyMint) {
+    auto result = verifyComponentNameInKeyMintDiceChain(kCsrWithKeyMintInComponentName);
+    ASSERT_TRUE(result) << result.message();
+    ASSERT_TRUE(*result) << "Leaf Certificate in CSR does not contain 'keymint' in component name";
+
+    auto result2 = verifyComponentNameInKeyMintDiceChain(kCsrWithUdsCerts);
+    ASSERT_TRUE(result2) << result2.message();
+    ASSERT_FALSE(*result2) << "Leaf Certificate in CSR contains 'keymint' in component name";
+}
+
+TEST(RemoteProvUtilsTest, checkModeOnCertificatesInDiceChain) {
+    auto hasNonNormalMode = hasNonNormalModeInDiceChain(kCsrWithDebugMode, DEFAULT_INSTANCE_NAME);
+    ASSERT_TRUE(hasNonNormalMode) << hasNonNormalMode.message();
+    ASSERT_TRUE(*hasNonNormalMode);
+
+    auto hasNonNormalModeInDiceChain2 =
+            hasNonNormalModeInDiceChain(kCsrWithUdsCerts, DEFAULT_INSTANCE_NAME);
+    ASSERT_TRUE(hasNonNormalModeInDiceChain2) << hasNonNormalModeInDiceChain2.message();
+    ASSERT_FALSE(*hasNonNormalModeInDiceChain2);
+}
+
 TEST(RemoteProvUtilsTest, parseFullyQualifiedInstanceNames) {
     ASSERT_EQ(deviceSuffix(RKPVM_INSTANCE_NAME), "avf");
     ASSERT_EQ(deviceSuffix(DEFAULT_INSTANCE_NAME), "default");
diff --git a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index 5467679..810cc38 100644
--- a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -151,20 +151,24 @@
     return corruptChain.encode();
 }
 
-bool matching_keymint_device(const string& rp_name, std::shared_ptr<IKeyMintDevice>* keyMint) {
-    auto rp_suffix = deviceSuffix(rp_name);
+template <class T>
+auto getHandle(const string& serviceName) {
+    ::ndk::SpAIBinder binder(AServiceManager_waitForService(serviceName.c_str()));
+    return T::fromBinder(binder);
+}
 
-    vector<string> km_names = ::android::getAidlHalInstanceNames(IKeyMintDevice::descriptor);
-    for (const string& km_name : km_names) {
+std::shared_ptr<IKeyMintDevice> matchingKeyMintDevice(const string& rpcName) {
+    auto rpcSuffix = deviceSuffix(rpcName);
+
+    vector<string> kmNames = ::android::getAidlHalInstanceNames(IKeyMintDevice::descriptor);
+    for (const string& kmName : kmNames) {
         // If the suffix of the KeyMint instance equals the suffix of the
         // RemotelyProvisionedComponent instance, assume they match.
-        if (deviceSuffix(km_name) == rp_suffix && AServiceManager_isDeclared(km_name.c_str())) {
-            ::ndk::SpAIBinder binder(AServiceManager_waitForService(km_name.c_str()));
-            *keyMint = IKeyMintDevice::fromBinder(binder);
-            return true;
+        if (deviceSuffix(kmName) == rpcSuffix && AServiceManager_isDeclared(kmName.c_str())) {
+            getHandle<IKeyMintDevice>(kmName);
         }
     }
-    return false;
+    return nullptr;
 }
 
 }  // namespace
@@ -173,8 +177,7 @@
   public:
     virtual void SetUp() override {
         if (AServiceManager_isDeclared(GetParam().c_str())) {
-            ::ndk::SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str()));
-            provisionable_ = IRemotelyProvisionedComponent::fromBinder(binder);
+            provisionable_ = getHandle<IRemotelyProvisionedComponent>(GetParam());
         }
         ASSERT_NE(provisionable_, nullptr);
         auto status = provisionable_->getHardwareInfo(&rpcHardwareInfo);
@@ -183,10 +186,10 @@
             if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
                 GTEST_SKIP() << "The RKP VM is not supported on this system.";
             }
-            int apiLevel = get_vsr_api_level();
-            if (apiLevel < __ANDROID_API_V__) {
-                GTEST_SKIP() << "The RKP VM is supported only on V+ devices. Vendor API level: "
-                             << apiLevel;
+            int vendorApiLevel = get_vendor_api_level();
+            if (vendorApiLevel < __ANDROID_API_V__) {
+                GTEST_SKIP() << "The RKP VM is supported only on vendor API level >= 202404. This "
+                             << "device has vendor API level: " << vendorApiLevel;
             }
         }
         ASSERT_TRUE(status.isOk());
@@ -210,9 +213,7 @@
     std::set<std::string> uniqueIds;
     for (auto hal : ::android::getAidlHalInstanceNames(IRemotelyProvisionedComponent::descriptor)) {
         ASSERT_TRUE(AServiceManager_isDeclared(hal.c_str()));
-        ::ndk::SpAIBinder binder(AServiceManager_waitForService(hal.c_str()));
-        std::shared_ptr<IRemotelyProvisionedComponent> rpc =
-                IRemotelyProvisionedComponent::fromBinder(binder);
+        auto rpc = getHandle<IRemotelyProvisionedComponent>(hal);
         ASSERT_NE(rpc, nullptr);
 
         RpcHardwareInfo hwInfo;
@@ -237,11 +238,91 @@
  * on the device.
  */
 // @VsrTest = 3.10-015
+// @VsrTest = 3.10-018.001
 TEST(NonParameterizedTests, requireDiceOnDefaultInstanceIfStrongboxPresent) {
-    int vsr_api_level = get_vsr_api_level();
-    if (vsr_api_level < 35) {
-        GTEST_SKIP() << "Applies only to VSR API level 35 or newer, this device is: "
-                     << vsr_api_level;
+    int vendor_api_level = get_vendor_api_level();
+    if (vendor_api_level < __ANDROID_API_V__) {
+        GTEST_SKIP() << "Applies only to vendor API level >= 202404, but this device is: "
+                     << vendor_api_level;
+    }
+
+    if (!AServiceManager_isDeclared(KEYMINT_STRONGBOX_INSTANCE_NAME.c_str())) {
+        GTEST_SKIP() << "Strongbox is not present on this device.";
+    }
+
+    auto rpc = getHandle<IRemotelyProvisionedComponent>(DEFAULT_INSTANCE_NAME);
+    ASSERT_NE(rpc, nullptr);
+
+    bytevec challenge = randomBytes(64);
+    bytevec csr;
+    auto status = rpc->generateCertificateRequestV2({} /* keysToSign */, challenge, &csr);
+    EXPECT_TRUE(status.isOk()) << status.getDescription();
+
+    auto result = isCsrWithProperDiceChain(csr, DEFAULT_INSTANCE_NAME);
+    ASSERT_TRUE(result) << result.message();
+    ASSERT_TRUE(*result);
+}
+
+/**
+ * Verify that if a protected VM (also called `avf` or RKP VM) implementation exists, then the
+ * protected VM and the primary KeyMint (also called 'default') implementation's DICE certificate
+ * chain has the same root public key, i.e., the same UDS public key
+ */
+// @VsrTest = 7.1-003.001
+TEST(NonParameterizedTests, equalUdsPubInDiceCertChainForRkpVmAndPrimaryKeyMintInstances) {
+    int vendorApiLevel = get_vendor_api_level();
+    if (vendorApiLevel < 202504 && !AServiceManager_isDeclared(RKPVM_INSTANCE_NAME.c_str())) {
+        GTEST_SKIP() << "The RKP VM (" << RKPVM_INSTANCE_NAME << ") is not present on this device.";
+    }
+    if (vendorApiLevel >= 202504) {
+        ASSERT_TRUE(AServiceManager_isDeclared(RKPVM_INSTANCE_NAME.c_str()));
+    }
+
+    auto rkpVmRpc = getHandle<IRemotelyProvisionedComponent>(RKPVM_INSTANCE_NAME);
+    ASSERT_NE(rkpVmRpc, nullptr) << "The RKP VM (" << RKPVM_INSTANCE_NAME
+                                 << ") RPC is unavailable.";
+
+    RpcHardwareInfo hardwareInfo;
+    auto status = rkpVmRpc->getHardwareInfo(&hardwareInfo);
+    if (!status.isOk()) {
+        GTEST_SKIP() << "The RKP VM is not supported on this system.";
+    }
+
+    bytevec rkpVmChallenge = randomBytes(MAX_CHALLENGE_SIZE);
+    bytevec rkpVmCsr;
+    auto rkpVmStatus =
+            rkpVmRpc->generateCertificateRequestV2({} /* keysToSign */, rkpVmChallenge, &rkpVmCsr);
+    ASSERT_TRUE(rkpVmStatus.isOk()) << rkpVmStatus.getDescription();
+
+    auto primaryKeyMintRpc = getHandle<IRemotelyProvisionedComponent>(DEFAULT_INSTANCE_NAME);
+    ASSERT_NE(primaryKeyMintRpc, nullptr)
+            << "The Primary KeyMint (" << DEFAULT_INSTANCE_NAME << ") RPC is unavailable.";
+
+    bytevec primaryKeyMintChallenge = randomBytes(MAX_CHALLENGE_SIZE);
+    bytevec primaryKeyMintCsr;
+    auto primaryKeyMintStatus = primaryKeyMintRpc->generateCertificateRequestV2(
+            {} /* keysToSign */, primaryKeyMintChallenge, &primaryKeyMintCsr);
+    ASSERT_TRUE(primaryKeyMintStatus.isOk()) << primaryKeyMintStatus.getDescription();
+
+    auto equal = compareRootPublicKeysInDiceChains(rkpVmCsr, RKPVM_INSTANCE_NAME, primaryKeyMintCsr,
+                                                   DEFAULT_INSTANCE_NAME);
+    ASSERT_TRUE(equal) << equal.message();
+    ASSERT_TRUE(*equal) << "Primary KeyMint and RKP VM RPCs have different UDS public keys";
+}
+
+/**
+ * Suppose that there is a StrongBox KeyMint instance on the device.
+ *
+ * Then, this test verifies that "keymint" is a substring of the component name in the configuration
+ * descriptor in the leaf certificate of the DICE chain for the primary ("default") KeyMint
+ * instance.
+ */
+// @VsrTest = 3.10-018.003
+TEST(NonParameterizedTests, componentNameInConfigurationDescriptorForPrimaryKeyMintInstance) {
+    int vendor_api_level = get_vendor_api_level();
+    if (vendor_api_level < 202504) {
+        GTEST_SKIP() << "Applies only to vendor API level >= 202504, but this device is: "
+                     << vendor_api_level;
     }
 
     if (!AServiceManager_isDeclared(KEYMINT_STRONGBOX_INSTANCE_NAME.c_str())) {
@@ -258,7 +339,7 @@
     auto status = rpc->generateCertificateRequestV2({} /* keysToSign */, challenge, &csr);
     EXPECT_TRUE(status.isOk()) << status.getDescription();
 
-    auto result = isCsrWithProperDiceChain(csr, DEFAULT_INSTANCE_NAME);
+    auto result = verifyComponentNameInKeyMintDiceChain(csr);
     ASSERT_TRUE(result) << result.message();
     ASSERT_TRUE(*result);
 }
@@ -336,9 +417,8 @@
  */
 TEST_P(GenerateKeyTests, generateAndUseEcdsaP256Key_prodMode) {
     // See if there is a matching IKeyMintDevice for this IRemotelyProvisionedComponent.
-    std::shared_ptr<IKeyMintDevice> keyMint;
-    if (!matching_keymint_device(GetParam(), &keyMint)) {
-        // No matching IKeyMintDevice.
+    auto keyMint = matchingKeyMintDevice(GetParam());
+    if (!keyMint) {
         GTEST_SKIP() << "Skipping key use test as no matching KeyMint device found";
         return;
     }
@@ -416,6 +496,32 @@
     check_maced_pubkey(macedPubKey, testMode, nullptr);
 }
 
+/**
+ * Generate and validate at most 2**16 production-mode keys. This aims to catch issues that do not
+ * deterministically show up. In practice, this will test far fewer keys, but a certain number are
+ * tested at a minimum.
+ */
+TEST_P(GenerateKeyTests, generateManyEcdsaP256KeysInProdMode) {
+    const auto start = std::chrono::steady_clock::now();
+    const auto time_bound = std::chrono::seconds(5);
+    const auto upper_bound = 1 << 16;
+    const auto lower_bound = 1 << 8;
+    for (auto iteration = 0; iteration < upper_bound; iteration++) {
+        MacedPublicKey macedPubKey;
+        bytevec privateKeyBlob;
+        bool testMode = false;
+        auto status =
+                provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
+        ASSERT_TRUE(status.isOk());
+        vector<uint8_t> coseKeyData;
+        check_maced_pubkey(macedPubKey, testMode, &coseKeyData);
+        const auto current_time = std::chrono::steady_clock::now() - start;
+        if (iteration >= lower_bound && current_time >= time_bound) {
+            break;
+        }
+    }
+}
+
 class CertificateRequestTestBase : public VtsRemotelyProvisionedComponentTests {
   protected:
     CertificateRequestTestBase()
@@ -743,6 +849,37 @@
 };
 
 /**
+ * Check that ro.boot.vbmeta.device_state is not "locked" or ro.boot.verifiedbootstate
+ * is not "green" if and only if the mode on at least one certificate in the DICE chain
+ * is non-normal.
+ */
+TEST_P(CertificateRequestV2Test, unlockedBootloaderStatesImpliesNonnormalDiceChain) {
+    auto challenge = randomBytes(MAX_CHALLENGE_SIZE);
+    bytevec csr;
+    auto status =
+            provisionable_->generateCertificateRequestV2({} /* keysToSign */, challenge, &csr);
+    ASSERT_TRUE(status.isOk()) << status.getDescription();
+
+    auto isProper = isCsrWithProperDiceChain(csr, GetParam());
+    ASSERT_TRUE(isProper) << isProper.message();
+    if (!*isProper) {
+        GTEST_SKIP() << "Skipping test: Only a proper DICE chain has a mode set.";
+    }
+
+    auto nonNormalMode = hasNonNormalModeInDiceChain(csr, GetParam());
+    ASSERT_TRUE(nonNormalMode) << nonNormalMode.message();
+
+    auto deviceState = ::android::base::GetProperty("ro.boot.vbmeta.device_state", "");
+    auto verifiedBootState = ::android::base::GetProperty("ro.boot.verifiedbootstate", "");
+
+    ASSERT_EQ(deviceState != "locked" || verifiedBootState != "green", *nonNormalMode)
+            << "ro.boot.vbmeta.device_state = '" << deviceState
+            << "' and ro.boot.verifiedbootstate = '" << verifiedBootState << "', but it is "
+            << *nonNormalMode
+            << " that the DICE chain has a certificate with a non-normal mode set.";
+}
+
+/**
  * Generate an empty certificate request with all possible length of challenge, and decrypt and
  * verify the structure and content.
  */
@@ -905,9 +1042,8 @@
 // @VsrTest = 3.10-015
 TEST_P(CertificateRequestV2Test, DeviceInfo) {
     // See if there is a matching IKeyMintDevice for this IRemotelyProvisionedComponent.
-    std::shared_ptr<IKeyMintDevice> keyMint;
-    if (!matching_keymint_device(GetParam(), &keyMint)) {
-        // No matching IKeyMintDevice.
+    std::shared_ptr<IKeyMintDevice> keyMint = matchingKeyMintDevice(GetParam());
+    if (!keyMint) {
         GTEST_SKIP() << "Skipping key use test as no matching KeyMint device found";
         return;
     }
@@ -973,6 +1109,7 @@
 
     std::unique_ptr<cppbor::Array> csrPayload = std::move(*result);
     ASSERT_TRUE(csrPayload);
+    ASSERT_TRUE(csrPayload->size() > 2);
 
     auto deviceInfo = csrPayload->get(2)->asMap();
     ASSERT_TRUE(deviceInfo);
@@ -1018,10 +1155,10 @@
 TEST_P(VsrRequirementTest, VsrEnforcementTest) {
     RpcHardwareInfo hwInfo;
     ASSERT_TRUE(provisionable_->getHardwareInfo(&hwInfo).isOk());
-    int vsr_api_level = get_vsr_api_level();
-    if (vsr_api_level < 34) {
-        GTEST_SKIP() << "Applies only to VSR API level 34 or newer, this device is: "
-                     << vsr_api_level;
+    int vendor_api_level = get_vendor_api_level();
+    if (vendor_api_level < __ANDROID_API_U__) {
+        GTEST_SKIP() << "Applies only to vendor API level >= 34, but this device is: "
+                     << vendor_api_level;
     }
     EXPECT_GE(hwInfo.versionNumber, 3)
             << "VSR 14+ requires IRemotelyProvisionedComponent v3 or newer.";
diff --git a/security/secretkeeper/aidl/Android.bp b/security/secretkeeper/aidl/Android.bp
index d282621..f0b7894 100644
--- a/security/secretkeeper/aidl/Android.bp
+++ b/security/secretkeeper/aidl/Android.bp
@@ -25,7 +25,7 @@
         "android.hardware.security.authgraph-V1",
     ],
     stability: "vintf",
-    frozen: true,
+    frozen: false,
     backend: {
         java: {
             enabled: true,
@@ -88,6 +88,6 @@
 rust_defaults {
     name: "secretkeeper_use_latest_hal_aidl_rust",
     rustlibs: [
-        "android.hardware.security.secretkeeper-V1-rust",
+        "android.hardware.security.secretkeeper-V2-rust",
     ],
 }
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ISecretkeeper.aidl b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ISecretkeeper.aidl
index 8ce37cd..ed48480 100644
--- a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ISecretkeeper.aidl
+++ b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ISecretkeeper.aidl
@@ -38,6 +38,7 @@
   byte[] processSecretManagementRequest(in byte[] request);
   void deleteIds(in android.hardware.security.secretkeeper.SecretId[] ids);
   void deleteAll();
+  android.hardware.security.secretkeeper.PublicKey getSecretkeeperIdentity();
   const int ERROR_UNKNOWN_KEY_ID = 1;
   const int ERROR_INTERNAL_ERROR = 2;
   const int ERROR_REQUEST_MALFORMED = 3;
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/PublicKey.aidl
similarity index 89%
copy from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
copy to security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/PublicKey.aidl
index 1e304ab..f690abf 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
+++ b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/PublicKey.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2024 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -31,7 +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.see.hwcrypto.types;
-enum ProtectionId {
-  WIDEVINE_OUTPUT_BUFFER = 1,
+package android.hardware.security.secretkeeper;
+/* @hide */
+@VintfStability
+parcelable PublicKey {
+  byte[] keyMaterial;
 }
diff --git a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl
index b07dba8..91493a1 100644
--- a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl
@@ -17,6 +17,7 @@
 package android.hardware.security.secretkeeper;
 
 import android.hardware.security.authgraph.IAuthGraphKeyExchange;
+import android.hardware.security.secretkeeper.PublicKey;
 import android.hardware.security.secretkeeper.SecretId;
 
 @VintfStability
@@ -101,4 +102,12 @@
      * Delete data of all clients.
      */
     void deleteAll();
+
+    /**
+     * Gets the public key of the secret keeper instance. This should be a CBOR-encoded
+     * COSE_Key, as a PubKeyEd25519 / PubKeyECDSA256 / PubKeyECDSA384, as defined in
+     * generateCertificateRequestV2.cddl. Clients must have a trusted way of ensuring
+     * this key is valid.
+     */
+    PublicKey getSecretkeeperIdentity();
 }
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/CipherModeParameters.aidl b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/PublicKey.aidl
similarity index 69%
copy from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/CipherModeParameters.aidl
copy to security/secretkeeper/aidl/android/hardware/security/secretkeeper/PublicKey.aidl
index bfa5daa..ccc89b3 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/CipherModeParameters.aidl
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/PublicKey.aidl
@@ -1,6 +1,5 @@
-
 /*
- * Copyright 2024 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,11 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.hardware.security.see.hwcrypto.types;
 
-/*
- * Type encapsulating nonce used on non-authenticated AES symmetric encryption.
+package android.hardware.security.secretkeeper;
+
+/**
+ * Contents of a pubkey.
+ * @hide
  */
-parcelable CipherModeParameters {
-    byte[16] nonce;
+@VintfStability
+parcelable PublicKey {
+    /**
+     * CBOR-encoded COSE_Key
+     */
+    byte[] keyMaterial;
 }
diff --git a/security/secretkeeper/aidl/vts/Android.bp b/security/secretkeeper/aidl/vts/Android.bp
index be07a7b..c84afae 100644
--- a/security/secretkeeper/aidl/vts/Android.bp
+++ b/security/secretkeeper/aidl/vts/Android.bp
@@ -38,6 +38,7 @@
     srcs: ["secretkeeper_test_client.rs"],
     defaults: [
         "rdroidtest.defaults",
+        "secretkeeper_use_latest_hal_aidl_rust",
     ],
     test_suites: [
         "general-tests",
@@ -45,7 +46,6 @@
     ],
     test_config: "AndroidTest.xml",
     rustlibs: [
-        "android.hardware.security.secretkeeper-V1-rust",
         "libauthgraph_boringssl",
         "libauthgraph_core",
         "libauthgraph_wire",
@@ -66,9 +66,10 @@
 rust_binary {
     name: "secretkeeper_cli",
     srcs: ["secretkeeper_cli.rs"],
+    defaults: ["secretkeeper_use_latest_hal_aidl_rust"],
     lints: "android",
-    rlibs: [
-        "android.hardware.security.secretkeeper-V1-rust",
+    prefer_rlib: true,
+    rustlibs: [
         "libanyhow",
         "libauthgraph_boringssl",
         "libauthgraph_core",
diff --git a/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs b/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
index 449a99a..b944865 100644
--- a/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
+++ b/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
@@ -16,6 +16,7 @@
 
 use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::ISecretkeeper::ISecretkeeper;
 use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::SecretId::SecretId;
+use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::PublicKey::PublicKey;
 use authgraph_vts_test as ag_vts;
 use authgraph_boringssl as boring;
 use authgraph_core::key;
@@ -70,20 +71,32 @@
     0x06, 0xAC, 0x36, 0x8B, 0x3C, 0x95, 0x50, 0x16, 0x67, 0x71, 0x65, 0x26, 0xEB, 0xD0, 0xC3, 0x98,
 ]);
 
-// Android expects the public key of Secretkeeper instance to be present in the Linux device tree.
+// Android expects the public key of Secretkeeper instance to be available either
+// a) by being present in the Linux device tree (prior to version 2 of the secretkeeper HAL), or
+// b) via the `getSecretKeeperIdentity` operation from v2 onwards.
 // This allows clients to (cryptographically) verify that they are indeed talking to the real
 // secretkeeper.
 // Note that this is the identity of the `default` instance (and not `nonsecure`)!
-fn get_secretkeeper_identity() -> Option<CoseKey> {
-    let path = Path::new(SECRETKEEPER_KEY_HOST_DT);
-    if path.exists() {
-        let key = fs::read(path).unwrap();
-        let mut key = CoseKey::from_slice(&key).unwrap();
-        key.canonicalize(CborOrdering::Lexicographic);
-        Some(key)
+fn get_secretkeeper_identity(instance: &str) -> Option<CoseKey> {
+    let sk = get_connection(instance);
+    let key_material = if sk.getInterfaceVersion().expect("Error getting sk interface version") >= 2 {
+        let PublicKey { keyMaterial } = sk.getSecretkeeperIdentity().expect("Error calling getSecretkeeperIdentity");
+        Some(keyMaterial)
     } else {
-        None
-    }
+        let path = Path::new(SECRETKEEPER_KEY_HOST_DT);
+        if path.exists() {
+            let key_material = fs::read(path).unwrap();
+            Some(key_material)
+        } else {
+            None
+        }
+    };
+
+    key_material.map(|km| {
+        let mut cose_key = CoseKey::from_slice(&km).expect("Error deserializing CoseKey from key material");
+        cose_key.canonicalize(CborOrdering::Lexicographic);
+        cose_key
+    })
 }
 
 fn get_instances() -> Vec<(String, String)> {
@@ -760,12 +773,12 @@
 }
 
 // This test checks that the identity of Secretkeeper (in context of AuthGraph key exchange) is
-// same as the one advertized in Linux device tree. This is only expected from `default` instance.
+// same as the one either a) advertized in Linux device tree or b) retrieved from SK itself
+// from (HAL v2 onwards). This is only expected from `default` instance.
 #[rdroidtest(get_instances())]
-#[ignore_if(|p| p != "default")]
 fn secretkeeper_check_identity(instance: String) {
-    let sk_key = get_secretkeeper_identity()
-        .expect("Failed to extract identity of default instance from device tree");
+    let sk_key = get_secretkeeper_identity(&instance)
+        .expect("Failed to extract identity of default instance");
     // Create a session with this expected identity. This succeeds only if the identity used by
     // Secretkeeper is sk_key.
     let _ = SkClient::with_expected_sk_identity(&instance, sk_key).unwrap();
diff --git a/security/secretkeeper/default/Android.bp b/security/secretkeeper/default/Android.bp
index 799188f..134afc9 100644
--- a/security/secretkeeper/default/Android.bp
+++ b/security/secretkeeper/default/Android.bp
@@ -28,9 +28,9 @@
     vendor_available: true,
     defaults: [
         "authgraph_use_latest_hal_aidl_rust",
+        "secretkeeper_use_latest_hal_aidl_rust",
     ],
     rustlibs: [
-        "android.hardware.security.secretkeeper-V1-rust",
         "libauthgraph_boringssl",
         "libauthgraph_core",
         "libauthgraph_hal",
@@ -50,9 +50,9 @@
     prefer_rlib: true,
     defaults: [
         "authgraph_use_latest_hal_aidl_rust",
+        "secretkeeper_use_latest_hal_aidl_rust",
     ],
     rustlibs: [
-        "android.hardware.security.secretkeeper-V1-rust",
         "libandroid_logger",
         "libbinder_rs",
         "liblog_rust",
diff --git a/security/secretkeeper/default/secretkeeper.xml b/security/secretkeeper/default/secretkeeper.xml
index 40aebe0..699fff0 100644
--- a/security/secretkeeper/default/secretkeeper.xml
+++ b/security/secretkeeper/default/secretkeeper.xml
@@ -19,7 +19,7 @@
 
     <hal format="aidl">
         <name>android.hardware.security.secretkeeper</name>
-        <version>1</version>
+        <version>2</version>
         <interface>
             <name>ISecretkeeper</name>
             <instance>nonsecure</instance>
diff --git a/security/see/hdcp/README.md b/security/see/hdcp/README.md
new file mode 100644
index 0000000..76b8670
--- /dev/null
+++ b/security/see/hdcp/README.md
@@ -0,0 +1,65 @@
+# IHDCPAuthControl as a Trusted HAL service
+
+IHDCPAuthControl is expected to be a service implemented in a TEE.
+We provide a default reference implementation and its integration in Trusty
+as an example.
+
+The VTS test for a Trusted HAL service ought to run in the VM.
+We provide an integration of the VTS test in a Trusty VM,
+and later in a Microdroid VM (b/380632474).
+
+This interface shall not be exposed to the host and thus shall be part of
+the list of excluded interfaces from
+[compatibility_matrices/exclude/fcm_exclude.cpp](../../../compatibility_matrices/exclude/fcm_exclude.cpp)
+
+## 1. Mock Implementation
+
+The mock implementation under default/src/lib.rs is expected to be integrated in a
+TEE. For AOSP testing we offer two virtual device testing options:
+
+- Cuttlefish AVD, where the reference implementation is integrated in an AVF VM, emulating a TEE.
+- Trusty QEMU AVD, where the reference implementation is integrated in a Trusty TEE image (executed in secure world)
+
+### 1.1. Cuttlefish: Integrate in an AVF HAL pVM (Trusty)
+
+In Cuttlefish, we emulate a TEE with an AVF Trusty pVM.
+The VM2TZ IPC is emulated with a vsock port forward utility (b/379582767).
+
+Until vsock port forwarding is supported, the trusty_test_vm is used temporarily.
+(VTS tests and HAL implementation will be in same pVM).
+
+TODO: complete when trusty_hal_vm is created
+
+In order to add the mock HdcpAuthControlService to the trusty_test_vm, make sure
+that `hardware/interfaces/security/see/hdcp/default` is added to the
+trusty_test_vm makefile, by adding it to
+[trusty/device/x86/generic-x86_64/project/generic-x86_64-inc.mk](../../../../../trusty/device/x86/generic-x86_64/project/generic-x86_64-inc.mk)
+
+### 1.2. Trusty QEMU AVD: Integrate as a TA in Trusty TEE
+
+In order to add the mock HdcpAuthControlService to the Trusty TEE, make sure
+that `hardware/interfaces/security/see/hdcp/default` is added to
+[trusty/device/arm/generic-arm64/project/generic-arm-inc.mk](../../../../../trusty/device/arm/generic-arm64/project/generic-arm-inc.mk)
+
+
+## 2. VTS Tests
+
+IHdcpAuthControl service is expected to only be exposed to AVF pVM.
+
+The VTS tests shall verify:
+
+- IHdcpAuthControl cannot be accessed from the Android Host:
+
+   see [aidl/vts/src/host_test.rs](aidl/vts/host_test.rs)
+
+- IHdcpAuthControl can be accessed from an AVF pVM:
+
+   see [aidl/vts/src/vm_test.rs](aidl/vts/src/vm_test.rs)
+   see [aidl/vts/AndroidTest.xml](aidl/vts/AndroidTest.xml)
+
+
+To integrate the VTS test in the trusty_test_vm:
+
+1.
+1. add the test to [hardware/interfaces/security/see/usertests-rust-inc.mk](../usertests-rust-inc.mk)
+
diff --git a/security/see/hdcp/aidl/Android.bp b/security/see/hdcp/aidl/Android.bp
new file mode 100644
index 0000000..ad1db37
--- /dev/null
+++ b/security/see/hdcp/aidl/Android.bp
@@ -0,0 +1,57 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_team: "trendy_team_trusty",
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+aidl_interface {
+    name: "android.hardware.security.see.hdcp",
+    vendor_available: true,
+    srcs: ["android/hardware/security/see/hdcp/*.aidl"],
+    imports: [
+        "android.hardware.drm.common-V1",
+    ],
+    stability: "vintf",
+    frozen: false,
+    backend: {
+        java: {
+            enabled: false,
+        },
+        cpp: {
+            enabled: false,
+        },
+        ndk: {
+            min_sdk_version: "34",
+        },
+        rust: {
+            enabled: true,
+            gen_mockall: true,
+            additional_rustlibs: [
+                "libmockall",
+            ],
+        },
+    },
+}
+
+// A rust_defaults that includes the latest hdcp AIDL library.
+// Modules that depend on hdcp directly can include this rust_defaults to avoid
+// managing dependency versions explicitly.
+rust_defaults {
+    name: "hdcp_use_latest_hal_aidl_rust",
+    rustlibs: [
+        "android.hardware.security.see.hdcp-V1-rust",
+    ],
+}
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl b/security/see/hdcp/aidl/aidl_api/android.hardware.security.see.hdcp/current/android/hardware/security/see/hdcp/IHdcpAuthControl.aidl
similarity index 64%
copy from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
copy to security/see/hdcp/aidl/aidl_api/android.hardware.security.see.hdcp/current/android/hardware/security/see/hdcp/IHdcpAuthControl.aidl
index 5c26cc2..b73d554 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
+++ b/security/see/hdcp/aidl/aidl_api/android.hardware.security.see.hdcp/current/android/hardware/security/see/hdcp/IHdcpAuthControl.aidl
@@ -31,7 +31,28 @@
 // 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.see.hwcrypto;
-interface IHwCryptoOperations {
-  android.hardware.security.see.hwcrypto.CryptoOperationResult[] processCommandList(inout android.hardware.security.see.hwcrypto.CryptoOperationSet[] operations, out android.hardware.security.see.hwcrypto.CryptoOperationErrorAdditionalInfo additionalErrorInfo);
+package android.hardware.security.see.hdcp;
+@VintfStability
+interface IHdcpAuthControl {
+  android.hardware.drm.HdcpLevels getHdcpLevels();
+  void trySetHdcpLevel(in android.hardware.drm.HdcpLevel level);
+  android.hardware.security.see.hdcp.IHdcpAuthControl.PendingHdcpLevelResult getPendingHdcpLevel();
+  parcelable HalErrorCode {
+    const int NO_ERROR = 0;
+    const int GENERIC_ERROR = (-1) /* -1 */;
+    const int BAD_STATE = (-2) /* -2 */;
+    const int UNSUPPORTED = (-3) /* -3 */;
+    const int SERIALIZATION_ERROR = (-4) /* -4 */;
+    const int ALLOCATION_ERROR = (-5) /* -5 */;
+    const int BAD_PARAMETER = (-7) /* -7 */;
+    const int UNAUTHORIZED = (-8) /* -8 */;
+  }
+  parcelable PendingHdcpLevelResult {
+    android.hardware.security.see.hdcp.IHdcpAuthControl.PendingHdcpLevelResult.Status status;
+    android.hardware.drm.HdcpLevel level;
+    enum Status {
+      NONE,
+      PENDING,
+    }
+  }
 }
diff --git a/security/see/hdcp/aidl/android/hardware/security/see/hdcp/IHdcpAuthControl.aidl b/security/see/hdcp/aidl/android/hardware/security/see/hdcp/IHdcpAuthControl.aidl
new file mode 100644
index 0000000..b9a1fe5
--- /dev/null
+++ b/security/see/hdcp/aidl/android/hardware/security/see/hdcp/IHdcpAuthControl.aidl
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.security.see.hdcp;
+
+/**
+ * IHdcpAuthControl is used by the OEMCrypto Trusted Application to interact
+ * with a HDCP Encryption Trusted Application in order to control the
+ * HDCP Authentication Levels.
+ */
+@VintfStability
+interface IHdcpAuthControl {
+    /*
+     * Service error codes. Will be returned as service specific errors.
+     */
+    parcelable HalErrorCode {
+        /* Success */
+        const int NO_ERROR = 0;
+
+        /* Generic error */
+        const int GENERIC_ERROR = -1;
+
+        /* Desired operation cannot be performed because of the server current state */
+        const int BAD_STATE = -2;
+
+        /* Operation or parameters are not supported by the server */
+        const int UNSUPPORTED = -3;
+
+        /* Error encountered when parsing parameters */
+        const int SERIALIZATION_ERROR = -4;
+
+        /* Server ran out of memory when performing operation */
+        const int ALLOCATION_ERROR = -5;
+
+        /* Bad parameter supplied for the desired operation */
+        const int BAD_PARAMETER = -7;
+
+        /* Caller is not authorized to make this call */
+        const int UNAUTHORIZED = -8;
+    }
+    /**
+     * Result returned from the getPendingHdcpLevelResult API.
+     */
+    parcelable PendingHdcpLevelResult {
+        enum Status {
+            /**
+             * No pending HdcpLevel request
+             */
+            NONE,
+            /**
+             * a HdcpLevel request is pending, its level is provided in the
+             * |level| attribute
+             */
+            PENDING,
+        }
+        Status status;
+        android.hardware.drm.HdcpLevel level;
+    }
+
+    /**
+     * Return the currently negotiated and max supported HDCP levels.
+     *
+     * The current level is based on the display(s) the device is connected to.
+     * If multiple HDCP-capable displays are simultaneously connected to
+     * separate interfaces, this method returns the lowest negotiated HDCP level
+     * of all interfaces.
+     *
+     * The maximum HDCP level is the highest level that can potentially be
+     * negotiated. It is a constant for any device, i.e. it does not depend on
+     * downstream receiving devices that could be connected. For example, if
+     * the device has HDCP 1.x keys and is capable of negotiating HDCP 1.x, but
+     * does not have HDCP 2.x keys, then the maximum HDCP capability would be
+     * reported as 1.x. If multiple HDCP-capable interfaces are present, it
+     * indicates the highest of the maximum HDCP levels of all interfaces.
+     *
+     * This method should only be used for informational purposes, not for
+     * enforcing compliance with HDCP requirements. Trusted enforcement of HDCP
+     * policies must be handled by the DRM system.
+     *
+     * @return HdcpLevels parcelable
+     */
+    android.hardware.drm.HdcpLevels getHdcpLevels();
+
+    /**
+     * Attempts to set the device's HDCP auth level to |level|.
+     *
+     * @param level: desired HDCP level
+     *
+     * @return:
+     *     a service specific error based on <code>HalErrorCode</code>,
+     *     specifically:
+     *       + BAD_PARAMETER: when HDCP_UNKNOWN is requested
+     *       + UNSUPPORTED: when |level| is greater than the MaxLevel supported
+     *       + BAD_STATE: when the HDCP's service currentLevel is HDCP_NO_OUTPUT
+     *
+     */
+    void trySetHdcpLevel(in android.hardware.drm.HdcpLevel level);
+
+    /**
+     * Retrieve the pending level currently being processed by the HDCP service.
+     * The pending HDCP protection level might be higher than the level initially
+     * requested. This can occur when multiple applications or services are
+     * using HDCP concurrently, and a higher level is needed to satisfy
+     * all requirements.
+     *
+     * @return:
+     *      PendingHdcpLevelResult on success, which contains a status
+     *      and an optional level; on error a service specific error based on
+     *      <code>HalErrorCode</code> otherwise.
+     *
+     */
+    PendingHdcpLevelResult getPendingHdcpLevel();
+}
diff --git a/security/see/hdcp/aidl/trusty/drm/rust/rules.mk b/security/see/hdcp/aidl/trusty/drm/rust/rules.mk
new file mode 100644
index 0000000..742b6ab
--- /dev/null
+++ b/security/see/hdcp/aidl/trusty/drm/rust/rules.mk
@@ -0,0 +1,39 @@
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+AIDL_DIR := hardware/interfaces/drm/aidl
+
+MODULE_AIDL_FLAGS := \
+	--stability=vintf \
+	--version=1 \
+
+MODULE_CRATE_NAME := android_hardware_drm
+
+MODULE_AIDL_LANGUAGE := rust
+
+MODULE_AIDL_PACKAGE := android/hardware/drm
+
+MODULE_AIDL_INCLUDES := \
+	-I $(AIDL_DIR) \
+
+MODULE_AIDLS := \
+    $(AIDL_DIR)/$(MODULE_AIDL_PACKAGE)/HdcpLevel.aidl   \
+    $(AIDL_DIR)/$(MODULE_AIDL_PACKAGE)/HdcpLevels.aidl   \
+
+include make/aidl.mk
diff --git a/security/see/hdcp/aidl/trusty/hdcp/rust/rules.mk b/security/see/hdcp/aidl/trusty/hdcp/rust/rules.mk
new file mode 100644
index 0000000..beab655
--- /dev/null
+++ b/security/see/hdcp/aidl/trusty/hdcp/rust/rules.mk
@@ -0,0 +1,47 @@
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+AIDL_DIR := hardware/interfaces/security/see/hdcp/aidl
+DRM_AIDL_DIR := hardware/interfaces/drm/aidl
+
+MODULE_AIDL_FLAGS := \
+	--mockall \
+	--version=1 \
+
+MODULE_CRATE_NAME := android_hardware_security_see_hdcp
+
+MODULE_AIDL_LANGUAGE := rust
+
+MODULE_AIDL_PACKAGE := android/hardware/security/see/hdcp
+
+MODULE_AIDL_INCLUDES := \
+	-I $(AIDL_DIR) \
+	-I $(DRM_AIDL_DIR) \
+
+MODULE_AIDLS := \
+    $(AIDL_DIR)/$(MODULE_AIDL_PACKAGE)/IHdcpAuthControl.aidl   \
+
+MODULE_AIDL_RUST_DEPS := \
+	android_hardware_drm
+
+MODULE_LIBRARY_DEPS := \
+	hardware/interfaces/security/see/hdcp/aidl/trusty/drm/rust \
+	$(call FIND_CRATE,mockall) \
+
+include make/aidl.mk
diff --git a/security/see/hdcp/aidl/vts/Android.bp b/security/see/hdcp/aidl/vts/Android.bp
new file mode 100644
index 0000000..eadb9cd
--- /dev/null
+++ b/security/see/hdcp/aidl/vts/Android.bp
@@ -0,0 +1,36 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // 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: ["Android-Apache-2.0"],
+    default_team: "trendy_team_trusty",
+}
+
+rust_test {
+    name: "VtsAidlHdcpNonExistentTest",
+    srcs: ["src/host_test.rs"],
+    require_root: true,
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+    rustlibs: [
+        "libbinder_rs",
+    ],
+}
diff --git a/security/see/hdcp/aidl/vts/src/host_test.rs b/security/see/hdcp/aidl/vts/src/host_test.rs
new file mode 100644
index 0000000..f64de20
--- /dev/null
+++ b/security/see/hdcp/aidl/vts/src/host_test.rs
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Test for asserting the non-existence of an IHdcpAuthControl.aidl
+
+#![cfg(test)]
+
+use binder;
+
+const HDCP_INTERFACE_NAME: &str = "android.hardware.security.see.hdcp.IHdcpAuthControl";
+
+#[test]
+fn test_hdcp_auth_control_non_existence() {
+    let hdcp_instances =  match binder::get_declared_instances(HDCP_INTERFACE_NAME) {
+        Ok(vec) => vec,
+        Err(e) => {
+            panic!("failed to retrieve the declared interfaces for HdcpAuthControl: {:?}", e);
+        }
+    };
+    assert!(hdcp_instances.is_empty());
+}
diff --git a/staging/security/see/hwcrypto/aidl/Android.bp b/security/see/hwcrypto/aidl/Android.bp
similarity index 77%
rename from staging/security/see/hwcrypto/aidl/Android.bp
rename to security/see/hwcrypto/aidl/Android.bp
index 2da59a4..e15f494 100644
--- a/staging/security/see/hwcrypto/aidl/Android.bp
+++ b/security/see/hwcrypto/aidl/Android.bp
@@ -8,10 +8,8 @@
 }
 
 aidl_interface {
-    name: "android.hardware.security.see",
-    unstable: false,
-    // TODO Remove this owner field when this interface is moved out of /staging
-    owner: "google_while_staging",
+    name: "android.hardware.security.see.hwcrypto",
+    stability: "vintf",
     host_supported: true,
     srcs: [
         "android/hardware/security/see/hwcrypto/*.aidl",
@@ -22,11 +20,15 @@
             enabled: false,
         },
         cpp: {
-            enabled: false,
+            enabled: true,
         },
         rust: {
             enabled: true,
         },
+        ndk: {
+            enabled: true,
+        },
     },
     frozen: false,
+    system_ext_specific: true,
 }
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/CryptoOperation.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/CryptoOperation.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/CryptoOperation.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/CryptoOperation.aidl
index 0a7e7a2..fd2904b 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/CryptoOperation.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/CryptoOperation.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto;
+@VintfStability
 union CryptoOperation {
   android.hardware.security.see.hwcrypto.MemoryBufferParameter setMemoryBuffer;
   android.hardware.security.see.hwcrypto.OperationParameters setOperationParameters;
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/CryptoOperationErrorAdditionalInfo.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/CryptoOperationErrorAdditionalInfo.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/CryptoOperationErrorAdditionalInfo.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/CryptoOperationErrorAdditionalInfo.aidl
index 05780e1..66bed55 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/CryptoOperationErrorAdditionalInfo.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/CryptoOperationErrorAdditionalInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto;
+@VintfStability
 parcelable CryptoOperationErrorAdditionalInfo {
   long failingCommandIndex;
 }
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/CryptoOperationResult.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/CryptoOperationResult.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/CryptoOperationResult.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/CryptoOperationResult.aidl
index 1088e27..7996b9a 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/CryptoOperationResult.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/CryptoOperationResult.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto;
+@VintfStability
 parcelable CryptoOperationResult {
   @nullable android.hardware.security.see.hwcrypto.ICryptoOperationContext context;
 }
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/CryptoOperationSet.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/CryptoOperationSet.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/CryptoOperationSet.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/CryptoOperationSet.aidl
index f3b9b43..75bb0dc 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/CryptoOperationSet.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/CryptoOperationSet.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto;
+@VintfStability
 parcelable CryptoOperationSet {
   @nullable android.hardware.security.see.hwcrypto.ICryptoOperationContext context;
   android.hardware.security.see.hwcrypto.CryptoOperation[] operations;
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/ICryptoOperationContext.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/ICryptoOperationContext.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/ICryptoOperationContext.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/ICryptoOperationContext.aidl
index 472215f..7646656 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/ICryptoOperationContext.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/ICryptoOperationContext.aidl
@@ -32,5 +32,6 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto;
+@VintfStability
 interface ICryptoOperationContext {
 }
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
similarity index 99%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
index 5b34572..b31a06c 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto;
+@VintfStability
 interface IHwCryptoKey {
   android.hardware.security.see.hwcrypto.IHwCryptoKey.DiceCurrentBoundKeyResult deriveCurrentDicePolicyBoundKey(in android.hardware.security.see.hwcrypto.IHwCryptoKey.DiceBoundDerivationKey derivationKey);
   android.hardware.security.see.hwcrypto.IHwCryptoKey.DiceBoundKeyResult deriveDicePolicyBoundKey(in android.hardware.security.see.hwcrypto.IHwCryptoKey.DiceBoundDerivationKey derivationKey, in byte[] dicePolicyForKeyVersion);
@@ -43,7 +44,6 @@
   android.hardware.security.see.hwcrypto.IOpaqueKey getKeyslotData(android.hardware.security.see.hwcrypto.IHwCryptoKey.KeySlot slotId);
   enum DeviceKeyId {
     DEVICE_BOUND_KEY,
-    BATCH_KEY,
   }
   enum KeySlot {
     KEYMINT_SHARED_HMAC_KEY,
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
index 5c26cc2..7c87dd3 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto;
+@VintfStability
 interface IHwCryptoOperations {
   android.hardware.security.see.hwcrypto.CryptoOperationResult[] processCommandList(inout android.hardware.security.see.hwcrypto.CryptoOperationSet[] operations, out android.hardware.security.see.hwcrypto.CryptoOperationErrorAdditionalInfo additionalErrorInfo);
 }
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/IOpaqueKey.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/IOpaqueKey.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/IOpaqueKey.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/IOpaqueKey.aidl
index 88dbdf1..1121f01 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/IOpaqueKey.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/IOpaqueKey.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto;
+@VintfStability
 interface IOpaqueKey {
   byte[] exportWrappedKey(in android.hardware.security.see.hwcrypto.IOpaqueKey wrappingKey);
   android.hardware.security.see.hwcrypto.KeyPolicy getKeyPolicy();
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/KeyPolicy.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/KeyPolicy.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/KeyPolicy.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/KeyPolicy.aidl
index 0e3896e..ca114c3 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/KeyPolicy.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/KeyPolicy.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto;
+@VintfStability
 parcelable KeyPolicy {
   android.hardware.security.see.hwcrypto.types.KeyUse usage;
   android.hardware.security.see.hwcrypto.types.KeyLifetime keyLifetime = android.hardware.security.see.hwcrypto.types.KeyLifetime.EPHEMERAL;
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/MemoryBufferParameter.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/MemoryBufferParameter.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/MemoryBufferParameter.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/MemoryBufferParameter.aidl
index d88d5c8..1c49297 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/MemoryBufferParameter.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/MemoryBufferParameter.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto;
+@VintfStability
 parcelable MemoryBufferParameter {
   android.hardware.security.see.hwcrypto.MemoryBufferParameter.MemoryBuffer bufferHandle;
   int sizeBytes;
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/OperationParameters.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/OperationParameters.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/OperationParameters.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/OperationParameters.aidl
index e069610..d6f57ab 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/OperationParameters.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/OperationParameters.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto;
+@VintfStability
 union OperationParameters {
   android.hardware.security.see.hwcrypto.types.SymmetricAuthOperationParameters symmetricAuthCrypto;
   android.hardware.security.see.hwcrypto.types.SymmetricOperationParameters symmetricCrypto;
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/PatternParameters.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/PatternParameters.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/PatternParameters.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/PatternParameters.aidl
index 0fd1ee7..7b9924e 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/PatternParameters.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/PatternParameters.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto;
+@VintfStability
 parcelable PatternParameters {
   long numberBlocksProcess;
   long numberBlocksCopy;
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/AesCipherMode.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/AesCipherMode.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/AesCipherMode.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/AesCipherMode.aidl
index e7501ff..6ad2c09 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/AesCipherMode.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/AesCipherMode.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto.types;
+@VintfStability
 union AesCipherMode {
   android.hardware.security.see.hwcrypto.types.CipherModeParameters cbc;
   android.hardware.security.see.hwcrypto.types.CipherModeParameters ctr;
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/AesGcmMode.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/AesGcmMode.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/AesGcmMode.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/AesGcmMode.aidl
index 4084abb..68ad142 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/AesGcmMode.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/AesGcmMode.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto.types;
+@VintfStability
 union AesGcmMode {
   android.hardware.security.see.hwcrypto.types.AesGcmMode.AesGcmModeParameters gcmTag16;
   parcelable AesGcmModeParameters {
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/AesKey.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/AesKey.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/AesKey.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/AesKey.aidl
index f4bf786..78b1ff8 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/AesKey.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/AesKey.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto.types;
+@VintfStability
 union AesKey {
   byte[16] aes128 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
   byte[32] aes256;
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/CipherModeParameters.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/CipherModeParameters.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/CipherModeParameters.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/CipherModeParameters.aidl
index 7a77521..83713ff 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/CipherModeParameters.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/CipherModeParameters.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto.types;
+@VintfStability
 parcelable CipherModeParameters {
   byte[16] nonce;
 }
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ExplicitKeyMaterial.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/ExplicitKeyMaterial.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ExplicitKeyMaterial.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/ExplicitKeyMaterial.aidl
index 9970678..45cb234 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ExplicitKeyMaterial.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/ExplicitKeyMaterial.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto.types;
+@VintfStability
 union ExplicitKeyMaterial {
   android.hardware.security.see.hwcrypto.types.AesKey aes;
   android.hardware.security.see.hwcrypto.types.HmacKey hmac;
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/HalErrorCode.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/HalErrorCode.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/HalErrorCode.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/HalErrorCode.aidl
index 742314c..969e9c8 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/HalErrorCode.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/HalErrorCode.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto.types;
+@VintfStability
 parcelable HalErrorCode {
   const int NO_ERROR = 0;
   const int GENERIC_ERROR = (-1) /* -1 */;
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/HmacKey.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/HmacKey.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/HmacKey.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/HmacKey.aidl
index f8de94a..4d4e65d 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/HmacKey.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/HmacKey.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto.types;
+@VintfStability
 union HmacKey {
   byte[32] sha256 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
   byte[64] sha512;
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/HmacOperationParameters.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/HmacOperationParameters.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/HmacOperationParameters.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/HmacOperationParameters.aidl
index 532cd8d..33a518d 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/HmacOperationParameters.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/HmacOperationParameters.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto.types;
+@VintfStability
 parcelable HmacOperationParameters {
   android.hardware.security.see.hwcrypto.IOpaqueKey key;
 }
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/KeyLifetime.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/KeyLifetime.aidl
similarity index 97%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/KeyLifetime.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/KeyLifetime.aidl
index db5964c..ddee337 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/KeyLifetime.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/KeyLifetime.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto.types;
-@Backing(type="byte")
+@Backing(type="byte") @VintfStability
 enum KeyLifetime {
   EPHEMERAL,
   HARDWARE,
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/KeyPermissions.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/KeyPermissions.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/KeyPermissions.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/KeyPermissions.aidl
index ea3a173..919be32 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/KeyPermissions.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/KeyPermissions.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto.types;
+@VintfStability
 enum KeyPermissions {
   ALLOW_EPHEMERAL_KEY_WRAPPING,
   ALLOW_HARDWARE_KEY_WRAPPING,
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/KeyType.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/KeyType.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/KeyType.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/KeyType.aidl
index 59b83c4..07a7ce4 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/KeyType.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/KeyType.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto.types;
+@VintfStability
 enum KeyType {
   AES_128_CBC_NO_PADDING,
   AES_128_CBC_PKCS7_PADDING,
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/KeyUse.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/KeyUse.aidl
similarity index 97%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/KeyUse.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/KeyUse.aidl
index e888bdf..b607fd5 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/KeyUse.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/KeyUse.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto.types;
-@Backing(type="int")
+@Backing(type="int") @VintfStability
 enum KeyUse {
   ENCRYPT = 1,
   DECRYPT = 2,
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/MemoryBufferReference.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/MemoryBufferReference.aidl
similarity index 96%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/MemoryBufferReference.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/MemoryBufferReference.aidl
index 59c8757..184e21f 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/MemoryBufferReference.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/MemoryBufferReference.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto.types;
-@RustDerive(Clone=true, Copy=true)
+@RustDerive(Clone=true, Copy=true) @VintfStability
 parcelable MemoryBufferReference {
   int startOffset;
   int sizeBytes;
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/OpaqueKeyToken.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/OpaqueKeyToken.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/OpaqueKeyToken.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/OpaqueKeyToken.aidl
index fc2dd63..6dfefcb 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/OpaqueKeyToken.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/OpaqueKeyToken.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto.types;
+@VintfStability
 parcelable OpaqueKeyToken {
   byte[] keyToken;
 }
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/OperationData.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/OperationData.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/OperationData.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/OperationData.aidl
index aad3ac1..858ef1c 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/OperationData.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/OperationData.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto.types;
+@VintfStability
 union OperationData {
   android.hardware.security.see.hwcrypto.types.MemoryBufferReference memoryBufferReference;
   byte[] dataBuffer;
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/OperationType.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/OperationType.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/OperationType.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/OperationType.aidl
index ca8b3eb..03c2bba 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/OperationType.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/OperationType.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto.types;
+@VintfStability
 enum OperationType {
   READ,
   WRITE,
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
index 1e304ab..cb963ee 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto.types;
+@VintfStability
 enum ProtectionId {
   WIDEVINE_OUTPUT_BUFFER = 1,
 }
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/SymmetricAuthCryptoParameters.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/SymmetricAuthCryptoParameters.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/SymmetricAuthCryptoParameters.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/SymmetricAuthCryptoParameters.aidl
index d3d1763..e42190e 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/SymmetricAuthCryptoParameters.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/SymmetricAuthCryptoParameters.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto.types;
+@VintfStability
 union SymmetricAuthCryptoParameters {
   android.hardware.security.see.hwcrypto.types.AesGcmMode aes;
 }
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/SymmetricAuthOperationParameters.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/SymmetricAuthOperationParameters.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/SymmetricAuthOperationParameters.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/SymmetricAuthOperationParameters.aidl
index 8a8ef09..78c4a4f 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/SymmetricAuthOperationParameters.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/SymmetricAuthOperationParameters.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto.types;
+@VintfStability
 parcelable SymmetricAuthOperationParameters {
   android.hardware.security.see.hwcrypto.IOpaqueKey key;
   android.hardware.security.see.hwcrypto.types.SymmetricOperation direction;
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/SymmetricCryptoParameters.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/SymmetricCryptoParameters.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/SymmetricCryptoParameters.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/SymmetricCryptoParameters.aidl
index cc93094..8fd5e85 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/SymmetricCryptoParameters.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/SymmetricCryptoParameters.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto.types;
+@VintfStability
 union SymmetricCryptoParameters {
   android.hardware.security.see.hwcrypto.types.AesCipherMode aes;
 }
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/SymmetricOperation.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/SymmetricOperation.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/SymmetricOperation.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/SymmetricOperation.aidl
index 1a17525..40fd2d5 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/SymmetricOperation.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/SymmetricOperation.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto.types;
+@VintfStability
 enum SymmetricOperation {
   ENCRYPT,
   DECRYPT,
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/SymmetricOperationParameters.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/SymmetricOperationParameters.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/SymmetricOperationParameters.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/SymmetricOperationParameters.aidl
index 769833b..7007074 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/SymmetricOperationParameters.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/SymmetricOperationParameters.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto.types;
+@VintfStability
 parcelable SymmetricOperationParameters {
   android.hardware.security.see.hwcrypto.IOpaqueKey key;
   android.hardware.security.see.hwcrypto.types.SymmetricOperation direction;
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/Void.aidl b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/Void.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/Void.aidl
rename to security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/Void.aidl
index b37848b..80c91ee 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/Void.aidl
+++ b/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see.hwcrypto/current/android/hardware/security/see/hwcrypto/types/Void.aidl
@@ -32,5 +32,6 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.security.see.hwcrypto.types;
+@VintfStability
 parcelable Void {
 }
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/CryptoOperation.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/CryptoOperation.aidl
similarity index 99%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/CryptoOperation.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/CryptoOperation.aidl
index 2fdbc78..0859d2a 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/CryptoOperation.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/CryptoOperation.aidl
@@ -25,6 +25,7 @@
  * Type that describes the different operations that can be performed along with its required
  * parameters. It will be used to construct a vector of operation that are executed sequentially.
  */
+@VintfStability
 union CryptoOperation {
     /*
      * Sets a memory buffer to operate on. References to positions of this memory buffer can be used
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/CryptoOperationErrorAdditionalInfo.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/CryptoOperationErrorAdditionalInfo.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/CryptoOperationErrorAdditionalInfo.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/CryptoOperationErrorAdditionalInfo.aidl
index f3ac8ea..cc94b02 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/CryptoOperationErrorAdditionalInfo.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/CryptoOperationErrorAdditionalInfo.aidl
@@ -18,6 +18,7 @@
 /*
  * Type that provides more information about failures when processing a list of commands.
  */
+@VintfStability
 parcelable CryptoOperationErrorAdditionalInfo {
     /*
      * Index indicating the first step of <code>CryptoOperationSet::operations</code> that failed
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/CryptoOperationResult.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/CryptoOperationResult.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/CryptoOperationResult.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/CryptoOperationResult.aidl
index 07c2983..5c3b81e 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/CryptoOperationResult.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/CryptoOperationResult.aidl
@@ -20,6 +20,7 @@
 /*
  * Type that describes the result of a set of crypto operations.
  */
+@VintfStability
 parcelable CryptoOperationResult {
     /*
      * Token that can be passed on a CryptoOperationSet to issue more operations on the same context
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/CryptoOperationSet.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/CryptoOperationSet.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/CryptoOperationSet.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/CryptoOperationSet.aidl
index 9aff1e8..285ed36 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/CryptoOperationSet.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/CryptoOperationSet.aidl
@@ -21,6 +21,7 @@
 /*
  * Type that describes a set of crypto operations to execute
  */
+@VintfStability
 parcelable CryptoOperationSet {
     /*
      * Token to be used to issue the operations. If NULL, a new context will be created and
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/ICryptoOperationContext.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/ICryptoOperationContext.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/ICryptoOperationContext.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/ICryptoOperationContext.aidl
index 68d0c03..8cfa735 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/ICryptoOperationContext.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/ICryptoOperationContext.aidl
@@ -22,4 +22,5 @@
  * operation in progress context includes any memory buffer previously mapped by a
  * <code>CryptoOperation::SetMemoryBuffer</code> call.
  */
+@VintfStability
 interface ICryptoOperationContext {}
diff --git a/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
new file mode 100644
index 0000000..97a4c37
--- /dev/null
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.security.see.hwcrypto;
+
+import android.hardware.security.see.hwcrypto.IHwCryptoOperations;
+import android.hardware.security.see.hwcrypto.IOpaqueKey;
+import android.hardware.security.see.hwcrypto.KeyPolicy;
+import android.hardware.security.see.hwcrypto.types.ExplicitKeyMaterial;
+import android.hardware.security.see.hwcrypto.types.OpaqueKeyToken;
+
+/*
+ * Higher level interface to access and generate keys.
+ */
+@VintfStability
+interface IHwCryptoKey {
+    /*
+     * Identifier for the requested device provided key. The currently supported identifiers are:
+     *
+     */
+    enum DeviceKeyId {
+        /*
+         * This is a key unique to the device.
+         */
+        DEVICE_BOUND_KEY,
+    }
+
+    /*
+     * Identifier for the requested key slot. The currently supported identifiers are:
+     *
+     */
+    enum KeySlot {
+        /*
+         * This is the shared HMAC key that will now be computed by HwCryptoKey after participating
+         * in the ISharedSecret protocol that can be shared with KeyMint and authenticators. See
+         * ISharedSecret.aidl for more information.
+         */
+        KEYMINT_SHARED_HMAC_KEY,
+    }
+
+    union DiceBoundDerivationKey {
+        /*
+         * Opaque to be used to derive the DICE bound key.
+         */
+        IOpaqueKey opaqueKey;
+
+        /*
+         * Device provided key to be used to derive the DICE bound key.
+         */
+        DeviceKeyId keyId;
+    }
+
+    parcelable DiceCurrentBoundKeyResult {
+        /*
+         * Key cryptographically bound to a DICE policy.
+         */
+        IOpaqueKey diceBoundKey;
+
+        /*
+         * Current dice policy which was used to generate the returned key. This policy is opaque
+         * from this service perspective (it will be sent to an Authentication Manager Service to be
+         * verified). It follows the structure defined on DicePolicy.cddl, located under
+         * hardware/interfaces/security/authgraph/aidl/android/hardware/security/authgraph/ with the
+         * caveat that it could be encrypted if the client does not have enough permissions to see
+         * the device dice policy information.
+         */
+        byte[] dicePolicyForKeyVersion;
+    }
+
+    parcelable DiceBoundKeyResult {
+        /*
+         * Key cryptographically bound to a DICE policy.
+         */
+        IOpaqueKey diceBoundKey;
+
+        /*
+         * Indicates if the diceBoundKey returned was created using a current DICE policy. The
+         * caller can use this to detect if an old policy was provided and rotate its keys if so
+         * desired. Old, valid policies remain usable, but care needs to be taken to not continue to
+         * use a potentially compromised key.
+         */
+        boolean dicePolicyWasCurrent;
+    }
+
+    parcelable ClearKeyPolicy {
+        /*
+         * Indicates the desired key size. It will be used to calculate how many bytes of key
+         * material should be returned.
+         */
+        int keySizeBytes;
+    }
+
+    union DerivedKeyPolicy {
+        /*
+         * If used we will derive a clear key and pass it back as an array of bytes on
+         * <code>HwCryptoKeyMaterial::explicitKey</code>.
+         */
+        ClearKeyPolicy clearKey;
+
+        /*
+         * Policy for the newly derived opaque key. Defines how the key can be used and its type.
+         */
+        byte[] opaqueKey;
+    }
+
+    parcelable DerivedKeyParameters {
+        /*
+         * Key to be used to derive the new key using HKDF.
+         */
+        IOpaqueKey derivationKey;
+
+        /*
+         * Policy for the newly derived key. Depending on its type, either a clear or opaque key
+         * will be derived.
+         */
+        DerivedKeyPolicy keyPolicy;
+
+        /*
+         * An arbitrary set of bytes incorporated into the key derivation. May have an
+         * implementation-specific maximum length, but it is guaranteed to accept at least 32 bytes.
+         */
+        byte[] context;
+    }
+
+    union DerivedKey {
+        /*
+         * Derived key in clear format.
+         */
+        byte[] explicitKey = {};
+
+        /*
+         * Derived key as a key token to be used only through the HWCrypto service.
+         */
+        IOpaqueKey opaque;
+    }
+
+    /*
+     * Derives a versioned key tied to the caller's current DICE policy. It will return this current
+     * policy back to the caller along with the generated key.
+     *
+     * @param derivationKey:
+     *     Key to be used to derive the new key using HKDF.
+     *
+     * @return:
+     *     A DiceCurrentBoundKeyResult containint the versioned key tied the current client version
+     *     on success.
+     *
+     * @throws:
+     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs.
+     */
+    DiceCurrentBoundKeyResult deriveCurrentDicePolicyBoundKey(
+            in DiceBoundDerivationKey derivationKey);
+
+    /*
+     * Derive a versioned key by checking the provided DICE policy against the caller and then using
+     * it as a context for deriving the returned key.
+     *
+     * @param derivationKey:
+     *     Key to be used to derive the new key using HKDF.
+     *
+     * @param dicePolicyForKeyVersion:
+     *     Policy used to derive keys tied to specific versions. Using this parameter the caller can
+     *     tie a derived key to a minimum version of itself, so in the future only itself or a more
+     *     recent version can derive the same key. This parameter is opaque to the caller and it
+     *     could be encrypted in the case the client doesn't have permission to know the dice chain.
+     *     When implementing this function, this parameter shall be one of the components fed to the
+     *     KDF context and it needs to be checked against the caller DICE certificate before being
+     *     used.
+     *
+     * @return:
+     *      A DiceBoundKeyResult containing the versioned key tied to the provided DICE policy on
+     *      success.
+     *
+     * @throws:
+     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs.
+     */
+    DiceBoundKeyResult deriveDicePolicyBoundKey(
+            in DiceBoundDerivationKey derivationKey, in byte[] dicePolicyForKeyVersion);
+
+    /*
+     * Derive a new key based on the given key, policy and context.
+     *
+     * @param parameters:
+     *      Parameters used for the key derivation. See <code>DerivedKeyParameters</code> on this
+     *      file for more information.
+     *
+     * @return:
+     *      A HwCryptoKeyMaterial containing the derived key on success.
+     *
+     * @throws:
+     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs.
+     */
+    DerivedKey deriveKey(in DerivedKeyParameters parameters);
+
+    /*
+     * Returns an interface used to work on opaque keys. This interface can also be used to operate
+     * on any opaque key generated by hwkeyDeriveVersioned, even if this key has been generated
+     * after retrieving a IHwCryptoOperations binder object, as long as the parent
+     * IHwCryptoDeviceKeyAccess is not dropped between retrieving the IHwCryptoOperations binder
+     * object and deriving the key. IHwCryptoOperations can also be used to create opaque keys that
+     * are not bound to the device.
+     *
+     * @return:
+     *      IHwCryptoOperations on success
+     */
+    IHwCryptoOperations getHwCryptoOperations();
+
+    /*
+     * Imports a SW clear key into the secure environment.
+     *
+     * @param keyMaterial:
+     *     key to be imported.
+     *
+     * @param newKeyPolicy:
+     *      Policy of the new key. Defines how the newly created key can be used. Because any clear
+     *      key imported into the system is considered to have a <code>KeyLifetime::PORTABLE</code>
+     *      lifetime, a call to this function will return an error if
+     *      <code>newKeyPolicy.newKeyPolicy</code> is not set to portable.
+     *
+     * @return:
+     *      IOpaqueKey on success.
+     *
+     * @throws:
+     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs.
+     */
+    IOpaqueKey importClearKey(in ExplicitKeyMaterial keyMaterial, in KeyPolicy newKeyPolicy);
+
+    /*
+     * Returns the client current DICE policy. This policy is encrypted and considered opaque from
+     * the client perspective. This policy is the same used to create DICE bound keys and will also
+     * be used to seal secrets that can only be retrieved by the DICE policy owner. The first use of
+     * this seal operation will be <code>IOpaqueKey::getShareableToken</code> and will call this
+     * <code>IHwCryptoKey::keyTokenImport</code>. To start this process, the intended key receiver
+     * function and then pass the generated DICE policy to the owner of the key that the receiver
+     * wants to import. The key owner will then call <code>IOpaqueKey::getShareableToken</code>
+     * passing the receiver DICE policy to insure that only that receiver can import the key.
+     *
+     * @return:
+     *      byte[] on success, which is the caller encrypted DICE policy.
+     */
+    byte[] getCurrentDicePolicy();
+
+    /*
+     * Imports a key from a different client service instance. Because IOpaqueKey are binder objects
+     * that cannot be directly shared between binder rpc clients, this method provide a way to send
+     * a key to another client. Keys to be imported by the receiver are represented by a token
+     * created using <code>IOpaqueKey::getShareableToken</code>. The flow to create this token is
+     * described in <code>IHwCryptoKey::getCurrentDicePolicy</code>.
+     *
+     * @param requested_key:
+     *      Handle to the key to be imported to the caller service.
+     *
+     * @param sealingDicePolicy:
+     *      DICE policy used to seal the exported key.
+     *
+     * @return:
+     *      An IOpaqueKey that can be directly be used on the local HWCrypto service on success.
+     *
+     * @throws:
+     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs.
+     */
+    IOpaqueKey keyTokenImport(in OpaqueKeyToken requestedKey, in byte[] sealingDicePolicy);
+
+    /*
+     * Gets the keyslot key material referenced by slotId. This interface is used to access device
+     * specific keys with known types and uses. Because the returned key is opaque, it can only be
+     * used through the different HwCrypto interfaces. Because the keys live in a global namespace
+     * the identity of the caller needs to be checked to verify that it has permission to access the
+     * requested key.
+     *
+     * @param slotId:
+     *      Identifier for the requested keyslot
+     *
+     * @return:
+     *      An IOpaqueKey corresponding to the requested key slot on success.
+     *
+     * @throws:
+     *      ServiceSpecificException <code>UNAUTHORIZED</code> if the caller cannot access the
+     *      requested key, another specific error based on <code>HalErrorCode</code> otherwise.
+     */
+    IOpaqueKey getKeyslotData(KeySlot slotId);
+}
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
similarity index 84%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
index 4d394ed..9df6d67 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoOperations.aidl
@@ -24,20 +24,25 @@
  * cryptographic keys. Interactions with this interface are done through a command-base API,
  * which allow callers to execute a large set of operations on a single call.
  */
+@VintfStability
 interface IHwCryptoOperations {
     /*
-     * processCommandList() - Executes a list of cryptographic commands in order
+     * Executes a list of cryptographic commands in order
      *
-     * @operations:
+     * @param operations:
      *      Parameter containing 1 or more set of commands to execute. Additionally, each set can
      *      also contain a context on which the commands will be executed.
-     * @additionalErrorInfo:
+     *
+     * @param additionalErrorInfo:
      *      Structure containing additional info when errors are encountered. Only valid if the
      *      function failed its execution.
-     * Return:
+     *
+     * @return:
      *      CryptoOperationResult[] on success, which can contain a context to continue executing
-     *      each of the provided operations sets, service specific error based on
-     *      <code>HalErrorCode</code> otherwise.
+     *      each of the provided operations sets.
+     *
+     * @throws:
+     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs.
      */
     CryptoOperationResult[] processCommandList(inout CryptoOperationSet[] operations,
             out CryptoOperationErrorAdditionalInfo additionalErrorInfo);
diff --git a/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IOpaqueKey.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IOpaqueKey.aidl
new file mode 100644
index 0000000..318a27e
--- /dev/null
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IOpaqueKey.aidl
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.security.see.hwcrypto;
+
+import android.hardware.security.see.hwcrypto.KeyPolicy;
+import android.hardware.security.see.hwcrypto.types.OpaqueKeyToken;
+import android.hardware.security.see.hwcrypto.types.OperationType;
+import android.hardware.security.see.hwcrypto.types.ProtectionId;
+
+@VintfStability
+interface IOpaqueKey {
+    /*
+     * Exports this key as a wrapped (encrypted) blob.
+     *
+     * @param wrapping_key:
+     *     wrapping key. It needs to be an opaque key and its policy needs to indicate that it can
+     *     be used for key wrapping.
+     *
+     * @return:
+     *      Wrapped key blob as a byte array on success. Format of the blob is opaque to the service
+     *      but has to match the command accepted by
+     *      <code>IHwCryptoKeyGeneration::importWrappedKey</code>
+     *
+     * @throws:
+     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs.
+     */
+    byte[] exportWrappedKey(in IOpaqueKey wrappingKey);
+
+    /*
+     * Returns the key policy.
+     *
+     * @return:
+     *      A <code>KeyPolicy</code> on success
+     *
+     * @throws:
+     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs.
+     */
+    KeyPolicy getKeyPolicy();
+
+    /*
+     * Returns the public key portion of this OpaqueKey. This operation is only valid for asymmetric
+     * keys.
+     *
+     * @return:
+     *      public key as a byte array on success. Format used for the returned public key is COSE.
+     *
+     * @throws:
+     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs.
+     */
+    byte[] getPublicKey();
+
+    /*
+     * Returns a token that can shared with another HWCrypto client.
+     *
+     * @param sealingDicePolicy:
+     *      Token to be used to protect the returned OpaqueKeyToken. It will be used so only
+     *      the owner of the sealingDicePolicy can import the key.
+     *
+     * @return:
+     *      <code>OpaqueKeyMaterial</code> token on success.
+     *
+     * @throws:
+     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs.
+     */
+    OpaqueKeyToken getShareableToken(in byte[] sealingDicePolicy);
+
+    /*
+     * Sets the protectionID associated with the buffers where the operation will be performed. A
+     * protection ID serves as a limitation on the key so it can only operate on buffers with a
+     * matching protection ID. The client calling this functions needs to have the necessary
+     * permissions to read and/or write to this buffer. Setting this parameter means that if the key
+     * is shared with a different client, the client receiving the key will be limited in which
+     * buffers can be used to read/write data for this operation.
+     *
+     * @param protectionId:
+     *      ID of the given use case to provide protection for. The method of protecting the buffer
+     *      will be platform dependent.
+     *
+     * @param allowedOperations:
+     *      array of allowed operations. Allowed operations are either READ or WRITE.
+     *
+     * @throws:
+     *      ServiceSpecificException based on <code>HalErrorCode</code> if any error occurs.
+     */
+    void setProtectionId(in ProtectionId protectionId, in OperationType[] allowedOperations);
+}
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/KeyPolicy.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/KeyPolicy.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/KeyPolicy.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/KeyPolicy.aidl
index 9266bfa..a20e99b 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/KeyPolicy.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/KeyPolicy.aidl
@@ -23,6 +23,7 @@
 /*
  * Parcelable that specified how a key can be used.
  */
+@VintfStability
 parcelable KeyPolicy {
     /*
      * Enum specifying the operations the key can perform (encryption, decryption, etc.).
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/KeyPolicy.cddl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/KeyPolicy.cddl
similarity index 100%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/KeyPolicy.cddl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/KeyPolicy.cddl
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/MemoryBufferParameter.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/MemoryBufferParameter.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/MemoryBufferParameter.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/MemoryBufferParameter.aidl
index c5a6a5c..efc5767 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/MemoryBufferParameter.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/MemoryBufferParameter.aidl
@@ -18,6 +18,7 @@
 /*
  * Parcelable representing a memory buffer.
  */
+@VintfStability
 parcelable MemoryBufferParameter {
     union MemoryBuffer {
         ParcelFileDescriptor input;
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/OperationParameters.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/OperationParameters.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/OperationParameters.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/OperationParameters.aidl
index a977f56..bf0b720 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/OperationParameters.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/OperationParameters.aidl
@@ -22,6 +22,7 @@
 /*
  * Type that describes the parameters for the different operations that can be performed.
  */
+@VintfStability
 union OperationParameters {
     /*
      * Parameters for authenticated symmetric cryptography (AES GCM).
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/PatternParameters.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/PatternParameters.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/PatternParameters.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/PatternParameters.aidl
index 3f62abe..9f8950f 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/PatternParameters.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/PatternParameters.aidl
@@ -18,6 +18,7 @@
 /*
  * Parcelable that specifies a pattern to process data.
  */
+@VintfStability
 parcelable PatternParameters {
     /*
      * Number of blocks that will be processed. The size of the block matches the size of the
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/AesCipherMode.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/AesCipherMode.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/AesCipherMode.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/AesCipherMode.aidl
index ac31557..8ce83aa 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/AesCipherMode.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/AesCipherMode.aidl
@@ -21,6 +21,7 @@
 /*
  * Type used for the parameters needed to run a non-authenticated AES operation.
  */
+@VintfStability
 union AesCipherMode {
     /*
      * Cipher Block Chaining mode. Padding will either be none or PKCS#7 depending on the key policy
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/AesGcmMode.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/AesGcmMode.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/AesGcmMode.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/AesGcmMode.aidl
index 4025553..1c6551c 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/AesGcmMode.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/AesGcmMode.aidl
@@ -18,6 +18,7 @@
 /*
  * Type used for the parameters needed to run an authenticated AES operation (GCM).
  */
+@VintfStability
 union AesGcmMode {
     parcelable AesGcmModeParameters {
         /*
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/AesKey.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/AesKey.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/AesKey.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/AesKey.aidl
index cf9082d..ae62ef9 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/AesKey.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/AesKey.aidl
@@ -18,6 +18,7 @@
 /*
  * Type that represents an AES key.
  */
+@VintfStability
 union AesKey {
     /*
      * Raw AES 128 bit key material.
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/CipherModeParameters.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/CipherModeParameters.aidl
similarity index 88%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/CipherModeParameters.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/CipherModeParameters.aidl
index bfa5daa..e7ede57 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/CipherModeParameters.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/CipherModeParameters.aidl
@@ -19,6 +19,10 @@
 /*
  * Type encapsulating nonce used on non-authenticated AES symmetric encryption.
  */
+@VintfStability
 parcelable CipherModeParameters {
+    /*
+     * nonce to be used as IV for AES-CBC or as the nonce in AES-CTR
+     */
     byte[16] nonce;
 }
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/ExplicitKeyMaterial.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/ExplicitKeyMaterial.aidl
similarity index 88%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/ExplicitKeyMaterial.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/ExplicitKeyMaterial.aidl
index 3aa5611..a5bf594 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/ExplicitKeyMaterial.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/ExplicitKeyMaterial.aidl
@@ -21,7 +21,15 @@
 /*
  * Type encapsulating a clear key.
  */
+@VintfStability
 union ExplicitKeyMaterial {
+    /*
+     * AES key in clear format.
+     */
     AesKey aes;
+
+    /*
+     * HMAC key in clear format.
+     */
     HmacKey hmac;
 }
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/HalErrorCode.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/HalErrorCode.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/HalErrorCode.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/HalErrorCode.aidl
index f536c0e..df12262 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/HalErrorCode.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/HalErrorCode.aidl
@@ -18,6 +18,7 @@
 /*
  * Service error codes. Will be returned as service specific errors.
  */
+@VintfStability
 parcelable HalErrorCode {
     /* Success */
     const int NO_ERROR = 0;
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/HmacKey.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/HmacKey.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/HmacKey.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/HmacKey.aidl
index a0b6ba7..b1a988e 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/HmacKey.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/HmacKey.aidl
@@ -18,6 +18,7 @@
 /*
  * Type that represents an Hmac key.
  */
+@VintfStability
 union HmacKey {
     /*
      * Raw Hmac key for use with sha256.
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/HmacOperationParameters.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/HmacOperationParameters.aidl
similarity index 97%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/HmacOperationParameters.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/HmacOperationParameters.aidl
index da09a2c..faa3072 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/HmacOperationParameters.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/HmacOperationParameters.aidl
@@ -19,6 +19,7 @@
 /*
  * Data needed to perform HMAC operations.
  */
+@VintfStability
 parcelable HmacOperationParameters {
     /*
      * Key to be used for the HMAC operation.
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/KeyLifetime.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/KeyLifetime.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/KeyLifetime.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/KeyLifetime.aidl
index 9958a0b..b03b850 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/KeyLifetime.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/KeyLifetime.aidl
@@ -20,6 +20,7 @@
  * represented as a bitmask to allow us to internally combine them on a single property to describe
  * a set of allowed lifetimes.
  */
+@VintfStability
 @Backing(type="byte")
 enum KeyLifetime {
     /*
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/KeyPermissions.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/KeyPermissions.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/KeyPermissions.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/KeyPermissions.aidl
index a1e4f21..c48ef8b 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/KeyPermissions.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/KeyPermissions.aidl
@@ -18,6 +18,7 @@
 /*
  * Additional characteristics and permissions of the key.
  */
+@VintfStability
 enum KeyPermissions {
     /*
      * Key can be wrapped by an ephemeral key.
diff --git a/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/KeyType.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/KeyType.aidl
new file mode 100644
index 0000000..ed90899
--- /dev/null
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/KeyType.aidl
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.security.see.hwcrypto.types;
+
+/*
+ * Enum describing all supported key types. Key types are strongly bound to the algorithm to
+ * prevent reusing the same key on different algorithms (e.g. using the same key for 2 different AES
+ * 128 Cipher modes).
+ */
+@VintfStability
+enum KeyType {
+    /*
+     * AES with key size 128 bits using CBC mode of operation and no padding.
+     */
+    AES_128_CBC_NO_PADDING,
+
+    /*
+     * AES with key size 128 bits using CBC mode of operation and PKCS7 padding.
+     */
+    AES_128_CBC_PKCS7_PADDING,
+
+    /*
+     * AES with key size 128 bits using counter mode.
+     */
+    AES_128_CTR,
+
+    /*
+     * AES with key size 128 bits using GCM mode for authenticated encryption.
+     */
+    AES_128_GCM,
+
+    /*
+     * AES with key size 128 bits for CMAC calculation.
+     */
+    AES_128_CMAC,
+
+    /*
+     * AES with key size 256 bits using CBC mode of operation and no padding.
+     */
+    AES_256_CBC_NO_PADDING,
+
+    /*
+     * AES with key size 256 bits using CBC mode of operation and PKCS7 padding.
+     */
+    AES_256_CBC_PKCS7_PADDING,
+
+    /*
+     * AES with key size 128 bits using counter mode.
+     */
+    AES_256_CTR,
+
+    /*
+     * AES with key size 128 bits using GCM mode for authenticated encryption.
+     */
+    AES_256_GCM,
+
+    /*
+     * AES with key size 128 bits for CMAC calculation.
+     */
+    AES_256_CMAC,
+
+    /*
+     * Key of length of 32 bytes for HMAC operations using SHA256.
+     */
+    HMAC_SHA256,
+
+    /*
+     * Key of length of 64 bytes for HMAC operations using SHA512.
+     */
+    HMAC_SHA512,
+
+    /*
+     * RSA of key size of 2048 bits for signing using PSS.
+     */
+    RSA2048_PSS_SHA256,
+
+    /*
+     * RSA of key size of 2048 bits for signing with padding PKCS 1.5 and SHA256 as the digest
+     * algorithm.
+     */
+    RSA2048_PKCS1_5_SHA256,
+
+    /*
+     * ECC key for signing using curve P-256 and no padding.
+     */
+    ECC_NIST_P256_SIGN_NO_PADDING,
+
+    /*
+     * ECC key for signing using curve P-256 and SHA256 as hashing algorithm.
+     */
+    ECC_NIST_P256_SIGN_SHA256,
+
+    /*
+     * ECC key for signing using curve P-521 and no padding.
+     */
+    ECC_NIST_P521_SIGN_NO_PADDING,
+
+    /*
+     * ECC key for signing using curve P-512 and SHA512 as hashing algorithm.
+     */
+    ECC_NIST_P521_SIGN_SHA512,
+
+    /*
+     * ECC key for signing using EdDSA.
+     */
+    ECC_ED25519_SIGN,
+}
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/KeyUse.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/KeyUse.aidl
similarity index 77%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/KeyUse.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/KeyUse.aidl
index 76bfd62..60bfd06 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/KeyUse.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/KeyUse.aidl
@@ -18,12 +18,24 @@
 /*
  * Enum describing the allowed operations that can be performed with the given key.
  */
+@VintfStability
 @Backing(type="int")
 enum KeyUse {
+    /* Key can be used to encrypt */
     ENCRYPT = 1,
+
+    /* Key can be used to decrypt */
     DECRYPT = 2,
+
+    /* Key can be used to encrypt or decrypt */
     ENCRYPT_DECRYPT = ENCRYPT | DECRYPT,
+
+    /* Key can be used to sign */
     SIGN = 4,
+
+    /* Key can be used to derive other keys */
     DERIVE = 8,
+
+    /* Key can be used to wrap other keys */
     WRAP = 16,
 }
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/MemoryBufferReference.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/MemoryBufferReference.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/MemoryBufferReference.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/MemoryBufferReference.aidl
index 1175dc5..0f3c099 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/MemoryBufferReference.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/MemoryBufferReference.aidl
@@ -18,6 +18,7 @@
 /*
  * Structure representing a section of a memory buffer.
  */
+@VintfStability
 @RustDerive(Copy=true, Clone=true)
 parcelable MemoryBufferReference {
     /*
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/OpaqueKeyToken.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/OpaqueKeyToken.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/OpaqueKeyToken.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/OpaqueKeyToken.aidl
index db95c18..25cc6fb 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/OpaqueKeyToken.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/OpaqueKeyToken.aidl
@@ -20,6 +20,7 @@
  * valid on the current boot, and its reuse after a session is closed (or between sessions) is not
  * guaranteed.
  */
+@VintfStability
 parcelable OpaqueKeyToken {
     /*
      * Opaque type used to send IOpaqueKeys keys to different clients. Its format is implementation
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/OperationData.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/OperationData.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/OperationData.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/OperationData.aidl
index 642d05e..8dfca72 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/OperationData.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/OperationData.aidl
@@ -20,6 +20,7 @@
 /*
  * Union holding buffers to be used by the cryptographic operation.
  */
+@VintfStability
 union OperationData {
     /*
      * Reference (offset, size) to the active operations' MemoryBuffer.
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/OperationType.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/OperationType.aidl
similarity index 90%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/OperationType.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/OperationType.aidl
index 76878a3..2dc9ae9 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/OperationType.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/OperationType.aidl
@@ -18,7 +18,11 @@
 /*
  * Enum describing the different types of operations allowed on a buffer.
  */
+@VintfStability
 enum OperationType {
+    /* Read operations allowed*/
     READ,
+
+    /* Write operations allowed*/
     WRITE,
 }
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
index 8686882..8fd0551 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
@@ -19,6 +19,7 @@
  * Enum describing the different types of protected buffers. Protected buffers are named by its
  * corresponding use case and its underlaying implementation is platform dependant.
  */
+@VintfStability
 enum ProtectionId {
     /*
      * ProtectionID used by HwCrypto to enable Keys that can be used for Widevine video buffers.
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricAuthCryptoParameters.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricAuthCryptoParameters.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricAuthCryptoParameters.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricAuthCryptoParameters.aidl
index 278e48d..79c39f9 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricAuthCryptoParameters.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricAuthCryptoParameters.aidl
@@ -20,6 +20,7 @@
 /*
  * Data needed to perform authenticated symmetric cryptographic operations.
  */
+@VintfStability
 union SymmetricAuthCryptoParameters {
     /*
      * AES (Advanced Encryption Standard) GCM parameters.
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricAuthOperationParameters.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricAuthOperationParameters.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricAuthOperationParameters.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricAuthOperationParameters.aidl
index 46568c3..844a3bc 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricAuthOperationParameters.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricAuthOperationParameters.aidl
@@ -23,6 +23,7 @@
  * Parameters needed to perform an authenticated symmetric cryptographic operation. Currently only
  * AES-GCM is supported.
  */
+@VintfStability
 parcelable SymmetricAuthOperationParameters {
     /*
      * Key to be used on the operation.
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricCryptoParameters.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricCryptoParameters.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricCryptoParameters.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricCryptoParameters.aidl
index 2350242..679fe6a 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricCryptoParameters.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricCryptoParameters.aidl
@@ -20,6 +20,7 @@
 /*
  * Data needed to perform non-authenticated symmetric cryptographic operations.
  */
+@VintfStability
 union SymmetricCryptoParameters {
     /*
      * AES (Advanced Encryption Standard) parameters.
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricOperation.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricOperation.aidl
similarity index 92%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricOperation.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricOperation.aidl
index 2717472..d88d4e9 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricOperation.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricOperation.aidl
@@ -18,4 +18,4 @@
 /*
  * Enum describing the type of symmetric operation desired.
  */
-enum SymmetricOperation { ENCRYPT, DECRYPT }
+@VintfStability enum SymmetricOperation { ENCRYPT, DECRYPT }
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricOperationParameters.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricOperationParameters.aidl
similarity index 98%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricOperationParameters.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricOperationParameters.aidl
index 1d1554d..509d416 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricOperationParameters.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/SymmetricOperationParameters.aidl
@@ -22,6 +22,7 @@
 /*
  * Parameters needed to perform a non-authenticated symmetric cryptographic operation.
  */
+@VintfStability
 parcelable SymmetricOperationParameters {
     /*
      * Key to be used on the operation.
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/Void.aidl b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/Void.aidl
similarity index 92%
rename from staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/Void.aidl
rename to security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/Void.aidl
index f9f608d..243fb45 100644
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/Void.aidl
+++ b/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/Void.aidl
@@ -15,4 +15,8 @@
  */
 package android.hardware.security.see.hwcrypto.types;
 
+/*
+ * Type used to represent no data.
+ */
+@VintfStability
 parcelable Void {}
diff --git a/sensors/aidl/android/hardware/sensors/SensorType.aidl b/sensors/aidl/android/hardware/sensors/SensorType.aidl
index 9098894..4904c3f 100644
--- a/sensors/aidl/android/hardware/sensors/SensorType.aidl
+++ b/sensors/aidl/android/hardware/sensors/SensorType.aidl
@@ -718,8 +718,8 @@
     HEADING = 42,
 
     /**
-     * Base for device manufacturers private sensor types.
-     * These sensor types can't be exposed in the SDK.
+     * Base of the range reserved for device manufacturers' private sensor
+     * types. These sensor types aren't documented in the SDK.
      */
     DEVICE_PRIVATE_BASE = 0x10000,
 }
diff --git a/sensors/aidl/default/include/sensors-impl/Sensors.h b/sensors/aidl/default/include/sensors-impl/Sensors.h
index 2adbc9d..c90db69 100644
--- a/sensors/aidl/default/include/sensors-impl/Sensors.h
+++ b/sensors/aidl/default/include/sensors-impl/Sensors.h
@@ -97,9 +97,13 @@
             return;
         }
         if (mEventQueue->write(&events.front(), events.size())) {
+            if (mEventQueueFlag == nullptr) {
+                // Don't take the wake lock if we can't wake the receiver to avoid holding it
+                // indefinitely.
+                return;
+            }
             mEventQueueFlag->wake(
                     static_cast<uint32_t>(BnSensors::EVENT_QUEUE_FLAG_BITS_READ_AND_PROCESS));
-
             if (wakeup) {
                 // Keep track of the number of outstanding WAKE_UP events in order to properly hold
                 // a wake lock until the framework has secured a wake lock
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl b/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
deleted file mode 100644
index bb194a3..0000000
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IHwCryptoKey.aidl
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.hardware.security.see.hwcrypto;
-
-import android.hardware.security.see.hwcrypto.IHwCryptoOperations;
-import android.hardware.security.see.hwcrypto.IOpaqueKey;
-import android.hardware.security.see.hwcrypto.KeyPolicy;
-import android.hardware.security.see.hwcrypto.types.ExplicitKeyMaterial;
-import android.hardware.security.see.hwcrypto.types.OpaqueKeyToken;
-
-/*
- * Higher level interface to access and generate keys.
- */
-interface IHwCryptoKey {
-    /*
-     * Identifier for the requested device provided key. The currently supported identifiers are:
-     *
-     * DEVICE_BOUND_KEY:
-     *      This is a key unique to the device.
-     * BATCH_KEY:
-     *      This is a shared by a set of devices.
-     */
-    enum DeviceKeyId {
-        DEVICE_BOUND_KEY,
-        BATCH_KEY,
-    }
-
-    /*
-     * Identifier for the requested key slot. The currently supported identifiers are:
-     *
-     * KEYMINT_SHARED_HMAC_KEY:
-     *      This is the shared HMAC key that will now be computed by HwCryptoKey after participating
-     *      in the ISharedSecret protocol that can be shared with KeyMint and authenticators. See
-     *      ISharedSecret.aidl for more information.
-     */
-    enum KeySlot {
-        KEYMINT_SHARED_HMAC_KEY,
-    }
-
-    union DiceBoundDerivationKey {
-        /*
-         * Opaque to be used to derive the DICE bound key.
-         */
-        IOpaqueKey opaqueKey;
-
-        /*
-         * Device provided key to be used to derive the DICE bound key.
-         */
-        DeviceKeyId keyId;
-    }
-
-    parcelable DiceCurrentBoundKeyResult {
-        /*
-         * Key cryptographically bound to a DICE policy.
-         */
-        IOpaqueKey diceBoundKey;
-
-        /*
-         * Current dice policy which was used to generate the returned key. This policy is
-         * opaque from this service perspective (it will be sent to an Authentication Manager
-         * Service to be verified). It follows the structure defined on DicePolicy.cddl, located
-         * under hardware/interfaces/security/authgraph/aidl/android/hardware/security/authgraph/
-         * with the caveat that it could be encrypted if the client does not have enough permissions
-         * to see the device dice policy information.
-         */
-        byte[] dicePolicyForKeyVersion;
-    }
-
-    parcelable DiceBoundKeyResult {
-        /*
-         * Key cryptographically bound to a DICE policy.
-         */
-        IOpaqueKey diceBoundKey;
-
-        /*
-         * Indicates if the diceBoundKey returned was created using a current DICE policy. The
-         * caller can use this to detect if an old policy was provided and rotate its keys if so
-         * desired. Old, valid policies remain usable, but care needs to be taken to not continue to
-         * use a potentially compromised key.
-         */
-        boolean dicePolicyWasCurrent;
-    }
-
-    parcelable ClearKeyPolicy {
-        /*
-         * Indicates the desired key size. It will be used to calculate how many bytes of key
-         * material should be returned.
-         */
-        int keySizeBytes;
-    }
-
-    union DerivedKeyPolicy {
-        /*
-         * If used we will derive a clear key and pass it back as an array of bytes on
-         * <code>HwCryptoKeyMaterial::explicitKey</code>.
-         */
-        ClearKeyPolicy clearKey;
-
-        /*
-         * Policy for the newly derived opaque key. Defines how the key can be used and its type.
-         */
-        byte[] opaqueKey;
-    }
-
-    parcelable DerivedKeyParameters {
-        /*
-         * Key to be used to derive the new key using HKDF.
-         */
-        IOpaqueKey derivationKey;
-
-        /*
-         * Policy for the newly derived key. Depending on its type, either a clear or opaque key
-         * will be derived.
-         */
-        DerivedKeyPolicy keyPolicy;
-
-        /*
-         * An arbitrary set of bytes incorporated into the key derivation. May have
-         * an implementation-specific maximum length, but it is guaranteed to accept
-         * at least 32 bytes.
-         */
-        byte[] context;
-    }
-
-    union DerivedKey {
-        /*
-         * Derived key in clear format.
-         */
-        byte[] explicitKey = {};
-
-        /*
-         * Derived key as a key token to be used only through the HWCrypto service.
-         */
-        IOpaqueKey opaque;
-    }
-
-    /*
-     * deriveCurrentDicePolicyBoundKey() - Derives a versioned key tied to the caller's current DICE
-     *                              policy. It will return this current policy back to the caller
-     *                              along with the generated key.
-     *
-     * @derivationKey:
-     *     Key to be used to derive the new key using HKDF.
-     *
-     * Return:
-     *      Ok(DiceCurrentBoundKeyResult) on success, service specific error based on
-     *      <code>HalErrorCode</code> otherwise.
-     */
-    DiceCurrentBoundKeyResult deriveCurrentDicePolicyBoundKey(
-            in DiceBoundDerivationKey derivationKey);
-
-    /*
-     * deriveDicePolicyBoundKey() - Derive a versioned key by checking the provided DICE policy
-     *                              against the caller and then using it as a context for deriving
-     *                              the returned key.
-     *
-     * @derivationKey:
-     *     Key to be used to derive the new key using HKDF.
-     *
-     * @dicePolicyForKeyVersion:
-     *     Policy used to derive keys tied to specific versions. Using this parameter
-     *     the caller can tie a derived key to a minimum version of itself, so in the future only
-     *     itself or a more recent version can derive the same key. This parameter is opaque to the
-     *     caller and it could be encrypted in the case the client doesn't have permission to know
-     *     the dice chain.
-     *     When implementing this function, this parameter shall be one of the components fed
-     *     to the KDF context and it needs to be checked against the caller DICE certificate before
-     *     being used.
-     *
-     * Return:
-     *      Ok(DiceBoundKeyResult) on success, service specific error based on
-     *      <code>HalErrorCode</code> otherwise.
-     */
-    DiceBoundKeyResult deriveDicePolicyBoundKey(
-            in DiceBoundDerivationKey derivationKey, in byte[] dicePolicyForKeyVersion);
-
-    /*
-     * deriveKey() - Derive a new key based on the given key, policy and context.
-     *
-     * @parameters:
-     *      Parameters used for the key derivation. See <code>DerivedKeyParameters</code> on this
-     *      file for more information.
-     *
-     * Return:
-     *      Ok(HwCryptoKeyMaterial) on success, service specific error based on
-     *      <code>HalErrorCode</code> otherwise.
-     */
-    DerivedKey deriveKey(in DerivedKeyParameters parameters);
-
-    /*
-     * getHwCryptoOperations() - Returns an interface used to work on opaque keys. This interface
-     *                           can also be used to operate on any opaque key generated by
-     *                           hwkeyDeriveVersioned, even if this key has been generated after
-     *                           retrieving a IHwCryptoOperations binder object, as long as the
-     *                           parent IHwCryptoDeviceKeyAccess is not dropped between retrieving
-     *                           the IHwCryptoOperations binder object and deriving the key.
-     *                           IHwCryptoOperations can also be used to create opaque keys that
-     *                           are not bound to the device.
-     *
-     * Return:
-     *      IHwCryptoOperations on success
-     */
-    IHwCryptoOperations getHwCryptoOperations();
-
-    /*
-     * importClearKey() - Imports a SW clear key into the secure environment.
-     *
-     * @keyMaterial:
-     *     key to be imported.
-     * @newKeyPolicy:
-     *      Policy of the new key. Defines how the newly created key can be used. Because any
-     *      clear key imported into the system is considered to have a
-     *      <code>KeyLifetime::PORTABLE</code> lifetime, a call to this function will return an
-     *      error if <code>newKeyPolicy.newKeyPolicy</code> is not set to portable.
-     *
-     * Return:
-     *      IOpaqueKey on success, service specific error based on <code>HalErrorCode</code>
-     *      otherwise.
-     */
-    IOpaqueKey importClearKey(in ExplicitKeyMaterial keyMaterial, in KeyPolicy newKeyPolicy);
-
-    /*
-     * getCurrentDicePolicy() - Returns the client current DICE policy. This policy is encrypted and
-     *                          considered opaque from the client perspective. This policy is the
-     *                          same used to create DICE bound keys and will also be used to seal
-     *                          secrets that can only be retrieved by the DICE policy owner. The
-     *                          first use of this seal operation will be
-     *                          <code>IOpaqueKey::getShareableToken</code> and
-     *                          <code>IHwCryptoKey::keyTokenImport</code>. To start this process,
-     *                          the intended key receiver will call this function and then pass the
-     *                          generated DICE policy to the owner of the key that the receiver
-     *                          wants to import. The key owner will then call
-     *                          <code>IOpaqueKey::getShareableToken</code> passing the receiver DICE
-     *                          policy to insure that only that receiver can import the key.
-     *
-     * Return:
-     *      byte[] on success, which is the caller encrypted DICE policy.
-     */
-    byte[] getCurrentDicePolicy();
-
-    /*
-     * key_token_import() - Imports a key from a different client service instance. Because
-     *                      IOpaqueKey are binder objects that cannot be directly shared between
-     *                      binder rpc clients, this method provide a way to send a key to another
-     *                      client. Keys to be imported by the receiver are represented by a token
-     *                      created using <code>IOpaqueKey::getShareableToken</code>. The flow
-     *                      to create this token is described in
-     *                      <code>IHwCryptoKey::getCurrentDicePolicy</code>.
-     *
-     * @requested_key:
-     *      Handle to the key to be imported to the caller service.
-     * @sealingDicePolicy:
-     *      DICE policy used to seal the exported key.
-     * Return:
-     *      A IOpaqueKey that can be directly be used on the local HWCrypto service on
-     *      success, service specific error based on <code>HalErrorCode</code> otherwise.
-     */
-    IOpaqueKey keyTokenImport(in OpaqueKeyToken requestedKey, in byte[] sealingDicePolicy);
-
-    /*
-     * getKeyslotData() - Gets the keyslot key material referenced by slotId.
-     *
-     * @slotId:
-     *      Identifier for the requested keyslot
-     *
-     * This interface is used to access device specific keys with known types and uses. Because the
-     * returned key is opaque, it can only be used through the different HwCrypto interfaces.
-     * Because the keys live in a global namespace the identity of the caller needs to be
-     * checked to verify that it has permission to accesses the requested key.
-     *
-     * Return:
-     *      Ok(IOpaqueKey) on success, UNAUTHORIZED if the caller cannot access the requested key,
-     *      another specific error code otherwise.
-     */
-    IOpaqueKey getKeyslotData(KeySlot slotId);
-}
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IOpaqueKey.aidl b/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IOpaqueKey.aidl
deleted file mode 100644
index 9a72639..0000000
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/IOpaqueKey.aidl
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.hardware.security.see.hwcrypto;
-
-import android.hardware.security.see.hwcrypto.KeyPolicy;
-import android.hardware.security.see.hwcrypto.types.OpaqueKeyToken;
-import android.hardware.security.see.hwcrypto.types.OperationType;
-import android.hardware.security.see.hwcrypto.types.ProtectionId;
-
-interface IOpaqueKey {
-    /*
-     * exportWrappedKey() - Exports this key as a wrapped (encrypted) blob.
-     *
-     * @wrapping_key:
-     *     wrapping key. It needs to be an opaque key and its policy needs to indicate that it can
-     *     be used for key wrapping.
-     *
-     * Return:
-     *      Wrapped key blob as a byte array on success. Format of the blob is opaque to the service
-     *      but has to match the command accepted by
-     *      <code>IHwCryptoKeyGeneration::importWrappedKey</code>, service specific error based on
-     *      <code>HalErrorCode</code> otherwise.
-     */
-    byte[] exportWrappedKey(in IOpaqueKey wrappingKey);
-
-    /*
-     * getKeyPolicy() - Returns the key policy.
-     *
-     * Return:
-     *      A <code>KeyPolicy</code> on success, service specific error based on
-     *      <code>HalErrorCode</code> otherwise.
-     */
-    KeyPolicy getKeyPolicy();
-
-    /*
-     * getPublicKey() - Returns the public key portion of this OpaqueKey. This operation is only
-     *                  valid for asymmetric keys
-     *
-     * Return:
-     *      public key as a byte array on success, service specific error based on
-     *      <code>HalErrorCode</code> otherwise. Format used for the returned public key is COSE.
-     */
-    byte[] getPublicKey();
-
-    /*
-     * getShareableToken() - Returns a token that can shared with another HWCrypto client.
-     *
-     * @sealingDicePolicy:
-     *      Token to be used to protect the returned OpaqueKeyToken. It will be used so only
-     *      the owner of the sealingDicePolicy can import the key.
-     * Return:
-     *      <code>OpaqueKeyMaterial</code> token on success, service specific error based on
-     *      <code>HalErrorCode</code> otherwise.
-     */
-    OpaqueKeyToken getShareableToken(in byte[] sealingDicePolicy);
-
-    /*
-     * setProtectionId() - Sets the protectionID associated with the buffers where the operation
-     *                     will be performed. A protection ID serves as a limitation on the key so
-     *                     it can only operate on buffers with a matching protection ID.
-     *                     The client calling this functions needs to have the necessary permissions
-     *                     to read and/or write to this buffer. Setting this parameter means that
-     *                     if the key is shared with a different client, the client receiving the
-     *                     key will be limited in which buffers can be used to read/write data for
-     *                     this operation.
-     *
-     * @protectionId:
-     *      ID of the given use case to provide protection for. The method of protecting the buffer
-     *      will be platform dependent.
-     * @allowedOperations:
-     *      array of allowed operations. Allowed operations are either READ or WRITE.
-     *
-     * Return:
-     *      service specific error based on <code>HalErrorCode</code> on failure.
-     */
-    void setProtectionId(in ProtectionId protectionId, in OperationType[] allowedOperations);
-}
diff --git a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/KeyType.aidl b/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/KeyType.aidl
deleted file mode 100644
index 3cf4670..0000000
--- a/staging/security/see/hwcrypto/aidl/android/hardware/security/see/hwcrypto/types/KeyType.aidl
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.hardware.security.see.hwcrypto.types;
-
-/*
- * Enum describing all supported key types. Key types are strongly bound to the algorithm to
- * prevent reusing the same key on different algorithms (e.g. using the same key for 2 different AES
- * 128 Cipher modes).
- */
-enum KeyType {
-    AES_128_CBC_NO_PADDING,
-    AES_128_CBC_PKCS7_PADDING,
-    AES_128_CTR,
-    AES_128_GCM,
-    AES_128_CMAC,
-    AES_256_CBC_NO_PADDING,
-    AES_256_CBC_PKCS7_PADDING,
-    AES_256_CTR,
-    AES_256_GCM,
-    AES_256_CMAC,
-    HMAC_SHA256,
-    HMAC_SHA512,
-    RSA2048_PSS_SHA256,
-    RSA2048_PKCS1_5_SHA256,
-    ECC_NIST_P256_SIGN_NO_PADDING,
-    ECC_NIST_P256_SIGN_SHA256,
-    ECC_NIST_P521_SIGN_NO_PADDING,
-    ECC_NIST_P521_SIGN_SHA512,
-    ECC_ED25519_SIGN,
-}
diff --git a/tests/extension/vibrator/aidl/Android.bp b/tests/extension/vibrator/aidl/Android.bp
index 0306dca..3ef8749 100644
--- a/tests/extension/vibrator/aidl/Android.bp
+++ b/tests/extension/vibrator/aidl/Android.bp
@@ -37,6 +37,15 @@
         java: {
             enabled: false,
         },
+        ndk: {
+            enabled: true,
+        },
+        cpp: {
+            enabled: false,
+        },
+        rust: {
+            enabled: false,
+        },
     },
     frozen: true,
     versions_with_info: [
diff --git a/tests/extension/vibrator/aidl/client/Android.bp b/tests/extension/vibrator/aidl/client/Android.bp
index 284ac74..00510b7 100644
--- a/tests/extension/vibrator/aidl/client/Android.bp
+++ b/tests/extension/vibrator/aidl/client/Android.bp
@@ -16,16 +16,10 @@
     srcs: [
         // system code has the option to use the unstable C++ libbinder API
         // or the NDK one. For maximum code portability, using the ndk client
-        // makes the most sense, but both are provided here as an example.
-        "test-cpp-client.cpp",
+        // makes the most sense.
         "test-ndk-client.cpp",
     ],
     shared_libs: [
-        "libbinder",
-        "libutils",
-        "android.hardware.vibrator-V2-cpp",
-        "android.hardware.tests.extension.vibrator-V1-cpp",
-
         "libbinder_ndk",
         "android.hardware.vibrator-V2-ndk",
         "android.hardware.tests.extension.vibrator-V1-ndk",
diff --git a/tests/extension/vibrator/aidl/client/test-cpp-client.cpp b/tests/extension/vibrator/aidl/client/test-cpp-client.cpp
deleted file mode 100644
index 015a345..0000000
--- a/tests/extension/vibrator/aidl/client/test-cpp-client.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android/hardware/tests/extension/vibrator/ICustomVibrator.h>
-#include <android/hardware/vibrator/IVibrator.h>
-#include <binder/IInterface.h>
-#include <binder/IServiceManager.h>
-#include <gtest/gtest.h>
-
-using android::checked_interface_cast;
-using android::IBinder;
-using android::IInterface;
-using android::OK;
-using android::sp;
-using android::waitForVintfService;
-using android::hardware::tests::extension::vibrator::Directionality;
-using android::hardware::tests::extension::vibrator::ICustomVibrator;
-using android::hardware::vibrator::IVibrator;
-
-TEST(Cpp, CallRootMethod) {
-    sp<IVibrator> vib = waitForVintfService<IVibrator>();
-    ASSERT_NE(nullptr, vib.get());
-    ASSERT_TRUE(vib->off().isOk());
-}
-
-TEST(Cpp, CallExtMethod) {
-    // normally you would want to cache this
-    sp<IVibrator> vib = waitForVintfService<IVibrator>();
-    ASSERT_NE(nullptr, vib.get());
-
-    // getting the extension
-    sp<IBinder> ext;
-    ASSERT_EQ(OK, IInterface::asBinder(vib)->getExtension(&ext));
-    sp<ICustomVibrator> cvib = checked_interface_cast<ICustomVibrator>(ext);
-    ASSERT_NE(nullptr, cvib.get());
-
-    // calling extension method
-    ASSERT_TRUE(cvib->setDirectionality(Directionality::TRANSVERSE).isOk());
-}
diff --git a/tests/extension/vibrator/aidl/client/test-ndk-client.cpp b/tests/extension/vibrator/aidl/client/test-ndk-client.cpp
index c846495..4dd86e8 100644
--- a/tests/extension/vibrator/aidl/client/test-ndk-client.cpp
+++ b/tests/extension/vibrator/aidl/client/test-ndk-client.cpp
@@ -28,7 +28,7 @@
 static const std::string kInstance = std::string() + IVibrator::descriptor + "/default";
 
 TEST(Ndk, CallRootMethod) {
-    SpAIBinder vibBinder = SpAIBinder(AServiceManager_getService(kInstance.c_str()));
+    SpAIBinder vibBinder = SpAIBinder(AServiceManager_waitForService(kInstance.c_str()));
     ASSERT_NE(nullptr, vibBinder.get());
     std::shared_ptr<IVibrator> vib = IVibrator::fromBinder(vibBinder);
     ASSERT_NE(nullptr, vib.get());
@@ -38,7 +38,7 @@
 TEST(Ndk, CallExtMethod) {
     // normally you would want to cache this
     //
-    SpAIBinder vibBinder = SpAIBinder(AServiceManager_getService(kInstance.c_str()));
+    SpAIBinder vibBinder = SpAIBinder(AServiceManager_waitForService(kInstance.c_str()));
     ASSERT_NE(nullptr, vibBinder.get());
     std::shared_ptr<IVibrator> vib = IVibrator::fromBinder(vibBinder);
     ASSERT_NE(nullptr, vib.get());
diff --git a/tests/extension/vibrator/aidl/default/Android.bp b/tests/extension/vibrator/aidl/default/Android.bp
index 5e156af..479b4fd 100644
--- a/tests/extension/vibrator/aidl/default/Android.bp
+++ b/tests/extension/vibrator/aidl/default/Android.bp
@@ -10,11 +10,6 @@
 cc_binary {
     name: "android.hardware.tests.extension.vibrator-service.example",
     relative_install_path: "hw",
-    // normally you implement a service directly, but we are using an implementation
-    // from a library to attach our extension to.
-    static_libs: [
-        "libvibratorexampleimpl",
-    ],
 
     // need to add this in the manifest and to init as well to use, see
     // android.hardware.vibrator-service.example. This binary is being tested
@@ -23,6 +18,7 @@
     vendor: true,
     srcs: [
         "service.cpp",
+        "Vibrator.cpp",
         "CustomVibrator.cpp",
     ],
     shared_libs: [
diff --git a/tests/extension/vibrator/aidl/default/Vibrator.cpp b/tests/extension/vibrator/aidl/default/Vibrator.cpp
new file mode 100644
index 0000000..5084096
--- /dev/null
+++ b/tests/extension/vibrator/aidl/default/Vibrator.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Vibrator.h"
+
+#include <android-base/logging.h>
+
+namespace aidl::android::hardware::vibrator {
+
+ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) {
+    // basic example with only amplitude control capability
+    *_aidl_return = IVibrator::CAP_AMPLITUDE_CONTROL;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::off() {
+    LOG(INFO) << "Vibrator off";
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs, const std::shared_ptr<IVibratorCallback>&) {
+    LOG(INFO) << "Vibrator on for timeoutMs: " << timeoutMs;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) {
+    LOG(INFO) << "Vibrator set amplitude: " << amplitude;
+    if (amplitude <= 0.0f || amplitude > 1.0f) {
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::perform(Effect, EffectStrength,
+                                     const std::shared_ptr<IVibratorCallback>&, int32_t*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector<Effect>* _aidl_return) {
+    *_aidl_return = {};
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::setExternalControl(bool) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getCompositionDelayMax(int32_t*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getSupportedPrimitives(std::vector<CompositePrimitive>*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive, int32_t*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect>&,
+                                     const std::shared_ptr<IVibratorCallback>&) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector<Effect>*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t, Effect, EffectStrength) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getResonantFrequency(float*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getQFactor(float*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getFrequencyResolution(float*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getFrequencyMinimum(float*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getBandwidthAmplitudeMap(std::vector<float>*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getPwlePrimitiveDurationMax(int32_t*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getPwleCompositionSizeMax(int32_t*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::getSupportedBraking(std::vector<Braking>*) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle>&,
+                                         const std::shared_ptr<IVibratorCallback>&) {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+}
+
+}  // namespace aidl::android::hardware::vibrator
diff --git a/tests/extension/vibrator/aidl/default/Vibrator.h b/tests/extension/vibrator/aidl/default/Vibrator.h
new file mode 100644
index 0000000..80916ae
--- /dev/null
+++ b/tests/extension/vibrator/aidl/default/Vibrator.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/vibrator/BnVibrator.h>
+
+namespace aidl::android::hardware::vibrator {
+
+class Vibrator : public BnVibrator {
+    ndk::ScopedAStatus getCapabilities(int32_t* _aidl_return) override;
+    ndk::ScopedAStatus off() override;
+    ndk::ScopedAStatus on(int32_t timeoutMs,
+                          const std::shared_ptr<IVibratorCallback>& callback) override;
+    ndk::ScopedAStatus perform(Effect effect, EffectStrength strength,
+                               const std::shared_ptr<IVibratorCallback>& callback,
+                               int32_t* _aidl_return) override;
+    ndk::ScopedAStatus getSupportedEffects(std::vector<Effect>* _aidl_return) override;
+    ndk::ScopedAStatus setAmplitude(float amplitude) override;
+    ndk::ScopedAStatus setExternalControl(bool enabled) override;
+    ndk::ScopedAStatus getCompositionDelayMax(int32_t* maxDelayMs);
+    ndk::ScopedAStatus getCompositionSizeMax(int32_t* maxSize);
+    ndk::ScopedAStatus getSupportedPrimitives(std::vector<CompositePrimitive>* supported) override;
+    ndk::ScopedAStatus getPrimitiveDuration(CompositePrimitive primitive,
+                                            int32_t* durationMs) override;
+    ndk::ScopedAStatus compose(const std::vector<CompositeEffect>& composite,
+                               const std::shared_ptr<IVibratorCallback>& callback) override;
+    ndk::ScopedAStatus getSupportedAlwaysOnEffects(std::vector<Effect>* _aidl_return) override;
+    ndk::ScopedAStatus alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) override;
+    ndk::ScopedAStatus alwaysOnDisable(int32_t id) override;
+    ndk::ScopedAStatus getResonantFrequency(float* resonantFreqHz) override;
+    ndk::ScopedAStatus getQFactor(float* qFactor) override;
+    ndk::ScopedAStatus getFrequencyResolution(float* freqResolutionHz) override;
+    ndk::ScopedAStatus getFrequencyMinimum(float* freqMinimumHz) override;
+    ndk::ScopedAStatus getBandwidthAmplitudeMap(std::vector<float>* _aidl_return) override;
+    ndk::ScopedAStatus getPwlePrimitiveDurationMax(int32_t* durationMs) override;
+    ndk::ScopedAStatus getPwleCompositionSizeMax(int32_t* maxSize) override;
+    ndk::ScopedAStatus getSupportedBraking(std::vector<Braking>* supported) override;
+    ndk::ScopedAStatus composePwle(const std::vector<PrimitivePwle>& composite,
+                                   const std::shared_ptr<IVibratorCallback>& callback) override;
+};
+
+}  // namespace aidl::android::hardware::vibrator
diff --git a/tests/extension/vibrator/aidl/default/service.cpp b/tests/extension/vibrator/aidl/default/service.cpp
index 16290df..5917d0f 100644
--- a/tests/extension/vibrator/aidl/default/service.cpp
+++ b/tests/extension/vibrator/aidl/default/service.cpp
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#include <vibrator-impl/Vibrator.h>
 #include "CustomVibrator.h"
+#include "Vibrator.h"
 
 #include <android-base/logging.h>
 #include <android/binder_manager.h>
diff --git a/thermal/OWNERS b/thermal/OWNERS
index 7229b22..13895bd 100644
--- a/thermal/OWNERS
+++ b/thermal/OWNERS
@@ -1,5 +1,3 @@
 # Bug component: 826709
-
-# ADPF virtual team
-lpy@google.com
+file:platform/frameworks/base:/ADPF_OWNERS
 wvw@google.com
diff --git a/tv/tuner/aidl/Android.bp b/tv/tuner/aidl/Android.bp
index 6cbf362..efcc327 100644
--- a/tv/tuner/aidl/Android.bp
+++ b/tv/tuner/aidl/Android.bp
@@ -41,6 +41,5 @@
         },
 
     ],
-    frozen: true,
 
 }
diff --git a/tv/tuner/aidl/default/Android.bp b/tv/tuner/aidl/default/Android.bp
index 4f0d04b..a76a653 100644
--- a/tv/tuner/aidl/default/Android.bp
+++ b/tv/tuner/aidl/default/Android.bp
@@ -29,7 +29,7 @@
     ],
     shared_libs: [
         "android.hardware.common.fmq-V1-ndk",
-        "android.hardware.tv.tuner-V2-ndk",
+        "android.hardware.tv.tuner-V3-ndk",
         "libbase",
         "libbinder_ndk",
         "libcutils",
diff --git a/tv/tuner/aidl/vts/functional/Android.bp b/tv/tuner/aidl/vts/functional/Android.bp
index ae4f598..4c961ad 100644
--- a/tv/tuner/aidl/vts/functional/Android.bp
+++ b/tv/tuner/aidl/vts/functional/Android.bp
@@ -56,7 +56,7 @@
         "android.hardware.cas-V1-ndk",
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
-        "android.hardware.tv.tuner-V2-ndk",
+        "android.hardware.tv.tuner-V3-ndk",
         "libaidlcommonsupport",
         "libfmq",
         "libcutils",
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
index 2b39bc6..158e4f1 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
@@ -100,7 +100,9 @@
     ASSERT_TRUE(mFilterTests.configFilter(filterReconf.settings, filterId));
     ASSERT_TRUE(mFilterTests.startFilter(filterId));
     ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
-    ASSERT_TRUE(mFilterTests.startIdTest(filterId));
+    if (!isPassthroughFilter(filterReconf)) {
+        ASSERT_TRUE(mFilterTests.startIdTest(filterId));
+    }
     ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
     ASSERT_TRUE(mFilterTests.stopFilter(filterId));
     ASSERT_TRUE(mFilterTests.closeFilter(filterId));
@@ -152,7 +154,9 @@
     ASSERT_TRUE(mFilterTests.startFilter(filterId));
     // tune test
     ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
-    ASSERT_TRUE(filterDataOutputTest());
+    if (!isPassthroughFilter(filterConf)) {
+        ASSERT_TRUE(filterDataOutputTest());
+    }
     ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
     ASSERT_TRUE(mFilterTests.stopFilter(filterId));
     ASSERT_TRUE(mFilterTests.closeFilter(filterId));
@@ -210,7 +214,9 @@
     ASSERT_TRUE(mFilterTests.startFilter(filterId));
     // tune test
     ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
-    ASSERT_TRUE(filterDataOutputTest());
+    if (!isPassthroughFilter(filterConf)) {
+        ASSERT_TRUE(filterDataOutputTest());
+    }
     ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
     ASSERT_TRUE(mFilterTests.stopFilter(filterId));
     ASSERT_TRUE(mFilterTests.releaseShareAvHandle(filterId));
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
index be9b996..5fdc3dc 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
@@ -89,6 +89,28 @@
     sectionFilterIds.clear();
 }
 
+bool isPassthroughFilter(FilterConfig filterConfig) {
+    auto type = filterConfig.type;
+    if (type.mainType == DemuxFilterMainType::TS) {
+        auto subType = type.subType.get<DemuxFilterSubType::Tag::tsFilterType>();
+        if (subType == DemuxTsFilterType::AUDIO || subType == DemuxTsFilterType::VIDEO) {
+            auto tsFilterSettings = filterConfig.settings.get<DemuxFilterSettings::Tag::ts>();
+            auto avSettings = tsFilterSettings.filterSettings
+                    .get<DemuxTsFilterSettingsFilterSettings::Tag::av>();
+            return avSettings.isPassthrough;
+        }
+    } else if (filterConfig.type.mainType != DemuxFilterMainType::MMTP) {
+        auto subType = type.subType.get<DemuxFilterSubType::Tag::mmtpFilterType>();
+        if (subType == DemuxMmtpFilterType::AUDIO || subType == DemuxMmtpFilterType::VIDEO) {
+            auto mmtpFilterSettings = filterConfig.settings.get<DemuxFilterSettings::Tag::mmtp>();
+            auto avSettings = mmtpFilterSettings.filterSettings
+                    .get<DemuxMmtpFilterSettingsFilterSettings::Tag::av>();
+            return avSettings.isPassthrough;
+        }
+    }
+    return false;
+}
+
 enum class Dataflow_Context { LNBRECORD, RECORD, DESCRAMBLING, LNBDESCRAMBLING };
 
 class TunerLnbAidlTest : public testing::TestWithParam<std::string> {
diff --git a/vibrator/aidl/Android.bp b/vibrator/aidl/Android.bp
index d3b72ee..b2d98f5 100644
--- a/vibrator/aidl/Android.bp
+++ b/vibrator/aidl/Android.bp
@@ -15,15 +15,33 @@
     srcs: [
         "android/hardware/vibrator/*.aidl",
     ],
+    headers: [
+        "PersistableBundle_aidl",
+    ],
     stability: "vintf",
     backend: {
         java: {
             sdk_version: "system_current",
         },
+        ndk: {
+            enabled: true,
+        },
+        cpp: {
+            enabled: false,
+        },
+        rust: {
+            enabled: false,
+        },
     },
-    versions: [
-        "1",
-        "2",
+    versions_with_info: [
+        {
+            version: "1",
+            imports: [],
+        },
+        {
+            version: "2",
+            imports: [],
+        },
     ],
-    frozen: true,
+    frozen: false,
 }
diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrator.aidl
index b7afb66..0dcc657 100644
--- a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrator.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrator.aidl
@@ -58,15 +58,23 @@
   int getPwleCompositionSizeMax();
   android.hardware.vibrator.Braking[] getSupportedBraking();
   void composePwle(in android.hardware.vibrator.PrimitivePwle[] composite, in android.hardware.vibrator.IVibratorCallback callback);
-  const int CAP_ON_CALLBACK = 1;
-  const int CAP_PERFORM_CALLBACK = 2;
-  const int CAP_AMPLITUDE_CONTROL = 4;
-  const int CAP_EXTERNAL_CONTROL = 8;
-  const int CAP_EXTERNAL_AMPLITUDE_CONTROL = 16;
-  const int CAP_COMPOSE_EFFECTS = 32;
-  const int CAP_ALWAYS_ON_CONTROL = 64;
-  const int CAP_GET_RESONANT_FREQUENCY = 128;
-  const int CAP_GET_Q_FACTOR = 256;
-  const int CAP_FREQUENCY_CONTROL = 512;
-  const int CAP_COMPOSE_PWLE_EFFECTS = 1024;
+  void performVendorEffect(in android.hardware.vibrator.VendorEffect vendorEffect, in android.hardware.vibrator.IVibratorCallback callback);
+  List<android.hardware.vibrator.PwleV2OutputMapEntry> getPwleV2FrequencyToOutputAccelerationMap();
+  int getPwleV2PrimitiveDurationMaxMillis();
+  int getPwleV2CompositionSizeMax();
+  int getPwleV2PrimitiveDurationMinMillis();
+  void composePwleV2(in android.hardware.vibrator.PwleV2Primitive[] composite, in android.hardware.vibrator.IVibratorCallback callback);
+  const int CAP_ON_CALLBACK = (1 << 0) /* 1 */;
+  const int CAP_PERFORM_CALLBACK = (1 << 1) /* 2 */;
+  const int CAP_AMPLITUDE_CONTROL = (1 << 2) /* 4 */;
+  const int CAP_EXTERNAL_CONTROL = (1 << 3) /* 8 */;
+  const int CAP_EXTERNAL_AMPLITUDE_CONTROL = (1 << 4) /* 16 */;
+  const int CAP_COMPOSE_EFFECTS = (1 << 5) /* 32 */;
+  const int CAP_ALWAYS_ON_CONTROL = (1 << 6) /* 64 */;
+  const int CAP_GET_RESONANT_FREQUENCY = (1 << 7) /* 128 */;
+  const int CAP_GET_Q_FACTOR = (1 << 8) /* 256 */;
+  const int CAP_FREQUENCY_CONTROL = (1 << 9) /* 512 */;
+  const int CAP_COMPOSE_PWLE_EFFECTS = (1 << 10) /* 1024 */;
+  const int CAP_PERFORM_VENDOR_EFFECTS = (1 << 11) /* 2048 */;
+  const int CAP_COMPOSE_PWLE_EFFECTS_V2 = (1 << 12) /* 4096 */;
 }
diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorManager.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorManager.aidl
index 290c68d..ef5794c 100644
--- a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorManager.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorManager.aidl
@@ -40,12 +40,12 @@
   void prepareSynced(in int[] vibratorIds);
   void triggerSynced(in android.hardware.vibrator.IVibratorCallback callback);
   void cancelSynced();
-  const int CAP_SYNC = 1;
-  const int CAP_PREPARE_ON = 2;
-  const int CAP_PREPARE_PERFORM = 4;
-  const int CAP_PREPARE_COMPOSE = 8;
-  const int CAP_MIXED_TRIGGER_ON = 16;
-  const int CAP_MIXED_TRIGGER_PERFORM = 32;
-  const int CAP_MIXED_TRIGGER_COMPOSE = 64;
-  const int CAP_TRIGGER_CALLBACK = 128;
+  const int CAP_SYNC = (1 << 0) /* 1 */;
+  const int CAP_PREPARE_ON = (1 << 1) /* 2 */;
+  const int CAP_PREPARE_PERFORM = (1 << 2) /* 4 */;
+  const int CAP_PREPARE_COMPOSE = (1 << 3) /* 8 */;
+  const int CAP_MIXED_TRIGGER_ON = (1 << 4) /* 16 */;
+  const int CAP_MIXED_TRIGGER_PERFORM = (1 << 5) /* 32 */;
+  const int CAP_MIXED_TRIGGER_COMPOSE = (1 << 6) /* 64 */;
+  const int CAP_TRIGGER_CALLBACK = (1 << 7) /* 128 */;
 }
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PwleV2OutputMapEntry.aidl
similarity index 88%
copy from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
copy to vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PwleV2OutputMapEntry.aidl
index 1e304ab..a5eda52 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PwleV2OutputMapEntry.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2024 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -31,7 +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.see.hwcrypto.types;
-enum ProtectionId {
-  WIDEVINE_OUTPUT_BUFFER = 1,
+package android.hardware.vibrator;
+@VintfStability
+parcelable PwleV2OutputMapEntry {
+  float frequencyHz;
+  float maxOutputAccelerationGs;
 }
diff --git a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PwleV2Primitive.aidl
similarity index 88%
copy from staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
copy to vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PwleV2Primitive.aidl
index 1e304ab..c4f3ea9 100644
--- a/staging/security/see/hwcrypto/aidl/aidl_api/android.hardware.security.see/current/android/hardware/security/see/hwcrypto/types/ProtectionId.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PwleV2Primitive.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2024 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -31,7 +31,10 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.security.see.hwcrypto.types;
-enum ProtectionId {
-  WIDEVINE_OUTPUT_BUFFER = 1,
+package android.hardware.vibrator;
+@VintfStability
+parcelable PwleV2Primitive {
+  float amplitude;
+  float frequencyHz;
+  int timeMillis;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/VendorEffect.aidl
similarity index 86%
rename from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
rename to vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/VendorEffect.aidl
index c1dc51c..62a7380 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/VendorEffect.aidl
@@ -31,10 +31,11 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
+package android.hardware.vibrator;
 @VintfStability
-union AcquiredInfoAndVendorCode {
-  android.hardware.biometrics.fingerprint.AcquiredInfo acquiredInfo = android.hardware.biometrics.fingerprint.AcquiredInfo.UNKNOWN;
-  int vendorCode;
+parcelable VendorEffect {
+  android.os.PersistableBundle vendorData;
+  android.hardware.vibrator.EffectStrength strength = android.hardware.vibrator.EffectStrength.MEDIUM;
+  float scale;
+  float vendorScale;
 }
diff --git a/vibrator/aidl/android/hardware/vibrator/Braking.aidl b/vibrator/aidl/android/hardware/vibrator/Braking.aidl
index 2bc51db..f934ff2 100644
--- a/vibrator/aidl/android/hardware/vibrator/Braking.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/Braking.aidl
@@ -23,12 +23,12 @@
      * No braking mechanism used.
      * This is the default if the hardware does not support any braking mechanism.
      */
-    NONE,
+    NONE = 0,
     /**
      * Closed-loop active braking.
      *
      * This effect should produce a sharp, crisp end to the waveform
      * Support is optional.
      */
-    CLAB,
+    CLAB = 1,
 }
diff --git a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
index 5314898..5f8ee8d 100644
--- a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
@@ -24,13 +24,13 @@
      *
      * Support is required.
      */
-    NOOP,
+    NOOP = 0,
     /**
      * This effect should produce a sharp, crisp click sensation.
      *
      * Support is required.
      */
-    CLICK,
+    CLICK = 1,
     /**
      * A haptic effect that simulates downwards movement with gravity. Often
      * followed by extra energy of hitting and reverberation to augment
@@ -38,43 +38,43 @@
      *
      * Support is optional.
      */
-    THUD,
+    THUD = 2,
     /**
      * A haptic effect that simulates spinning momentum.
      *
      * Support is optional.
      */
-    SPIN,
+    SPIN = 3,
     /**
      * A haptic effect that simulates quick upward movement against gravity.
      *
      * Support is required.
      */
-    QUICK_RISE,
+    QUICK_RISE = 4,
     /**
      * A haptic effect that simulates slow upward movement against gravity.
      *
      * Support is required.
      */
-    SLOW_RISE,
+    SLOW_RISE = 5,
     /**
      * A haptic effect that simulates quick downwards movement with gravity.
      *
      * Support is required.
      */
-    QUICK_FALL,
+    QUICK_FALL = 6,
     /**
      * This very short effect should produce a light crisp sensation intended
      * to be used repetitively for dynamic feedback.
      *
      * Support is required.
      */
-    LIGHT_TICK,
+    LIGHT_TICK = 7,
     /**
      * This very short low frequency effect should produce a light crisp sensation intended
      * to be used repetitively for dynamic feedback.
      *
      * Support is required.
      */
-    LOW_TICK,
+    LOW_TICK = 8,
 }
diff --git a/vibrator/aidl/android/hardware/vibrator/Effect.aidl b/vibrator/aidl/android/hardware/vibrator/Effect.aidl
index c60bfe9..f5cf9e3 100644
--- a/vibrator/aidl/android/hardware/vibrator/Effect.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/Effect.aidl
@@ -24,57 +24,57 @@
      *
      * This effect should produce a sharp, crisp click sensation.
      */
-    CLICK,
+    CLICK = 0,
     /**
      * A double click effect.
      *
      * This effect should produce two sequential sharp, crisp click sensations with a minimal
      * amount of time between them.
      */
-    DOUBLE_CLICK,
+    DOUBLE_CLICK = 1,
     /**
      * A tick effect.
      *
      * This effect should produce a soft, short sensation, like the tick of a clock.
      */
-    TICK,
+    TICK = 2,
     /**
      * A thud effect.
      *
      * This effect should solid feeling bump, like the depression of a heavy mechanical button.
      */
-    THUD,
+    THUD = 3,
     /**
      * A pop effect.
      *
      * A short, quick burst effect.
      */
-    POP,
+    POP = 4,
     /**
      * A heavy click effect.
      *
      * This should produce a sharp striking sensation, like a click but stronger.
      */
-    HEAVY_CLICK,
+    HEAVY_CLICK = 5,
     /**
      * Ringtone patterns. They may correspond with the device's ringtone audio, or may just be a
      * pattern that can be played as a ringtone with any audio, depending on the device.
      */
-    RINGTONE_1,
-    RINGTONE_2,
-    RINGTONE_3,
-    RINGTONE_4,
-    RINGTONE_5,
-    RINGTONE_6,
-    RINGTONE_7,
-    RINGTONE_8,
-    RINGTONE_9,
-    RINGTONE_10,
-    RINGTONE_11,
-    RINGTONE_12,
-    RINGTONE_13,
-    RINGTONE_14,
-    RINGTONE_15,
+    RINGTONE_1 = 6,
+    RINGTONE_2 = 7,
+    RINGTONE_3 = 8,
+    RINGTONE_4 = 9,
+    RINGTONE_5 = 10,
+    RINGTONE_6 = 11,
+    RINGTONE_7 = 12,
+    RINGTONE_8 = 13,
+    RINGTONE_9 = 14,
+    RINGTONE_10 = 15,
+    RINGTONE_11 = 16,
+    RINGTONE_12 = 17,
+    RINGTONE_13 = 18,
+    RINGTONE_14 = 19,
+    RINGTONE_15 = 20,
     /**
      * A soft tick effect meant to be played as a texture.
      *
@@ -82,5 +82,5 @@
      * are expected to be played multiple times in quick succession, replicating a specific
      * texture to the user as a form of haptic feedback.
      */
-    TEXTURE_TICK,
+    TEXTURE_TICK = 21,
 }
diff --git a/vibrator/aidl/android/hardware/vibrator/EffectStrength.aidl b/vibrator/aidl/android/hardware/vibrator/EffectStrength.aidl
index 66f70e5..c6a78d4 100644
--- a/vibrator/aidl/android/hardware/vibrator/EffectStrength.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/EffectStrength.aidl
@@ -19,7 +19,7 @@
 @VintfStability
 @Backing(type="byte")
 enum EffectStrength {
-    LIGHT,
-    MEDIUM,
-    STRONG,
+    LIGHT = 0,
+    MEDIUM = 1,
+    STRONG = 2,
 }
diff --git a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
index b4e7e44..11f36ba 100644
--- a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
@@ -16,13 +16,16 @@
 
 package android.hardware.vibrator;
 
-import android.hardware.vibrator.IVibratorCallback;
 import android.hardware.vibrator.Braking;
-import android.hardware.vibrator.Effect;
-import android.hardware.vibrator.EffectStrength;
 import android.hardware.vibrator.CompositeEffect;
 import android.hardware.vibrator.CompositePrimitive;
+import android.hardware.vibrator.Effect;
+import android.hardware.vibrator.EffectStrength;
+import android.hardware.vibrator.IVibratorCallback;
 import android.hardware.vibrator.PrimitivePwle;
+import android.hardware.vibrator.PwleV2OutputMapEntry;
+import android.hardware.vibrator.PwleV2Primitive;
+import android.hardware.vibrator.VendorEffect;
 
 @VintfStability
 interface IVibrator {
@@ -70,6 +73,14 @@
      * Whether composePwle is supported.
      */
     const int CAP_COMPOSE_PWLE_EFFECTS = 1 << 10;
+    /**
+     * Whether perform w/ vendor effect is supported.
+     */
+    const int CAP_PERFORM_VENDOR_EFFECTS = 1 << 11;
+    /**
+     * Whether composePwleV2 for PwlePrimitives is supported.
+     */
+    const int CAP_COMPOSE_PWLE_EFFECTS_V2 = 1 << 12;
 
     /**
      * Determine capabilities of the vibrator HAL (CAP_* mask)
@@ -359,4 +370,103 @@
      * @param composite Array of PWLEs.
      */
     void composePwle(in PrimitivePwle[] composite, in IVibratorCallback callback);
+
+    /**
+     * Fire off a vendor-defined haptic event.
+     *
+     * This may not be supported and this support is reflected in
+     * getCapabilities (CAP_PERFORM_VENDOR_EFFECTS).
+     *
+     * The duration of the effect is unknown and can be undefined for looping effects.
+     * IVibratorCallback.onComplete() support is required for this API.
+     *
+     * Doing this operation while the vibrator is already on is undefined behavior. Clients should
+     * explicitly call off.
+     *
+     * @param effect The vendor data representing the effect to be performed.
+     * @param callback A callback used to inform Frameworks of state change.
+     * @throws :
+     *         - EX_UNSUPPORTED_OPERATION if unsupported, as reflected by getCapabilities.
+     *         - EX_ILLEGAL_ARGUMENT for bad framework parameters, e.g. scale or effect strength.
+     *         - EX_SERVICE_SPECIFIC for bad vendor data, vibration is not triggered.
+     */
+    void performVendorEffect(in VendorEffect vendorEffect, in IVibratorCallback callback);
+
+    /**
+     * Retrieves a mapping of vibration frequency (Hz) to the maximum achievable output
+     * acceleration (Gs) the device can reach at that frequency.
+     *
+     * The map, represented as a list of `PwleV2OutputMapEntry` (frequency, output acceleration)
+     * pairs, defines the device's frequency response. The platform uses the minimum and maximum
+     * frequency values to determine the supported input range for `IVibrator.composePwleV2`.
+     * Output acceleration values are used to identify a frequency range suitable to safely play
+     * perceivable vibrations with a simple API. The map is also exposed for developers using an
+     * advanced API.
+     *
+     * The platform does not impose specific requirements on map resolution which can vary
+     * depending on the shape of device output curve. The values will be linearly interpolated
+     * during lookups. The platform will provide a simple API, defined by the first frequency range
+     * where output acceleration consistently exceeds a minimum threshold of 10 db SL.
+     *
+     *
+     * This may not be supported and this support is reflected in getCapabilities
+     * (CAP_COMPOSE_PWLE_EFFECTS_V2). If this is supported, it's expected to be non-empty and
+     * describe a valid non-empty frequency range where the simple API can be defined
+     * (i.e. a range where the output acceleration is always above 10 db SL).
+     *
+     * @return A list of map entries representing the frequency to max acceleration
+     *         mapping.
+     * @throws EX_UNSUPPORTED_OPERATION if unsupported, as reflected by getCapabilities.
+     */
+    List<PwleV2OutputMapEntry> getPwleV2FrequencyToOutputAccelerationMap();
+
+    /**
+     * Retrieve the maximum duration allowed for any primitive PWLE in units of
+     * milliseconds.
+     *
+     * This may not be supported and this support is reflected in
+     * getCapabilities (CAP_COMPOSE_PWLE_EFFECTS_V2).
+     *
+     * @return The maximum duration allowed for a single PrimitivePwle. Non-zero value if supported.
+     * @throws EX_UNSUPPORTED_OPERATION if unsupported, as reflected by getCapabilities.
+     */
+    int getPwleV2PrimitiveDurationMaxMillis();
+
+    /**
+     * Retrieve the maximum number of PWLE primitives input supported by IVibrator.composePwleV2.
+     *
+     * This may not be supported and this support is reflected in
+     * getCapabilities (CAP_COMPOSE_PWLE_EFFECTS_V2). Devices supporting PWLE effects must
+     * support effects with at least 16 PwleV2Primitive.
+     *
+     * @return The maximum count allowed. Non-zero value if supported.
+     * @throws EX_UNSUPPORTED_OPERATION if unsupported, as reflected by getCapabilities.
+     */
+    int getPwleV2CompositionSizeMax();
+
+    /**
+     * Retrieves the minimum duration (in milliseconds) of any segment within a
+     * PWLE effect. Devices supporting PWLE effects must support a minimum ramp
+     * time of 20 milliseconds.
+     *
+     * This may not be supported and this support is reflected in
+     * getCapabilities (CAP_COMPOSE_PWLE_EFFECTS_V2).
+     *
+     * @return The minimum duration allowed for a single PrimitivePwle. Non-zero value if supported.
+     * @throws EX_UNSUPPORTED_OPERATION if unsupported, as reflected by getCapabilities.
+     */
+    int getPwleV2PrimitiveDurationMinMillis();
+
+    /**
+     * Play composed sequence of chirps with optional callback upon completion.
+     *
+     * This may not be supported and this support is reflected in
+     * getCapabilities (CAP_COMPOSE_PWLE_EFFECTS_V2).
+     *
+     * Doing this operation while the vibrator is already on is undefined behavior. Clients should
+     * explicitly call off. IVibratorCallback.onComplete() support is required for this API.
+     *
+     * @param composite An array of primitives that represents a PWLE (Piecewise-Linear Envelope).
+     */
+    void composePwleV2(in PwleV2Primitive[] composite, in IVibratorCallback callback);
 }
diff --git a/vibrator/aidl/android/hardware/vibrator/PwleV2OutputMapEntry.aidl b/vibrator/aidl/android/hardware/vibrator/PwleV2OutputMapEntry.aidl
new file mode 100644
index 0000000..a8db87c
--- /dev/null
+++ b/vibrator/aidl/android/hardware/vibrator/PwleV2OutputMapEntry.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.vibrator;
+
+@VintfStability
+parcelable PwleV2OutputMapEntry {
+    /**
+     * Absolute frequency point in the units of hertz
+     *
+     */
+    float frequencyHz;
+
+    /**
+     * Max output acceleration for the specified frequency in units of Gs.
+     *
+     * This value represents the maximum safe output acceleration (in Gs) achievable at the
+     * specified frequency, typically determined during calibration. The actual output acceleration
+     * is assumed to scale linearly with the input amplitude within the range of [0, 1].
+     */
+    float maxOutputAccelerationGs;
+}
diff --git a/vibrator/aidl/android/hardware/vibrator/PwleV2Primitive.aidl b/vibrator/aidl/android/hardware/vibrator/PwleV2Primitive.aidl
new file mode 100644
index 0000000..bd7bec6
--- /dev/null
+++ b/vibrator/aidl/android/hardware/vibrator/PwleV2Primitive.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.vibrator;
+
+@VintfStability
+parcelable PwleV2Primitive {
+    /**
+     * Input amplitude ranges from 0.0 (inclusive) to 1.0 (inclusive), representing the relative
+     * input value. Actual output acceleration depends on frequency and device response curve
+     * (see IVibrator.getPwleV2FrequencyToOutputAccelerationMap for max values).
+     *
+     * Input amplitude linearly maps to output acceleration (e.g., 0.5 amplitude yields half the
+     * max acceleration for that frequency).
+     *
+     * 0.0 represents no output acceleration amplitude
+     * 1.0 represents the maximum achievable strength for each frequency, as determined by the
+     *     actuator response curve
+     */
+    float amplitude;
+
+    /**
+     * Absolute frequency point in the units of hertz
+     *
+     * Values are within the continuous inclusive frequency range defined by
+     * IVibrator#getPwleV2FrequencyToOutputAccelerationMap.
+     */
+    float frequencyHz;
+
+    /* Total time from the previous PWLE point to the current one in units of milliseconds. */
+    int timeMillis;
+}
diff --git a/vibrator/aidl/android/hardware/vibrator/VendorEffect.aidl b/vibrator/aidl/android/hardware/vibrator/VendorEffect.aidl
new file mode 100644
index 0000000..6b1af53
--- /dev/null
+++ b/vibrator/aidl/android/hardware/vibrator/VendorEffect.aidl
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.vibrator;
+
+import android.hardware.vibrator.EffectStrength;
+import android.os.PersistableBundle;
+
+@VintfStability
+parcelable VendorEffect {
+    /**
+     * Vendor data describing the haptic effect. Expected fields should be defined by the vendor.
+     *
+     * Vendors can use this as a platform extension point for experimental hardware capabilities,
+     * but they are strongly discouraged from using it as an alternative to the AOSP support for
+     * stable vibrator APIs. Implemenitng vendor-specific custom effects outside the platform APIs
+     * will hinder portability for the code and overall user experience.
+     *
+     * Vendors are encouraged to upstream new capabilities to the IVibrator surface once it has
+     * matured into a stable interface.
+     */
+    PersistableBundle vendorData;
+
+    /**
+     * The intensity of the haptic effect.
+     *
+     * This value is defined by discrete scale levels that represents the intensity of this haptic
+     * effect. This is a discrete representation of the scale parameter below.
+     */
+    EffectStrength strength = EffectStrength.MEDIUM;
+
+    /**
+     * The intensity of the haptic effect.
+     *
+     * This value is defined by continuous scale that represents the intensity of this haptic
+     * effect. The vendor implementation can follow the platform scaling function or customize the
+     * implementation to their needs. This is a continuous representation of the strength parameter
+     * above.
+     *
+     * Values in [0,1) should scale down. Values > 1 should scale up within hardware bounds.
+     */
+    float scale;
+
+    /**
+     * The dynamic scale parameter provided by the vendor vibrator controller.
+     *
+     * This value is the same provided by the vendor to the platform IVibratorControlService and
+     * should be applied on top of the effect intensity provided by the strength/scale fields.
+     * The vendor can use this to dynamically adapt the haptic effect intensity to the device state.
+     *
+     * See frameworks/hardware/interfaces/vibrator for more documentation on vendor vibrator
+     * controller, and ScaleParam for more about this scale parameter.
+     *
+     * Values in [0,1) should scale down. Values > 1 should scale up within hardware bounds.
+     */
+    float vendorScale;
+}
diff --git a/vibrator/aidl/default/Android.bp b/vibrator/aidl/default/Android.bp
index 596c1a6..b25a5ba 100644
--- a/vibrator/aidl/default/Android.bp
+++ b/vibrator/aidl/default/Android.bp
@@ -15,7 +15,7 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.vibrator-V2-ndk",
+        "android.hardware.vibrator-V3-ndk",
     ],
     export_include_dirs: ["include"],
     srcs: [
@@ -49,7 +49,7 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.vibrator-V2-ndk",
+        "android.hardware.vibrator-V3-ndk",
     ],
     static_libs: [
         "libvibratorexampleimpl",
@@ -62,7 +62,7 @@
     host_supported: true,
     defaults: ["service_fuzzer_defaults"],
     static_libs: [
-        "android.hardware.vibrator-V2-ndk",
+        "android.hardware.vibrator-V3-ndk",
         "liblog",
         "libvibratorexampleimpl",
     ],
diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp
index 01602ab..4f8c2b8 100644
--- a/vibrator/aidl/default/Vibrator.cpp
+++ b/vibrator/aidl/default/Vibrator.cpp
@@ -27,9 +27,12 @@
 static constexpr int32_t COMPOSE_DELAY_MAX_MS = 1000;
 static constexpr int32_t COMPOSE_SIZE_MAX = 256;
 static constexpr int32_t COMPOSE_PWLE_SIZE_MAX = 127;
+static constexpr int32_t COMPOSE_PWLE_V2_SIZE_MAX = 16;
 
 static constexpr float Q_FACTOR = 11.0;
 static constexpr int32_t COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS = 16383;
+static constexpr int32_t COMPOSE_PWLE_V2_PRIMITIVE_DURATION_MAX_MS = 1000;
+static constexpr int32_t COMPOSE_PWLE_V2_PRIMITIVE_DURATION_MIN_MS = 20;
 static constexpr float PWLE_LEVEL_MIN = 0.0;
 static constexpr float PWLE_LEVEL_MAX = 1.0;
 static constexpr float PWLE_FREQUENCY_RESOLUTION_HZ = 1.0;
@@ -39,14 +42,30 @@
 static constexpr float PWLE_BW_MAP_SIZE =
         1 + ((PWLE_FREQUENCY_MAX_HZ - PWLE_FREQUENCY_MIN_HZ) / PWLE_FREQUENCY_RESOLUTION_HZ);
 
+// Service specific error code used for vendor vibration effects.
+static constexpr int32_t ERROR_CODE_INVALID_DURATION = 1;
+
 ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) {
     LOG(VERBOSE) << "Vibrator reporting capabilities";
-    *_aidl_return = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK |
-                    IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_EXTERNAL_CONTROL |
-                    IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL | IVibrator::CAP_COMPOSE_EFFECTS |
-                    IVibrator::CAP_ALWAYS_ON_CONTROL | IVibrator::CAP_GET_RESONANT_FREQUENCY |
-                    IVibrator::CAP_GET_Q_FACTOR | IVibrator::CAP_FREQUENCY_CONTROL |
-                    IVibrator::CAP_COMPOSE_PWLE_EFFECTS;
+    std::lock_guard lock(mMutex);
+    if (mCapabilities == 0) {
+        if (!getInterfaceVersion(&mVersion).isOk()) {
+            return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_STATE));
+        }
+        mCapabilities = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK |
+                        IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_EXTERNAL_CONTROL |
+                        IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL | IVibrator::CAP_COMPOSE_EFFECTS |
+                        IVibrator::CAP_ALWAYS_ON_CONTROL | IVibrator::CAP_GET_RESONANT_FREQUENCY |
+                        IVibrator::CAP_GET_Q_FACTOR | IVibrator::CAP_FREQUENCY_CONTROL |
+                        IVibrator::CAP_COMPOSE_PWLE_EFFECTS;
+
+        if (mVersion >= 3) {
+            mCapabilities |= (IVibrator::CAP_PERFORM_VENDOR_EFFECTS |
+                              IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2);
+        }
+    }
+
+    *_aidl_return = mCapabilities;
     return ndk::ScopedAStatus::ok();
 }
 
@@ -102,6 +121,47 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Vibrator::performVendorEffect(
+        const VendorEffect& effect, const std::shared_ptr<IVibratorCallback>& callback) {
+    LOG(VERBOSE) << "Vibrator perform vendor effect";
+    int32_t capabilities = 0;
+    if (!getCapabilities(&capabilities).isOk()) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if ((capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) == 0) {
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+    }
+    EffectStrength strength = effect.strength;
+    if (strength != EffectStrength::LIGHT && strength != EffectStrength::MEDIUM &&
+        strength != EffectStrength::STRONG) {
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
+    }
+    float scale = effect.scale;
+    if (scale <= 0) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    float vendorScale = effect.vendorScale;
+    if (vendorScale <= 0) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+
+    int32_t durationMs = 0;
+    if (!effect.vendorData.getInt("DURATION_MS", &durationMs) || durationMs <= 0) {
+        return ndk::ScopedAStatus::fromServiceSpecificError(ERROR_CODE_INVALID_DURATION);
+    }
+
+    if (callback != nullptr) {
+        std::thread([callback, durationMs] {
+            LOG(VERBOSE) << "Starting perform on another thread for durationMs:" << durationMs;
+            usleep(durationMs * 1000);
+            LOG(VERBOSE) << "Notifying perform vendor effect complete";
+            callback->onComplete();
+        }).detach();
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector<Effect>* _aidl_return) {
     *_aidl_return = {Effect::CLICK, Effect::TICK};
     return ndk::ScopedAStatus::ok();
@@ -412,6 +472,122 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Vibrator::getPwleV2FrequencyToOutputAccelerationMap(
+        std::vector<PwleV2OutputMapEntry>* _aidl_return) {
+    std::vector<PwleV2OutputMapEntry> frequencyToOutputAccelerationMap;
+
+    std::vector<std::pair<float, float>> frequencyToOutputAccelerationData = {
+            {30.0f, 0.01f},  {46.0f, 0.09f},  {50.0f, 0.1f},   {55.0f, 0.12f},  {62.0f, 0.66f},
+            {83.0f, 0.82f},  {85.0f, 0.85f},  {92.0f, 1.05f},  {107.0f, 1.63f}, {115.0f, 1.72f},
+            {123.0f, 1.81f}, {135.0f, 2.23f}, {144.0f, 2.47f}, {145.0f, 2.5f},  {150.0f, 3.0f},
+            {175.0f, 2.51f}, {181.0f, 2.41f}, {190.0f, 2.28f}, {200.0f, 2.08f}, {204.0f, 1.96f},
+            {205.0f, 1.9f},  {224.0f, 1.7f},  {235.0f, 1.5f},  {242.0f, 1.46f}, {253.0f, 1.41f},
+            {263.0f, 1.39f}, {65.0f, 1.38f},  {278.0f, 1.37f}, {294.0f, 1.35f}, {300.0f, 1.34f}};
+    for (const auto& entry : frequencyToOutputAccelerationData) {
+        frequencyToOutputAccelerationMap.push_back(
+                PwleV2OutputMapEntry(/*frequency=*/entry.first,
+                                     /*maxOutputAcceleration=*/entry.second));
+    }
+
+    *_aidl_return = frequencyToOutputAccelerationMap;
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::getPwleV2PrimitiveDurationMaxMillis(int32_t* maxDurationMs) {
+    *maxDurationMs = COMPOSE_PWLE_V2_PRIMITIVE_DURATION_MAX_MS;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::getPwleV2CompositionSizeMax(int32_t* maxSize) {
+    *maxSize = COMPOSE_PWLE_V2_SIZE_MAX;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::getPwleV2PrimitiveDurationMinMillis(int32_t* minDurationMs) {
+    *minDurationMs = COMPOSE_PWLE_V2_PRIMITIVE_DURATION_MIN_MS;
+    return ndk::ScopedAStatus::ok();
+}
+
+float getPwleV2FrequencyMinHz(std::vector<PwleV2OutputMapEntry> frequencyToOutputAccelerationMap) {
+    if (frequencyToOutputAccelerationMap.empty()) {
+        return 0.0f;
+    }
+
+    float minFrequency = frequencyToOutputAccelerationMap[0].frequencyHz;
+
+    for (const auto& entry : frequencyToOutputAccelerationMap) {
+        if (entry.frequencyHz < minFrequency) {
+            minFrequency = entry.frequencyHz;
+        }
+    }
+
+    return minFrequency;
+}
+
+float getPwleV2FrequencyMaxHz(std::vector<PwleV2OutputMapEntry> frequencyToOutputAccelerationMap) {
+    if (frequencyToOutputAccelerationMap.empty()) {
+        return 0.0f;
+    }
+
+    float maxFrequency = frequencyToOutputAccelerationMap[0].frequencyHz;
+
+    for (const auto& entry : frequencyToOutputAccelerationMap) {
+        if (entry.frequencyHz > maxFrequency) {
+            maxFrequency = entry.frequencyHz;
+        }
+    }
+
+    return maxFrequency;
+}
+
+ndk::ScopedAStatus Vibrator::composePwleV2(const std::vector<PwleV2Primitive>& composite,
+                                           const std::shared_ptr<IVibratorCallback>& callback) {
+    int32_t capabilities = 0;
+    if (!getCapabilities(&capabilities).isOk()) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if ((capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2) == 0) {
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+    }
+
+    int compositionSizeMax;
+    getPwleV2CompositionSizeMax(&compositionSizeMax);
+    if (composite.size() <= 0 || composite.size() > compositionSizeMax) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+
+    int32_t totalEffectDuration = 0;
+    std::vector<PwleV2OutputMapEntry> frequencyToOutputAccelerationMap;
+    getPwleV2FrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap);
+    float minFrequency = getPwleV2FrequencyMinHz(frequencyToOutputAccelerationMap);
+    float maxFrequency = getPwleV2FrequencyMaxHz(frequencyToOutputAccelerationMap);
+
+    for (auto& e : composite) {
+        if (e.timeMillis < 0.0f || e.timeMillis > COMPOSE_PWLE_V2_PRIMITIVE_DURATION_MAX_MS) {
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        }
+        if (e.amplitude < 0.0f || e.amplitude > 1.0f) {
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        }
+        if (e.frequencyHz < minFrequency || e.frequencyHz > maxFrequency) {
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        }
+        totalEffectDuration += e.timeMillis;
+    }
+
+    std::thread([totalEffectDuration, callback] {
+        LOG(VERBOSE) << "Starting composePwleV2 on another thread";
+        usleep(totalEffectDuration * 1000);
+        if (callback != nullptr) {
+            LOG(VERBOSE) << "Notifying compose PWLE V2 complete";
+            callback->onComplete();
+        }
+    }).detach();
+
+    return ndk::ScopedAStatus::ok();
+}
+
 }  // namespace vibrator
 }  // namespace hardware
 }  // namespace android
diff --git a/vibrator/aidl/default/android.hardware.vibrator.xml b/vibrator/aidl/default/android.hardware.vibrator.xml
index b5bd3dd..b730046 100644
--- a/vibrator/aidl/default/android.hardware.vibrator.xml
+++ b/vibrator/aidl/default/android.hardware.vibrator.xml
@@ -1,12 +1,12 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.vibrator</name>
-        <version>2</version>
+        <version>3</version>
         <fqname>IVibrator/default</fqname>
     </hal>
     <hal format="aidl">
         <name>android.hardware.vibrator</name>
-        <version>2</version>
+        <version>3</version>
         <fqname>IVibratorManager/default</fqname>
     </hal>
 </manifest>
diff --git a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
index 4203bf2..28bc763 100644
--- a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
+++ b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <aidl/android/hardware/vibrator/BnVibrator.h>
+#include <android-base/thread_annotations.h>
 
 namespace aidl {
 namespace android {
@@ -31,6 +32,9 @@
     ndk::ScopedAStatus perform(Effect effect, EffectStrength strength,
                                const std::shared_ptr<IVibratorCallback>& callback,
                                int32_t* _aidl_return) override;
+    ndk::ScopedAStatus performVendorEffect(
+            const VendorEffect& effect,
+            const std::shared_ptr<IVibratorCallback>& callback) override;
     ndk::ScopedAStatus getSupportedEffects(std::vector<Effect>* _aidl_return) override;
     ndk::ScopedAStatus setAmplitude(float amplitude) override;
     ndk::ScopedAStatus setExternalControl(bool enabled) override;
@@ -54,7 +58,18 @@
     ndk::ScopedAStatus getSupportedBraking(std::vector<Braking>* supported) override;
     ndk::ScopedAStatus composePwle(const std::vector<PrimitivePwle> &composite,
                                    const std::shared_ptr<IVibratorCallback> &callback) override;
+    ndk::ScopedAStatus getPwleV2FrequencyToOutputAccelerationMap(
+            std::vector<PwleV2OutputMapEntry>* _aidl_return) override;
+    ndk::ScopedAStatus getPwleV2PrimitiveDurationMaxMillis(int32_t* maxDurationMs) override;
+    ndk::ScopedAStatus getPwleV2PrimitiveDurationMinMillis(int32_t* minDurationMs) override;
+    ndk::ScopedAStatus getPwleV2CompositionSizeMax(int32_t* maxSize) override;
+    ndk::ScopedAStatus composePwleV2(const std::vector<PwleV2Primitive>& composite,
+                                     const std::shared_ptr<IVibratorCallback>& callback) override;
 
+  private:
+    mutable std::mutex mMutex;
+    int32_t mVersion GUARDED_BY(mMutex) = 0;  // current Hal version
+    int32_t mCapabilities GUARDED_BY(mMutex) = 0;
 };
 
 }  // namespace vibrator
diff --git a/vibrator/aidl/vts/Android.bp b/vibrator/aidl/vts/Android.bp
index b6d2fb2..a48bb2e 100644
--- a/vibrator/aidl/vts/Android.bp
+++ b/vibrator/aidl/vts/Android.bp
@@ -17,10 +17,10 @@
     tidy_timeout_srcs: ["VtsHalVibratorTargetTest.cpp"],
     srcs: ["VtsHalVibratorTargetTest.cpp"],
     shared_libs: [
-        "libbinder",
+        "libbinder_ndk",
     ],
     static_libs: [
-        "android.hardware.vibrator-V2-cpp",
+        "android.hardware.vibrator-V3-ndk",
     ],
     test_suites: [
         "general-tests",
@@ -36,10 +36,10 @@
     ],
     srcs: ["VtsHalVibratorManagerTargetTest.cpp"],
     shared_libs: [
-        "libbinder",
+        "libbinder_ndk",
     ],
     static_libs: [
-        "android.hardware.vibrator-V2-cpp",
+        "android.hardware.vibrator-V3-ndk",
     ],
     test_suites: [
         "general-tests",
diff --git a/vibrator/aidl/vts/VtsHalVibratorManagerTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorManagerTargetTest.cpp
index e8ed26a..3c2a360 100644
--- a/vibrator/aidl/vts/VtsHalVibratorManagerTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorManagerTargetTest.cpp
@@ -15,42 +15,40 @@
  */
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
+#include <aidl/android/hardware/vibrator/BnVibratorCallback.h>
+#include <aidl/android/hardware/vibrator/IVibrator.h>
+#include <aidl/android/hardware/vibrator/IVibratorManager.h>
 
-#include <android/hardware/vibrator/BnVibratorCallback.h>
-#include <android/hardware/vibrator/IVibrator.h>
-#include <android/hardware/vibrator/IVibratorManager.h>
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
 
 #include <cmath>
 #include <future>
 
-using android::ProcessState;
-using android::sp;
-using android::String16;
-using android::binder::Status;
-using android::hardware::vibrator::BnVibratorCallback;
-using android::hardware::vibrator::CompositeEffect;
-using android::hardware::vibrator::CompositePrimitive;
-using android::hardware::vibrator::Effect;
-using android::hardware::vibrator::EffectStrength;
-using android::hardware::vibrator::IVibrator;
-using android::hardware::vibrator::IVibratorManager;
+#include "test_utils.h"
+
+using aidl::android::hardware::vibrator::BnVibratorCallback;
+using aidl::android::hardware::vibrator::CompositeEffect;
+using aidl::android::hardware::vibrator::CompositePrimitive;
+using aidl::android::hardware::vibrator::Effect;
+using aidl::android::hardware::vibrator::EffectStrength;
+using aidl::android::hardware::vibrator::IVibrator;
+using aidl::android::hardware::vibrator::IVibratorManager;
 using std::chrono::high_resolution_clock;
 
-const std::vector<Effect> kEffects{android::enum_range<Effect>().begin(),
-                                   android::enum_range<Effect>().end()};
-const std::vector<EffectStrength> kEffectStrengths{android::enum_range<EffectStrength>().begin(),
-                                                   android::enum_range<EffectStrength>().end()};
-const std::vector<CompositePrimitive> kPrimitives{android::enum_range<CompositePrimitive>().begin(),
-                                                  android::enum_range<CompositePrimitive>().end()};
+const std::vector<Effect> kEffects{ndk::enum_range<Effect>().begin(),
+                                   ndk::enum_range<Effect>().end()};
+const std::vector<EffectStrength> kEffectStrengths{ndk::enum_range<EffectStrength>().begin(),
+                                                   ndk::enum_range<EffectStrength>().end()};
+const std::vector<CompositePrimitive> kPrimitives{ndk::enum_range<CompositePrimitive>().begin(),
+                                                  ndk::enum_range<CompositePrimitive>().end()};
 
 class CompletionCallback : public BnVibratorCallback {
   public:
     CompletionCallback(const std::function<void()>& callback) : mCallback(callback) {}
-    Status onComplete() override {
+    ndk::ScopedAStatus onComplete() override {
         mCallback();
-        return Status::ok();
+        return ndk::ScopedAStatus::ok();
     }
 
   private:
@@ -60,55 +58,50 @@
 class VibratorAidl : public testing::TestWithParam<std::string> {
   public:
     virtual void SetUp() override {
-        manager = android::waitForDeclaredService<IVibratorManager>(String16(GetParam().c_str()));
+        auto serviceName = GetParam().c_str();
+        manager = IVibratorManager::fromBinder(
+                ndk::SpAIBinder(AServiceManager_waitForService(serviceName)));
         ASSERT_NE(manager, nullptr);
-        ASSERT_TRUE(manager->getCapabilities(&capabilities).isOk());
-        EXPECT_TRUE(manager->getVibratorIds(&vibratorIds).isOk());
+        EXPECT_OK(manager->getCapabilities(&capabilities));
+        EXPECT_OK(manager->getVibratorIds(&vibratorIds));
     }
 
-    sp<IVibratorManager> manager;
+    std::shared_ptr<IVibratorManager> manager;
     int32_t capabilities;
     std::vector<int32_t> vibratorIds;
 };
 
-inline bool isUnknownOrUnsupported(Status status) {
-    return status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
-           status.transactionError() == android::UNKNOWN_TRANSACTION;
-}
-
 TEST_P(VibratorAidl, ValidateExistingVibrators) {
-    sp<IVibrator> vibrator;
-    for (auto& id : vibratorIds) {
-        EXPECT_TRUE(manager->getVibrator(id, &vibrator).isOk());
+    std::shared_ptr<IVibrator> vibrator;
+    for (int32_t id : vibratorIds) {
+        EXPECT_OK(manager->getVibrator(id, &vibrator));
         ASSERT_NE(vibrator, nullptr);
     }
 }
 
 TEST_P(VibratorAidl, GetVibratorWithInvalidId) {
     int32_t invalidId = *max_element(vibratorIds.begin(), vibratorIds.end()) + 1;
-    sp<IVibrator> vibrator;
-    EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-              manager->getVibrator(invalidId, &vibrator).exceptionCode());
+    std::shared_ptr<IVibrator> vibrator;
+    EXPECT_ILLEGAL_ARGUMENT(manager->getVibrator(invalidId, &vibrator));
     ASSERT_EQ(vibrator, nullptr);
 }
 
 TEST_P(VibratorAidl, ValidatePrepareSyncedExistingVibrators) {
     if (!(capabilities & IVibratorManager::CAP_SYNC)) return;
     if (vibratorIds.empty()) return;
-    EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
-    EXPECT_TRUE(manager->cancelSynced().isOk());
+    EXPECT_OK(manager->prepareSynced(vibratorIds));
+    EXPECT_OK(manager->cancelSynced());
 }
 
 TEST_P(VibratorAidl, PrepareSyncedEmptySetIsInvalid) {
     if (!(capabilities & IVibratorManager::CAP_SYNC)) return;
     std::vector<int32_t> emptyIds;
-    EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, manager->prepareSynced(emptyIds).exceptionCode());
+    EXPECT_ILLEGAL_ARGUMENT(manager->prepareSynced(emptyIds));
 }
 
 TEST_P(VibratorAidl, PrepareSyncedNotSupported) {
     if (!(capabilities & IVibratorManager::CAP_SYNC)) {
-        Status status = manager->prepareSynced(vibratorIds);
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(manager->prepareSynced(vibratorIds));
     }
 }
 
@@ -117,15 +110,14 @@
     if (!(capabilities & IVibratorManager::CAP_SYNC)) return;
     if (!(capabilities & IVibratorManager::CAP_PREPARE_ON)) {
         uint32_t durationMs = 250;
-        EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
-        sp<IVibrator> vibrator;
-        for (auto& id : vibratorIds) {
-            EXPECT_TRUE(manager->getVibrator(id, &vibrator).isOk());
+        EXPECT_OK(manager->prepareSynced(vibratorIds));
+        std::shared_ptr<IVibrator> vibrator;
+        for (int32_t id : vibratorIds) {
+            EXPECT_OK(manager->getVibrator(id, &vibrator));
             ASSERT_NE(vibrator, nullptr);
-            Status status = vibrator->on(durationMs, nullptr);
-            EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+            EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->on(durationMs, nullptr));
         }
-        EXPECT_TRUE(manager->cancelSynced().isOk());
+        EXPECT_OK(manager->cancelSynced());
     }
 }
 
@@ -133,16 +125,16 @@
     if (vibratorIds.empty()) return;
     if (!(capabilities & IVibratorManager::CAP_SYNC)) return;
     if (!(capabilities & IVibratorManager::CAP_PREPARE_ON)) {
-        EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
-        sp<IVibrator> vibrator;
-        for (auto& id : vibratorIds) {
-            EXPECT_TRUE(manager->getVibrator(id, &vibrator).isOk());
+        EXPECT_OK(manager->prepareSynced(vibratorIds));
+        std::shared_ptr<IVibrator> vibrator;
+        for (int32_t id : vibratorIds) {
+            EXPECT_OK(manager->getVibrator(id, &vibrator));
             ASSERT_NE(vibrator, nullptr);
             int32_t lengthMs = 0;
-            Status status = vibrator->perform(kEffects[0], kEffectStrengths[0], nullptr, &lengthMs);
-            EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+            EXPECT_UNKNOWN_OR_UNSUPPORTED(
+                    vibrator->perform(kEffects[0], kEffectStrengths[0], nullptr, &lengthMs));
         }
-        EXPECT_TRUE(manager->cancelSynced().isOk());
+        EXPECT_OK(manager->cancelSynced());
     }
 }
 
@@ -157,15 +149,14 @@
         effect.scale = 1.0f;
         composite.emplace_back(effect);
 
-        EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
-        sp<IVibrator> vibrator;
-        for (auto& id : vibratorIds) {
-            EXPECT_TRUE(manager->getVibrator(id, &vibrator).isOk());
+        EXPECT_OK(manager->prepareSynced(vibratorIds));
+        std::shared_ptr<IVibrator> vibrator;
+        for (int32_t id : vibratorIds) {
+            EXPECT_OK(manager->getVibrator(id, &vibrator));
             ASSERT_NE(vibrator, nullptr);
-            Status status = vibrator->compose(composite, nullptr);
-            EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+            EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->compose(composite, nullptr));
         }
-        EXPECT_TRUE(manager->cancelSynced().isOk());
+        EXPECT_OK(manager->cancelSynced());
     }
 }
 
@@ -177,51 +168,58 @@
 
     std::promise<void> completionPromise;
     std::future<void> completionFuture{completionPromise.get_future()};
-    sp<CompletionCallback> callback =
-            new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+    auto callback = ndk::SharedRefBase::make<CompletionCallback>(
+            [&completionPromise] { completionPromise.set_value(); });
     uint32_t durationMs = 250;
     std::chrono::milliseconds timeout{durationMs * 2};
 
-    EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
-    sp<IVibrator> vibrator;
-    for (auto& id : vibratorIds) {
-        EXPECT_TRUE(manager->getVibrator(id, &vibrator).isOk());
+    EXPECT_OK(manager->prepareSynced(vibratorIds));
+    std::shared_ptr<IVibrator> vibrator;
+    for (int32_t id : vibratorIds) {
+        EXPECT_OK(manager->getVibrator(id, &vibrator));
         ASSERT_NE(vibrator, nullptr);
-        EXPECT_TRUE(vibrator->on(durationMs, nullptr).isOk());
+        EXPECT_OK(vibrator->on(durationMs, nullptr));
     }
 
-    EXPECT_TRUE(manager->triggerSynced(callback).isOk());
+    EXPECT_OK(manager->triggerSynced(callback));
     EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
-    EXPECT_TRUE(manager->cancelSynced().isOk());
+    EXPECT_OK(manager->cancelSynced());
 }
 
 TEST_P(VibratorAidl, TriggerSyncNotSupported) {
     if (!(capabilities & IVibratorManager::CAP_SYNC)) {
-        Status status = manager->triggerSynced(nullptr);
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(manager->triggerSynced(nullptr));
     }
 }
 
 TEST_P(VibratorAidl, TriggerCallbackNotSupported) {
     if (!(capabilities & IVibratorManager::CAP_SYNC)) return;
     if (!(capabilities & IVibratorManager::CAP_TRIGGER_CALLBACK)) {
-        sp<CompletionCallback> callback = new CompletionCallback([] {});
-        EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
-        Status status = manager->triggerSynced(callback);
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
-        EXPECT_TRUE(manager->cancelSynced().isOk());
+        auto callback = ndk::SharedRefBase::make<CompletionCallback>([] {});
+        EXPECT_OK(manager->prepareSynced(vibratorIds));
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(manager->triggerSynced(callback));
+        EXPECT_OK(manager->cancelSynced());
     }
 }
 
+std::vector<std::string> FindVibratorManagerNames() {
+    std::vector<std::string> names;
+    constexpr auto callback = [](const char* instance, void* context) {
+        std::string fullName = std::string(IVibratorManager::descriptor) + "/" + instance;
+        static_cast<std::vector<std::string>*>(context)->emplace_back(fullName);
+    };
+    AServiceManager_forEachDeclaredInstance(IVibratorManager::descriptor,
+                                            static_cast<void*>(&names), callback);
+    return names;
+}
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VibratorAidl);
-INSTANTIATE_TEST_SUITE_P(
-        Vibrator, VibratorAidl,
-        testing::ValuesIn(android::getAidlHalInstanceNames(IVibratorManager::descriptor)),
-        android::PrintInstanceNameToString);
+INSTANTIATE_TEST_SUITE_P(Vibrator, VibratorAidl, testing::ValuesIn(FindVibratorManagerNames()),
+                         android::PrintInstanceNameToString);
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
-    ProcessState::self()->setThreadPoolMaxThreadCount(1);
-    ProcessState::self()->startThreadPool();
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
 }
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index db474d6..bc017ae 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -15,38 +15,51 @@
  */
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
-#include <android/hardware/vibrator/BnVibratorCallback.h>
-#include <android/hardware/vibrator/IVibrator.h>
-#include <android/hardware/vibrator/IVibratorManager.h>
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
+#include <aidl/android/hardware/vibrator/BnVibratorCallback.h>
+#include <aidl/android/hardware/vibrator/IVibrator.h>
+#include <aidl/android/hardware/vibrator/IVibratorManager.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <android/persistable_bundle_aidl.h>
 
 #include <cmath>
+#include <cstdlib>
+#include <ctime>
 #include <future>
+#include <iomanip>
+#include <iostream>
+#include <random>
 
-using android::ProcessState;
-using android::sp;
-using android::String16;
-using android::binder::Status;
-using android::hardware::vibrator::ActivePwle;
-using android::hardware::vibrator::BnVibratorCallback;
-using android::hardware::vibrator::Braking;
-using android::hardware::vibrator::BrakingPwle;
-using android::hardware::vibrator::CompositeEffect;
-using android::hardware::vibrator::CompositePrimitive;
-using android::hardware::vibrator::Effect;
-using android::hardware::vibrator::EffectStrength;
-using android::hardware::vibrator::IVibrator;
-using android::hardware::vibrator::IVibratorManager;
-using android::hardware::vibrator::PrimitivePwle;
+#include "persistable_bundle_utils.h"
+#include "pwle_v2_utils.h"
+#include "test_utils.h"
+
+using aidl::android::hardware::vibrator::ActivePwle;
+using aidl::android::hardware::vibrator::BnVibratorCallback;
+using aidl::android::hardware::vibrator::Braking;
+using aidl::android::hardware::vibrator::BrakingPwle;
+using aidl::android::hardware::vibrator::CompositeEffect;
+using aidl::android::hardware::vibrator::CompositePrimitive;
+using aidl::android::hardware::vibrator::Effect;
+using aidl::android::hardware::vibrator::EffectStrength;
+using aidl::android::hardware::vibrator::IVibrator;
+using aidl::android::hardware::vibrator::IVibratorManager;
+using aidl::android::hardware::vibrator::PrimitivePwle;
+using aidl::android::hardware::vibrator::PwleV2OutputMapEntry;
+using aidl::android::hardware::vibrator::PwleV2Primitive;
+using aidl::android::hardware::vibrator::VendorEffect;
+using aidl::android::os::PersistableBundle;
 using std::chrono::high_resolution_clock;
 
 using namespace ::std::chrono_literals;
 
-const std::vector<Effect> kEffects{android::enum_range<Effect>().begin(),
-                                   android::enum_range<Effect>().end()};
-const std::vector<EffectStrength> kEffectStrengths{android::enum_range<EffectStrength>().begin(),
-                                                   android::enum_range<EffectStrength>().end()};
+namespace pwle_v2_utils = aidl::android::hardware::vibrator::testing::pwlev2;
+
+const std::vector<Effect> kEffects{ndk::enum_range<Effect>().begin(),
+                                   ndk::enum_range<Effect>().end()};
+const std::vector<EffectStrength> kEffectStrengths{ndk::enum_range<EffectStrength>().begin(),
+                                                   ndk::enum_range<EffectStrength>().end()};
 
 const std::vector<Effect> kInvalidEffects = {
     static_cast<Effect>(static_cast<int32_t>(kEffects.front()) - 1),
@@ -59,8 +72,7 @@
 };
 
 const std::vector<CompositePrimitive> kCompositePrimitives{
-    android::enum_range<CompositePrimitive>().begin(),
-    android::enum_range<CompositePrimitive>().end()};
+        ndk::enum_range<CompositePrimitive>().begin(), ndk::enum_range<CompositePrimitive>().end()};
 
 const std::vector<CompositePrimitive> kRequiredPrimitives = {
         CompositePrimitive::CLICK,      CompositePrimitive::LIGHT_TICK,
@@ -74,14 +86,39 @@
 };
 
 // Timeout to wait for vibration callback completion.
-static constexpr auto VIBRATION_CALLBACK_TIMEOUT = 100ms;
+static constexpr std::chrono::milliseconds VIBRATION_CALLBACK_TIMEOUT = 100ms;
+
+static constexpr int32_t VENDOR_EFFECTS_MIN_VERSION = 3;
+static constexpr int32_t PWLE_V2_MIN_VERSION = 3;
+
+static std::vector<std::string> findVibratorManagerNames() {
+    std::vector<std::string> names;
+    constexpr auto callback = [](const char* instance, void* context) {
+        auto fullName = std::string(IVibratorManager::descriptor) + "/" + instance;
+        static_cast<std::vector<std::string>*>(context)->emplace_back(fullName);
+    };
+    AServiceManager_forEachDeclaredInstance(IVibratorManager::descriptor,
+                                            static_cast<void*>(&names), callback);
+    return names;
+}
+
+static std::vector<std::string> findUnmanagedVibratorNames() {
+    std::vector<std::string> names;
+    constexpr auto callback = [](const char* instance, void* context) {
+        auto fullName = std::string(IVibrator::descriptor) + "/" + instance;
+        static_cast<std::vector<std::string>*>(context)->emplace_back(fullName);
+    };
+    AServiceManager_forEachDeclaredInstance(IVibrator::descriptor, static_cast<void*>(&names),
+                                            callback);
+    return names;
+}
 
 class CompletionCallback : public BnVibratorCallback {
   public:
     CompletionCallback(const std::function<void()> &callback) : mCallback(callback) {}
-    Status onComplete() override {
+    ndk::ScopedAStatus onComplete() override {
         mCallback();
-        return Status::ok();
+        return ndk::ScopedAStatus::ok();
     }
 
   private:
@@ -93,88 +130,89 @@
     virtual void SetUp() override {
         int32_t managerIdx = std::get<0>(GetParam());
         int32_t vibratorId = std::get<1>(GetParam());
-        auto managerAidlNames = android::getAidlHalInstanceNames(IVibratorManager::descriptor);
 
         if (managerIdx < 0) {
             // Testing a unmanaged vibrator, using vibratorId as index from registered HALs
-            auto vibratorAidlNames = android::getAidlHalInstanceNames(IVibrator::descriptor);
-            ASSERT_LT(vibratorId, vibratorAidlNames.size());
-            auto vibratorName = String16(vibratorAidlNames[vibratorId].c_str());
-            vibrator = android::waitForDeclaredService<IVibrator>(vibratorName);
+            std::vector<std::string> vibratorNames = findUnmanagedVibratorNames();
+            ASSERT_LT(vibratorId, vibratorNames.size());
+            vibrator = IVibrator::fromBinder(ndk::SpAIBinder(
+                    AServiceManager_waitForService(vibratorNames[vibratorId].c_str())));
         } else {
             // Testing a managed vibrator, using vibratorId to retrieve it from the manager
-            ASSERT_LT(managerIdx, managerAidlNames.size());
-            auto managerName = String16(managerAidlNames[managerIdx].c_str());
-            auto vibratorManager = android::waitForDeclaredService<IVibratorManager>(managerName);
-            auto vibratorResult = vibratorManager->getVibrator(vibratorId, &vibrator);
-            ASSERT_TRUE(vibratorResult.isOk());
+            std::vector<std::string> managerNames = findVibratorManagerNames();
+            ASSERT_LT(managerIdx, managerNames.size());
+            auto vibratorManager = IVibratorManager::fromBinder(ndk::SpAIBinder(
+                    AServiceManager_waitForService(managerNames[managerIdx].c_str())));
+            EXPECT_OK(vibratorManager->getVibrator(vibratorId, &vibrator))
+                    << "\n  For vibrator id: " << vibratorId;
         }
 
         ASSERT_NE(vibrator, nullptr);
-        ASSERT_TRUE(vibrator->getCapabilities(&capabilities).isOk());
+        EXPECT_OK(vibrator->getInterfaceVersion(&version));
+        EXPECT_OK(vibrator->getCapabilities(&capabilities));
     }
 
     virtual void TearDown() override {
         // Reset vibrator state between tests.
-        EXPECT_TRUE(vibrator->off().isOk());
+        EXPECT_OK(vibrator->off());
     }
 
-    sp<IVibrator> vibrator;
+    std::shared_ptr<IVibrator> vibrator;
+    int32_t version;
     int32_t capabilities;
 };
 
-inline bool isUnknownOrUnsupported(Status status) {
-    return status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
-           status.transactionError() == android::UNKNOWN_TRANSACTION;
-}
-
-static float getResonantFrequencyHz(sp<IVibrator> vibrator, int32_t capabilities) {
+static float getResonantFrequencyHz(const std::shared_ptr<IVibrator>& vibrator,
+                                    int32_t capabilities) {
     float resonantFrequencyHz;
-    Status status = vibrator->getResonantFrequency(&resonantFrequencyHz);
+    ndk::ScopedAStatus status = vibrator->getResonantFrequency(&resonantFrequencyHz);
     if (capabilities & IVibrator::CAP_GET_RESONANT_FREQUENCY) {
+        EXPECT_OK(std::move(status));
         EXPECT_GT(resonantFrequencyHz, 0);
-        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
     } else {
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
     }
     return resonantFrequencyHz;
 }
 
-static float getFrequencyResolutionHz(sp<IVibrator> vibrator, int32_t capabilities) {
+static float getFrequencyResolutionHz(const std::shared_ptr<IVibrator>& vibrator,
+                                      int32_t capabilities) {
     float freqResolutionHz;
-    Status status = vibrator->getFrequencyResolution(&freqResolutionHz);
+    ndk::ScopedAStatus status = vibrator->getFrequencyResolution(&freqResolutionHz);
     if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
+        EXPECT_OK(std::move(status));
         EXPECT_GT(freqResolutionHz, 0);
-        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
     } else {
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
     }
     return freqResolutionHz;
 }
 
-static float getFrequencyMinimumHz(sp<IVibrator> vibrator, int32_t capabilities) {
+static float getFrequencyMinimumHz(const std::shared_ptr<IVibrator>& vibrator,
+                                   int32_t capabilities) {
     float freqMinimumHz;
-    Status status = vibrator->getFrequencyMinimum(&freqMinimumHz);
+    ndk::ScopedAStatus status = vibrator->getFrequencyMinimum(&freqMinimumHz);
     if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
-        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+        EXPECT_OK(std::move(status));
 
         float resonantFrequencyHz = getResonantFrequencyHz(vibrator, capabilities);
 
         EXPECT_GT(freqMinimumHz, 0);
         EXPECT_LE(freqMinimumHz, resonantFrequencyHz);
     } else {
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
     }
     return freqMinimumHz;
 }
 
-static float getFrequencyMaximumHz(sp<IVibrator> vibrator, int32_t capabilities) {
+static float getFrequencyMaximumHz(const std::shared_ptr<IVibrator>& vibrator,
+                                   int32_t capabilities) {
     std::vector<float> bandwidthAmplitudeMap;
-    Status status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap);
+    ndk::ScopedAStatus status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap);
     if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
-        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+        EXPECT_OK(std::move(status));
     } else {
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
     }
 
     float freqMaximumHz = ((bandwidthAmplitudeMap.size() - 1) *
@@ -191,7 +229,8 @@
     return 1.0;
 }
 
-static ActivePwle composeValidActivePwle(sp<IVibrator> vibrator, int32_t capabilities) {
+static ActivePwle composeValidActivePwle(const std::shared_ptr<IVibrator>& vibrator,
+                                         int32_t capabilities) {
     float frequencyHz;
     if (capabilities & IVibrator::CAP_GET_RESONANT_FREQUENCY) {
         frequencyHz = getResonantFrequencyHz(vibrator, capabilities);
@@ -212,9 +251,9 @@
 }
 
 TEST_P(VibratorAidl, OnThenOffBeforeTimeout) {
-    EXPECT_TRUE(vibrator->on(2000, nullptr /*callback*/).isOk());
+    EXPECT_OK(vibrator->on(2000, nullptr /*callback*/));
     sleep(1);
-    EXPECT_TRUE(vibrator->off().isOk());
+    EXPECT_OK(vibrator->off());
 }
 
 TEST_P(VibratorAidl, OnWithCallback) {
@@ -223,26 +262,25 @@
 
     std::promise<void> completionPromise;
     std::future<void> completionFuture{completionPromise.get_future()};
-    sp<CompletionCallback> callback =
-        new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+    auto callback = ndk::SharedRefBase::make<CompletionCallback>(
+            [&completionPromise] { completionPromise.set_value(); });
     uint32_t durationMs = 250;
     auto timeout = std::chrono::milliseconds(durationMs) + VIBRATION_CALLBACK_TIMEOUT;
-    EXPECT_TRUE(vibrator->on(durationMs, callback).isOk());
+    EXPECT_OK(vibrator->on(durationMs, callback));
     EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
-    EXPECT_TRUE(vibrator->off().isOk());
+    EXPECT_OK(vibrator->off());
 }
 
 TEST_P(VibratorAidl, OnCallbackNotSupported) {
     if (!(capabilities & IVibrator::CAP_ON_CALLBACK)) {
-        sp<CompletionCallback> callback = new CompletionCallback([] {});
-        Status status = vibrator->on(250, callback);
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        auto callback = ndk::SharedRefBase::make<CompletionCallback>([] {});
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->on(250, callback));
     }
 }
 
 TEST_P(VibratorAidl, ValidateEffect) {
     std::vector<Effect> supported;
-    ASSERT_TRUE(vibrator->getSupportedEffects(&supported).isOk());
+    EXPECT_OK(vibrator->getSupportedEffects(&supported));
 
     for (Effect effect : kEffects) {
         bool isEffectSupported =
@@ -250,15 +288,18 @@
 
         for (EffectStrength strength : kEffectStrengths) {
             int32_t lengthMs = 0;
-            Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs);
+            ndk::ScopedAStatus status =
+                    vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs);
 
             if (isEffectSupported) {
-                EXPECT_TRUE(status.isOk()) << toString(effect) << " " << toString(strength);
+                EXPECT_OK(std::move(status))
+                        << "\n  For effect: " << toString(effect) << " " << toString(strength);
                 EXPECT_GT(lengthMs, 0);
                 usleep(lengthMs * 1000);
+                EXPECT_OK(vibrator->off());
             } else {
-                EXPECT_TRUE(isUnknownOrUnsupported(status))
-                        << status << " " << toString(effect) << " " << toString(strength);
+                EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status))
+                        << "\n  For effect: " << toString(effect) << " " << toString(strength);
             }
         }
     }
@@ -269,7 +310,7 @@
         return;
 
     std::vector<Effect> supported;
-    ASSERT_TRUE(vibrator->getSupportedEffects(&supported).isOk());
+    EXPECT_OK(vibrator->getSupportedEffects(&supported));
 
     for (Effect effect : kEffects) {
         bool isEffectSupported =
@@ -278,25 +319,26 @@
         for (EffectStrength strength : kEffectStrengths) {
             std::promise<void> completionPromise;
             std::future<void> completionFuture{completionPromise.get_future()};
-            sp<CompletionCallback> callback =
-                new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+            auto callback = ndk::SharedRefBase::make<CompletionCallback>(
+                    [&completionPromise] { completionPromise.set_value(); });
             int lengthMs = 0;
-            Status status = vibrator->perform(effect, strength, callback, &lengthMs);
+            ndk::ScopedAStatus status = vibrator->perform(effect, strength, callback, &lengthMs);
 
             if (isEffectSupported) {
-                EXPECT_TRUE(status.isOk());
+                EXPECT_OK(std::move(status))
+                        << "\n  For effect: " << toString(effect) << " " << toString(strength);
                 EXPECT_GT(lengthMs, 0);
             } else {
-                EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+                EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status))
+                        << "\n  For effect: " << toString(effect) << " " << toString(strength);
             }
 
-            if (!status.isOk())
-                continue;
+            if (lengthMs <= 0) continue;
 
             auto timeout = std::chrono::milliseconds(lengthMs) + VIBRATION_CALLBACK_TIMEOUT;
             EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
 
-            EXPECT_TRUE(vibrator->off().isOk());
+            EXPECT_OK(vibrator->off());
         }
     }
 }
@@ -307,10 +349,10 @@
 
     for (Effect effect : kEffects) {
         for (EffectStrength strength : kEffectStrengths) {
-            sp<CompletionCallback> callback = new CompletionCallback([] {});
+            auto callback = ndk::SharedRefBase::make<CompletionCallback>([] {});
             int lengthMs;
-            Status status = vibrator->perform(effect, strength, callback, &lengthMs);
-            EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+            EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->perform(effect, strength, callback, &lengthMs))
+                    << "\n  For effect: " << toString(effect) << " " << toString(strength);
         }
     }
 }
@@ -319,53 +361,182 @@
     for (Effect effect : kInvalidEffects) {
         for (EffectStrength strength : kEffectStrengths) {
             int32_t lengthMs;
-            Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs);
-            EXPECT_TRUE(isUnknownOrUnsupported(status))
-                    << status << toString(effect) << " " << toString(strength);
+            EXPECT_UNKNOWN_OR_UNSUPPORTED(
+                    vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs))
+                    << "\n  For effect: " << toString(effect) << " " << toString(strength);
         }
     }
     for (Effect effect : kEffects) {
         for (EffectStrength strength : kInvalidEffectStrengths) {
             int32_t lengthMs;
-            Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs);
-            EXPECT_TRUE(isUnknownOrUnsupported(status))
-                    << status << " " << toString(effect) << " " << toString(strength);
+            EXPECT_UNKNOWN_OR_UNSUPPORTED(
+                    vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs))
+                    << "\n  For effect: " << toString(effect) << " " << toString(strength);
         }
     }
 }
 
+TEST_P(VibratorAidl, PerformVendorEffectSupported) {
+    if ((capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) == 0) return;
+
+    float scale = 0.0f;
+    float vendorScale = 0.0f;
+    for (EffectStrength strength : kEffectStrengths) {
+        PersistableBundle vendorData;
+        ::aidl::android::hardware::vibrator::testing::fillBasicData(&vendorData);
+
+        PersistableBundle nestedData;
+        ::aidl::android::hardware::vibrator::testing::fillBasicData(&nestedData);
+        vendorData.putPersistableBundle("test_nested_bundle", nestedData);
+
+        VendorEffect effect;
+        effect.vendorData = vendorData;
+        effect.strength = strength;
+        effect.scale = scale;
+        effect.vendorScale = vendorScale;
+        scale += 0.5f;
+        vendorScale += 0.2f;
+
+        auto callback = ndk::SharedRefBase::make<CompletionCallback>([] {});
+        ndk::ScopedAStatus status = vibrator->performVendorEffect(effect, callback);
+
+        // No expectations on the actual status, the effect might be refused with illegal argument
+        // or the vendor might return a service-specific error code.
+        EXPECT_TRUE(status.getExceptionCode() != EX_UNSUPPORTED_OPERATION &&
+                    status.getStatus() != STATUS_UNKNOWN_TRANSACTION)
+                << status << "\n For vendor effect with strength" << toString(strength)
+                << " and scale " << effect.scale;
+
+        if (status.isOk()) {
+            // Generic vendor data should not trigger vibrations, but if it does trigger one
+            // then we make sure the vibrator is reset by triggering off().
+            EXPECT_OK(vibrator->off());
+        }
+    }
+}
+
+TEST_P(VibratorAidl, PerformVendorEffectStability) {
+    if ((capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) == 0) return;
+
+    // Run some iterations of performVendorEffect with randomized vendor data to check basic
+    // stability of the implementation.
+    uint8_t iterations = 200;
+
+    for (EffectStrength strength : kEffectStrengths) {
+        float scale = 0.5f;
+        float vendorScale = 0.2f;
+        for (uint8_t i = 0; i < iterations; i++) {
+            PersistableBundle vendorData;
+            ::aidl::android::hardware::vibrator::testing::fillRandomData(&vendorData);
+
+            VendorEffect effect;
+            effect.vendorData = vendorData;
+            effect.strength = strength;
+            effect.scale = scale;
+            effect.vendorScale = vendorScale;
+            scale *= 2;
+            vendorScale *= 1.5f;
+
+            auto callback = ndk::SharedRefBase::make<CompletionCallback>([] {});
+            ndk::ScopedAStatus status = vibrator->performVendorEffect(effect, callback);
+
+            // No expectations on the actual status, the effect might be refused with illegal
+            // argument or the vendor might return a service-specific error code.
+            EXPECT_TRUE(status.getExceptionCode() != EX_UNSUPPORTED_OPERATION &&
+                        status.getStatus() != STATUS_UNKNOWN_TRANSACTION)
+                    << status << "\n For random vendor effect with strength " << toString(strength)
+                    << " and scale " << effect.scale;
+
+            if (status.isOk()) {
+                // Random vendor data should not trigger vibrations, but if it does trigger one
+                // then we make sure the vibrator is reset by triggering off().
+                EXPECT_OK(vibrator->off());
+            }
+        }
+    }
+}
+
+TEST_P(VibratorAidl, PerformVendorEffectEmptyVendorData) {
+    if ((capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) == 0) return;
+
+    for (EffectStrength strength : kEffectStrengths) {
+        VendorEffect effect;
+        effect.strength = strength;
+        effect.scale = 1.0f;
+        effect.vendorScale = 1.0f;
+
+        ndk::ScopedAStatus status = vibrator->performVendorEffect(effect, nullptr /*callback*/);
+
+        EXPECT_TRUE(status.getExceptionCode() == EX_SERVICE_SPECIFIC)
+                << status << "\n For vendor effect with strength " << toString(strength)
+                << " and scale " << effect.scale;
+    }
+}
+
+TEST_P(VibratorAidl, PerformVendorEffectInvalidScale) {
+    if ((capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) == 0) return;
+
+    VendorEffect effect;
+    effect.strength = EffectStrength::MEDIUM;
+
+    effect.scale = -1.0f;
+    effect.vendorScale = 1.0f;
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->performVendorEffect(effect, nullptr /*callback*/));
+
+    effect.scale = 1.0f;
+    effect.vendorScale = -1.0f;
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->performVendorEffect(effect, nullptr /*callback*/));
+}
+
+TEST_P(VibratorAidl, PerformVendorEffectUnsupported) {
+    if (version < VENDOR_EFFECTS_MIN_VERSION) {
+        EXPECT_EQ(capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS, 0)
+                << "Vibrator version " << version << " should not report vendor effects capability";
+    }
+    if (capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) return;
+
+    for (EffectStrength strength : kEffectStrengths) {
+        VendorEffect effect;
+        effect.strength = strength;
+        effect.scale = 1.0f;
+        effect.vendorScale = 1.0f;
+
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->performVendorEffect(effect, nullptr /*callback*/))
+                << "\n  For vendor effect with strength " << toString(strength);
+    }
+}
+
 TEST_P(VibratorAidl, ChangeVibrationAmplitude) {
     if (capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) {
-        EXPECT_EQ(Status::EX_NONE, vibrator->setAmplitude(0.1f).exceptionCode());
-        EXPECT_TRUE(vibrator->on(2000, nullptr /*callback*/).isOk());
-        EXPECT_EQ(Status::EX_NONE, vibrator->setAmplitude(0.5f).exceptionCode());
+        EXPECT_OK(vibrator->setAmplitude(0.1f));
+        EXPECT_OK(vibrator->on(2000, nullptr /*callback*/));
+        EXPECT_OK(vibrator->setAmplitude(0.5f));
         sleep(1);
-        EXPECT_EQ(Status::EX_NONE, vibrator->setAmplitude(1.0f).exceptionCode());
+        EXPECT_OK(vibrator->setAmplitude(1.0f));
         sleep(1);
-        EXPECT_TRUE(vibrator->off().isOk());
+        EXPECT_OK(vibrator->off());
     }
 }
 
 TEST_P(VibratorAidl, AmplitudeOutsideRangeFails) {
     if (capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) {
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(-1).exceptionCode());
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(0).exceptionCode());
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(1.1).exceptionCode());
+        EXPECT_ILLEGAL_ARGUMENT(vibrator->setAmplitude(-1));
+        EXPECT_ILLEGAL_ARGUMENT(vibrator->setAmplitude(0));
+        EXPECT_ILLEGAL_ARGUMENT(vibrator->setAmplitude(1.1));
     }
 }
 
 TEST_P(VibratorAidl, AmplitudeReturnsUnsupportedMatchingCapabilities) {
     if ((capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) == 0) {
-        Status status = vibrator->setAmplitude(1);
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->setAmplitude(1));
     }
 }
 
 TEST_P(VibratorAidl, ChangeVibrationExternalControl) {
     if (capabilities & IVibrator::CAP_EXTERNAL_CONTROL) {
-        EXPECT_TRUE(vibrator->setExternalControl(true).isOk());
+        EXPECT_OK(vibrator->setExternalControl(true));
         sleep(1);
-        EXPECT_TRUE(vibrator->setExternalControl(false).isOk());
+        EXPECT_OK(vibrator->setExternalControl(false));
         sleep(1);
     }
 }
@@ -375,15 +546,15 @@
         (capabilities & IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL) > 0;
 
     if (capabilities & IVibrator::CAP_EXTERNAL_CONTROL) {
-        EXPECT_TRUE(vibrator->setExternalControl(true).isOk());
+        EXPECT_OK(vibrator->setExternalControl(true));
 
-        Status amplitudeStatus = vibrator->setAmplitude(0.5);
         if (supportsExternalAmplitudeControl) {
-            EXPECT_TRUE(amplitudeStatus.isOk());
+            EXPECT_OK(vibrator->setAmplitude(0.5));
         } else {
-            EXPECT_TRUE(isUnknownOrUnsupported(amplitudeStatus)) << amplitudeStatus;
+            EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->setAmplitude(0.5));
         }
-        EXPECT_TRUE(vibrator->setExternalControl(false).isOk());
+
+        EXPECT_OK(vibrator->setExternalControl(false));
     } else {
         EXPECT_FALSE(supportsExternalAmplitudeControl);
     }
@@ -391,18 +562,16 @@
 
 TEST_P(VibratorAidl, ExternalControlUnsupportedMatchingCapabilities) {
     if ((capabilities & IVibrator::CAP_EXTERNAL_CONTROL) == 0) {
-        Status status = vibrator->setExternalControl(true);
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->setExternalControl(true));
     }
 }
 
 TEST_P(VibratorAidl, GetSupportedPrimitives) {
     if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
         std::vector<CompositePrimitive> supported;
+        EXPECT_OK(vibrator->getSupportedPrimitives(&supported));
 
-        EXPECT_EQ(Status::EX_NONE, vibrator->getSupportedPrimitives(&supported).exceptionCode());
-
-        for (auto primitive : kCompositePrimitives) {
+        for (CompositePrimitive primitive : kCompositePrimitives) {
             bool isPrimitiveSupported =
                 std::find(supported.begin(), supported.end(), primitive) != supported.end();
             bool isPrimitiveRequired =
@@ -417,22 +586,23 @@
 TEST_P(VibratorAidl, GetPrimitiveDuration) {
     if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
         std::vector<CompositePrimitive> supported;
-        ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk());
+        EXPECT_OK(vibrator->getSupportedPrimitives(&supported));
 
-        for (auto primitive : kCompositePrimitives) {
+        for (CompositePrimitive primitive : kCompositePrimitives) {
             bool isPrimitiveSupported =
                 std::find(supported.begin(), supported.end(), primitive) != supported.end();
             int32_t duration;
 
-            Status status = vibrator->getPrimitiveDuration(primitive, &duration);
-
             if (isPrimitiveSupported) {
-                EXPECT_EQ(Status::EX_NONE, status.exceptionCode());
+                EXPECT_OK(vibrator->getPrimitiveDuration(primitive, &duration))
+                        << "\n  For primitive: " << toString(primitive) << " " << duration;
                 if (primitive != CompositePrimitive::NOOP) {
-                    ASSERT_GT(duration, 0) << toString(primitive) << " " << duration;
+                    ASSERT_GT(duration, 0)
+                            << "\n  For primitive: " << toString(primitive) << " " << duration;
                 }
             } else {
-                EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+                EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->getPrimitiveDuration(primitive, &duration))
+                        << "\n  For primitive: " << toString(primitive);
             }
         }
     }
@@ -446,14 +616,14 @@
     std::vector<CompositePrimitive> supported;
     int32_t maxDelay, maxSize;
 
-    ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk());
-    EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionDelayMax(&maxDelay).exceptionCode());
-    EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionSizeMax(&maxSize).exceptionCode());
+    EXPECT_OK(vibrator->getSupportedPrimitives(&supported));
+    EXPECT_OK(vibrator->getCompositionDelayMax(&maxDelay));
+    EXPECT_OK(vibrator->getCompositionSizeMax(&maxSize));
 
     std::vector<CompositeEffect> composite;
 
     for (int i = 0; i < supported.size(); i++) {
-        auto primitive = supported[i];
+        CompositePrimitive primitive = supported[i];
         float t = static_cast<float>(i + 1) / supported.size();
         CompositeEffect effect;
 
@@ -467,8 +637,8 @@
     }
 
     if (composite.size() != 0) {
-        EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
-        EXPECT_TRUE(vibrator->off().isOk());
+        EXPECT_OK(vibrator->compose(composite, nullptr));
+        EXPECT_OK(vibrator->off());
     }
 }
 
@@ -477,12 +647,12 @@
         GTEST_SKIP() << "CAP_COMPOSE_EFFECTS not supported";
     }
 
-    auto unsupported = kInvalidPrimitives;
+    std::vector<CompositePrimitive> unsupported(kInvalidPrimitives);
     std::vector<CompositePrimitive> supported;
 
-    ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk());
+    EXPECT_OK(vibrator->getSupportedPrimitives(&supported));
 
-    for (auto primitive : kCompositePrimitives) {
+    for (CompositePrimitive primitive : kCompositePrimitives) {
         bool isPrimitiveSupported =
                 std::find(supported.begin(), supported.end(), primitive) != supported.end();
 
@@ -491,16 +661,15 @@
         }
     }
 
-    for (auto primitive : unsupported) {
+    for (CompositePrimitive primitive : unsupported) {
         std::vector<CompositeEffect> composite(1);
 
-        for (auto& effect : composite) {
+        for (CompositeEffect& effect : composite) {
             effect.delayMs = 0;
             effect.primitive = primitive;
             effect.scale = 1.0f;
         }
-        Status status = vibrator->compose(composite, nullptr);
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->compose(composite, nullptr));
     }
 }
 
@@ -516,18 +685,18 @@
     effect.primitive = CompositePrimitive::CLICK;
 
     effect.scale = std::nextafter(0.0f, -1.0f);
-    EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->compose(composite, nullptr).exceptionCode());
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->compose(composite, nullptr));
 
     effect.scale = 0.0f;
-    EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
-    EXPECT_TRUE(vibrator->off().isOk());
+    EXPECT_OK(vibrator->compose(composite, nullptr));
+    EXPECT_OK(vibrator->off());
 
     effect.scale = 1.0f;
-    EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
-    EXPECT_TRUE(vibrator->off().isOk());
+    EXPECT_OK(vibrator->compose(composite, nullptr));
+    EXPECT_OK(vibrator->off());
 
     effect.scale = std::nextafter(1.0f, 2.0f);
-    EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->compose(composite, nullptr).exceptionCode());
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->compose(composite, nullptr));
 }
 
 TEST_P(VibratorAidl, ComposeDelayBoundary) {
@@ -537,7 +706,7 @@
 
     int32_t maxDelay;
 
-    EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionDelayMax(&maxDelay).exceptionCode());
+    EXPECT_OK(vibrator->getCompositionDelayMax(&maxDelay));
 
     std::vector<CompositeEffect> composite(1);
     CompositeEffect& effect = composite[0];
@@ -546,19 +715,19 @@
     effect.scale = 1.0f;
 
     effect.delayMs = 0;
-    EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
-    EXPECT_TRUE(vibrator->off().isOk());
+    EXPECT_OK(vibrator->compose(composite, nullptr));
+    EXPECT_OK(vibrator->off());
 
     effect.delayMs = 1;
-    EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
-    EXPECT_TRUE(vibrator->off().isOk());
+    EXPECT_OK(vibrator->compose(composite, nullptr));
+    EXPECT_OK(vibrator->off());
 
     effect.delayMs = maxDelay;
-    EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
-    EXPECT_TRUE(vibrator->off().isOk());
+    EXPECT_OK(vibrator->compose(composite, nullptr));
+    EXPECT_OK(vibrator->off());
 
     effect.delayMs = maxDelay + 1;
-    EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->compose(composite, nullptr).exceptionCode());
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->compose(composite, nullptr));
 }
 
 TEST_P(VibratorAidl, ComposeSizeBoundary) {
@@ -568,7 +737,7 @@
 
     int32_t maxSize;
 
-    EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionSizeMax(&maxSize).exceptionCode());
+    EXPECT_OK(vibrator->getCompositionSizeMax(&maxSize));
 
     std::vector<CompositeEffect> composite(maxSize);
     CompositeEffect effect;
@@ -578,11 +747,11 @@
     effect.scale = 1.0f;
 
     std::fill(composite.begin(), composite.end(), effect);
-    EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
-    EXPECT_TRUE(vibrator->off().isOk());
+    EXPECT_OK(vibrator->compose(composite, nullptr));
+    EXPECT_OK(vibrator->off());
 
     composite.emplace_back(effect);
-    EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->compose(composite, nullptr).exceptionCode());
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->compose(composite, nullptr));
 }
 
 TEST_P(VibratorAidl, ComposeCallback) {
@@ -591,18 +760,17 @@
     }
 
     std::vector<CompositePrimitive> supported;
+    EXPECT_OK(vibrator->getSupportedPrimitives(&supported));
 
-    ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk());
-
-    for (auto primitive : supported) {
+    for (CompositePrimitive primitive : supported) {
         if (primitive == CompositePrimitive::NOOP) {
             continue;
         }
 
         std::promise<void> completionPromise;
         std::future<void> completionFuture{completionPromise.get_future()};
-        sp<CompletionCallback> callback =
-                new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+        auto callback = ndk::SharedRefBase::make<CompletionCallback>(
+                [&completionPromise] { completionPromise.set_value(); });
         CompositeEffect effect;
         std::vector<CompositeEffect> composite;
         int32_t durationMs;
@@ -615,50 +783,50 @@
         effect.scale = 1.0f;
         composite.emplace_back(effect);
 
-        EXPECT_EQ(Status::EX_NONE,
-                  vibrator->getPrimitiveDuration(primitive, &durationMs).exceptionCode())
-                << toString(primitive);
+        EXPECT_OK(vibrator->getPrimitiveDuration(primitive, &durationMs))
+                << "\n  For primitive: " << toString(primitive);
         duration = std::chrono::milliseconds(durationMs);
 
         start = high_resolution_clock::now();
-        EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, callback).exceptionCode())
-                << toString(primitive);
+        EXPECT_OK(vibrator->compose(composite, callback))
+                << "\n  For primitive: " << toString(primitive);
 
         EXPECT_EQ(completionFuture.wait_for(duration + VIBRATION_CALLBACK_TIMEOUT),
                   std::future_status::ready)
-                << toString(primitive);
+                << "\n  For primitive: " << toString(primitive);
         end = high_resolution_clock::now();
 
         elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
-        EXPECT_GE(elapsed.count(), duration.count()) << toString(primitive);
+        EXPECT_GE(elapsed.count(), duration.count())
+                << "\n  For primitive: " << toString(primitive);
 
-        EXPECT_TRUE(vibrator->off().isOk());
+        EXPECT_OK(vibrator->off()) << "\n  For primitive: " << toString(primitive);
     }
 }
 
 TEST_P(VibratorAidl, AlwaysOn) {
     if (capabilities & IVibrator::CAP_ALWAYS_ON_CONTROL) {
         std::vector<Effect> supported;
-        ASSERT_TRUE(vibrator->getSupportedAlwaysOnEffects(&supported).isOk());
+        EXPECT_OK(vibrator->getSupportedAlwaysOnEffects(&supported));
 
         for (Effect effect : kEffects) {
             bool isEffectSupported =
                 std::find(supported.begin(), supported.end(), effect) != supported.end();
 
             for (EffectStrength strength : kEffectStrengths) {
-                Status status = vibrator->alwaysOnEnable(0, effect, strength);
+                ndk::ScopedAStatus status = vibrator->alwaysOnEnable(0, effect, strength);
 
                 if (isEffectSupported) {
-                    EXPECT_EQ(Status::EX_NONE, status.exceptionCode())
-                        << toString(effect) << " " << toString(strength);
+                    EXPECT_OK(std::move(status))
+                            << "\n  For effect: " << toString(effect) << " " << toString(strength);
                 } else {
-                    EXPECT_TRUE(isUnknownOrUnsupported(status))
-                            << status << " " << toString(effect) << " " << toString(strength);
+                    EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status))
+                            << "\n  For effect: " << toString(effect) << " " << toString(strength);
                 }
             }
         }
 
-        EXPECT_EQ(Status::EX_NONE, vibrator->alwaysOnDisable(0).exceptionCode());
+        EXPECT_OK(vibrator->alwaysOnDisable(0));
     }
 }
 
@@ -668,12 +836,12 @@
 
 TEST_P(VibratorAidl, GetQFactor) {
     float qFactor;
-    Status status = vibrator->getQFactor(&qFactor);
+    ndk::ScopedAStatus status = vibrator->getQFactor(&qFactor);
     if (capabilities & IVibrator::CAP_GET_Q_FACTOR) {
+        EXPECT_OK(std::move(status));
         ASSERT_GT(qFactor, 0);
-        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
     } else {
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
     }
 }
 
@@ -687,9 +855,9 @@
 
 TEST_P(VibratorAidl, GetBandwidthAmplitudeMap) {
     std::vector<float> bandwidthAmplitudeMap;
-    Status status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap);
+    ndk::ScopedAStatus status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap);
     if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
-        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+        EXPECT_OK(std::move(status));
         ASSERT_FALSE(bandwidthAmplitudeMap.empty());
 
         int minMapSize = (getResonantFrequencyHz(vibrator, capabilities) -
@@ -702,42 +870,42 @@
             ASSERT_LE(e, 1.0);
         }
     } else {
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
     }
 }
 
 TEST_P(VibratorAidl, GetPwlePrimitiveDurationMax) {
     int32_t durationMs;
-    Status status = vibrator->getPwlePrimitiveDurationMax(&durationMs);
+    ndk::ScopedAStatus status = vibrator->getPwlePrimitiveDurationMax(&durationMs);
     if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
+        EXPECT_OK(std::move(status));
         ASSERT_NE(durationMs, 0);
-        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
     } else {
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
     }
 }
 
 TEST_P(VibratorAidl, GetPwleCompositionSizeMax) {
     int32_t maxSize;
-    Status status = vibrator->getPwleCompositionSizeMax(&maxSize);
+    ndk::ScopedAStatus status = vibrator->getPwleCompositionSizeMax(&maxSize);
     if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
+        EXPECT_OK(std::move(status));
         ASSERT_NE(maxSize, 0);
-        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
     } else {
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
     }
 }
 
 TEST_P(VibratorAidl, GetSupportedBraking) {
     std::vector<Braking> supported;
-    Status status = vibrator->getSupportedBraking(&supported);
+    ndk::ScopedAStatus status = vibrator->getSupportedBraking(&supported);
     if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
         bool isDefaultNoneSupported =
             std::find(supported.begin(), supported.end(), Braking::NONE) != supported.end();
+        EXPECT_OK(std::move(status));
         ASSERT_TRUE(isDefaultNoneSupported);
-        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
     } else {
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
     }
 }
 
@@ -746,7 +914,7 @@
         ActivePwle firstActive = composeValidActivePwle(vibrator, capabilities);
 
         std::vector<Braking> supported;
-        ASSERT_TRUE(vibrator->getSupportedBraking(&supported).isOk());
+        EXPECT_OK(vibrator->getSupportedBraking(&supported));
         bool isClabSupported =
             std::find(supported.begin(), supported.end(), Braking::CLAB) != supported.end();
         BrakingPwle firstBraking;
@@ -765,11 +933,11 @@
         secondBraking.braking = Braking::NONE;
         secondBraking.duration = 10;
 
-        auto pwleQueue =
-            std::vector<PrimitivePwle>{firstActive, firstBraking, secondActive, secondBraking};
+        std::vector<PrimitivePwle> pwleQueue = {firstActive, firstBraking, secondActive,
+                                                secondBraking};
 
-        EXPECT_EQ(Status::EX_NONE, vibrator->composePwle(pwleQueue, nullptr).exceptionCode());
-        EXPECT_TRUE(vibrator->off().isOk());
+        EXPECT_OK(vibrator->composePwle(pwleQueue, nullptr));
+        EXPECT_OK(vibrator->off());
     }
 }
 
@@ -780,8 +948,8 @@
 
     std::promise<void> completionPromise;
     std::future<void> completionFuture{completionPromise.get_future()};
-    sp<CompletionCallback> callback =
-        new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+    auto callback = ndk::SharedRefBase::make<CompletionCallback>(
+            [&completionPromise] { completionPromise.set_value(); });
     int32_t segmentDurationMaxMs;
     vibrator->getPwlePrimitiveDurationMax(&segmentDurationMaxMs);
     uint32_t durationMs = segmentDurationMaxMs * 2 + 100;  // Sum of 2 active and 1 braking below
@@ -790,27 +958,25 @@
     ActivePwle active = composeValidActivePwle(vibrator, capabilities);
 
     std::vector<Braking> supported;
-    ASSERT_TRUE(vibrator->getSupportedBraking(&supported).isOk());
+    EXPECT_OK(vibrator->getSupportedBraking(&supported));
     bool isClabSupported =
         std::find(supported.begin(), supported.end(), Braking::CLAB) != supported.end();
     BrakingPwle braking;
     braking.braking = isClabSupported ? Braking::CLAB : Braking::NONE;
     braking.duration = 100;
 
-    auto pwleQueue = std::vector<PrimitivePwle>{active, braking, active};
+    std::vector<PrimitivePwle> pwleQueue = {active, braking, active};
 
-    EXPECT_TRUE(vibrator->composePwle(pwleQueue, callback).isOk());
+    EXPECT_OK(vibrator->composePwle(pwleQueue, callback));
     EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
-    EXPECT_TRUE(vibrator->off().isOk());
+    EXPECT_OK(vibrator->off());
 }
 
 TEST_P(VibratorAidl, ComposePwleSegmentBoundary) {
     if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
         std::vector<PrimitivePwle> pwleQueue;
         // test empty queue
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-                  vibrator->composePwle(pwleQueue, nullptr).exceptionCode());
-        EXPECT_TRUE(vibrator->off().isOk());
+        EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueue, nullptr));
 
         ActivePwle active = composeValidActivePwle(vibrator, capabilities);
 
@@ -824,9 +990,7 @@
             pwleQueue.emplace_back(std::move(pwle));
         }
 
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-                  vibrator->composePwle(pwleQueue, nullptr).exceptionCode());
-        EXPECT_TRUE(vibrator->off().isOk());
+        EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueue, nullptr));
     }
 }
 
@@ -836,20 +1000,16 @@
         active.startAmplitude = getAmplitudeMax() + 1.0;  // Amplitude greater than allowed
         active.endAmplitude = getAmplitudeMax() + 1.0;    // Amplitude greater than allowed
 
-        auto pwleQueueGreater = std::vector<PrimitivePwle>{active};
+        std::vector<PrimitivePwle> pwleQueueGreater = {active};
 
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-                  vibrator->composePwle(pwleQueueGreater, nullptr).exceptionCode());
-        EXPECT_TRUE(vibrator->off().isOk());
+        EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueueGreater, nullptr));
 
         active.startAmplitude = getAmplitudeMin() - 1.0;  // Amplitude less than allowed
         active.endAmplitude = getAmplitudeMin() - 1.0;    // Amplitude less than allowed
 
-        auto pwleQueueLess = std::vector<PrimitivePwle>{active};
+        std::vector<PrimitivePwle> pwleQueueLess = {active};
 
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-                  vibrator->composePwle(pwleQueueLess, nullptr).exceptionCode());
-        EXPECT_TRUE(vibrator->off().isOk());
+        EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueueLess, nullptr));
     }
 }
 
@@ -865,20 +1025,16 @@
             freqMaximumHz + freqResolutionHz;                    // Frequency greater than allowed
         active.endFrequency = freqMaximumHz + freqResolutionHz;  // Frequency greater than allowed
 
-        auto pwleQueueGreater = std::vector<PrimitivePwle>{active};
+        std::vector<PrimitivePwle> pwleQueueGreater = {active};
 
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-                  vibrator->composePwle(pwleQueueGreater, nullptr).exceptionCode());
-        EXPECT_TRUE(vibrator->off().isOk());
+        EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueueGreater, nullptr));
 
         active.startFrequency = freqMinimumHz - freqResolutionHz;  // Frequency less than allowed
         active.endFrequency = freqMinimumHz - freqResolutionHz;    // Frequency less than allowed
 
-        auto pwleQueueLess = std::vector<PrimitivePwle>{active};
+        std::vector<PrimitivePwle> pwleQueueLess = {active};
 
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-                  vibrator->composePwle(pwleQueueLess, nullptr).exceptionCode());
-        EXPECT_TRUE(vibrator->off().isOk());
+        EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueueLess, nullptr));
     }
 }
 
@@ -890,32 +1046,196 @@
         vibrator->getPwlePrimitiveDurationMax(&segmentDurationMaxMs);
         active.duration = segmentDurationMaxMs + 10;  // Segment duration greater than allowed
 
-        auto pwleQueue = std::vector<PrimitivePwle>{active};
+        std::vector<PrimitivePwle> pwleQueue = {active};
 
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-                  vibrator->composePwle(pwleQueue, nullptr).exceptionCode());
-        EXPECT_TRUE(vibrator->off().isOk());
+        EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueue, nullptr));
     }
 }
 
+TEST_P(VibratorAidl, PwleV2FrequencyToOutputAccelerationMapHasValidFrequencyRange) {
+    if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) {
+        GTEST_SKIP() << "PWLE V2 not supported, skipping test";
+        return;
+    }
+
+    std::vector<PwleV2OutputMapEntry> frequencyToOutputAccelerationMap;
+    ndk::ScopedAStatus status =
+            vibrator->getPwleV2FrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap);
+    EXPECT_OK(std::move(status));
+    ASSERT_FALSE(frequencyToOutputAccelerationMap.empty());
+    auto sharpnessRange =
+            pwle_v2_utils::getPwleV2SharpnessRange(vibrator, frequencyToOutputAccelerationMap);
+    // Validate the curve provides a usable sharpness range, which is a range of frequencies
+    // that are supported by the device.
+    ASSERT_TRUE(sharpnessRange.first >= 0);
+    // Validate that the sharpness range is a valid interval, not a single point.
+    ASSERT_TRUE(sharpnessRange.first < sharpnessRange.second);
+}
+
+TEST_P(VibratorAidl, GetPwleV2PrimitiveDurationMaxMillis) {
+    if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) {
+        GTEST_SKIP() << "PWLE V2 not supported, skipping test";
+        return;
+    }
+
+    int32_t durationMs;
+    ndk::ScopedAStatus status = vibrator->getPwleV2PrimitiveDurationMaxMillis(&durationMs);
+    EXPECT_OK(std::move(status));
+    ASSERT_GT(durationMs, 0);  // Ensure greater than zero
+    ASSERT_GE(durationMs, pwle_v2_utils::COMPOSE_PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS);
+}
+
+TEST_P(VibratorAidl, GetPwleV2CompositionSizeMax) {
+    if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) {
+        GTEST_SKIP() << "PWLE V2 not supported, skipping test";
+        return;
+    }
+
+    int32_t maxSize;
+    ndk::ScopedAStatus status = vibrator->getPwleV2CompositionSizeMax(&maxSize);
+    EXPECT_OK(std::move(status));
+    ASSERT_GT(maxSize, 0);  // Ensure greater than zero
+    ASSERT_GE(maxSize, pwle_v2_utils::COMPOSE_PWLE_V2_MIN_REQUIRED_SIZE);
+}
+
+TEST_P(VibratorAidl, GetPwleV2PrimitiveDurationMinMillis) {
+    if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) {
+        GTEST_SKIP() << "PWLE V2 not supported, skipping test";
+        return;
+    }
+
+    int32_t durationMs;
+    ndk::ScopedAStatus status = vibrator->getPwleV2PrimitiveDurationMinMillis(&durationMs);
+    EXPECT_OK(std::move(status));
+    ASSERT_GT(durationMs, 0);  // Ensure greater than zero
+    ASSERT_LE(durationMs, pwle_v2_utils::COMPOSE_PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS);
+}
+
+TEST_P(VibratorAidl, ComposeValidPwleV2Effect) {
+    if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) {
+        GTEST_SKIP() << "PWLE V2 not supported, skipping test";
+        return;
+    }
+
+    EXPECT_OK(vibrator->composePwleV2(pwle_v2_utils::composeValidPwleV2Effect(vibrator), nullptr));
+    EXPECT_OK(vibrator->off());
+}
+
+TEST_P(VibratorAidl, ComposePwleV2Unsupported) {
+    if (version < PWLE_V2_MIN_VERSION) {
+        EXPECT_EQ(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2, 0)
+                << "Vibrator version " << version << " should not report PWLE V2 capability.";
+    }
+    if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2) return;
+
+    std::vector<PwleV2Primitive> pwleEffect{
+            PwleV2Primitive(/*amplitude=*/1.0f, /*frequencyHz=*/100.0f, /*timeMillis=*/50)};
+
+    EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->composePwleV2(pwleEffect, nullptr));
+}
+
+TEST_P(VibratorAidl, ComposeValidPwleV2EffectWithCallback) {
+    if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) {
+        GTEST_SKIP() << "PWLE V2 not supported, skipping test";
+        return;
+    }
+
+    std::promise<void> completionPromise;
+    std::future<void> completionFuture{completionPromise.get_future()};
+    auto callback = ndk::SharedRefBase::make<CompletionCallback>(
+            [&completionPromise] { completionPromise.set_value(); });
+
+    int32_t minDuration;
+    EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMinMillis(&minDuration));
+    auto timeout = std::chrono::milliseconds(minDuration) + VIBRATION_CALLBACK_TIMEOUT;
+    float minFrequency = pwle_v2_utils::getPwleV2FrequencyMinHz(vibrator);
+
+    EXPECT_OK(vibrator->composePwleV2(
+            {PwleV2Primitive(/*amplitude=*/0.5, minFrequency, minDuration)}, callback));
+    EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
+    EXPECT_OK(vibrator->off());
+}
+
+TEST_P(VibratorAidl, composePwleV2EffectWithTooManyPoints) {
+    if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) {
+        GTEST_SKIP() << "PWLE V2 not supported, skipping test";
+        return;
+    }
+
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(
+            pwle_v2_utils::composePwleV2EffectWithTooManyPoints(vibrator), nullptr));
+}
+
+TEST_P(VibratorAidl, composeInvalidPwleV2Effect) {
+    if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) {
+        GTEST_SKIP() << "PWLE V2 not supported, skipping test";
+        return;
+    }
+
+    // Retrieve min and max durations
+    int32_t minDurationMs, maxDurationMs;
+    EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMinMillis(&minDurationMs));
+    EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMaxMillis(&maxDurationMs));
+
+    std::vector<PwleV2Primitive> composePwle;
+
+    // Negative amplitude
+    composePwle.push_back(PwleV2Primitive(/*amplitude=*/-0.8f, /*frequency=*/100, minDurationMs));
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr))
+            << "Composing PWLE V2 effect with negative amplitude should fail";
+    composePwle.clear();
+
+    // Amplitude exceeding 1.0
+    composePwle.push_back(PwleV2Primitive(/*amplitude=*/1.2f, /*frequency=*/100, minDurationMs));
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr))
+            << "Composing PWLE V2 effect with amplitude greater than 1.0 should fail";
+    composePwle.clear();
+
+    // Duration exceeding maximum
+    composePwle.push_back(
+            PwleV2Primitive(/*amplitude=*/0.2f, /*frequency=*/100, maxDurationMs + 10));
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr))
+            << "Composing PWLE V2 effect with duration exceeding maximum should fail";
+    composePwle.clear();
+
+    // Negative duration
+    composePwle.push_back(PwleV2Primitive(/*amplitude=*/0.2f, /*frequency=*/100, /*time=*/-1));
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr))
+            << "Composing PWLE V2 effect with negative duration should fail";
+    composePwle.clear();
+
+    // Frequency below minimum
+    float minFrequency = pwle_v2_utils::getPwleV2FrequencyMinHz(vibrator);
+    composePwle.push_back(PwleV2Primitive(/*amplitude=*/0.2f, minFrequency - 1, minDurationMs));
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr))
+            << "Composing PWLE V2 effect with frequency below minimum should fail";
+    composePwle.clear();
+
+    // Frequency above maximum
+    float maxFrequency = pwle_v2_utils::getPwleV2FrequencyMaxHz(vibrator);
+    composePwle.push_back(PwleV2Primitive(/*amplitude=*/0.2f, maxFrequency + 1, minDurationMs));
+    EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr))
+            << "Composing PWLE V2 effect with frequency above maximum should fail";
+}
+
 std::vector<std::tuple<int32_t, int32_t>> GenerateVibratorMapping() {
     std::vector<std::tuple<int32_t, int32_t>> tuples;
-    auto managerAidlNames = android::getAidlHalInstanceNames(IVibratorManager::descriptor);
-    std::vector<int32_t> vibratorIds;
 
-    for (int i = 0; i < managerAidlNames.size(); i++) {
-        auto managerName = String16(managerAidlNames[i].c_str());
-        auto vibratorManager = android::waitForDeclaredService<IVibratorManager>(managerName);
+    std::vector<std::string> managerNames = findVibratorManagerNames();
+    std::vector<int32_t> vibratorIds;
+    for (int i = 0; i < managerNames.size(); i++) {
+        auto vibratorManager = IVibratorManager::fromBinder(
+                ndk::SpAIBinder(AServiceManager_waitForService(managerNames[i].c_str())));
         if (vibratorManager->getVibratorIds(&vibratorIds).isOk()) {
-            for (auto &vibratorId : vibratorIds) {
-                tuples.push_back(std::make_tuple(i, vibratorId));
+            for (int32_t vibratorId : vibratorIds) {
+                tuples.emplace_back(i, vibratorId);
             }
         }
     }
 
-    auto vibratorAidlNames = android::getAidlHalInstanceNames(IVibrator::descriptor);
-    for (int i = 0; i < vibratorAidlNames.size(); i++) {
-        tuples.push_back(std::make_tuple(-1, i));
+    std::vector<std::string> vibratorNames = findUnmanagedVibratorNames();
+    for (int i = 0; i < vibratorNames.size(); i++) {
+        tuples.emplace_back(-1, i);
     }
 
     return tuples;
@@ -935,8 +1255,11 @@
                          PrintGeneratedTest);
 
 int main(int argc, char **argv) {
+    // Random values are used in the implementation.
+    std::srand(std::time(nullptr));
+
     ::testing::InitGoogleTest(&argc, argv);
-    ProcessState::self()->setThreadPoolMaxThreadCount(1);
-    ProcessState::self()->startThreadPool();
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
 }
diff --git a/vibrator/aidl/vts/persistable_bundle_utils.h b/vibrator/aidl/vts/persistable_bundle_utils.h
new file mode 100644
index 0000000..a765a49
--- /dev/null
+++ b/vibrator/aidl/vts/persistable_bundle_utils.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef VIBRATOR_HAL_PERSISTABLE_BUNDLE_UTILS_H
+#define VIBRATOR_HAL_PERSISTABLE_BUNDLE_UTILS_H
+
+#include <android/persistable_bundle_aidl.h>
+
+#include <cstdlib>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace testing {
+
+using aidl::android::os::PersistableBundle;
+
+namespace {
+
+template <typename T>
+T nextValue() {
+    return static_cast<T>(std::rand());
+}
+
+template <>
+std::string nextValue() {
+    std::string str;
+    uint8_t entryCount = nextValue<uint8_t>();
+    for (uint8_t i = 0; i < entryCount; i++) {
+        str.push_back(nextValue<char>());
+    }
+    return str;
+}
+
+template <typename T>
+T nextValue(T limit) {
+    assert(limit > 0);
+    return static_cast<T>(std::rand()) / (static_cast<T>(RAND_MAX / limit));
+}
+
+template <typename T>
+void fillVector(std::vector<T>* values) {
+    uint8_t entryCount = nextValue<uint8_t>();
+    for (uint8_t i = 0; i < entryCount; i++) {
+        values->push_back(nextValue<T>());
+    }
+}
+
+const std::vector<std::function<void(PersistableBundle*, const std::string&)>>
+        sPersistableBundleSetters = {[](PersistableBundle* bundle, const std::string& key) -> void {
+                                         bundle->putBoolean(key, nextValue<bool>());
+                                     },
+                                     [](PersistableBundle* bundle, const std::string& key) -> void {
+                                         bundle->putInt(key, nextValue<int32_t>());
+                                     },
+                                     [](PersistableBundle* bundle, const std::string& key) -> void {
+                                         bundle->putLong(key, nextValue<int64_t>());
+                                     },
+                                     [](PersistableBundle* bundle, const std::string& key) -> void {
+                                         bundle->putDouble(key, nextValue<double>());
+                                     },
+                                     [](PersistableBundle* bundle, const std::string& key) -> void {
+                                         bundle->putString(key, nextValue<std::string>());
+                                     },
+                                     [](PersistableBundle* bundle, const std::string& key) -> void {
+                                         std::vector<bool> value;
+                                         fillVector<bool>(&value);
+                                         bundle->putBooleanVector(key, value);
+                                     },
+                                     [](PersistableBundle* bundle, const std::string& key) -> void {
+                                         std::vector<int32_t> value;
+                                         fillVector<int32_t>(&value);
+                                         bundle->putIntVector(key, value);
+                                     },
+                                     [](PersistableBundle* bundle, const std::string& key) -> void {
+                                         std::vector<int64_t> value;
+                                         fillVector<int64_t>(&value);
+                                         bundle->putLongVector(key, value);
+                                     },
+                                     [](PersistableBundle* bundle, const std::string& key) -> void {
+                                         std::vector<double> value;
+                                         fillVector<double>(&value);
+                                         bundle->putDoubleVector(key, value);
+                                     },
+                                     [](PersistableBundle* bundle, const std::string& key) -> void {
+                                         std::vector<std::string> value;
+                                         fillVector<std::string>(&value);
+                                         bundle->putStringVector(key, value);
+                                     }};
+
+}  // namespace
+
+void fillBasicData(PersistableBundle* bundle) {
+    bundle->putBoolean("test_bool", true);
+    bundle->putInt("test_int", 2147483647);
+    bundle->putLong("test_long", 2147483647L);
+    bundle->putDouble("test_double", 1.23);
+    bundle->putString("test_string", "test data");
+    bundle->putBooleanVector("test_bool_vector", {true, false, false});
+    bundle->putIntVector("test_int_vector", {1, 2, 3, 4});
+    bundle->putLongVector("test_long_vector", {100L, 200L, 300L});
+    bundle->putDoubleVector("test_double_vector", {1.1, 2.2});
+    bundle->putStringVector("test_string_vector", {"test", "val"});
+}
+
+void fillRandomData(PersistableBundle* bundle) {
+    uint8_t entryCount = nextValue<uint8_t>();
+    for (uint8_t i = 0; i < entryCount; i++) {
+        std::string key(nextValue<std::string>());
+        uint8_t setterIdx = nextValue<uint8_t>(sPersistableBundleSetters.size() - 1);
+        sPersistableBundleSetters[setterIdx](bundle, key);
+    }
+}
+
+}  // namespace testing
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+
+#endif  // VIBRATOR_HAL_PERSISTABLE_BUNDLE_UTILS_H
diff --git a/vibrator/aidl/vts/pwle_v2_utils.h b/vibrator/aidl/vts/pwle_v2_utils.h
new file mode 100644
index 0000000..2163908
--- /dev/null
+++ b/vibrator/aidl/vts/pwle_v2_utils.h
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VIBRATOR_HAL_PWLE_V2_UTILS_H
+#define VIBRATOR_HAL_PWLE_V2_UTILS_H
+
+#include <aidl/android/hardware/vibrator/IVibrator.h>
+#include "test_utils.h"
+
+using aidl::android::hardware::vibrator::IVibrator;
+using aidl::android::hardware::vibrator::PwleV2OutputMapEntry;
+using aidl::android::hardware::vibrator::PwleV2Primitive;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace testing {
+namespace pwlev2 {
+
+static constexpr int32_t COMPOSE_PWLE_V2_MIN_REQUIRED_SIZE = 16;
+static constexpr int32_t COMPOSE_PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS = 1000;
+static constexpr int32_t COMPOSE_PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS = 20;
+static constexpr int32_t COMPOSE_PWLE_V2_MIN_REQUIRED_SENSITIVITY_DB_SL = 10;
+
+namespace {
+/**
+ * Returns a vector of (frequency in Hz, acceleration in dB) pairs, where the acceleration
+ * value denotes the minimum output required at the corresponding frequency to be perceptible
+ * by a human.
+ */
+static std::vector<std::pair<float, float>> getMinPerceptibleLevel() {
+    return {{0.4f, -97.81f},   {2.0f, -69.86f},   {3.0f, -62.81f},    {4.0f, -58.81f},
+            {5.0f, -56.69f},   {6.0f, -54.77f},   {7.2f, -52.85f},    {8.0f, -51.77f},
+            {8.64f, -50.84f},  {10.0f, -48.90f},  {10.37f, -48.52f},  {12.44f, -46.50f},
+            {14.93f, -44.43f}, {15.0f, -44.35f},  {17.92f, -41.96f},  {20.0f, -40.36f},
+            {21.5f, -39.60f},  {25.0f, -37.48f},  {25.8f, -36.93f},   {30.0f, -34.31f},
+            {35.0f, -33.13f},  {40.0f, -32.81f},  {50.0f, -31.94f},   {60.0f, -31.77f},
+            {70.0f, -31.59f},  {72.0f, -31.55f},  {80.0f, -31.77f},   {86.4f, -31.94f},
+            {90.0f, -31.73f},  {100.0f, -31.90f}, {103.68f, -31.77f}, {124.42f, -31.70f},
+            {149.3f, -31.38f}, {150.0f, -31.35f}, {179.16f, -31.02f}, {200.0f, -30.86f},
+            {215.0f, -30.35f}, {250.0f, -28.98f}, {258.0f, -28.68f},  {300.0f, -26.81f},
+            {400.0f, -19.81f}};
+}
+
+static float interpolateLinearly(const std::vector<float>& xAxis, const std::vector<float>& yAxis,
+                                 float x) {
+    EXPECT_TRUE(!xAxis.empty());
+    EXPECT_TRUE(xAxis.size() == yAxis.size());
+
+    if (x <= xAxis.front()) return yAxis.front();
+    if (x >= xAxis.back()) return yAxis.back();
+
+    auto it = std::upper_bound(xAxis.begin(), xAxis.end(), x);
+    int i = std::distance(xAxis.begin(), it) - 1;  // Index of the lower bound
+
+    const float& x0 = xAxis[i];
+    const float& y0 = yAxis[i];
+    const float& x1 = xAxis[i + 1];
+    const float& y1 = yAxis[i + 1];
+
+    return y0 + (x - x0) * (y1 - y0) / (x1 - x0);
+}
+
+static float minPerceptibleDbCurve(float frequency) {
+    // Initialize minPerceptibleMap only once
+    static auto minPerceptibleMap = []() -> std::function<float(float)> {
+        static std::vector<float> minPerceptibleFrequencies;
+        static std::vector<float> minPerceptibleAccelerations;
+
+        auto minPerceptibleLevel = getMinPerceptibleLevel();
+        // Sort the 'minPerceptibleLevel' data in ascending order based on the
+        // frequency values (first element of each pair).
+        std::sort(minPerceptibleLevel.begin(), minPerceptibleLevel.end(),
+                  [](const auto& a, const auto& b) { return a.first < b.first; });
+
+        for (const auto& entry : minPerceptibleLevel) {
+            minPerceptibleFrequencies.push_back(entry.first);
+            minPerceptibleAccelerations.push_back(entry.second);
+        }
+
+        return [&](float freq) {
+            return interpolateLinearly(minPerceptibleFrequencies, minPerceptibleAccelerations,
+                                       freq);
+        };
+    }();
+
+    return minPerceptibleMap(frequency);
+}
+
+static float convertSensitivityLevelToDecibel(int sl, float frequency) {
+    return sl + minPerceptibleDbCurve(frequency);
+}
+
+static float convertDecibelToAcceleration(float db) {
+    return std::pow(10.0f, db / 20.0f);
+}
+}  // namespace
+
+static float convertSensitivityLevelToAcceleration(int sl, float frequency) {
+    return pwlev2::convertDecibelToAcceleration(
+            pwlev2::convertSensitivityLevelToDecibel(sl, frequency));
+}
+
+static float getPwleV2FrequencyMinHz(const std::shared_ptr<IVibrator>& vibrator) {
+    std::vector<PwleV2OutputMapEntry> frequencyToOutputAccelerationMap;
+    EXPECT_OK(
+            vibrator->getPwleV2FrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap));
+    EXPECT_TRUE(!frequencyToOutputAccelerationMap.empty());
+    // We can't use ASSERT_TRUE() above because this is a non-void function,
+    // but we need to return to assure we don't crash from a null dereference.
+    if (frequencyToOutputAccelerationMap.empty()) {
+        return std::numeric_limits<float>::quiet_NaN();
+    }
+
+    auto entry = std::min_element(
+            frequencyToOutputAccelerationMap.begin(), frequencyToOutputAccelerationMap.end(),
+            [](const auto& a, const auto& b) { return a.frequencyHz < b.frequencyHz; });
+
+    return entry->frequencyHz;
+}
+
+static float getPwleV2FrequencyMaxHz(const std::shared_ptr<IVibrator>& vibrator) {
+    std::vector<PwleV2OutputMapEntry> frequencyToOutputAccelerationMap;
+    EXPECT_OK(
+            vibrator->getPwleV2FrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap));
+    EXPECT_TRUE(!frequencyToOutputAccelerationMap.empty());
+    // We can't use ASSERT_TRUE() above because this is a non-void function,
+    // but we need to return to assure we don't crash from a null dereference.
+    if (frequencyToOutputAccelerationMap.empty()) {
+        return std::numeric_limits<float>::quiet_NaN();
+    }
+
+    auto entry = std::max_element(
+            frequencyToOutputAccelerationMap.begin(), frequencyToOutputAccelerationMap.end(),
+            [](const auto& a, const auto& b) { return a.frequencyHz < b.frequencyHz; });
+
+    return entry->frequencyHz;
+}
+
+static std::vector<PwleV2Primitive> composeValidPwleV2Effect(
+        const std::shared_ptr<IVibrator>& vibrator) {
+    int32_t minDurationMs;
+    EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMinMillis(&minDurationMs));
+    int32_t maxDurationMs;
+    EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMaxMillis(&maxDurationMs));
+    float minFrequency = getPwleV2FrequencyMinHz(vibrator);
+    float maxFrequency = getPwleV2FrequencyMaxHz(vibrator);
+    int32_t maxCompositionSize;
+    EXPECT_OK(vibrator->getPwleV2CompositionSizeMax(&maxCompositionSize));
+
+    std::vector<PwleV2Primitive> pwleEffect;
+
+    pwleEffect.emplace_back(0.1f, minFrequency, minDurationMs);
+    pwleEffect.emplace_back(0.5f, maxFrequency, maxDurationMs);
+
+    float variedFrequency = (minFrequency + maxFrequency) / 2.0f;
+    for (int i = 0; i < maxCompositionSize - 2; i++) {
+        pwleEffect.emplace_back(0.7f, variedFrequency, minDurationMs);
+    }
+
+    return pwleEffect;
+}
+
+static std::vector<PwleV2Primitive> composePwleV2EffectWithTooManyPoints(
+        const std::shared_ptr<IVibrator>& vibrator) {
+    int32_t minDurationMs, maxCompositionSize;
+    EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMinMillis(&minDurationMs));
+    EXPECT_OK(vibrator->getPwleV2CompositionSizeMax(&maxCompositionSize));
+    float maxFrequency = getPwleV2FrequencyMaxHz(vibrator);
+
+    std::vector<PwleV2Primitive> pwleEffect(maxCompositionSize + 1);  // +1 to exceed the limit
+
+    std::fill(pwleEffect.begin(), pwleEffect.end(),
+              PwleV2Primitive(/*amplitude=*/0.2f, maxFrequency, minDurationMs));
+
+    return pwleEffect;
+}
+
+static std::pair<float, float> getPwleV2SharpnessRange(
+        const std::shared_ptr<IVibrator>& vibrator,
+        std::vector<PwleV2OutputMapEntry> freqToOutputAccelerationMap) {
+    std::pair<float, float> sharpnessRange = {-1, -1};
+
+    // Sort the entries by frequency in ascending order
+    std::sort(freqToOutputAccelerationMap.begin(), freqToOutputAccelerationMap.end(),
+              [](const auto& a, const auto& b) { return a.frequencyHz < b.frequencyHz; });
+
+    for (const auto& entry : freqToOutputAccelerationMap) {
+        float minAcceptableOutputAcceleration = convertSensitivityLevelToAcceleration(
+                pwlev2::COMPOSE_PWLE_V2_MIN_REQUIRED_SENSITIVITY_DB_SL, entry.frequencyHz);
+
+        if (sharpnessRange.first < 0 &&
+            minAcceptableOutputAcceleration <= entry.maxOutputAccelerationGs) {
+            sharpnessRange.first = entry.frequencyHz;  // Found the lower bound
+        } else if (sharpnessRange.first >= 0 &&
+                   minAcceptableOutputAcceleration >= entry.maxOutputAccelerationGs) {
+            sharpnessRange.second = entry.frequencyHz;  // Found the upper bound
+            return sharpnessRange;
+        }
+    }
+
+    if (sharpnessRange.first >= 0) {
+        // If only the lower bound was found, set the upper bound to the max frequency.
+        sharpnessRange.second = getPwleV2FrequencyMaxHz(vibrator);
+    }
+
+    return sharpnessRange;
+}
+}  // namespace pwlev2
+}  // namespace testing
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+#endif  // VIBRATOR_HAL_PWLE_V2_UTILS_H
diff --git a/vibrator/aidl/vts/test_utils.h b/vibrator/aidl/vts/test_utils.h
new file mode 100644
index 0000000..aaf3211
--- /dev/null
+++ b/vibrator/aidl/vts/test_utils.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef VIBRATOR_HAL_TEST_UTILS_H
+#define VIBRATOR_HAL_TEST_UTILS_H
+
+#include <android/binder_auto_utils.h>
+#include <gtest/gtest.h>
+
+#if !defined(EXPECT_OK)
+#define EXPECT_OK(expression)                                                \
+    GTEST_AMBIGUOUS_ELSE_BLOCKER_                                            \
+    if (const ::ndk::ScopedAStatus&& _status = (expression); _status.isOk()) \
+        ;                                                                    \
+    else                                                                     \
+        ADD_FAILURE() << "Expected STATUS_OK for: " << #expression << "\n  Actual: " << _status
+#else
+#error Macro EXPECT_OK already defined unexpectedly
+#endif
+
+#if !defined(EXPECT_UNKNOWN_OR_UNSUPPORTED)
+#define EXPECT_UNKNOWN_OR_UNSUPPORTED(expression)                                                \
+    GTEST_AMBIGUOUS_ELSE_BLOCKER_                                                                \
+    if (const ::ndk::ScopedAStatus&& _status = (expression);                                     \
+        _status.getExceptionCode() == EX_UNSUPPORTED_OPERATION ||                                \
+        _status.getStatus() == STATUS_UNKNOWN_TRANSACTION)                                       \
+        ;                                                                                        \
+    else                                                                                         \
+        ADD_FAILURE() << "Expected STATUS_UNKNOWN_TRANSACTION or EX_UNSUPPORTED_OPERATION for: " \
+                      << #expression << "\n  Actual: " << _status
+#else
+#error Macro EXPECT_UNKNOWN_OR_UNSUPPORTED already defined unexpectedly
+#endif
+
+#if !defined(EXPECT_ILLEGAL_ARGUMENT)
+#define EXPECT_ILLEGAL_ARGUMENT(expression)                                  \
+    GTEST_AMBIGUOUS_ELSE_BLOCKER_                                            \
+    if (const ::ndk::ScopedAStatus&& _status = (expression);                 \
+        _status.getExceptionCode() == EX_ILLEGAL_ARGUMENT)                   \
+        ;                                                                    \
+    else                                                                     \
+        ADD_FAILURE() << "Expected EX_ILLEGAL_ARGUMENT for: " << #expression \
+                      << "\n  Actual: " << _status
+#else
+#error Macro EXPECT_ILLEGAL_ARGUMENT already defined unexpectedly
+#endif
+
+#endif  // VIBRATOR_HAL_TEST_UTILS_H
diff --git a/vibrator/bench/Android.bp b/vibrator/bench/Android.bp
index 87bdab4..cd56516 100644
--- a/vibrator/bench/Android.bp
+++ b/vibrator/bench/Android.bp
@@ -30,12 +30,12 @@
         "benchmark.cpp",
     ],
     shared_libs: [
-        "android.hardware.vibrator-V2-cpp",
+        "android.hardware.vibrator-V3-ndk",
         "android.hardware.vibrator@1.0",
         "android.hardware.vibrator@1.1",
         "android.hardware.vibrator@1.2",
         "android.hardware.vibrator@1.3",
-        "libbinder",
+        "libbinder_ndk",
         "libhardware",
         "libhidlbase",
         "libutils",
diff --git a/vibrator/bench/benchmark.cpp b/vibrator/bench/benchmark.cpp
index deaa6f2..8fe9cf7 100644
--- a/vibrator/bench/benchmark.cpp
+++ b/vibrator/bench/benchmark.cpp
@@ -16,15 +16,14 @@
 
 #include "benchmark/benchmark.h"
 
+#include <aidl/android/hardware/vibrator/BnVibratorCallback.h>
+#include <aidl/android/hardware/vibrator/IVibrator.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
 #include <android/hardware/vibrator/1.3/IVibrator.h>
-#include <android/hardware/vibrator/BnVibratorCallback.h>
-#include <android/hardware/vibrator/IVibrator.h>
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
 #include <future>
 
-using ::android::enum_range;
-using ::android::sp;
 using ::android::hardware::hidl_enum_range;
 using ::android::hardware::Return;
 using ::android::hardware::details::hidl_enum_values;
@@ -33,10 +32,11 @@
 using ::benchmark::kMicrosecond;
 using ::benchmark::State;
 using ::benchmark::internal::Benchmark;
+using ::ndk::enum_range;
 
 using namespace ::std::chrono_literals;
 
-namespace Aidl = ::android::hardware::vibrator;
+namespace Aidl = ::aidl::android::hardware::vibrator;
 namespace V1_0 = ::android::hardware::vibrator::V1_0;
 namespace V1_1 = ::android::hardware::vibrator::V1_1;
 namespace V1_2 = ::android::hardware::vibrator::V1_2;
@@ -56,8 +56,8 @@
 class BaseBench : public Fixture {
   public:
     void SetUp(State& /*state*/) override {
-        android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
-        android::ProcessState::self()->startThreadPool();
+        ABinderProcess_setThreadPoolMaxThreadCount(1);
+        ABinderProcess_startThreadPool();
     }
 
     void TearDown(State& /*state*/) override {
@@ -75,7 +75,7 @@
     auto getOtherArg(const State& state, std::size_t index) const { return state.range(index + 0); }
 
   protected:
-    sp<I> mVibrator;
+    std::shared_ptr<I> mVibrator;
 };
 
 template <typename I>
@@ -83,7 +83,12 @@
   public:
     void SetUp(State& state) override {
         BaseBench<I>::SetUp(state);
-        this->mVibrator = I::getService();
+        auto service = I::getService();
+        if (service) {
+            this->mVibrator = std::shared_ptr<I>(service.release());
+        } else {
+            this->mVibrator = nullptr;
+        }
     }
 
   protected:
@@ -356,7 +361,9 @@
   public:
     void SetUp(State& state) override {
         BaseBench::SetUp(state);
-        this->mVibrator = android::waitForVintfService<Aidl::IVibrator>();
+        auto serviceName = std::string(Aidl::IVibrator::descriptor) + "/default";
+        this->mVibrator = Aidl::IVibrator::fromBinder(
+                ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str())));
     }
 
     void TearDown(State& state) override {
@@ -373,14 +380,24 @@
         return (deviceCapabilities & capabilities) == capabilities;
     }
 
-    bool shouldSkipWithError(State& state, const android::binder::Status&& status) {
+    bool shouldSkipWithError(State& state, const ndk::ScopedAStatus&& status) {
         if (!status.isOk()) {
-            state.SkipWithError(status.toString8().c_str());
+            state.SkipWithError(status.getMessage());
             return true;
         }
         return false;
     }
 
+    void waitForComplete(std::future<void>& callbackFuture) {
+        // Wait until the HAL has finished processing previous vibration before starting a new one,
+        // so the HAL state is consistent on each run and metrics are less noisy. Some of the newest
+        // HAL implementations are waiting on previous vibration cleanup and might be significantly
+        // slower, so make sure we measure vibrations on a clean slate.
+        if (callbackFuture.valid()) {
+            callbackFuture.wait_for(VIBRATION_CALLBACK_TIMEOUT);
+        }
+    }
+
     static void SlowBenchConfig(Benchmark* b) { b->Iterations(VIBRATION_ITERATIONS); }
 };
 
@@ -397,18 +414,12 @@
     HalCallback() = default;
     ~HalCallback() = default;
 
-    android::binder::Status onComplete() override {
+    ndk::ScopedAStatus onComplete() override {
         mPromise.set_value();
-        return android::binder::Status::ok();
+        return ndk::ScopedAStatus::ok();
     }
 
-    void waitForComplete() {
-        // Wait until the HAL has finished processing previous vibration before starting a new one,
-        // so the HAL state is consistent on each run and metrics are less noisy. Some of the newest
-        // HAL implementations are waiting on previous vibration cleanup and might be significantly
-        // slower, so make sure we measure vibrations on a clean slate.
-        mPromise.get_future().wait_for(VIBRATION_CALLBACK_TIMEOUT);
-    }
+    std::future<void> getFuture() { return mPromise.get_future(); }
 
   private:
     std::promise<void> mPromise;
@@ -418,7 +429,11 @@
     auto ms = MAX_ON_DURATION_MS;
 
     for (auto _ : state) {
-        auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK) ? new HalCallback() : nullptr;
+        auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK)
+                          ? ndk::SharedRefBase::make<HalCallback>()
+                          : nullptr;
+        // Grab the future before callback promise is destroyed by the HAL.
+        auto cbFuture = cb ? cb->getFuture() : std::future<void>();
 
         // Test
         if (shouldSkipWithError(state, mVibrator->on(ms, cb))) {
@@ -430,9 +445,7 @@
         if (shouldSkipWithError(state, mVibrator->off())) {
             return;
         }
-        if (cb) {
-            cb->waitForComplete();
-        }
+        waitForComplete(cbFuture);
         state.ResumeTiming();
     }
 });
@@ -441,7 +454,11 @@
     auto ms = MAX_ON_DURATION_MS;
 
     for (auto _ : state) {
-        auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK) ? new HalCallback() : nullptr;
+        auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK)
+                          ? ndk::SharedRefBase::make<HalCallback>()
+                          : nullptr;
+        // Grab the future before callback promise is destroyed by the HAL.
+        auto cbFuture = cb ? cb->getFuture() : std::future<void>();
 
         // Setup
         state.PauseTiming();
@@ -457,9 +474,7 @@
 
         // Cleanup
         state.PauseTiming();
-        if (cb) {
-            cb->waitForComplete();
-        }
+        waitForComplete(cbFuture);
         state.ResumeTiming();
     }
 });
@@ -483,7 +498,9 @@
         return;
     }
 
-    auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK) ? new HalCallback() : nullptr;
+    auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK)
+                      ? ndk::SharedRefBase::make<HalCallback>()
+                      : nullptr;
     if (shouldSkipWithError(state, mVibrator->on(ms, cb))) {
         return;
     }
@@ -685,8 +702,11 @@
     int32_t lengthMs = 0;
 
     for (auto _ : state) {
-        auto cb = hasCapabilities(Aidl::IVibrator::CAP_PERFORM_CALLBACK) ? new HalCallback()
-                                                                         : nullptr;
+        auto cb = hasCapabilities(Aidl::IVibrator::CAP_PERFORM_CALLBACK)
+                          ? ndk::SharedRefBase::make<HalCallback>()
+                          : nullptr;
+        // Grab the future before callback promise is destroyed by the HAL.
+        auto cbFuture = cb ? cb->getFuture() : std::future<void>();
 
         // Test
         if (shouldSkipWithError(state, mVibrator->perform(effect, strength, cb, &lengthMs))) {
@@ -698,9 +718,7 @@
         if (shouldSkipWithError(state, mVibrator->off())) {
             return;
         }
-        if (cb) {
-            cb->waitForComplete();
-        }
+        waitForComplete(cbFuture);
         state.ResumeTiming();
     }
 });
@@ -799,7 +817,9 @@
     effects.push_back(effect);
 
     for (auto _ : state) {
-        auto cb = new HalCallback();
+        auto cb = ndk::SharedRefBase::make<HalCallback>();
+        // Grab the future before callback promise is moved and destroyed by the HAL.
+        auto cbFuture = cb->getFuture();
 
         // Test
         if (shouldSkipWithError(state, mVibrator->compose(effects, cb))) {
@@ -811,7 +831,7 @@
         if (shouldSkipWithError(state, mVibrator->off())) {
             return;
         }
-        cb->waitForComplete();
+        waitForComplete(cbFuture);
         state.ResumeTiming();
     }
 });
diff --git a/virtualization/capabilities_service/aidl/Android.bp b/virtualization/capabilities_service/aidl/Android.bp
new file mode 100644
index 0000000..b0bbbdd
--- /dev/null
+++ b/virtualization/capabilities_service/aidl/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_team: "trendy_team_virtualization",
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+aidl_interface {
+    name: "android.hardware.virtualization.capabilities.capabilities_service",
+    vendor_available: true,
+    srcs: ["android/**/*.aidl"],
+    stability: "vintf",
+    backend: {
+        rust: {
+            enabled: true,
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.virt",
+            ],
+        },
+    },
+    frozen: false,
+}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/virtualization/capabilities_service/aidl/aidl_api/android.hardware.virtualization.capabilities.capabilities_service/current/android/hardware/virtualization/capabilities/IVmCapabilitiesService.aidl
similarity index 88%
rename from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
rename to virtualization/capabilities_service/aidl/aidl_api/android.hardware.virtualization.capabilities.capabilities_service/current/android/hardware/virtualization/capabilities/IVmCapabilitiesService.aidl
index 173ac17..68ff021 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/virtualization/capabilities_service/aidl/aidl_api/android.hardware.virtualization.capabilities.capabilities_service/current/android/hardware/virtualization/capabilities/IVmCapabilitiesService.aidl
@@ -31,10 +31,8 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
+package android.hardware.virtualization.capabilities;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+interface IVmCapabilitiesService {
+  void grantAccessToVendorTeeServices(in ParcelFileDescriptor vmFd, in String[] vendorTeeServices);
 }
diff --git a/virtualization/capabilities_service/aidl/android/hardware/virtualization/capabilities/IVmCapabilitiesService.aidl b/virtualization/capabilities_service/aidl/android/hardware/virtualization/capabilities/IVmCapabilitiesService.aidl
new file mode 100644
index 0000000..0d09ecb
--- /dev/null
+++ b/virtualization/capabilities_service/aidl/android/hardware/virtualization/capabilities/IVmCapabilitiesService.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.virtualization.capabilities;
+
+/**
+ * Encapsulates vendor-specific capabilities that can be granted to VMs.
+ */
+@VintfStability
+interface IVmCapabilitiesService {
+    /**
+     * Grant access for the VM represented by the given vm_fd to the given vendor-owned tee
+     * services. The names in |vendorTeeServices| must match the ones defined in the
+     * tee_service_contexts files.
+     * TODO(ioffe): link to the integration doc for custom smc filtering feature once
+     * it's ready.
+     */
+    void grantAccessToVendorTeeServices(
+            in ParcelFileDescriptor vmFd, in String[] vendorTeeServices);
+}
diff --git a/wifi/aidl/default/aidl_struct_util.cpp b/wifi/aidl/default/aidl_struct_util.cpp
index d82450e..d99edaa 100644
--- a/wifi/aidl/default/aidl_struct_util.cpp
+++ b/wifi/aidl/default/aidl_struct_util.cpp
@@ -3394,6 +3394,7 @@
     *legacy_request = {};
 
     legacy_request->service_instance_id = aidl_request.bootstrappingInstanceId;
+    legacy_request->bootstrapping_instance_id = aidl_request.bootstrappingInstanceId;
     legacy_request->rsp_code = aidl_request.acceptRequest ? NAN_BOOTSTRAPPING_REQUEST_ACCEPT
                                                           : NAN_BOOTSTRAPPING_REQUEST_REJECT;
     legacy_request->publish_subscribe_id = static_cast<uint8_t>(aidl_request.discoverySessionId);
diff --git a/wifi/aidl/default/wifi_chip.cpp b/wifi/aidl/default/wifi_chip.cpp
index 9b9c565..fccfc15 100644
--- a/wifi/aidl/default/wifi_chip.cpp
+++ b/wifi/aidl/default/wifi_chip.cpp
@@ -62,7 +62,9 @@
 std::vector<std::string> getNames(std::vector<std::shared_ptr<Iface>>& ifaces) {
     std::vector<std::string> names;
     for (const auto& iface : ifaces) {
-        names.emplace_back(iface->getName());
+        if (iface) {
+            names.emplace_back(iface->getName());
+        }
     }
     return names;
 }
@@ -971,6 +973,10 @@
     }
     std::shared_ptr<WifiNanIface> iface =
             WifiNanIface::create(ifname, is_dedicated_iface, legacy_hal_, iface_util_);
+    if (!iface) {
+        LOG(ERROR) << "Unable to create NAN iface";
+        return {nullptr, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
+    }
     nan_ifaces_.push_back(iface);
     for (const auto& callback : event_cb_handler_.getCallbacks()) {
         if (!callback->onIfaceAdded(IfaceType::NAN_IFACE, ifname).isOk()) {
diff --git a/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp b/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp
index 21d50ac..c68d8fd 100644
--- a/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp
+++ b/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp
@@ -177,8 +177,7 @@
     return iface;
 }
 
-std::shared_ptr<IWifiApIface> getWifiApIface(const char* instance_name) {
-    std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(instance_name);
+std::shared_ptr<IWifiApIface> getWifiApIface(std::shared_ptr<IWifiChip> wifi_chip) {
     if (!wifi_chip.get()) {
         return nullptr;
     }
@@ -193,6 +192,11 @@
     return iface;
 }
 
+std::shared_ptr<IWifiApIface> getWifiApIface(const char* instance_name) {
+    std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(instance_name);
+    return getWifiApIface(wifi_chip);
+}
+
 std::shared_ptr<IWifiApIface> getBridgedWifiApIface(std::shared_ptr<IWifiChip> wifi_chip) {
     if (!wifi_chip.get()) {
         return nullptr;
diff --git a/wifi/aidl/vts/functional/wifi_aidl_test_utils.h b/wifi/aidl/vts/functional/wifi_aidl_test_utils.h
index 1369dd4..9b47a9f 100644
--- a/wifi/aidl/vts/functional/wifi_aidl_test_utils.h
+++ b/wifi/aidl/vts/functional/wifi_aidl_test_utils.h
@@ -40,6 +40,7 @@
 std::shared_ptr<IWifiStaIface> getWifiStaIface(const char* instance_name);
 std::shared_ptr<IWifiNanIface> getWifiNanIface(const char* instance_name);
 std::shared_ptr<IWifiApIface> getWifiApIface(const char* instance_name);
+std::shared_ptr<IWifiApIface> getWifiApIface(std::shared_ptr<IWifiChip> wifi_chip);
 std::shared_ptr<IWifiApIface> getBridgedWifiApIface(const char* instance_name);
 std::shared_ptr<IWifiApIface> getBridgedWifiApIface(std::shared_ptr<IWifiChip> wifi_chip);
 // Configure the chip in a mode to support the creation of the provided iface type.
diff --git a/wifi/aidl/vts/functional/wifi_ap_iface_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_ap_iface_aidl_test.cpp
index d39cfb4..a58fd5b 100644
--- a/wifi/aidl/vts/functional/wifi_ap_iface_aidl_test.cpp
+++ b/wifi/aidl/vts/functional/wifi_ap_iface_aidl_test.cpp
@@ -37,12 +37,21 @@
                 "/system/bin/cmd wifi get-softap-supported-features",
                 "wifi_softap_bridged_ap_supported");
         stopWifiService(getInstanceName());
+
+        wifi_chip_ = getWifiChip(getInstanceName());
+        ASSERT_NE(nullptr, wifi_chip_.get());
+
+        bool isApSupported = doesChipSupportConcurrencyType(wifi_chip_, IfaceConcurrencyType::AP);
+        if (!isApSupported) {
+            GTEST_SKIP() << "AP interfaces are not supported";
+        }
     }
 
     void TearDown() override { stopWifiService(getInstanceName()); }
 
   protected:
     bool isBridgedSupport_ = false;
+    std::shared_ptr<IWifiChip> wifi_chip_;
     const char* getInstanceName() { return GetParam().c_str(); }
 };
 
@@ -50,7 +59,7 @@
  * SetMacAddress
  */
 TEST_P(WifiApIfaceAidlTest, SetMacAddress) {
-    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(getInstanceName());
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(wifi_chip_);
     ASSERT_NE(nullptr, wifi_ap_iface.get());
     std::array<uint8_t, 6> mac = {0x12, 0x22, 0x33, 0x52, 0x10, 0x44};
     EXPECT_TRUE(wifi_ap_iface->setMacAddress(mac).isOk());
@@ -60,7 +69,7 @@
  * SetCountryCode
  */
 TEST_P(WifiApIfaceAidlTest, SetCountryCode) {
-    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(getInstanceName());
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(wifi_chip_);
     ASSERT_NE(nullptr, wifi_ap_iface.get());
 
     const std::array<uint8_t, 2> country_code = {0x55, 0x53};
@@ -71,7 +80,7 @@
  * GetFactoryMacAddress
  */
 TEST_P(WifiApIfaceAidlTest, GetFactoryMacAddress) {
-    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(getInstanceName());
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(wifi_chip_);
     ASSERT_NE(nullptr, wifi_ap_iface.get());
 
     std::array<uint8_t, 6> mac;
@@ -84,7 +93,7 @@
  * GetBridgedInstances - non-bridged mode
  */
 TEST_P(WifiApIfaceAidlTest, GetBridgedInstances) {
-    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(getInstanceName());
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(wifi_chip_);
     ASSERT_NE(nullptr, wifi_ap_iface.get());
 
     std::vector<std::string> instances;
@@ -99,7 +108,7 @@
     if (!isBridgedSupport_) {
         GTEST_SKIP() << "Missing Bridged AP support";
     }
-    std::shared_ptr<IWifiApIface> wifi_ap_iface = getBridgedWifiApIface(getInstanceName());
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getBridgedWifiApIface(wifi_chip_);
     ASSERT_NE(nullptr, wifi_ap_iface.get());
 
     std::vector<std::string> instances;
@@ -111,7 +120,7 @@
  * ResetToFactoryMacAddress - non-bridged mode
  */
 TEST_P(WifiApIfaceAidlTest, ResetToFactoryMacAddress) {
-    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(getInstanceName());
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(wifi_chip_);
     ASSERT_NE(nullptr, wifi_ap_iface.get());
     EXPECT_TRUE(wifi_ap_iface->resetToFactoryMacAddress().isOk());
 }
@@ -123,7 +132,7 @@
     if (!isBridgedSupport_) {
         GTEST_SKIP() << "Missing Bridged AP support";
     }
-    std::shared_ptr<IWifiApIface> wifi_ap_iface = getBridgedWifiApIface(getInstanceName());
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getBridgedWifiApIface(wifi_chip_);
     ASSERT_NE(nullptr, wifi_ap_iface.get());
     EXPECT_TRUE(wifi_ap_iface->resetToFactoryMacAddress().isOk());
 }
diff --git a/wifi/hostapd/aidl/Android.bp b/wifi/hostapd/aidl/Android.bp
index 2e4d4d1..88f4ef2 100644
--- a/wifi/hostapd/aidl/Android.bp
+++ b/wifi/hostapd/aidl/Android.bp
@@ -65,5 +65,5 @@
         },
 
     ],
-    frozen: true,
+    frozen: false,
 }
diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/BandMask.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/BandMask.aidl
index b1e7f66..fa9f198 100644
--- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/BandMask.aidl
+++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/BandMask.aidl
@@ -34,8 +34,8 @@
 package android.hardware.wifi.hostapd;
 @Backing(type="int") @VintfStability
 enum BandMask {
-  BAND_2_GHZ = 1,
-  BAND_5_GHZ = 2,
-  BAND_6_GHZ = 4,
-  BAND_60_GHZ = 8,
+  BAND_2_GHZ = (1 << 0) /* 1 */,
+  BAND_5_GHZ = (1 << 1) /* 2 */,
+  BAND_6_GHZ = (1 << 2) /* 4 */,
+  BAND_60_GHZ = (1 << 3) /* 8 */,
 }
diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/EncryptionType.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/EncryptionType.aidl
index a7b20fa..840b875 100644
--- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/EncryptionType.aidl
+++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/EncryptionType.aidl
@@ -34,11 +34,11 @@
 package android.hardware.wifi.hostapd;
 @Backing(type="int") @VintfStability
 enum EncryptionType {
-  NONE = 0,
-  WPA = 1,
-  WPA2 = 2,
-  WPA3_SAE_TRANSITION = 3,
-  WPA3_SAE = 4,
-  WPA3_OWE_TRANSITION = 5,
-  WPA3_OWE = 6,
+  NONE,
+  WPA,
+  WPA2,
+  WPA3_SAE_TRANSITION,
+  WPA3_SAE,
+  WPA3_OWE_TRANSITION,
+  WPA3_OWE,
 }
diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Generation.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Generation.aidl
index 5bb0d32..a0c1886 100644
--- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Generation.aidl
+++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Generation.aidl
@@ -34,7 +34,7 @@
 package android.hardware.wifi.hostapd;
 @Backing(type="int") @VintfStability
 enum Generation {
-  WIFI_STANDARD_UNKNOWN = -1,
+  WIFI_STANDARD_UNKNOWN = (-1) /* -1 */,
   WIFI_STANDARD_LEGACY = 0,
   WIFI_STANDARD_11N = 1,
   WIFI_STANDARD_11AC = 2,
diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/HostapdStatusCode.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/HostapdStatusCode.aidl
index 548e497..7edff15 100644
--- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/HostapdStatusCode.aidl
+++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/HostapdStatusCode.aidl
@@ -34,10 +34,10 @@
 package android.hardware.wifi.hostapd;
 @Backing(type="int") @VintfStability
 enum HostapdStatusCode {
-  SUCCESS = 0,
-  FAILURE_UNKNOWN = 1,
-  FAILURE_ARGS_INVALID = 2,
-  FAILURE_IFACE_UNKNOWN = 3,
-  FAILURE_IFACE_EXISTS = 4,
-  FAILURE_CLIENT_UNKNOWN = 5,
+  SUCCESS,
+  FAILURE_UNKNOWN,
+  FAILURE_ARGS_INVALID,
+  FAILURE_IFACE_UNKNOWN,
+  FAILURE_IFACE_EXISTS,
+  FAILURE_CLIENT_UNKNOWN,
 }
diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IfaceParams.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IfaceParams.aidl
index 64367bb..8da3441 100644
--- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IfaceParams.aidl
+++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IfaceParams.aidl
@@ -38,4 +38,6 @@
   android.hardware.wifi.hostapd.HwModeParams hwModeParams;
   android.hardware.wifi.hostapd.ChannelParams[] channelParams;
   @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
+  @nullable String[] instanceIdentities;
+  boolean isMlo;
 }
diff --git a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl
index 3f8ee39..bb646e3 100644
--- a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl
+++ b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl
@@ -41,4 +41,12 @@
      * Optional vendor-specific configuration parameters.
      */
     @nullable OuiKeyedData[] vendorData;
+    /**
+     * The list of the instance identities.
+     */
+    @nullable String[] instanceIdentities;
+    /**
+     * Whether the current iface is MLO.
+     */
+    boolean isMlo;
 }
diff --git a/wifi/hostapd/aidl/vts/functional/Android.bp b/wifi/hostapd/aidl/vts/functional/Android.bp
index f614679..bf1b0d0 100644
--- a/wifi/hostapd/aidl/vts/functional/Android.bp
+++ b/wifi/hostapd/aidl/vts/functional/Android.bp
@@ -21,7 +21,7 @@
         "libvndksupport",
     ],
     static_libs: [
-        "android.hardware.wifi.hostapd-V2-ndk",
+        "android.hardware.wifi.hostapd-V3-ndk",
         "VtsHalWifiV1_0TargetTestUtil",
         "VtsHalWifiV1_5TargetTestUtil",
         "VtsHalWifiV1_6TargetTestUtil",
diff --git a/wifi/legacy_headers/include/hardware_legacy/wifi_nan.h b/wifi/legacy_headers/include/hardware_legacy/wifi_nan.h
index 55034d1..4e490d9 100644
--- a/wifi/legacy_headers/include/hardware_legacy/wifi_nan.h
+++ b/wifi/legacy_headers/include/hardware_legacy/wifi_nan.h
@@ -2972,11 +2972,17 @@
     u16 publish_subscribe_id;
 
     /*
-       This Id is the Peer Instance that is passed as
-       part of earlier MatchInd/FollowupInd message.
+      Same as the bootstrapping_instance_id
     */
     u32 service_instance_id;
 
+    /*
+      Unique Instance Id corresponding to a service/session.
+      This is similar to the publish_id generated on the
+      publisher side
+    */
+    u32 bootstrapping_instance_id;
+
     /* Discovery MAC addr of the peer/initiator */
     u8 peer_disc_mac_addr[NAN_MAC_ADDR_LEN];
 
diff --git a/wifi/supplicant/aidl/Android.bp b/wifi/supplicant/aidl/Android.bp
index b7242ed..8d16cb7 100644
--- a/wifi/supplicant/aidl/Android.bp
+++ b/wifi/supplicant/aidl/Android.bp
@@ -71,5 +71,5 @@
         },
 
     ],
-    frozen: true,
+    frozen: false,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl
index 330f2aa..6bae4cf 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl
@@ -41,4 +41,5 @@
   TRUST_ON_FIRST_USE = (1 << 4) /* 16 */,
   SET_TLS_MINIMUM_VERSION = (1 << 5) /* 32 */,
   TLS_V1_3 = (1 << 6) /* 64 */,
+  RSN_OVERRIDING = (1 << 7) /* 128 */,
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl
index a9434c4..b6e57c6 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl
@@ -50,4 +50,8 @@
      * TLS V1.3
      */
     TLS_V1_3 = 1 << 6,
+    /**
+     * RSN Overriding
+     */
+    RSN_OVERRIDING = 1 << 7,
 }
diff --git a/wifi/supplicant/aidl/vts/functional/Android.bp b/wifi/supplicant/aidl/vts/functional/Android.bp
index 4166850..4ffec3f 100644
--- a/wifi/supplicant/aidl/vts/functional/Android.bp
+++ b/wifi/supplicant/aidl/vts/functional/Android.bp
@@ -46,7 +46,7 @@
         "android.hardware.wifi.common-V1-ndk",
         "android.hardware.wifi.supplicant@1.0",
         "android.hardware.wifi.supplicant@1.1",
-        "android.hardware.wifi.supplicant-V3-ndk",
+        "android.hardware.wifi.supplicant-V4-ndk",
         "libwifi-system",
         "libwifi-system-iface",
         "VtsHalWifiV1_0TargetTestUtil",
@@ -84,7 +84,7 @@
         "android.hardware.wifi.common-V1-ndk",
         "android.hardware.wifi.supplicant@1.0",
         "android.hardware.wifi.supplicant@1.1",
-        "android.hardware.wifi.supplicant-V3-ndk",
+        "android.hardware.wifi.supplicant-V4-ndk",
         "libwifi-system",
         "libwifi-system-iface",
         "VtsHalWifiV1_0TargetTestUtil",
@@ -122,7 +122,7 @@
         "android.hardware.wifi.common-V1-ndk",
         "android.hardware.wifi.supplicant@1.0",
         "android.hardware.wifi.supplicant@1.1",
-        "android.hardware.wifi.supplicant-V3-ndk",
+        "android.hardware.wifi.supplicant-V4-ndk",
         "libwifi-system",
         "libwifi-system-iface",
         "VtsHalWifiV1_0TargetTestUtil",