Merge "Expect SHA-256 digest for attested VBMeta digest on VSR-V+." into main am: a742007dfa am: 62c4684eb7

Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/3326633

Change-Id: Ied4bbd0ea30820ac20586706df7512dc59202824
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index 4902497..1e6df46 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -303,6 +303,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",
@@ -317,6 +318,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/EnrollmentProgressStep.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/EnrollmentProgressStep.aidl
copy to audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Eraser.aidl
index 173ac17..5d8abd5 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.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
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+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/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/default/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml
index a54f4db..2cef9eb 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"/>
diff --git a/audio/aidl/default/config/audioPolicy/api/current.txt b/audio/aidl/default/config/audioPolicy/api/current.txt
index e57c108..7fce8fb 100644
--- a/audio/aidl/default/config/audioPolicy/api/current.txt
+++ b/audio/aidl/default/config/audioPolicy/api/current.txt
@@ -144,6 +144,7 @@
     enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_HEARING_AID;
     enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_IP;
     enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_LINE;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_MULTICHANNEL_GROUP;
     enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_PROXY;
     enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
     enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_SPDIF;
diff --git a/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd b/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
index 108a6a3..1f90313 100644
--- a/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
+++ b/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
@@ -262,6 +262,7 @@
             <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_LINE"/>
             <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER_SAFE"/>
             <xs:enumeration value="AUDIO_DEVICE_OUT_IP"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_MULTICHANNEL_GROUP"/>
             <xs:enumeration value="AUDIO_DEVICE_OUT_BUS"/>
             <xs:enumeration value="AUDIO_DEVICE_OUT_PROXY"/>
             <xs:enumeration value="AUDIO_DEVICE_OUT_USB_HEADSET"/>
diff --git a/audio/aidl/default/config/audioPolicy/engine/api/current.txt b/audio/aidl/default/config/audioPolicy/engine/api/current.txt
index 8e0e9a2..1ba91e6 100644
--- a/audio/aidl/default/config/audioPolicy/engine/api/current.txt
+++ b/audio/aidl/default/config/audioPolicy/engine/api/current.txt
@@ -227,6 +227,7 @@
     enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_EVENT;
     enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
     enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_SAFETY;
+    enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_SPEAKER_CLEANUP;
     enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_UNKNOWN;
     enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_VEHICLE_STATUS;
     enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_VIRTUAL_SOURCE;
diff --git a/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd b/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd
index e2508ea..6422277 100644
--- a/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd
+++ b/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd
@@ -377,6 +377,7 @@
             <xs:enumeration value="AUDIO_USAGE_SAFETY" />
             <xs:enumeration value="AUDIO_USAGE_VEHICLE_STATUS" />
             <xs:enumeration value="AUDIO_USAGE_ANNOUNCEMENT" />
+            <xs:enumeration value="AUDIO_USAGE_SPEAKER_CLEANUP" />
         </xs:restriction>
     </xs:simpleType>
 
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..157ec79
--- /dev/null
+++ b/audio/aidl/default/eraser/Eraser.cpp
@@ -0,0 +1,187 @@
+/*
+ * 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__;
+}
+
+// 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");
+    return mContext->process(in, out, samples);
+}
+
+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 status = {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 status;
+    }
+
+    int iFrames = samples / inputChannelCount;
+    for (int i = 0; i < iFrames; i++) {
+        std::memcpy(out, in, outputChannelCount);
+        in += inputChannelCount;
+        out += outputChannelCount;
+    }
+    return {STATUS_OK, static_cast<int32_t>(iFrames * inputChannelCount),
+            static_cast<int32_t>(iFrames * outputChannelCount)};
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/eraser/Eraser.h b/audio/aidl/default/eraser/Eraser.h
new file mode 100644
index 0000000..0d4eb8f
--- /dev/null
+++ b/audio/aidl/default/eraser/Eraser.h
@@ -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.
+ */
+
+#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;
+
+  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/vts/Android.bp b/audio/aidl/vts/Android.bp
index cbd42c0..9ebe518 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",
     ],
@@ -136,6 +137,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 f0622a8..e2501fe 100644
--- a/audio/aidl/vts/EffectHelper.h
+++ b/audio/aidl/vts/EffectHelper.h
@@ -470,6 +470,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/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/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioDeviceConfiguration.aidl
similarity index 83%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioDeviceConfiguration.aidl
index 173ac17..2685f58 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioDeviceConfiguration.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 */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.automotive.audiocontrol;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable AudioDeviceConfiguration {
+  android.hardware.automotive.audiocontrol.RoutingDeviceConfiguration routingConfig;
+  boolean useCoreAudioVolume;
+  boolean useHalDuckingSignals;
+  boolean useCarVolumeGroupMuting;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioFadeConfiguration.aidl
similarity index 62%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioFadeConfiguration.aidl
index 173ac17..0a3c677 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioFadeConfiguration.aidl
@@ -31,10 +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 */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.automotive.audiocontrol;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable AudioFadeConfiguration {
+  String name;
+  android.hardware.automotive.audiocontrol.FadeState fadeState;
+  long fadeInDurationMs = DEFAULT_FADE_IN_DURATION_MS /* 1000 */;
+  long fadeOutDurationMs = DEFAULT_FADE_OUT_DURATION_MS /* 2000 */;
+  long fadeInDelayedForOffendersMs = DEFAULT_DELAY_FADE_IN_OFFENDERS_MS /* 2000 */;
+  android.media.audio.common.AudioUsage[] fadeableUsages;
+  @nullable android.media.audio.common.AudioContentType[] unfadeableContentTypes;
+  List<android.media.audio.common.AudioAttributes> unfadableAudioAttributes;
+  List<android.hardware.automotive.audiocontrol.FadeConfiguration> fadeOutConfigurations;
+  List<android.hardware.automotive.audiocontrol.FadeConfiguration> fadeInConfigurations;
+  const long DEFAULT_FADE_IN_DURATION_MS = 1000;
+  const long DEFAULT_FADE_OUT_DURATION_MS = 2000;
+  const long DEFAULT_DELAY_FADE_IN_OFFENDERS_MS = 2000;
 }
diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioFocusChange.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioFocusChange.aidl
index 58a3667..8eab521 100644
--- a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioFocusChange.aidl
+++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioFocusChange.aidl
@@ -39,7 +39,7 @@
   GAIN_TRANSIENT = 2,
   GAIN_TRANSIENT_MAY_DUCK = 3,
   GAIN_TRANSIENT_EXCLUSIVE = 4,
-  LOSS = -1,
-  LOSS_TRANSIENT = -2,
-  LOSS_TRANSIENT_CAN_DUCK = -3,
+  LOSS = ((-1) * GAIN) /* -1 */,
+  LOSS_TRANSIENT = ((-1) * GAIN_TRANSIENT) /* -2 */,
+  LOSS_TRANSIENT_CAN_DUCK = ((-1) * GAIN_TRANSIENT_MAY_DUCK) /* -3 */,
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZone.aidl
similarity index 76%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZone.aidl
index 173ac17..2cb1760 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZone.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 */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.automotive.audiocontrol;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable AudioZone {
+  String name;
+  int id;
+  int occupantZoneId = UNASSIGNED_OCCUPANT /* -1 */;
+  android.hardware.automotive.audiocontrol.AudioZoneContext audioZoneContext;
+  List<android.hardware.automotive.audiocontrol.AudioZoneConfig> audioZoneConfigs;
+  List<android.media.audio.common.AudioPort> inputAudioDevices;
+  const int PRIMARY_AUDIO_ZONE = 0;
+  const int UNASSIGNED_OCCUPANT = (-1) /* -1 */;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneConfig.aidl
similarity index 82%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneConfig.aidl
index 173ac17..3fd37bc 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneConfig.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 */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.automotive.audiocontrol;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable AudioZoneConfig {
+  String name;
+  boolean isDefault;
+  List<android.hardware.automotive.audiocontrol.VolumeGroupConfig> volumeGroups;
+  @nullable android.hardware.automotive.audiocontrol.AudioZoneFadeConfiguration fadeConfiguration;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneContext.aidl
similarity index 87%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneContext.aidl
index 173ac17..0f8b946 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneContext.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 */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.automotive.audiocontrol;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable AudioZoneContext {
+  List<android.hardware.automotive.audiocontrol.AudioZoneContextInfo> audioContextInfos;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneContextInfo.aidl
similarity index 83%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneContextInfo.aidl
index 173ac17..01ab1be 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneContextInfo.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 */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.automotive.audiocontrol;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable AudioZoneContextInfo {
+  String name;
+  int id = UNASSIGNED_CONTEXT_ID /* -1 */;
+  List<android.media.audio.common.AudioAttributes> audioAttributes;
+  const int UNASSIGNED_CONTEXT_ID = (-1) /* -1 */;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneFadeConfiguration.aidl
similarity index 82%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneFadeConfiguration.aidl
index 173ac17..f3f32bf 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneFadeConfiguration.aidl
@@ -31,10 +31,9 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.automotive.audiocontrol;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable AudioZoneFadeConfiguration {
+  android.hardware.automotive.audiocontrol.AudioFadeConfiguration defaultConfiguration;
+  List<android.hardware.automotive.audiocontrol.TransientFadeConfigurationEntry> transientConfiguration;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/DeviceToContextEntry.aidl
similarity index 87%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/DeviceToContextEntry.aidl
index 173ac17..923b0bd 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/DeviceToContextEntry.aidl
@@ -31,10 +31,9 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.automotive.audiocontrol;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable DeviceToContextEntry {
+  List<String> contextNames;
+  android.media.audio.common.AudioPort device;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/FadeConfiguration.aidl
similarity index 77%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/FadeConfiguration.aidl
index 173ac17..2c978e7 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/FadeConfiguration.aidl
@@ -31,10 +31,14 @@
 // 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
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.automotive.audiocontrol;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable FadeConfiguration {
+  long fadeDurationMillis;
+  android.hardware.automotive.audiocontrol.FadeConfiguration.AudioAttributesOrUsage audioAttributesOrUsage;
+  @JavaDerive(equals=true, toString=true) @VintfStability
+  union AudioAttributesOrUsage {
+    android.media.audio.common.AudioAttributes fadeAttribute;
+    android.media.audio.common.AudioUsage usage;
+  }
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/FadeState.aidl
similarity index 87%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/FadeState.aidl
index 173ac17..9b25dfb 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/FadeState.aidl
@@ -31,10 +31,9 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.automotive.audiocontrol;
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
+enum FadeState {
+  FADE_STATE_DISABLED,
+  FADE_STATE_ENABLED_DEFAULT,
 }
diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/IAudioControl.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/IAudioControl.aidl
index ffd575d..fe39f92 100644
--- a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/IAudioControl.aidl
+++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/IAudioControl.aidl
@@ -12,6 +12,34 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ *//**
+ * Important note on Metadata:
+ * Metadata qualifies a playback track for an output stream.
+ * This is highly closed to {@link android.media.AudioAttributes}.
+ * It allows to identify the audio stream rendered / requesting / abandonning the focus.
+ *
+ * AudioControl 1.0 was limited to identification through {@code AttributeUsage} listed as
+ * {@code audioUsage} in audio_policy_configuration.xsd.
+ *
+ * Any new OEM needs would not be possible without extension.
+ *
+ * Relying on {@link android.hardware.automotive.audiocontrol.PlaybackTrackMetadata} allows
+ * to use a combination of {@code AttributeUsage}, {@code AttributeContentType} and
+ * {@code AttributeTags} to identify the use case / routing thanks to
+ * {@link android.media.audiopolicy.AudioProductStrategy}.
+ * The belonging to a strategy is deduced by an AOSP logic (in sync at native and java layer).
+ *
+ * IMPORTANT NOTE ON TAGS:
+ * To limit the possibilies and prevent from confusion, we expect the String to follow
+ * a given formalism that will be enforced.
+ *
+ * 1 / By convention, tags shall be a "key=value" pair.
+ * Vendor must namespace their tag's key (for example com.google.strategy=VR) to avoid conflicts.
+ * vendor specific applications and must be prefixed by "VX_". Vendor must
+ *
+ * 2 / Tags reported here shall be the same as the tags used to define a given
+ * {@link android.media.audiopolicy.AudioProductStrategy} and so in
+ * audio_policy_engine_configuration.xml file.
  */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
@@ -48,4 +76,7 @@
   oneway void registerGainCallback(in android.hardware.automotive.audiocontrol.IAudioGainCallback callback);
   void setModuleChangeCallback(in android.hardware.automotive.audiocontrol.IModuleChangeCallback callback);
   void clearModuleChangeCallback();
+  android.hardware.automotive.audiocontrol.AudioDeviceConfiguration getAudioDeviceConfiguration();
+  List<android.media.audio.common.AudioPort> getOutputMirroringDevices();
+  List<android.hardware.automotive.audiocontrol.AudioZone> getCarAudioZones();
 }
diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/Reasons.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/Reasons.aidl
index c1e22d4..8d66985 100644
--- a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/Reasons.aidl
+++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/Reasons.aidl
@@ -34,14 +34,14 @@
 package android.hardware.automotive.audiocontrol;
 @Backing(type="int") @VintfStability
 enum Reasons {
-  FORCED_MASTER_MUTE = 1,
-  REMOTE_MUTE = 2,
-  TCU_MUTE = 4,
-  ADAS_DUCKING = 8,
-  NAV_DUCKING = 16,
-  PROJECTION_DUCKING = 32,
-  THERMAL_LIMITATION = 64,
-  SUSPEND_EXIT_VOL_LIMITATION = 128,
-  EXTERNAL_AMP_VOL_FEEDBACK = 256,
-  OTHER = -2147483648,
+  FORCED_MASTER_MUTE = 0x1,
+  REMOTE_MUTE = 0x2,
+  TCU_MUTE = 0x4,
+  ADAS_DUCKING = 0x8,
+  NAV_DUCKING = 0x10,
+  PROJECTION_DUCKING = 0x20,
+  THERMAL_LIMITATION = 0x40,
+  SUSPEND_EXIT_VOL_LIMITATION = 0x80,
+  EXTERNAL_AMP_VOL_FEEDBACK = 0x100,
+  OTHER = 0x80000000,
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/RoutingDeviceConfiguration.aidl
similarity index 87%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/RoutingDeviceConfiguration.aidl
index 173ac17..901078c 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/RoutingDeviceConfiguration.aidl
@@ -31,10 +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.biometrics.fingerprint;
-/* @hide */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.automotive.audiocontrol;
+@JavaDerive(equals=true, toString=true) @VintfStability
+enum RoutingDeviceConfiguration {
+  DEFAULT_AUDIO_ROUTING,
+  DYNAMIC_AUDIO_ROUTING,
+  CONFIGURABLE_AUDIO_ENGINE_ROUTING,
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/TransientFadeConfigurationEntry.aidl
similarity index 84%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/TransientFadeConfigurationEntry.aidl
index 173ac17..72b247b 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/TransientFadeConfigurationEntry.aidl
@@ -31,10 +31,9 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.automotive.audiocontrol;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable TransientFadeConfigurationEntry {
+  android.media.audio.common.AudioUsage[] transientUsages;
+  android.hardware.automotive.audiocontrol.AudioFadeConfiguration transientFadeConfiguration;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeActivationConfiguration.aidl
similarity index 84%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeActivationConfiguration.aidl
index 173ac17..50b76a1 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeActivationConfiguration.aidl
@@ -31,10 +31,9 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.automotive.audiocontrol;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable VolumeActivationConfiguration {
+  @nullable String name;
+  List<android.hardware.automotive.audiocontrol.VolumeActivationConfigurationEntry> volumeActivationEntries;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeActivationConfigurationEntry.aidl
similarity index 74%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeActivationConfigurationEntry.aidl
index 173ac17..d457e57 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeActivationConfigurationEntry.aidl
@@ -31,10 +31,12 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.automotive.audiocontrol;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable VolumeActivationConfigurationEntry {
+  android.hardware.automotive.audiocontrol.VolumeInvocationType type = android.hardware.automotive.audiocontrol.VolumeInvocationType.ON_PLAYBACK_CHANGED;
+  int maxActivationVolumePercentage = DEFAULT_MAX_ACTIVATION_VALUE /* 100 */;
+  int minActivationVolumePercentage = DEFAULT_MIN_ACTIVATION_VALUE /* 0 */;
+  const int DEFAULT_MAX_ACTIVATION_VALUE = 100;
+  const int DEFAULT_MIN_ACTIVATION_VALUE = 0;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeGroupConfig.aidl
similarity index 79%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeGroupConfig.aidl
index 173ac17..cc90bbe 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeGroupConfig.aidl
@@ -31,10 +31,12 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.automotive.audiocontrol;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable VolumeGroupConfig {
+  String name;
+  int id = UNASSIGNED_ID /* -1 */;
+  List<android.hardware.automotive.audiocontrol.DeviceToContextEntry> carAudioRoutes;
+  @nullable android.hardware.automotive.audiocontrol.VolumeActivationConfiguration activationConfiguration;
+  const int UNASSIGNED_ID = (-1) /* -1 */;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeInvocationType.aidl
similarity index 87%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeInvocationType.aidl
index 173ac17..8ce8491 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeInvocationType.aidl
@@ -31,10 +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.biometrics.fingerprint;
-/* @hide */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.automotive.audiocontrol;
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
+enum VolumeInvocationType {
+  ON_PLAYBACK_CHANGED,
+  ON_SOURCE_CHANGED,
+  ON_BOOT,
 }
diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioDeviceConfiguration.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioDeviceConfiguration.aidl
new file mode 100644
index 0000000..9b5e724
--- /dev/null
+++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioDeviceConfiguration.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.automotive.audiocontrol;
+
+import android.hardware.automotive.audiocontrol.RoutingDeviceConfiguration;
+
+/**
+ * Use to configure audio configurations at boot up time.
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable AudioDeviceConfiguration {
+    /**
+     * Use to configure audio device routing mechanism
+     */
+    RoutingDeviceConfiguration routingConfig;
+
+    /**
+     * Use to configure core audio volume usage in car audio service
+     */
+    boolean useCoreAudioVolume;
+
+    /**
+     * Use to determine if HAL ducking signal should be sent to audio control HAL from car audio
+     * service
+     */
+    boolean useHalDuckingSignals;
+
+    /**
+     * Use to determine if HAL volume signal should be sent to audio control HAL from car audio
+     * service
+     */
+    boolean useCarVolumeGroupMuting;
+}
diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioFadeConfiguration.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioFadeConfiguration.aidl
new file mode 100644
index 0000000..d3181da
--- /dev/null
+++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioFadeConfiguration.aidl
@@ -0,0 +1,118 @@
+/*
+ * 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.automotive.audiocontrol;
+
+import android.hardware.automotive.audiocontrol.FadeConfiguration;
+import android.hardware.automotive.audiocontrol.FadeState;
+import android.media.audio.common.AudioAttributes;
+import android.media.audio.common.AudioContentType;
+import android.media.audio.common.AudioUsage;
+
+/**
+ * Encapsulates the audio fade configuration info
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable AudioFadeConfiguration {
+    /**
+     * Default fade in duration
+     */
+    const long DEFAULT_FADE_IN_DURATION_MS = 1000;
+
+    /**
+     * Default fade out duration
+     */
+    const long DEFAULT_FADE_OUT_DURATION_MS = 2000;
+
+    /**
+     * Default delay for fade in offenders
+     */
+    const long DEFAULT_DELAY_FADE_IN_OFFENDERS_MS = 2000;
+
+    /**
+     * Audio configuration name, use for debugging purposes
+     */
+    String name;
+
+    /**
+     * Audio configuration state
+     */
+    FadeState fadeState;
+
+    /**
+     * Fade in duration in milliseconds
+     *
+     * <p>Use to construct the default fade in configuration. This can be overwritten for different
+     * attributes/usages by passing a list of fade-in configuration,
+     * see {@code #fadeInConfigurations}
+     */
+    long fadeInDurationMs = DEFAULT_FADE_IN_DURATION_MS;
+
+    /**
+     * Fade out duration in milliseconds
+     *
+     * <p>Use to construct the default fade out configuration. This can be overwritten for different
+     * attributes/usages by passing a list of fade-out configuration,
+     * see {@code #fadeOutConfigurations}
+     */
+    long fadeOutDurationMs = DEFAULT_FADE_OUT_DURATION_MS;
+
+    /**
+     * Fade in delayed duration for audio focus offender in milliseconds
+     */
+    long fadeInDelayedForOffendersMs = DEFAULT_DELAY_FADE_IN_OFFENDERS_MS;
+
+    /**
+     * List of audio attribute usage that should be faded using the parameters in
+     * this configuration.
+     *
+     *<p>If the list is empty car audio service will overwrite the list for the confgiruation with
+     * default usages, e.g. {AudioUsage#MEDIA, AudioUsage#GAME}
+     */
+    AudioUsage[] fadeableUsages;
+
+    /**
+     * Optional list of audio attribute content types that should not be faded.
+     *
+     **<p>The list can be empty in cases where there are no unfadeable content types.
+     *
+     *<p>If the list is not set car audio service will overwrite the list for the confgiruation
+     * with default content type, e.g. {AudioContentType#SPEECH}.
+     */
+    @nullable AudioContentType[] unfadeableContentTypes;
+
+    /**
+     * List of audio attribute that should not be faded.
+     *
+     *<p>The list can be empty in cases where there are no unfadeable attributes
+     */
+    List<AudioAttributes> unfadableAudioAttributes;
+
+    /**
+     * List of fade out configutions which should apply to this audio fade configurations
+     *
+     *<p>The list can be empty in cases where there are no fade out configurations.
+     */
+    List<FadeConfiguration> fadeOutConfigurations;
+
+    /**
+     * List of fade in configutions which should apply to this audio fade configurations
+     *
+     *<p>The list can be empty in cases where there are no fade out configurations
+     */
+    List<FadeConfiguration> fadeInConfigurations;
+}
diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZone.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZone.aidl
new file mode 100644
index 0000000..c90bcfd
--- /dev/null
+++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZone.aidl
@@ -0,0 +1,74 @@
+/*
+ * 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.automotive.audiocontrol;
+
+import android.hardware.automotive.audiocontrol.AudioZoneConfig;
+import android.hardware.automotive.audiocontrol.AudioZoneContext;
+import android.media.audio.common.AudioPort;
+
+/**
+ * Encapsulates the audio configurations for each audio zone
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable AudioZone {
+    /**
+     * Value indicating the primary audio zone
+     */
+    const int PRIMARY_AUDIO_ZONE = 0;
+
+    /**
+     * Value indicating the occupant zone is not assigned.
+     */
+    const int UNASSIGNED_OCCUPANT = -1;
+
+    /**
+     * Audio zone name, only use for debug purposes.
+     *
+     * <p>If present it must be non-empty otherwise car audio service will construct a name
+     * based on audio zone id.
+     */
+    String name;
+
+    /**
+     * Audio zone id use to distiguish between the different audio zones for
+     * volume management, fade, and min/max activation management.
+     */
+    int id;
+
+    /**
+     * Occupant zone id that should be mapped to this audio zone.
+     *
+     * <p>For audio zones not mapped to an occupant zone use UNASSIGNED_OCCUPANT
+     */
+    int occupantZoneId = UNASSIGNED_OCCUPANT;
+
+    /**
+     * Car audio context which can be used in the audio zone
+     */
+    AudioZoneContext audioZoneContext;
+
+    /**
+     * List of car audio configurations
+     */
+    List<AudioZoneConfig> audioZoneConfigs;
+
+    /**
+     * List of input audio devices used for this zone
+     */
+    List<AudioPort> inputAudioDevices;
+}
diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneConfig.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneConfig.aidl
new file mode 100644
index 0000000..6822da5
--- /dev/null
+++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneConfig.aidl
@@ -0,0 +1,51 @@
+/*
+ * 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.automotive.audiocontrol;
+
+import android.hardware.automotive.audiocontrol.AudioZoneFadeConfiguration;
+import android.hardware.automotive.audiocontrol.VolumeGroupConfig;
+
+/**
+ * Encapsulates the audio zone config information
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable AudioZoneConfig {
+    /**
+     * Audio zone config name
+     *
+     * <p>Must be non-empty and unique among the configurations within a zone.
+     */
+    String name;
+
+    /**
+     * Determines if the audio configuration is the default configuration.
+     *
+     * <p>There can only be a single default configuration per zone.
+     */
+    boolean isDefault;
+
+    /**
+     * List car volume group that should be managed within this configuration
+     */
+    List<VolumeGroupConfig> volumeGroups;
+
+    /**
+     * Car audio zone fade configuration
+     */
+    @nullable AudioZoneFadeConfiguration fadeConfiguration;
+}
diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneContext.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneContext.aidl
new file mode 100644
index 0000000..390cb09
--- /dev/null
+++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneContext.aidl
@@ -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.
+ */
+
+package android.hardware.automotive.audiocontrol;
+
+import android.hardware.automotive.audiocontrol.AudioZoneContextInfo;
+
+/**
+ * Encapsulates the list of car audio context info definitions
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable AudioZoneContext {
+    /**
+     * List of car audio context info.
+     *
+     * <p>The list must include all audio attributes usages currently supported so that all audio
+     * attribute usages can be routed for each car audio configuration.
+     */
+    List<AudioZoneContextInfo> audioContextInfos;
+}
diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneContextInfo.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneContextInfo.aidl
new file mode 100644
index 0000000..0ca425c
--- /dev/null
+++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneContextInfo.aidl
@@ -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.
+ */
+
+package android.hardware.automotive.audiocontrol;
+
+import android.media.audio.common.AudioAttributes;
+
+/**
+ * Encapsulates groups of audio attributes which should be managed together.
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable AudioZoneContextInfo {
+    /**
+     * Value indicating the context info id is not assigned.
+     */
+    const int UNASSIGNED_CONTEXT_ID = -1;
+
+    /**
+     * Context name which can be used to map the info to an audio route
+     * management as described in each audio configuration.
+     *
+     * <P>Name must be non-empty and unique among all audio context info within the same
+     * {@link android.hardware.automotive.audiocontrol.AudioZoneContext} container.
+     */
+    String name;
+
+    /**
+     * Used in car audio service to manage the info
+     *
+     * <P>Must be non-negative integer if assigned, or UNASSIGNED_CONTEXT_ID otherwise. If using
+     * configurable audio policy engine audio routing with multi-zone configurations the value must
+     * be assigned.
+     */
+    int id = UNASSIGNED_CONTEXT_ID;
+
+    /**
+     * List of audio attributes that belong to the context
+     */
+    List<AudioAttributes> audioAttributes;
+}
diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneFadeConfiguration.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneFadeConfiguration.aidl
new file mode 100644
index 0000000..a604214
--- /dev/null
+++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneFadeConfiguration.aidl
@@ -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 android.hardware.automotive.audiocontrol;
+
+import android.hardware.automotive.audiocontrol.AudioFadeConfiguration;
+import android.hardware.automotive.audiocontrol.TransientFadeConfigurationEntry;
+
+/**
+ * Encapsulates the audio zone fade configuration
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable AudioZoneFadeConfiguration {
+    /**
+     * Defines the default fade configuration
+     */
+    AudioFadeConfiguration defaultConfiguration;
+
+    /**
+     * List of transient fade configurations.
+     *
+     * <p>The list can be empty if the fade configuration for the zone does not have transient fade
+     * configurations.
+     */
+    List<TransientFadeConfigurationEntry> transientConfiguration;
+}
diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/DeviceToContextEntry.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/DeviceToContextEntry.aidl
new file mode 100644
index 0000000..bcb5ee7
--- /dev/null
+++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/DeviceToContextEntry.aidl
@@ -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.
+ */
+
+package android.hardware.automotive.audiocontrol;
+
+import android.media.audio.common.AudioPort;
+
+/**
+ * Encapsulates the audio context that should be route to particular device
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable DeviceToContextEntry {
+    /**
+     * List of audio context names that should be routed to the audio device.
+     *
+     * <p>The names must match a {@link AudioZoneContextInfo#name} in the corresponding
+     * {@link AudioZone#audioZoneContext).
+     *
+     * <p>Within a {@link AudioZoneConfig} a context name must not repeat among the different
+     * {@link VolumeGroupConfig}. The value can repeat among different {@link AudioZoneConfig}
+     * within a {@link AudioZone}.
+     */
+    List<String> contextNames;
+
+    /**
+     * Audio port where contexts should be routed.
+     *
+     * <p>For dynamic devices (OUT_HEADSET, OUT_HEADPHONE, etc.) , the audio device address can be
+     * omitted since the information will be obtained at run time when the device is
+     * connected/enabled.
+     */
+    AudioPort device;
+}
diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/FadeConfiguration.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/FadeConfiguration.aidl
new file mode 100644
index 0000000..e700d6c
--- /dev/null
+++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/FadeConfiguration.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.automotive.audiocontrol;
+
+import android.media.audio.common.AudioAttributes;
+import android.media.audio.common.AudioUsage;
+
+/**
+ * Encapsulates the in/out fade configuration
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable FadeConfiguration {
+    /**
+     * Fade duration in milliseconds
+     */
+    long fadeDurationMillis;
+
+    @JavaDerive(equals=true, toString=true)
+    @VintfStability
+    union AudioAttributesOrUsage {
+        AudioAttributes fadeAttribute;
+        AudioUsage usage;
+    }
+
+    /**
+     * Audio attribute or usage that should be impacted by the fade out duration
+     * {@code #fadeDurationMillis}
+     */
+    AudioAttributesOrUsage audioAttributesOrUsage;
+}
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/FadeState.aidl
similarity index 67%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
copy to automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/FadeState.aidl
index c7be950..346caae 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/FadeState.aidl
@@ -14,22 +14,21 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
-
-import android.hardware.biometrics.fingerprint.AcquiredInfo;
+package android.hardware.automotive.audiocontrol;
 
 /**
- * @hide
+ * Encapsulates the audio fade configuration state
  */
 @VintfStability
-union AcquiredInfoAndVendorCode {
+@Backing(type="int")
+@JavaDerive(toString=true)
+enum FadeState {
     /**
-     * Acquired info as specified in AcqauiredInfo.aidl
+     * Fade configuration should be disabled
      */
-    AcquiredInfo acquiredInfo = AcquiredInfo.UNKNOWN;
-
+    FADE_STATE_DISABLED,
     /**
-     * Vendor specific code
+     * Fade configuration should be enabled by default
      */
-    int vendorCode;
+    FADE_STATE_ENABLED_DEFAULT,
 }
diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/IAudioControl.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/IAudioControl.aidl
index 9564efc..1202b4c 100644
--- a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/IAudioControl.aidl
+++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/IAudioControl.aidl
@@ -46,14 +46,17 @@
  * audio_policy_engine_configuration.xml file.
  */
 import android.hardware.audio.common.PlaybackTrackMetadata;
+import android.hardware.automotive.audiocontrol.AudioDeviceConfiguration;
 import android.hardware.automotive.audiocontrol.AudioFocusChange;
 import android.hardware.automotive.audiocontrol.AudioGainConfigInfo;
+import android.hardware.automotive.audiocontrol.AudioZone;
 import android.hardware.automotive.audiocontrol.DuckingInfo;
 import android.hardware.automotive.audiocontrol.IAudioGainCallback;
 import android.hardware.automotive.audiocontrol.IFocusListener;
 import android.hardware.automotive.audiocontrol.IModuleChangeCallback;
 import android.hardware.automotive.audiocontrol.MutingInfo;
 import android.hardware.automotive.audiocontrol.Reasons;
+import android.media.audio.common.AudioPort;
 
 /**
  * Interacts with the car's audio subsystem to manage audio sources and volumes
@@ -206,4 +209,41 @@
      * @throws EX_UNSUPPORTED_OPERATION if dynamic audio configs are not supported.
      */
     void clearModuleChangeCallback();
+
+    /**
+     * Returns the audio device configurations that should be used to configure
+     * the car audio service audio management.
+     *
+     * <p>If this method is not supported, car audio service will attempt to configure the car audio
+     * service properties based on previously supported mechanisms.
+     *
+     * <p>If the returned value contains the
+     * {@link RoutingDeviceConfiguration#DEFAULT_AUDIO_ROUTING} value, the car audio service will
+     * attempt to configure audio routing based on the mechanism previously supported by car audio
+     * service (e.g. car audio configuration file). Otherwise, the {@link #getCarAudioZones()}
+     * API must return valid audio zone(s) configuration(s) for the device.
+     *
+     */
+    AudioDeviceConfiguration getAudioDeviceConfiguration();
+
+    /**
+     * Returns the list of audio devices that can be used for mirroring between different audio
+     * zones.
+     *
+     * @throws EX_UNSUPPORTED_OPERATION if mirroring devices are not supported.
+     */
+    List<AudioPort> getOutputMirroringDevices();
+
+    /**
+     * List of audio zones used to configure car audio service at bootup.
+     *
+     * <p>If the returned value from {@link #getAudioDeviceConfiguration()} contains
+     * {@link RoutingDeviceConfiguration#DEFAULT_AUDIO_ROUTING} value, the car audio service will
+     * attempt to configure the audio routing based on the mechanism previously supported by
+     * car audio service (e.g. car audio configuration file). Otherwise, this method must return
+     * valid audio zone(s) configuration(s) for the device.
+     *
+     * @throws EX_UNSUPPORTED_OPERATION if audio zone configuration are not supported.
+     */
+    List<AudioZone> getCarAudioZones();
 }
diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/RoutingDeviceConfiguration.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/RoutingDeviceConfiguration.aidl
new file mode 100644
index 0000000..2d17540
--- /dev/null
+++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/RoutingDeviceConfiguration.aidl
@@ -0,0 +1,52 @@
+/*
+ * 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.automotive.audiocontrol;
+
+/**
+ * Use to configure audio device routing mechanism
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+enum RoutingDeviceConfiguration {
+    /**
+     * Use to indicate that audio should be managed based on previously supportec mechamisms in
+     * car audio service.
+     *
+     * <p>If this used then the API to setup the audio zones can just throw
+     * {@code EX_UNSUPPORTED_OPERATION} if called.
+     */
+    DEFAULT_AUDIO_ROUTING,
+    /**
+     * Use to indicate that audio should be managed using the dynamic audio
+     * policy as setup by car audio service using the setup configuration from
+     * the {@Link android.hardware.automotive.audiocontrol.AudioZone}'s info from audio control HAL.
+     *
+     * <p>If this used then the APIs to setup the audio zones must return a valid audio zone
+     * configuration for the device.
+     */
+    DYNAMIC_AUDIO_ROUTING,
+    /**
+     * Use to indicate that audio should be managed using the core audio
+     * routing as setup by car audio service using the setup configuration from
+     * the {@Link android.hardware.automotive.audiocontrol.AudioZone}'s info from audio control HAL
+     * and the information contained within the configurable audio policy engine.
+     *
+     * <p>If this used then the APIs to setup the audio zone(s) must return valid audio zone
+     * configuration(s) for the device.
+     */
+    CONFIGURABLE_AUDIO_ENGINE_ROUTING,
+}
diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/TransientFadeConfigurationEntry.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/TransientFadeConfigurationEntry.aidl
new file mode 100644
index 0000000..1984236
--- /dev/null
+++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/TransientFadeConfigurationEntry.aidl
@@ -0,0 +1,38 @@
+/*
+ * 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.automotive.audiocontrol;
+
+import android.hardware.automotive.audiocontrol.AudioFadeConfiguration;
+import android.media.audio.common.AudioUsage;
+
+/**
+ * Encapsulates the transient audio fade configuration entry.
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable TransientFadeConfigurationEntry {
+    /**
+     * List of audio usages gainers that should be used for this configuration entry.
+     */
+    AudioUsage[] transientUsages;
+
+    /**
+     * Defines the transient fade configuration that should be used for the focus interaction with
+     * the usages defined in {@link #transientUsages}
+     */
+    AudioFadeConfiguration transientFadeConfiguration;
+}
diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeActivationConfiguration.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeActivationConfiguration.aidl
new file mode 100644
index 0000000..edc5f60
--- /dev/null
+++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeActivationConfiguration.aidl
@@ -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.
+ */
+
+package android.hardware.automotive.audiocontrol;
+
+import android.hardware.automotive.audiocontrol.VolumeActivationConfigurationEntry;
+
+/**
+ * Use to configure audio activiations, only used at boot up time.
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable VolumeActivationConfiguration {
+    /**
+     * Configuration name used for debugging purposes to identify config used.
+     *
+     * <p>Is present, it must be non-empty and unique for all volume acvitations, otherwise
+     * car audio service will construct one based on audio zone, configuration and volume group
+     * info.
+     */
+    @nullable String name;
+
+    /**
+     * List of activation configurations.
+     *
+     * <P>Car audio service currently only  uses the first activation config on the list.
+     */
+    List<VolumeActivationConfigurationEntry> volumeActivationEntries;
+}
diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeActivationConfigurationEntry.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeActivationConfigurationEntry.aidl
new file mode 100644
index 0000000..7072a2c
--- /dev/null
+++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeActivationConfigurationEntry.aidl
@@ -0,0 +1,63 @@
+/*
+ * 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.automotive.audiocontrol;
+
+import android.hardware.automotive.audiocontrol.VolumeInvocationType;
+
+/**
+ * Audio activiation volume configuration entry.
+ *
+ * <p> The entry can defined both the minimum and maximum activation values or only one. The latter
+ * allows activations to occur only on the minimum value or maximum value as configured.
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable VolumeActivationConfigurationEntry {
+    /**
+     * Default maximum activation value.
+     */
+    const int DEFAULT_MAX_ACTIVATION_VALUE = 100;
+
+    /**
+     * Default minimum activation value.
+     */
+    const int DEFAULT_MIN_ACTIVATION_VALUE = 0;
+
+    /**
+     * Activation type, should be one of:
+     *  ON_PLAYBACK_CHANGED, ON_SOURCE_CHANGED, ON_BOOT
+     */
+    VolumeInvocationType type = VolumeInvocationType.ON_PLAYBACK_CHANGED;
+
+    /**
+     * Max activation percentage between {@code DEFAULT_MIN_ACTIVATION_VALUE} to
+     * {@code DEFAULT_MAX_ACTIVATION_VALUE} percen.
+     *
+     * <p>The value should be {@code DEFAULT_MAX_ACTIVATION_VALUE} if max activation should not
+     * apply.
+     */
+    int maxActivationVolumePercentage = DEFAULT_MAX_ACTIVATION_VALUE;
+
+    /**
+     * Min activation percentage between {@code DEFAULT_MIN_ACTIVATION_VALUE} to
+     * {@code DEFAULT_MAX_ACTIVATION_VALUE} percent.
+     *
+     * <p>The value should be {@code DEFAULT_MIN_ACTIVATION_VALUE} if min activation should not
+     * apply.
+     */
+    int minActivationVolumePercentage = DEFAULT_MIN_ACTIVATION_VALUE;
+}
diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeGroupConfig.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeGroupConfig.aidl
new file mode 100644
index 0000000..7e3bc60
--- /dev/null
+++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeGroupConfig.aidl
@@ -0,0 +1,59 @@
+/*
+ * 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.automotive.audiocontrol;
+
+import android.hardware.automotive.audiocontrol.DeviceToContextEntry;
+import android.hardware.automotive.audiocontrol.VolumeActivationConfiguration;
+
+/**
+ * Encapsulates the audio volume grouping for audio zone config.
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable VolumeGroupConfig {
+    /**
+     * Value indicating the volume group is not assigned an ID.
+     */
+    const int UNASSIGNED_ID = -1;
+
+    /**
+     * Audio zone group name.
+     *
+     * <p>Must be non-empty if using configurable audio policy engine volume management, see
+     * {@code AudioDeviceConfiguration#useCoreAudioVolume} for details.
+     */
+    String name;
+
+    /**
+     * Audio zone group id.
+     *
+     * <p>Must be set if using configurable audio policy engine volume management, can be
+     * {@code #UNASSIGNED_ID} otherwise. See {@code AudioDeviceConfiguration#useCoreAudioVolume}
+     * for details.
+     */
+    int id = UNASSIGNED_ID;
+
+    /**
+     * Entries of audio device to audio context that are managed similarly for this volume group.
+     */
+    List<DeviceToContextEntry> carAudioRoutes;
+
+    /**
+     * Optional volume activation configuration that should be used for this volume group.
+     */
+    @nullable VolumeActivationConfiguration activationConfiguration;
+}
diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeInvocationType.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeInvocationType.aidl
new file mode 100644
index 0000000..0323505
--- /dev/null
+++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeInvocationType.aidl
@@ -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 android.hardware.automotive.audiocontrol;
+
+/**
+ * Audio activiation type which can be used to activate the min/max
+ * volume changes.
+ */
+@VintfStability
+@Backing(type="int")
+@JavaDerive(toString=true)
+enum VolumeInvocationType {
+    /**
+     * Invocation of volume group activation performed at every playback change.
+     */
+    ON_PLAYBACK_CHANGED,
+    /**
+     * Invocation of volume group activation performed only once at playback after first playback
+     * for a client (app/service UID).
+     */
+    ON_SOURCE_CHANGED,
+    /**
+     * Invocation of volume group activation in perform only at playback once after boot up.
+     */
+    ON_BOOT,
+}
diff --git a/automotive/audiocontrol/aidl/default/Android.bp b/automotive/audiocontrol/aidl/default/Android.bp
index fd7e167..1c11c989 100644
--- a/automotive/audiocontrol/aidl/default/Android.bp
+++ b/automotive/audiocontrol/aidl/default/Android.bp
@@ -31,13 +31,19 @@
         "latest_android_hardware_audio_common_ndk_shared",
         "latest_android_hardware_automotive_audiocontrol_ndk_shared",
         "powerpolicyclient_defaults",
+        "car.audio.configuration.xsd.default",
+        "car.fade.configuration.xsd.default",
     ],
     shared_libs: [
         "android.hardware.audio.common@7.0-enums",
-        "libbase",
         "libbinder_ndk",
         "libcutils",
         "liblog",
+        "libbase",
+        "libxml2",
+        "libutils",
+        "android.hardware.audiocontrol.internal",
+        "libaudio_aidl_conversion_common_ndk",
     ],
     srcs: [
         "AudioControl.cpp",
diff --git a/automotive/audiocontrol/aidl/default/AudioControl.cpp b/automotive/audiocontrol/aidl/default/AudioControl.cpp
index 7e7e145..9ae422b 100644
--- a/automotive/audiocontrol/aidl/default/AudioControl.cpp
+++ b/automotive/audiocontrol/aidl/default/AudioControl.cpp
@@ -19,6 +19,7 @@
 
 #include "AudioControl.h"
 
+#include <aidl/android/hardware/automotive/audiocontrol/AudioDeviceConfiguration.h>
 #include <aidl/android/hardware/automotive/audiocontrol/AudioFocusChange.h>
 #include <aidl/android/hardware/automotive/audiocontrol/DuckingInfo.h>
 #include <aidl/android/hardware/automotive/audiocontrol/IFocusListener.h>
@@ -27,8 +28,8 @@
 #include <android-base/parsebool.h>
 #include <android-base/parseint.h>
 #include <android-base/strings.h>
-
 #include <android_audio_policy_configuration_V7_0-enums.h>
+
 #include <private/android_filesystem_config.h>
 
 #include <numeric>
@@ -41,16 +42,18 @@
 using ::android::base::ParseBool;
 using ::android::base::ParseBoolResult;
 using ::android::base::ParseInt;
+using ::android::hardware::audiocontrol::internal::CarAudioConfigurationXmlConverter;
 using ::std::shared_ptr;
 using ::std::string;
 
-namespace xsd {
-using namespace ::android::audio::policy::configuration::V7_0;
+namespace converter {
+using namespace ::android::hardware::audiocontrol::internal;
 }
 
+namespace api = aidl::android::hardware::automotive::audiocontrol;
+namespace xsd = ::android::audio::policy::configuration::V7_0;
+
 namespace {
-const float kLowerBound = -1.0f;
-const float kUpperBound = 1.0f;
 bool checkCallerHasWritePermissions(int fd) {
     // Double check that's only called by root - it should be be blocked at debug() level,
     // but it doesn't hurt to make sure...
@@ -62,7 +65,7 @@
 }
 
 bool isValidValue(float value) {
-    return (value >= kLowerBound) && (value <= kUpperBound);
+    return (value >= -1.0f) && (value <= 1.0f);
 }
 
 bool safelyParseInt(string s, int* out) {
@@ -71,6 +74,53 @@
     }
     return true;
 }
+
+std::string formatDump(const std::string& input) {
+    const char kSpacer = ' ';
+    std::string output;
+    int indentLevel = 0;
+    bool newLine = false;
+
+    for (char c : input) {
+        switch (c) {
+            case '{':
+                if (!newLine) {
+                    output += '\n';
+                }
+                newLine = true;
+                indentLevel++;
+                for (int i = 0; i < indentLevel; ++i) {
+                    output += kSpacer;
+                }
+                break;
+            case '}':
+                if (!newLine) {
+                    output += '\n';
+                }
+                newLine = true;
+                indentLevel--;
+                for (int i = 0; i < indentLevel; ++i) {
+                    output += kSpacer;
+                }
+                break;
+            case ',':
+                if (!newLine) {
+                    output += '\n';
+                }
+                newLine = true;
+                for (int i = 0; i < indentLevel; ++i) {
+                    output += kSpacer;
+                }
+                break;
+            default:
+                newLine = false;
+                output += c;
+        }
+    }
+
+    return output;
+}
+
 }  // namespace
 
 namespace {
@@ -90,6 +140,9 @@
 using ::aidl::android::media::audio::common::AudioProfile;
 using ::aidl::android::media::audio::common::PcmType;
 
+const static std::string kAudioConfigFile = "/vendor/etc/car_audio_configuration.xml";
+const static std::string kFadeConfigFile = "/vendor/etc/car_audio_fade_configuration.xml";
+
 // reuse common code artifacts
 void fillProfile(const std::vector<int32_t>& channelLayouts,
                  const std::vector<int32_t>& sampleRates, AudioProfile* profile) {
@@ -162,6 +215,12 @@
 }
 }  // namespace
 
+AudioControl::AudioControl() : AudioControl(kAudioConfigFile, kFadeConfigFile) {}
+
+AudioControl::AudioControl(const std::string& carAudioConfig, const std::string& audioFadeConfig)
+    : mCarAudioConfigurationConverter(std::make_shared<CarAudioConfigurationXmlConverter>(
+              carAudioConfig, audioFadeConfig)) {}
+
 ndk::ScopedAStatus AudioControl::registerFocusListener(
         const shared_ptr<IFocusListener>& in_listener) {
     LOG(DEBUG) << "registering focus listener";
@@ -245,14 +304,23 @@
 static inline std::string toString(const std::vector<aidl_type>& in_values) {
     return std::accumulate(std::begin(in_values), std::end(in_values), std::string{},
                            [](const std::string& ls, const aidl_type& rs) {
-                               return ls + (ls.empty() ? "" : ",") + rs.toString();
+                               return ls + (ls.empty() ? "" : ", ") + rs.toString();
                            });
 }
 template <typename aidl_enum_type>
 static inline std::string toEnumString(const std::vector<aidl_enum_type>& in_values) {
     return std::accumulate(std::begin(in_values), std::end(in_values), std::string{},
                            [](const std::string& ls, const aidl_enum_type& rs) {
-                               return ls + (ls.empty() ? "" : ",") + toString(rs);
+                               return ls + (ls.empty() ? "" : ", ") + toString(rs);
+                           });
+}
+
+template <typename aidl_type>
+static inline std::string toString(const std::vector<std::optional<aidl_type>>& in_values) {
+    return std::accumulate(std::begin(in_values), std::end(in_values), std::string{},
+                           [](const std::string& ls, const std::optional<aidl_type>& rs) {
+                               return ls + (ls.empty() ? "" : ", ") +
+                                      (rs.has_value() ? rs.value().toString() : "empty");
                            });
 }
 
@@ -309,6 +377,50 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus AudioControl::getAudioDeviceConfiguration(
+        AudioDeviceConfiguration* audioDeviceConfig) {
+    if (!audioDeviceConfig) {
+        LOG(ERROR) << __func__ << "Audio device configuration must not be null";
+        return ndk::ScopedAStatus::fromStatus(STATUS_UNEXPECTED_NULL);
+    }
+    if (!mCarAudioConfigurationConverter) {
+        return ndk::ScopedAStatus::ok();
+    }
+    const auto& innerDeviceConfig = mCarAudioConfigurationConverter->getAudioDeviceConfiguration();
+    audioDeviceConfig->routingConfig = innerDeviceConfig.routingConfig;
+    audioDeviceConfig->useCoreAudioVolume = innerDeviceConfig.useCoreAudioVolume;
+    audioDeviceConfig->useCarVolumeGroupMuting = innerDeviceConfig.useCarVolumeGroupMuting;
+    audioDeviceConfig->useHalDuckingSignals = innerDeviceConfig.useHalDuckingSignals;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AudioControl::getOutputMirroringDevices(
+        std::vector<AudioPort>* mirroringDevices) {
+    if (!mirroringDevices) {
+        LOG(ERROR) << __func__ << "Mirroring devices must not be null";
+        return ndk::ScopedAStatus::fromStatus(STATUS_UNEXPECTED_NULL);
+    }
+    if (!mCarAudioConfigurationConverter || !mCarAudioConfigurationConverter->getErrors().empty()) {
+        return ndk::ScopedAStatus::ok();
+    }
+    const auto& innerDevice = mCarAudioConfigurationConverter->getOutputMirroringDevices();
+    mirroringDevices->insert(mirroringDevices->end(), innerDevice.begin(), innerDevice.end());
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AudioControl::getCarAudioZones(std::vector<AudioZone>* audioZones) {
+    if (!audioZones) {
+        LOG(ERROR) << __func__ << "Audio zones must not be null";
+        return ndk::ScopedAStatus::fromStatus(STATUS_UNEXPECTED_NULL);
+    }
+    if (!mCarAudioConfigurationConverter || !mCarAudioConfigurationConverter->getErrors().empty()) {
+        return ndk::ScopedAStatus::ok();
+    }
+    const auto& innerZones = mCarAudioConfigurationConverter->getAudioZones();
+    audioZones->insert(audioZones->end(), innerZones.begin(), innerZones.end());
+    return ndk::ScopedAStatus::ok();
+}
+
 binder_status_t AudioControl::dump(int fd, const char** args, uint32_t numArgs) {
     if (numArgs == 0) {
         return dumpsys(fd);
@@ -342,6 +454,25 @@
         dprintf(fd, "Focus listener registered\n");
     }
     dprintf(fd, "AudioGainCallback %sregistered\n", (mAudioGainCallback == nullptr ? "NOT " : ""));
+
+    AudioDeviceConfiguration configuration;
+    if (getAudioDeviceConfiguration(&configuration).isOk()) {
+        dprintf(fd, "AudioDeviceConfiguration: %s\n", configuration.toString().c_str());
+    }
+    std::vector<AudioZone> audioZones;
+    if (getCarAudioZones(&audioZones).isOk()) {
+        dprintf(fd, "Audio zones count: %zu\n", audioZones.size());
+        for (const auto& zone : audioZones) {
+            dprintf(fd, "AudioZone: %s\n", formatDump(zone.toString()).c_str());
+        }
+    }
+    std::vector<AudioPort> mirroringDevices;
+    if (getOutputMirroringDevices(&mirroringDevices).isOk()) {
+        dprintf(fd, "Mirroring devices count: %zu\n", mirroringDevices.size());
+        for (const auto& device : mirroringDevices) {
+            dprintf(fd, "Mirroring device: %s\n", formatDump(device.toString()).c_str());
+        }
+    }
     return STATUS_OK;
 }
 
diff --git a/automotive/audiocontrol/aidl/default/AudioControl.h b/automotive/audiocontrol/aidl/default/AudioControl.h
index 7eca446..0425570 100644
--- a/automotive/audiocontrol/aidl/default/AudioControl.h
+++ b/automotive/audiocontrol/aidl/default/AudioControl.h
@@ -35,13 +35,17 @@
 #include <aidl/android/media/audio/common/AudioIoFlags.h>
 #include <aidl/android/media/audio/common/AudioOutputFlags.h>
 
+#include "converter/include/CarAudioConfigurationXmlConverter.h"
+
 namespace aidl::android::hardware::automotive::audiocontrol {
 
-namespace audiohalcommon = ::aidl::android::hardware::audio::common;
 namespace audiomediacommon = ::aidl::android::media::audio::common;
+namespace audiohalcommon = ::aidl::android::hardware::audio::common;
 
 class AudioControl : public BnAudioControl {
   public:
+    AudioControl();
+    AudioControl(const std::string& carAudioConfig, const std::string& audioFadeConfig);
     ndk::ScopedAStatus onAudioFocusChange(const std::string& in_usage, int32_t in_zoneId,
                                           AudioFocusChange in_focusChange) override;
     ndk::ScopedAStatus onDevicesToDuckChange(
@@ -63,6 +67,11 @@
     ndk::ScopedAStatus setModuleChangeCallback(
             const std::shared_ptr<IModuleChangeCallback>& in_callback) override;
     ndk::ScopedAStatus clearModuleChangeCallback() override;
+    ndk::ScopedAStatus getAudioDeviceConfiguration(
+            AudioDeviceConfiguration* audioDeviceConfig) override;
+    ndk::ScopedAStatus getOutputMirroringDevices(
+            std::vector<::aidl::android::media::audio::common::AudioPort>* mirrorDevices) override;
+    ndk::ScopedAStatus getCarAudioZones(std::vector<AudioZone>* audioZones) override;
 
     binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
 
@@ -81,6 +90,9 @@
 
     std::shared_ptr<IModuleChangeCallback> mModuleChangeCallback = nullptr;
 
+    std::shared_ptr<::android::hardware::audiocontrol::internal::CarAudioConfigurationXmlConverter>
+            mCarAudioConfigurationConverter = nullptr;
+
     binder_status_t cmdHelp(int fd) const;
     binder_status_t cmdRequestFocus(int fd, const char** args, uint32_t numArgs);
     binder_status_t cmdAbandonFocus(int fd, const char** args, uint32_t numArgs);
diff --git a/automotive/audiocontrol/aidl/default/audiocontrol-default.xml b/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
index bcb5669..ffef7fc 100644
--- a/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
+++ b/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
@@ -1,7 +1,7 @@
 <manifest version="2.0" type="device">
     <hal format="aidl">
         <name>android.hardware.automotive.audiocontrol</name>
-        <version>4</version>
+        <version>5</version>
         <fqname>IAudioControl/default</fqname>
     </hal>
 </manifest>
diff --git a/automotive/audiocontrol/aidl/default/converter/Android.bp b/automotive/audiocontrol/aidl/default/converter/Android.bp
new file mode 100644
index 0000000..c00afa2
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/converter/Android.bp
@@ -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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library {
+    name: "android.hardware.audiocontrol.internal",
+    vendor: true,
+    srcs: [
+        "src/CarAudioConfigurationXmlConverter.cpp",
+        "src/CarAudioConfigurationUtils.cpp",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+    defaults: [
+        "latest_android_hardware_audio_common_ndk_static",
+        "latest_android_hardware_automotive_audiocontrol_ndk_shared",
+        "car.audio.configuration.xsd.default",
+        "car.fade.configuration.xsd.default",
+        "aidlaudioservice_defaults",
+        "latest_android_media_audio_common_types_ndk_static",
+    ],
+    shared_libs: [
+        "libbase",
+        "libutils",
+        "libmedia_helper",
+        "car.audio.configuration.xsd.default",
+        "car.fade.configuration.xsd.default",
+        "liblog",
+    ],
+    static_libs: [
+        "libaudio_aidl_conversion_common_ndk_cpp",
+    ],
+    header_libs: [
+        "libaudio_system_headers",
+    ],
+}
diff --git a/automotive/audiocontrol/aidl/default/converter/include/CarAudioConfigurationUtils.h b/automotive/audiocontrol/aidl/default/converter/include/CarAudioConfigurationUtils.h
new file mode 100644
index 0000000..29fec0b
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/converter/include/CarAudioConfigurationUtils.h
@@ -0,0 +1,37 @@
+/*
+ * 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 ANDROID_HARDWARE_AUDIOCONTROL_INTERNAL_CONFIGURATION_UTILS_H
+#define ANDROID_HARDWARE_AUDIOCONTROL_INTERNAL_CONFIGURATION_UTILS_H
+
+#include <string>
+
+#include <aidl/android/hardware/automotive/audiocontrol/AudioZoneContext.h>
+#include <aidl/android/hardware/automotive/audiocontrol/AudioZoneContextInfo.h>
+
+namespace android {
+namespace hardware {
+namespace audiocontrol {
+namespace internal {
+
+::aidl::android::hardware::automotive::audiocontrol::AudioZoneContext getDefaultCarAudioContext();
+
+}  // namespace internal
+}  // namespace audiocontrol
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_AUDIOCONTROL_INTERNAL_CONFIGURATION_UTILS_H
diff --git a/automotive/audiocontrol/aidl/default/converter/include/CarAudioConfigurationXmlConverter.h b/automotive/audiocontrol/aidl/default/converter/include/CarAudioConfigurationXmlConverter.h
new file mode 100644
index 0000000..ed29172
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/converter/include/CarAudioConfigurationXmlConverter.h
@@ -0,0 +1,87 @@
+/*
+ * 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 MAIN8_CARAUDIOCONFIGURATIONXMLCONVERTER_H
+#define MAIN8_CARAUDIOCONFIGURATIONXMLCONVERTER_H
+
+#include <string>
+
+#include "../include/CarAudioConfigurationUtils.h"
+
+#include <aidl/android/hardware/automotive/audiocontrol/AudioDeviceConfiguration.h>
+#include <aidl/android/hardware/automotive/audiocontrol/AudioZone.h>
+#include <aidl/android/hardware/automotive/audiocontrol/AudioZoneContext.h>
+
+namespace android::hardware::automotive::audiocontrol {
+class CarAudioConfigurationType;
+}
+
+namespace android {
+namespace hardware {
+namespace audiocontrol {
+namespace internal {
+
+class CarAudioConfigurationXmlConverter {
+  public:
+    explicit CarAudioConfigurationXmlConverter(const std::string& audioConfigFile,
+                                               const std::string& fadeConfigFile)
+        : mAudioConfigFile(audioConfigFile), mFadeConfigFile(fadeConfigFile) {
+        init();
+    }
+
+    ::aidl::android::hardware::automotive::audiocontrol::AudioDeviceConfiguration
+    getAudioDeviceConfiguration() const;
+
+    std::vector<::aidl::android::hardware::automotive::audiocontrol::AudioZone> getAudioZones()
+            const;
+    std::vector<::aidl::android::media::audio::common::AudioPort> getOutputMirroringDevices() const;
+
+    const std::string getErrors() const { return mParseErrors; }
+
+  private:
+    void init();
+    void initNonDynamicRouting();
+    void initFadeConfigurations();
+    void initAudioDeviceConfiguration(
+            const ::android::hardware::automotive::audiocontrol::CarAudioConfigurationType&
+                    carAudioConfigurationType);
+    void initCarAudioConfigurations(
+            const ::android::hardware::automotive::audiocontrol::CarAudioConfigurationType&
+                    carAudioConfigurationType);
+    void parseAudioDeviceConfigurations(
+            const ::android::hardware::automotive::audiocontrol::CarAudioConfigurationType&
+                    carAudioConfigurationType);
+
+    const std::string mAudioConfigFile;
+    const std::string mFadeConfigFile;
+    ::aidl::android::hardware::automotive::audiocontrol::AudioDeviceConfiguration
+            mAudioDeviceConfiguration;
+    std::optional<::aidl::android::hardware::automotive::audiocontrol::AudioZoneContext>
+            mAudioZoneContext;
+    std::vector<::aidl::android::hardware::automotive::audiocontrol::AudioZone> mAudioZones;
+    std::vector<::aidl::android::media::audio::common::AudioPort> mOutputMirroringDevices;
+    std::string mParseErrors;
+    std::unordered_map<std::string,
+                       ::aidl::android::hardware::automotive::audiocontrol::AudioFadeConfiguration>
+            mFadeConfigurations;
+};
+
+}  // namespace internal
+}  // namespace audiocontrol
+}  // namespace hardware
+}  // namespace android
+
+#endif  // MAIN8_CARAUDIOCONFIGURATIONXMLCONVERTER_H
diff --git a/automotive/audiocontrol/aidl/default/converter/src/CarAudioConfigurationUtils.cpp b/automotive/audiocontrol/aidl/default/converter/src/CarAudioConfigurationUtils.cpp
new file mode 100644
index 0000000..e2f8191
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/converter/src/CarAudioConfigurationUtils.cpp
@@ -0,0 +1,104 @@
+/*
+ * 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-base/logging.h>
+
+#include "../include/CarAudioConfigurationUtils.h"
+
+#include <aidl/android/media/audio/common/AudioAttributes.h>
+#include <aidl/android/media/audio/common/AudioUsage.h>
+
+#include <tuple>
+#include <vector>
+
+using ::aidl::android::hardware::automotive::audiocontrol::AudioZoneContext;
+using ::aidl::android::hardware::automotive::audiocontrol::AudioZoneContextInfo;
+
+using aidl::android::media::audio::common::AudioAttributes;
+using aidl::android::media::audio::common::AudioUsage;
+using aidl::android::media::audio::common::AudioUsage::ALARM;
+using aidl::android::media::audio::common::AudioUsage::ANNOUNCEMENT;
+using aidl::android::media::audio::common::AudioUsage::ASSISTANCE_ACCESSIBILITY;
+using aidl::android::media::audio::common::AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE;
+using aidl::android::media::audio::common::AudioUsage::ASSISTANCE_SONIFICATION;
+using aidl::android::media::audio::common::AudioUsage::ASSISTANT;
+using aidl::android::media::audio::common::AudioUsage::CALL_ASSISTANT;
+using aidl::android::media::audio::common::AudioUsage::EMERGENCY;
+using aidl::android::media::audio::common::AudioUsage::GAME;
+using aidl::android::media::audio::common::AudioUsage::MEDIA;
+using aidl::android::media::audio::common::AudioUsage::NOTIFICATION;
+using aidl::android::media::audio::common::AudioUsage::NOTIFICATION_EVENT;
+using aidl::android::media::audio::common::AudioUsage::NOTIFICATION_TELEPHONY_RINGTONE;
+using aidl::android::media::audio::common::AudioUsage::SAFETY;
+using aidl::android::media::audio::common::AudioUsage::UNKNOWN;
+using aidl::android::media::audio::common::AudioUsage::VEHICLE_STATUS;
+using aidl::android::media::audio::common::AudioUsage::VOICE_COMMUNICATION;
+using aidl::android::media::audio::common::AudioUsage::VOICE_COMMUNICATION_SIGNALLING;
+
+namespace android {
+namespace hardware {
+namespace audiocontrol {
+namespace internal {
+
+std::vector<AudioAttributes> createAudioAttributes(const std::vector<AudioUsage>& usages) {
+    std::vector<AudioAttributes> audioAttributes;
+    for (const auto& usage : usages) {
+        AudioAttributes attributes;
+        attributes.usage = usage;
+        audioAttributes.push_back(attributes);
+    }
+    return audioAttributes;
+}
+
+AudioZoneContextInfo createAudioZoneContextInfo(const std::string& name, int id,
+                                                const std::vector<AudioUsage>& usages) {
+    AudioZoneContextInfo info;
+    info.name = name;
+    info.id = id;
+    info.audioAttributes = createAudioAttributes(usages);
+    return info;
+}
+
+AudioZoneContext createAudioZoneContextInfo(const std::vector<AudioZoneContextInfo>& info) {
+    AudioZoneContext context;
+    context.audioContextInfos.insert(context.audioContextInfos.begin(), info.begin(), info.end());
+    return context;
+}
+
+AudioZoneContext getDefaultCarAudioContext() {
+    // For legacy reasons, context names are lower case here.
+    static const AudioZoneContext kDefaultContext = createAudioZoneContextInfo(
+            {createAudioZoneContextInfo("music", 1, {UNKNOWN, MEDIA, GAME}),
+             createAudioZoneContextInfo("navigation", 2, {ASSISTANCE_NAVIGATION_GUIDANCE}),
+             createAudioZoneContextInfo("voice_command", 3, {ASSISTANCE_ACCESSIBILITY, ASSISTANT}),
+             createAudioZoneContextInfo("call_ring", 4, {NOTIFICATION_TELEPHONY_RINGTONE}),
+             createAudioZoneContextInfo(
+                     "call", 5,
+                     {VOICE_COMMUNICATION, CALL_ASSISTANT, VOICE_COMMUNICATION_SIGNALLING}),
+             createAudioZoneContextInfo("alarm", 6, {ALARM}),
+             createAudioZoneContextInfo("notification", 7, {NOTIFICATION, NOTIFICATION_EVENT}),
+             createAudioZoneContextInfo("system_sound", 8, {ASSISTANCE_SONIFICATION}),
+             createAudioZoneContextInfo("emergency", 9, {EMERGENCY}),
+             createAudioZoneContextInfo("safety", 10, {SAFETY}),
+             createAudioZoneContextInfo("vehicle_status", 11, {VEHICLE_STATUS}),
+             createAudioZoneContextInfo("announcement", 12, {ANNOUNCEMENT})});
+    return kDefaultContext;
+}
+
+}  // namespace internal
+}  // namespace audiocontrol
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/audiocontrol/aidl/default/converter/src/CarAudioConfigurationXmlConverter.cpp b/automotive/audiocontrol/aidl/default/converter/src/CarAudioConfigurationXmlConverter.cpp
new file mode 100644
index 0000000..d43b595
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/converter/src/CarAudioConfigurationXmlConverter.cpp
@@ -0,0 +1,1134 @@
+/*
+ * 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 "AudioControl::XSD_Converter"
+
+#define LOG_NDEBUG 0
+#include <android-base/logging.h>
+
+#include "../include/CarAudioConfigurationXmlConverter.h"
+
+#include <aidl/android/hardware/automotive/audiocontrol/RoutingDeviceConfiguration.h>
+#include <android-base/parsebool.h>
+#include <android_hardware_automotive_audiocontrol.h>
+#include <android_hardware_automotive_audiocontrol_fade.h>
+
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+#include <media/AidlConversionCppNdk.h>
+#include <media/TypeConverter.h>
+#include <media/convert.h>
+#include <system/audio.h>
+#include <unistd.h>
+#include <unordered_map>
+
+namespace android {
+namespace hardware {
+namespace audiocontrol {
+namespace internal {
+namespace xsd = ::android::hardware::automotive::audiocontrol;
+namespace fade = android::hardware::automotive::audiocontrol::fade;
+namespace api = ::aidl::android::hardware::automotive::audiocontrol;
+
+using aidl::android::media::audio::common::AudioAttributes;
+using aidl::android::media::audio::common::AudioContentType;
+using aidl::android::media::audio::common::AudioDevice;
+using aidl::android::media::audio::common::AudioDeviceAddress;
+using aidl::android::media::audio::common::AudioDeviceDescription;
+using aidl::android::media::audio::common::AudioDeviceType;
+using aidl::android::media::audio::common::AudioPort;
+using aidl::android::media::audio::common::AudioPortDeviceExt;
+using aidl::android::media::audio::common::AudioPortExt;
+using aidl::android::media::audio::common::AudioUsage;
+
+using namespace ::android::base;
+
+namespace {
+
+static const std::string kUseCoreRouting{"useCoreAudioRouting"};
+static const std::string kUseCoreVolume{"useCoreAudioVolume"};
+static const std::string kUseHalDuckingSignals{"useHalDuckingSignals"};
+static const std::string kUseCarVolumeGroupMuting{"useCarVolumeGroupMuting"};
+
+static constexpr char kOutBusType[] = "AUDIO_DEVICE_OUT_BUS";
+static constexpr char kInBusType[] = "AUDIO_DEVICE_IN_BUS";
+
+using ActivationMap = std::unordered_map<std::string, api::VolumeActivationConfiguration>;
+using FadeConfigurationMap = std::unordered_map<
+        std::string, ::aidl::android::hardware::automotive::audiocontrol::AudioFadeConfiguration>;
+
+inline bool isReadableConfigurationFile(const std::string& filePath) {
+    return !filePath.empty() && filePath.ends_with(".xml") && (access(filePath.c_str(), R_OK) == 0);
+}
+
+inline bool parseBoolOrDefaultIfFailed(const std::string& value, bool defaultValue) {
+    ParseBoolResult results = ParseBool(value);
+    return results == ParseBoolResult::kError ? defaultValue : results == ParseBoolResult::kTrue;
+}
+
+void parseCoreRoutingInfo(const std::string& value, api::AudioDeviceConfiguration& config) {
+    if (!parseBoolOrDefaultIfFailed(value, /* defaultValue= */ false)) {
+        return;
+    }
+    config.routingConfig = api::RoutingDeviceConfiguration::CONFIGURABLE_AUDIO_ENGINE_ROUTING;
+}
+
+void parseCoreVolumeInfo(const std::string& value, api::AudioDeviceConfiguration& config) {
+    config.useCoreAudioVolume = parseBoolOrDefaultIfFailed(value, config.useCoreAudioVolume);
+}
+
+void parseHalDuckingInfo(const std::string& value, api::AudioDeviceConfiguration& config) {
+    config.useHalDuckingSignals = parseBoolOrDefaultIfFailed(value, config.useHalDuckingSignals);
+}
+
+void parseHalMutingInfo(const std::string& value, api::AudioDeviceConfiguration& config) {
+    config.useCarVolumeGroupMuting =
+            parseBoolOrDefaultIfFailed(value, config.useCarVolumeGroupMuting);
+}
+
+bool parseAudioAttributeUsageString(const std::string& usageString, AudioUsage& usage) {
+    audio_usage_t legacyUsage;
+    if (!::android::UsageTypeConverter::fromString(usageString, legacyUsage)) {
+        LOG(ERROR) << __func__ << " could not parse usage from string " << usageString;
+        return false;
+    }
+    ConversionResult<AudioUsage> result =
+            ::aidl::android::legacy2aidl_audio_usage_t_AudioUsage(legacyUsage);
+    if (!result.ok()) {
+        LOG(ERROR) << __func__ << " could not parse usage legacy type " << legacyUsage;
+        return false;
+    }
+    usage = result.value();
+    return true;
+}
+
+bool parseAudioAttributeUsage(const xsd::UsageType& usageType, AudioAttributes& attributes) {
+    if (!usageType.hasValue()) {
+        LOG(ERROR) << __func__ << " usage does not have value";
+        return false;
+    }
+    if (!parseAudioAttributeUsageString(xsd::toString(usageType.getValue()), attributes.usage)) {
+        return false;
+    }
+    return true;
+}
+
+bool parseAudioAttributesUsages(const std::vector<xsd::UsageType>& usages,
+                                std::vector<AudioAttributes>& audioAttributes) {
+    for (const auto& xsdUsage : usages) {
+        AudioAttributes attributes;
+        if (!parseAudioAttributeUsage(xsdUsage, attributes)) {
+            return false;
+        }
+        audioAttributes.push_back(attributes);
+    }
+    return true;
+}
+
+bool parseContentTypeString(const std::string& typeString, AudioContentType& type) {
+    audio_content_type_t legacyContentType;
+    if (!::android::AudioContentTypeConverter::fromString(typeString, legacyContentType)) {
+        LOG(ERROR) << __func__ << " could not parse content type from string " << typeString;
+        return false;
+    }
+    ConversionResult<AudioContentType> result =
+            ::aidl::android::legacy2aidl_audio_content_type_t_AudioContentType(legacyContentType);
+    if (!result.ok()) {
+        LOG(ERROR) << __func__ << " could not convert legacy content type " << legacyContentType;
+        return false;
+    }
+    type = result.value();
+    return true;
+}
+
+bool parseAudioAttribute(const xsd::AttributesType& attributesType, AudioAttributes& attributes) {
+    if (attributesType.hasUsage()) {
+        if (!parseAudioAttributeUsageString(xsd::toString(attributesType.getUsage()),
+                                            attributes.usage)) {
+            LOG(ERROR) << __func__ << " could not parse audio usage: "
+                       << xsd::toString(attributesType.getUsage());
+            return false;
+        }
+    }
+
+    if (attributesType.hasContentType()) {
+        if (!parseContentTypeString(xsd::toString(attributesType.getContentType()),
+                                    attributes.contentType)) {
+            return false;
+        }
+    }
+
+    if (attributesType.hasTags()) {
+        attributes.tags.push_back(attributesType.getTags());
+    }
+    return true;
+}
+
+bool parseAudioAttributes(const std::vector<xsd::AttributesType>& xsdAttributes,
+                          std::vector<AudioAttributes>& audioAttributes) {
+    for (const auto& xsdAttribute : xsdAttributes) {
+        AudioAttributes attribute;
+        if (!parseAudioAttribute(xsdAttribute, attribute)) {
+            return false;
+        }
+        audioAttributes.push_back(attribute);
+    }
+    return true;
+}
+
+bool parseAudioAttributes(const xsd::AudioAttributesUsagesType& xsdAttributeOrUsages,
+                          std::vector<AudioAttributes>& audioAttributes) {
+    if (xsdAttributeOrUsages.hasUsage_optional()) {
+        if (!parseAudioAttributesUsages(xsdAttributeOrUsages.getUsage_optional(),
+                                        audioAttributes)) {
+            LOG(ERROR) << __func__ << " could not parse audio usages";
+            return false;
+        }
+    }
+
+    if (xsdAttributeOrUsages.hasAudioAttribute_optional()) {
+        if (!parseAudioAttributes(xsdAttributeOrUsages.getAudioAttribute_optional(),
+                                  audioAttributes)) {
+            LOG(ERROR) << __func__ << " could not parse audio attributes";
+            return false;
+        }
+    }
+    return true;
+}
+
+bool parseAudioContext(const xsd::OemContextType& xsdContextInfo,
+                       api::AudioZoneContextInfo& contextInfo) {
+    if (!xsdContextInfo.hasName()) {
+        LOG(ERROR) << __func__ << " Audio context info missing name";
+        return false;
+    }
+
+    contextInfo.name = xsdContextInfo.getName();
+
+    if (xsdContextInfo.hasId()) {
+        ParseInt(xsdContextInfo.getId().c_str(), &contextInfo.id);
+    }
+
+    if (xsdContextInfo.hasAudioAttributes()) {
+        if (!parseAudioAttributes(*xsdContextInfo.getFirstAudioAttributes(),
+                                  contextInfo.audioAttributes)) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool parseAudioContexts(const xsd::OemContextsType* xsdContexts, api::AudioZoneContext& context) {
+    if (!xsdContexts->hasOemContext()) {
+        return false;
+    }
+    const auto xsdContextInfos = xsdContexts->getOemContext();
+    for (const auto& xsdContextInfo : xsdContextInfos) {
+        api::AudioZoneContextInfo info;
+        if (!parseAudioContext(xsdContextInfo, info)) {
+            continue;
+        }
+        context.audioContextInfos.push_back(info);
+    }
+    return true;
+}
+
+bool createAudioDevice(const std::string& address, const std::string& type, AudioPort& port) {
+    audio_devices_t legacyDeviceType = AUDIO_DEVICE_NONE;
+    ::android::DeviceConverter::fromString(type, legacyDeviceType);
+    std::string tempString;
+    ::android::DeviceConverter::toString(legacyDeviceType, tempString);
+    ConversionResult<AudioDeviceDescription> result =
+            ::aidl::android::legacy2aidl_audio_devices_t_AudioDeviceDescription(legacyDeviceType);
+    if (legacyDeviceType == AUDIO_DEVICE_NONE || !result.ok()) {
+        LOG(ERROR) << __func__ << " could not parse legacy device type";
+        return false;
+    }
+    AudioDevice device;
+    if (!address.empty()) {
+        device.address = AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(address);
+    }
+    device.type = result.value();
+
+    port.ext = AudioPortExt::make<AudioPortExt::Tag::device>(device);
+
+    return true;
+}
+
+std::string outTypeToOutAudioDevice(const std::string& device) {
+    const static std::unordered_map<std::string, std::string> typeToOutDevice{
+            {"TYPE_BUILTIN_SPEAKER", "AUDIO_DEVICE_OUT_SPEAKER"},
+            {"TYPE_WIRED_HEADSET", "AUDIO_DEVICE_OUT_WIRED_HEADSET"},
+            {"TYPE_WIRED_HEADPHONES", "AUDIO_DEVICE_OUT_WIRED_HEADPHONE,"},
+            {"TYPE_BLUETOOTH_A2DP", "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP"},
+            {"TYPE_HDMI", "AUDIO_DEVICE_OUT_HDMI"},
+            {"TYPE_USB_ACCESSORY", "AUDIO_DEVICE_OUT_USB_ACCESSORY"},
+            {"TYPE_USB_DEVICE", "AUDIO_DEVICE_OUT_USB_DEVICE,"},
+            {"TYPE_USB_HEADSET", "AUDIO_DEVICE_OUT_USB_HEADSET"},
+            {"TYPE_AUX_LINE", "AUDIO_DEVICE_OUT_AUX_LINE"},
+            {"TYPE_BUS", "AUDIO_DEVICE_OUT_BUS"},
+            {"TYPE_BLE_HEADSET", "AUDIO_DEVICE_OUT_BLE_HEADSET"},
+            {"TYPE_BLE_SPEAKER", "AUDIO_DEVICE_OUT_BLE_SPEAKER"},
+            {"TYPE_BLE_BROADCAST", "AUDIO_DEVICE_OUT_BLE_BROADCAST"},
+    };
+
+    if (!device.starts_with("TYPE_")) {
+        return device;
+    }
+
+    const auto it = typeToOutDevice.find(device);
+    return it != typeToOutDevice.end() ? it->second : device;
+}
+
+bool parseAudioDeviceToContexts(const xsd::DeviceRoutesType& deviceRoutesType,
+                                api::DeviceToContextEntry& route) {
+    std::string address = deviceRoutesType.hasAddress() ? deviceRoutesType.getAddress() : "";
+    // Default type is bus for schema
+    std::string type = outTypeToOutAudioDevice(deviceRoutesType.hasType()
+                                                       ? xsd::toString(deviceRoutesType.getType())
+                                                       : std::string(kOutBusType));
+    // Address must be present for audio device bus
+    if (address.empty() && type == std::string(kOutBusType)) {
+        LOG(ERROR) << __func__ << " empty device address for bus device type";
+        return false;
+    }
+    if (!createAudioDevice(address, type, route.device)) {
+        return false;
+    }
+
+    if (!deviceRoutesType.hasContext()) {
+        LOG(ERROR) << __func__ << " empty device context mapping";
+        return false;
+    }
+
+    for (const auto& xsdContext : deviceRoutesType.getContext()) {
+        if (!xsdContext.hasContext()) {
+            LOG(ERROR) << __func__ << " audio device route missing context info";
+            return false;
+        }
+        route.contextNames.push_back(xsdContext.getContext());
+    }
+
+    return true;
+}
+
+bool parseAudioDeviceRoutes(const std::vector<xsd::DeviceRoutesType> deviceRoutesTypes,
+                            std::vector<api::DeviceToContextEntry>& routes) {
+    for (const auto& deviceRouteType : deviceRoutesTypes) {
+        api::DeviceToContextEntry entry;
+        if (!parseAudioDeviceToContexts(deviceRouteType, entry)) {
+            return false;
+        }
+        routes.push_back(entry);
+    }
+    return true;
+}
+
+void parseVolumeGroupActivation(const std::string& activationConfigName,
+                                const ActivationMap& activations,
+                                api::VolumeGroupConfig& volumeGroup) {
+    if (activationConfigName.empty()) {
+        LOG(ERROR) << __func__ << " Volume group " << volumeGroup.name
+                   << " has empty volume group activation name";
+        return;
+    }
+    const auto& it = activations.find(activationConfigName);
+    if (it == activations.end()) {
+        LOG(ERROR) << __func__ << " Volume group " << volumeGroup.name
+                   << " has non-existing volume group activation name " << activationConfigName;
+        return;
+    }
+    volumeGroup.activationConfiguration = it->second;
+}
+
+bool parseVolumeGroup(const xsd::VolumeGroupType& volumeGroupType, const ActivationMap& activations,
+                      api::VolumeGroupConfig& volumeGroup) {
+    if (!volumeGroupType.hasDevice()) {
+        LOG(ERROR) << __func__ << " no device found";
+        return false;
+    }
+
+    if (volumeGroupType.hasName()) {
+        volumeGroup.name = volumeGroupType.getName();
+    }
+
+    if (!parseAudioDeviceRoutes(volumeGroupType.getDevice(), volumeGroup.carAudioRoutes)) {
+        return false;
+    }
+
+    if (volumeGroupType.hasActivationConfig()) {
+        parseVolumeGroupActivation(volumeGroupType.getActivationConfig(), activations, volumeGroup);
+    }
+
+    return true;
+}
+
+bool parseVolumeGroups(const xsd::VolumeGroupsType* volumeGroupsType,
+                       const ActivationMap& activations,
+                       std::vector<api::VolumeGroupConfig>& volumeGroups) {
+    if (!volumeGroupsType->hasGroup()) {
+        LOG(ERROR) << __func__ << " no volume groups found";
+        return false;
+    }
+    for (const auto& volumeGroupType : volumeGroupsType->getGroup()) {
+        api::VolumeGroupConfig volumeGroup;
+        if (!parseVolumeGroup(volumeGroupType, activations, volumeGroup)) {
+            return false;
+        }
+        volumeGroups.push_back(volumeGroup);
+    }
+    return true;
+}
+
+void parseFadeConfigurationUsages(const xsd::ApplyFadeConfigType& fadeConfigType,
+                                  std::vector<AudioUsage>& usages) {
+    if (!fadeConfigType.hasAudioAttributes()) {
+        return;
+    }
+    const xsd::AudioAttributeUsagesType* attributesOrUsagesType =
+            fadeConfigType.getFirstAudioAttributes();
+    if (!attributesOrUsagesType->hasUsage()) {
+        return;
+    }
+    for (const auto& usageType : attributesOrUsagesType->getUsage()) {
+        AudioUsage usage;
+        if (!usageType.hasValue() ||
+            !parseAudioAttributeUsageString(xsd::toString(usageType.getValue()), usage)) {
+            continue;
+        }
+        usages.push_back(usage);
+    }
+}
+
+void parseZoneFadeConfiguration(const xsd::ApplyFadeConfigType& fadeConfigType,
+                                const FadeConfigurationMap& fadeConfigurations,
+                                api::AudioZoneFadeConfiguration& zoneFadeConfiguration) {
+    if (!fadeConfigType.hasName()) {
+        LOG(ERROR) << __func__ << " Found a fade config without a name, skipping assignment";
+        return;
+    }
+
+    const auto it = fadeConfigurations.find(fadeConfigType.getName());
+    if (it == fadeConfigurations.end()) {
+        LOG(ERROR) << __func__ << " Config name " << fadeConfigType.getName()
+                   << " not found, skipping assignment";
+        return;
+    }
+    // Return for default since default configurations do not have any audio attributes mapping
+    if (fadeConfigType.hasIsDefault()) {
+        zoneFadeConfiguration.defaultConfiguration = it->second;
+        return;
+    }
+
+    api::TransientFadeConfigurationEntry entry;
+    entry.transientFadeConfiguration = it->second;
+    parseFadeConfigurationUsages(fadeConfigType, entry.transientUsages);
+    zoneFadeConfiguration.transientConfiguration.push_back(entry);
+}
+
+void parseZoneFadeConfigurations(const xsd::ZoneConfigType& zoneConfigType,
+                                 const FadeConfigurationMap& fadeConfigurations,
+                                 std::optional<api::AudioZoneFadeConfiguration>& zoneFadeConfig) {
+    if (!zoneConfigType.hasApplyFadeConfigs()) {
+        return;
+    }
+    const xsd::ApplyFadeConfigsType* applyFadeConfigs = zoneConfigType.getFirstApplyFadeConfigs();
+    if (!applyFadeConfigs->hasFadeConfig()) {
+        return;
+    }
+    api::AudioZoneFadeConfiguration zoneFadeConfiguration;
+    for (const auto& fadeConfigType : applyFadeConfigs->getFadeConfig()) {
+        parseZoneFadeConfiguration(fadeConfigType, fadeConfigurations, zoneFadeConfiguration);
+    }
+    zoneFadeConfig = zoneFadeConfiguration;
+}
+
+bool parseAudioZoneConfig(const xsd::ZoneConfigType& zoneConfigType,
+                          const ActivationMap& activations,
+                          const FadeConfigurationMap& fadeConfigurations,
+                          api::AudioZoneConfig& config) {
+    if (!zoneConfigType.hasVolumeGroups()) {
+        LOG(ERROR) << __func__ << " no volume groups found";
+        return false;
+    }
+
+    if (zoneConfigType.hasName()) {
+        config.name = zoneConfigType.getName();
+    }
+    if (!parseVolumeGroups(zoneConfigType.getFirstVolumeGroups(), activations,
+                           config.volumeGroups)) {
+        return false;
+    }
+
+    parseZoneFadeConfigurations(zoneConfigType, fadeConfigurations, config.fadeConfiguration);
+
+    config.isDefault = zoneConfigType.hasIsDefault() && zoneConfigType.getIsDefault();
+
+    return true;
+}
+
+bool parseAudioZoneConfigs(const xsd::ZoneConfigsType* zoneConfigsType,
+                           const ActivationMap& activations,
+                           const FadeConfigurationMap& fadeConfigurations,
+                           std::vector<api::AudioZoneConfig>& configs) {
+    if (!zoneConfigsType->hasZoneConfig()) {
+        LOG(ERROR) << __func__ << " No zone configs found";
+        return false;
+    }
+
+    if (zoneConfigsType->getZoneConfig().empty()) {
+        LOG(ERROR) << __func__ << " Empty list of audio configurations";
+        return false;
+    }
+
+    for (const auto& zoneConfigType : zoneConfigsType->getZoneConfig()) {
+        api::AudioZoneConfig config;
+        if (!parseAudioZoneConfig(zoneConfigType, activations, fadeConfigurations, config)) {
+            return false;
+        }
+        configs.push_back(config);
+    }
+
+    return true;
+}
+
+bool parseInputDevice(const xsd::InputDeviceType& xsdInputDevice, AudioPort& inputDevice) {
+    // Input device must have a non-empty address
+    if (!xsdInputDevice.hasAddress() || xsdInputDevice.getAddress().empty()) {
+        LOG(ERROR) << __func__ << " missing device address";
+        return false;
+    }
+    // By default a device is bus type, unless specified
+    std::string inputDeviceType =
+            xsdInputDevice.hasType() ? xsd::toString(xsdInputDevice.getType()) : kInBusType;
+    if (!createAudioDevice(xsdInputDevice.getAddress(), inputDeviceType, inputDevice)) {
+        return false;
+    }
+    return true;
+}
+
+void parseInputDevices(const xsd::InputDevicesType* xsdInputDevices,
+                       std::vector<AudioPort>& inputDevices) {
+    if (!xsdInputDevices->hasInputDevice()) {
+        return;
+    }
+    for (const auto& xsdInputDevice : xsdInputDevices->getInputDevice()) {
+        AudioPort inputDevice;
+        if (!parseInputDevice(xsdInputDevice, inputDevice)) {
+            continue;
+        }
+        inputDevices.push_back(inputDevice);
+    }
+}
+
+bool parseAudioZone(const xsd::ZoneType& zone, const ActivationMap& activations,
+                    const FadeConfigurationMap& fadeConfigurations, api::AudioZone& audioZone) {
+    if (zone.hasName()) {
+        audioZone.name = zone.getName();
+    }
+
+    if (zone.hasOccupantZoneId()) {
+        ParseInt(zone.getOccupantZoneId().c_str(), &audioZone.occupantZoneId);
+    }
+
+    if (zone.hasInputDevices()) {
+        parseInputDevices(zone.getFirstInputDevices(), audioZone.inputAudioDevices);
+    }
+
+    // Audio zone id is required
+    if (!zone.hasAudioZoneId()) {
+        LOG(ERROR) << __func__ << " Audio zone id required for each zone";
+        return false;
+    }
+
+    bool isPrimary = zone.hasIsPrimary() && zone.getIsPrimary();
+
+    if (isPrimary) {
+        audioZone.id = api::AudioZone::PRIMARY_AUDIO_ZONE;
+    }
+
+    // ID not required in XML for primary zone
+    if (!ParseInt(zone.getAudioZoneId().c_str(), &audioZone.id) && !isPrimary) {
+        LOG(ERROR) << __func__
+                   << " Could not parse audio zone id, must be a non-negative integer or isPrimary "
+                      "must be specify as true for primary zone";
+        return false;
+    }
+
+    if (isPrimary && audioZone.id != api::AudioZone::PRIMARY_AUDIO_ZONE) {
+        LOG(ERROR) << __func__ << " Audio zone is primary but has zone id "
+                   << std::to_string(audioZone.id) << " instead of primary zone id "
+                   << std::to_string(api::AudioZone::PRIMARY_AUDIO_ZONE);
+        return false;
+    }
+
+    if (!zone.hasZoneConfigs()) {
+        LOG(ERROR) << __func__ << " Missing audio zone configs for audio zone id " << audioZone.id;
+        return false;
+    }
+    if (!parseAudioZoneConfigs(zone.getFirstZoneConfigs(), activations, fadeConfigurations,
+                               audioZone.audioZoneConfigs)) {
+        LOG(ERROR) << __func__ << " Could not parse zone configs for audio zone id " << audioZone.id
+                   << ", name " << audioZone.name;
+        return false;
+    }
+
+    return true;
+}
+
+std::string parseAudioZones(const xsd::ZonesType* zones, const api::AudioZoneContext& context,
+                            const ActivationMap& activations,
+                            const FadeConfigurationMap& fadeConfigurations,
+                            std::vector<api::AudioZone>& audioZones) {
+    if (!zones->hasZone()) {
+        return "audio zones are missing";
+    }
+    const auto& xsdZones = zones->getZone();
+    for (const auto& xsdZone : xsdZones) {
+        api::AudioZone audioZone;
+        audioZone.audioZoneContext = context;
+        if (!parseAudioZone(xsdZone, activations, fadeConfigurations, audioZone)) {
+            continue;
+        }
+        audioZones.push_back(audioZone);
+    }
+    return "";
+}
+
+std::unordered_map<std::string,
+                   std::function<void(const std::string&, api::AudioDeviceConfiguration&)>>
+getConfigsParsers() {
+    static const std::unordered_map<
+            std::string, std::function<void(const std::string&, api::AudioDeviceConfiguration&)>>
+            parsers{
+                    {kUseCoreRouting, parseCoreRoutingInfo},
+                    {kUseCoreVolume, parseCoreVolumeInfo},
+                    {kUseHalDuckingSignals, parseHalDuckingInfo},
+                    {kUseCarVolumeGroupMuting, parseHalMutingInfo},
+            };
+
+    return parsers;
+}
+
+bool parseVolumeActivationType(const xsd::ActivationType& xsdType,
+                               api::VolumeInvocationType& activationType) {
+    switch (xsdType) {
+        case xsd::ActivationType::onBoot:
+            activationType = api::VolumeInvocationType::ON_BOOT;
+            break;
+        case xsd::ActivationType::onSourceChanged:
+            activationType = api::VolumeInvocationType::ON_SOURCE_CHANGED;
+            break;
+        case xsd::ActivationType::onPlaybackChanged:
+            activationType = api::VolumeInvocationType::ON_PLAYBACK_CHANGED;
+            break;
+        default:
+            return false;
+    }
+    return true;
+}
+
+bool parseVolumeGroupActivationEntry(const xsd::ActivationVolumeConfigEntryType& xsdEntry,
+                                     api::VolumeActivationConfigurationEntry& entry) {
+    if (!xsdEntry.hasInvocationType()) {
+        LOG(ERROR) << __func__ << " Activation config entry missing invocation type";
+        return false;
+    }
+
+    if (!parseVolumeActivationType(xsdEntry.getInvocationType(), entry.type)) {
+        LOG(ERROR) << __func__ << " Could not parse configuration entry type";
+        return false;
+    }
+
+    if (xsdEntry.hasMaxActivationVolumePercentage()) {
+        // Parse int ranges are not inclusive
+        ParseInt(xsdEntry.getMaxActivationVolumePercentage().c_str(),
+                 &entry.maxActivationVolumePercentage,
+                 api::VolumeActivationConfigurationEntry::DEFAULT_MIN_ACTIVATION_VALUE - 1,
+                 api::VolumeActivationConfigurationEntry::DEFAULT_MAX_ACTIVATION_VALUE + 1);
+    }
+
+    if (xsdEntry.hasMinActivationVolumePercentage()) {
+        // Parse int ranges are not inclusive
+        ParseInt(xsdEntry.getMinActivationVolumePercentage().c_str(),
+                 &entry.minActivationVolumePercentage,
+                 api::VolumeActivationConfigurationEntry::DEFAULT_MIN_ACTIVATION_VALUE - 1,
+                 api::VolumeActivationConfigurationEntry::DEFAULT_MAX_ACTIVATION_VALUE + 1);
+    }
+
+    return true;
+}
+
+bool parseVolumeGroupActivationEntries(
+        const std::vector<xsd::ActivationVolumeConfigEntryType>& xsdEntries,
+        std::vector<api::VolumeActivationConfigurationEntry>& entries) {
+    for (const auto& xsdEntry : xsdEntries) {
+        api::VolumeActivationConfigurationEntry entry;
+        if (!parseVolumeGroupActivationEntry(xsdEntry, entry)) {
+            LOG(ERROR) << __func__ << " Could not parse volume group activation entries";
+            return false;
+        }
+        entries.push_back(entry);
+    }
+    return true;
+}
+
+bool parseVolumeGroupActivation(const xsd::ActivationVolumeConfigType& xsdActivationConfig,
+                                api::VolumeActivationConfiguration& activation) {
+    if (!xsdActivationConfig.hasName()) {
+        LOG(ERROR) << __func__ << " Activation config missing volume activation name";
+        return false;
+    }
+    if (!xsdActivationConfig.hasActivationVolumeConfigEntry()) {
+        LOG(ERROR) << __func__ << " Activation config missing volume activation entries";
+        return false;
+    }
+    if (!parseVolumeGroupActivationEntries(xsdActivationConfig.getActivationVolumeConfigEntry(),
+                                           activation.volumeActivationEntries)) {
+        LOG(ERROR) << __func__ << " Could not parse volume activation name";
+        return false;
+    }
+    activation.name = xsdActivationConfig.getName();
+    return true;
+}
+
+void parseVolumeGroupActivations(const xsd::ActivationVolumeConfigsType* xsdActivationConfigs,
+                                 ActivationMap& activations) {
+    if (!xsdActivationConfigs->hasActivationVolumeConfig()) {
+        LOG(ERROR) << __func__ << " No volume group activations found";
+        return;
+    }
+    for (const auto& xsdActivationConfig : xsdActivationConfigs->getActivationVolumeConfig()) {
+        api::VolumeActivationConfiguration activationConfiguration;
+        if (!parseVolumeGroupActivation(xsdActivationConfig, activationConfiguration)) {
+            continue;
+        }
+        std::string name = xsdActivationConfig.getName();
+        activations.emplace(name, activationConfiguration);
+    }
+}
+
+void parseOutputMirroringDevices(const xsd::MirroringDevicesType* mirroringDevicesType,
+                                 std::vector<AudioPort>& mirroringDevices) {
+    if (!mirroringDevicesType->hasMirroringDevice()) {
+        LOG(ERROR) << __func__ << " Missing audio mirroring devices";
+        return;
+    }
+    for (const auto& xsdMirrorDevice : mirroringDevicesType->getMirroringDevice()) {
+        AudioPort mirrorDevicePort;
+        if (!xsdMirrorDevice.hasAddress()) {
+            LOG(ERROR) << __func__ << " Missing audio mirroring device address";
+            continue;
+        }
+        if (!createAudioDevice(xsdMirrorDevice.getAddress(), kOutBusType, mirrorDevicePort)) {
+            LOG(ERROR) << __func__ << " Could not create mirror device with address "
+                       << xsdMirrorDevice.getAddress();
+            continue;
+        }
+        mirroringDevices.push_back(mirrorDevicePort);
+    }
+}
+
+api::FadeState getFadeState(const fade::FadeStateType& xsdFadeState) {
+    // Return default value if missing
+    if (!xsdFadeState.hasValue()) {
+        return api::FadeState::FADE_STATE_ENABLED_DEFAULT;
+    }
+    // For legacy files, "0" and "1 " need to be supported.
+    switch (xsdFadeState.getValue()) {
+        case fade::FadeStateEnumType::_0:
+            // Fallthrough
+        case fade::FadeStateEnumType::FADE_STATE_DISABLED:
+            return api::FadeState::FADE_STATE_DISABLED;
+        case fade::FadeStateEnumType::_1:
+            // Fallthrough
+        case fade::FadeStateEnumType::FADE_STATE_ENABLED_DEFAULT:
+            // Fallthrough
+        default:
+            return api::FadeState::FADE_STATE_ENABLED_DEFAULT;
+    }
+}
+
+void parseFadeableUsages(const fade::FadeableUsagesType& fadeUsages,
+                         std::vector<AudioUsage>& usages) {
+    if (!fadeUsages.hasUsage()) {
+        return;
+    }
+    for (const auto& fadeUsage : fadeUsages.getUsage()) {
+        AudioUsage audioUsage;
+        if (!fadeUsage.hasValue() ||
+            !parseAudioAttributeUsageString(fade::toString(fadeUsage.getValue()), audioUsage)) {
+            continue;
+        }
+        usages.push_back(audioUsage);
+    }
+}
+
+void parseFadeAudioAttribute(const fade::AttributesType& fadeAttributes,
+                             AudioAttributes& attributes) {
+    if (fadeAttributes.hasUsage()) {
+        parseAudioAttributeUsageString(fade::toString(fadeAttributes.getUsage()), attributes.usage);
+    }
+    if (fadeAttributes.hasContentType()) {
+        parseContentTypeString(fade::toString(fadeAttributes.getContentType()),
+                               attributes.contentType);
+    }
+    if (fadeAttributes.hasTags()) {
+        attributes.tags.push_back(fadeAttributes.getTags());
+    }
+}
+
+bool parseFadeAudioAttribute(const fade::AudioAttributesUsagesType& fadeAttributes,
+                             std::vector<AudioAttributes>& audioAttributes) {
+    if (fadeAttributes.hasUsage_optional()) {
+        for (const auto& usage : fadeAttributes.getUsage_optional()) {
+            AudioAttributes attributes;
+            if (!usage.hasValue() || !parseAudioAttributeUsageString(
+                                             fade::toString(usage.getValue()), attributes.usage)) {
+                continue;
+            }
+            audioAttributes.push_back(attributes);
+        }
+    }
+    if (fadeAttributes.hasAudioAttribute_optional()) {
+        for (const auto& fadeAttribute : fadeAttributes.getAudioAttribute_optional()) {
+            AudioAttributes attribute;
+            parseFadeAudioAttribute(fadeAttribute, attribute);
+            audioAttributes.push_back(attribute);
+        }
+    }
+    return true;
+}
+
+void parseUnfadeableAudioAttributes(const fade::UnfadeableAudioAttributesType& fadeAttributes,
+                                    std::vector<AudioAttributes>& audioAttributes) {
+    if (!fadeAttributes.hasAudioAttributes()) {
+        return;
+    }
+    parseFadeAudioAttribute(*fadeAttributes.getFirstAudioAttributes(), audioAttributes);
+}
+
+void parseUnfadeableContentType(const fade::UnfadeableContentTypesType& fadeTypes,
+                                std::optional<std::vector<AudioContentType>>& contentTypes) {
+    if (!fadeTypes.hasContentType()) {
+        return;
+    }
+    std::vector<AudioContentType> contents;
+    for (const auto& fadeContentType : fadeTypes.getContentType()) {
+        AudioContentType contentType;
+        if (!fadeContentType.hasValue() ||
+            !parseContentTypeString(fade::toString(fadeContentType.getValue()), contentType)) {
+            continue;
+        }
+        contents.push_back(contentType);
+    }
+    contentTypes = contents;
+}
+
+void parseFadeConfigAudioAttributes(const fade::AudioAttributesUsagesType& fadeAudioAttributesType,
+                                    const int64_t fadeDurationMillins,
+                                    std::vector<api::FadeConfiguration>& fadeInConfigurations) {
+    if (fadeAudioAttributesType.hasAudioAttribute_optional()) {
+        for (const auto& fadeAudioAttribute :
+             fadeAudioAttributesType.getAudioAttribute_optional()) {
+            api::FadeConfiguration fadeConfiguration;
+            AudioAttributes attributes;
+            parseFadeAudioAttribute(fadeAudioAttribute, attributes);
+            fadeConfiguration.fadeDurationMillis = fadeDurationMillins;
+            fadeConfiguration.audioAttributesOrUsage
+                    .set<api::FadeConfiguration::AudioAttributesOrUsage::fadeAttribute>(attributes);
+            fadeInConfigurations.push_back(fadeConfiguration);
+        }
+    }
+
+    if (fadeAudioAttributesType.hasUsage_optional()) {
+        for (const auto& fadeAudioUsage : fadeAudioAttributesType.getUsage_optional()) {
+            api::FadeConfiguration fadeConfiguration;
+            AudioUsage usage;
+            if (!fadeAudioUsage.hasValue() ||
+                !parseAudioAttributeUsageString(fade::toString(fadeAudioUsage.getValue()), usage)) {
+                continue;
+            }
+            fadeConfiguration.fadeDurationMillis = fadeDurationMillins;
+            fadeConfiguration.audioAttributesOrUsage
+                    .set<api::FadeConfiguration::AudioAttributesOrUsage::usage>(usage);
+            fadeInConfigurations.push_back(fadeConfiguration);
+        }
+    }
+}
+void parseFadeConfiguration(const fade::FadeConfigurationType& fadeConfigurationType,
+                            std::vector<api::FadeConfiguration>& fadeConfigurations) {
+    if (!fadeConfigurationType.hasFadeDurationMillis() ||
+        !fadeConfigurationType.hasAudioAttributes() ||
+        fadeConfigurationType.getAudioAttributes().empty()) {
+        return;
+    }
+
+    int64_t fadeDurationMillis = 0L;
+
+    if (!ParseInt(fadeConfigurationType.getFadeDurationMillis().c_str(), &fadeDurationMillis,
+                  static_cast<int64_t>(0))) {
+        return;
+    }
+    parseFadeConfigAudioAttributes(*fadeConfigurationType.getFirstAudioAttributes(),
+                                   fadeDurationMillis, fadeConfigurations);
+}
+
+void parseFadeInConfigurations(const fade::FadeInConfigurationsType& fadeInConfigurationsType,
+                               std::vector<api::FadeConfiguration>& fadeInConfigurations) {
+    if (!fadeInConfigurationsType.hasFadeConfiguration()) {
+        return;
+    }
+    for (const auto& fadeConfigurationType : fadeInConfigurationsType.getFadeConfiguration()) {
+        parseFadeConfiguration(fadeConfigurationType, fadeInConfigurations);
+    }
+}
+
+void parseFadeOutConfigurations(const fade::FadeOutConfigurationsType& fadeOutConfigurationsType,
+                                std::vector<api::FadeConfiguration>& fadeOutConfigurations) {
+    if (!fadeOutConfigurationsType.hasFadeConfiguration()) {
+        return;
+    }
+    for (const auto& fadeConfigurationType : fadeOutConfigurationsType.getFadeConfiguration()) {
+        parseFadeConfiguration(fadeConfigurationType, fadeOutConfigurations);
+    }
+}
+
+bool parseFadeConfig(const fade::FadeConfigurationConfig& fadeConfig,
+                     api::AudioFadeConfiguration& configuration) {
+    // Fade configuration must have a name for zone association. Fade state is also needed to
+    // determine accurate usage.
+    if (!fadeConfig.hasName()) {
+        LOG(ERROR) << __func__ << " Fade configuration missing name";
+        return false;
+    }
+    if (!fadeConfig.hasFadeState()) {
+        LOG(ERROR) << __func__ << " Fade configuration missing fade state";
+        return false;
+    }
+    configuration.name = fadeConfig.getName();
+    configuration.fadeState = getFadeState(*fadeConfig.getFirstFadeState());
+    if (fadeConfig.hasDefaultFadeOutDurationInMillis()) {
+        ParseInt(fadeConfig.getDefaultFadeOutDurationInMillis().c_str(),
+                 &configuration.fadeOutDurationMs, static_cast<int64_t>(0));
+    }
+    if (fadeConfig.hasDefaultFadeInDurationInMillis()) {
+        ParseInt(fadeConfig.getDefaultFadeInDurationInMillis().c_str(),
+                 &configuration.fadeInDurationMs, static_cast<int64_t>(0));
+    }
+    if (fadeConfig.hasDefaultFadeInDelayForOffenders()) {
+        ParseInt(fadeConfig.getDefaultFadeInDelayForOffenders().c_str(),
+                 &configuration.fadeInDelayedForOffendersMs, static_cast<int64_t>(0));
+    }
+
+    if (fadeConfig.hasFadeableUsages()) {
+        parseFadeableUsages(*fadeConfig.getFirstFadeableUsages(), configuration.fadeableUsages);
+    }
+
+    if (fadeConfig.hasUnfadeableContentTypes()) {
+        parseUnfadeableContentType(*fadeConfig.getFirstUnfadeableContentTypes(),
+                                   configuration.unfadeableContentTypes);
+    }
+
+    if (fadeConfig.hasUnfadeableAudioAttributes()) {
+        parseUnfadeableAudioAttributes(*fadeConfig.getFirstUnfadeableAudioAttributes(),
+                                       configuration.unfadableAudioAttributes);
+    }
+    if (fadeConfig.hasFadeInConfigurations()) {
+        parseFadeInConfigurations(*fadeConfig.getFirstFadeInConfigurations(),
+                                  configuration.fadeInConfigurations);
+    }
+    if (fadeConfig.hasFadeOutConfigurations()) {
+        parseFadeOutConfigurations(*fadeConfig.getFirstFadeOutConfigurations(),
+                                   configuration.fadeOutConfigurations);
+    }
+
+    return true;
+}
+
+void parseFadeConfigs(const std::vector<fade::FadeConfigurationConfig>& fadeConfigTypes,
+                      std::vector<api::AudioFadeConfiguration>& fadeConfigs) {
+    for (const auto& fadeConfig : fadeConfigTypes) {
+        api::AudioFadeConfiguration configuration;
+        if (!parseFadeConfig(fadeConfig, configuration)) {
+            continue;
+        }
+        fadeConfigs.push_back(configuration);
+    }
+}
+
+void parseFadeConfigs(const fade::FadeConfigurationConfigs& fadeConfigsType,
+                      std::vector<api::AudioFadeConfiguration>& fadeConfigs) {
+    if (!fadeConfigsType.hasConfig()) {
+        LOG(ERROR) << __func__ << " Fade config file does not contains any fade configs";
+        return;
+    }
+    parseFadeConfigs(fadeConfigsType.getConfig(), fadeConfigs);
+}
+}  // namespace
+
+void CarAudioConfigurationXmlConverter::init() {
+    if (!isReadableConfigurationFile(mAudioConfigFile)) {
+        mParseErrors = "Configuration file " + mAudioConfigFile + " is not readable";
+        initNonDynamicRouting();
+        return;
+    }
+
+    // Supports loading legacy fade configurations from a different file
+    if (isReadableConfigurationFile(mFadeConfigFile)) {
+        initFadeConfigurations();
+    }
+
+    const auto& configOptional = xsd::read(mAudioConfigFile.c_str());
+
+    if (!configOptional.has_value()) {
+        mParseErrors =
+                "Configuration file " + mAudioConfigFile + " , does not have any configurations";
+        initNonDynamicRouting();
+        return;
+    }
+
+    const auto& configurations = configOptional.value();
+    initAudioDeviceConfiguration(configurations);
+    initCarAudioConfigurations(configurations);
+}
+
+void CarAudioConfigurationXmlConverter::initFadeConfigurations() {
+    const auto& fadeConfigOptional = fade::read(mFadeConfigFile.c_str());
+    if (!fadeConfigOptional.has_value() || !fadeConfigOptional.value().hasConfigs()) {
+        LOG(ERROR) << __func__ << " Fade config file " << mFadeConfigFile.c_str()
+                   << " does not contains fade configuration";
+        return;
+    }
+
+    const auto& fadeConfigs = fadeConfigOptional.value().getConfigs();
+
+    if (fadeConfigs.empty()) {
+        LOG(ERROR) << __func__ << " Fade config file " << mFadeConfigFile.c_str()
+                   << " does not contains fade configs";
+    }
+    std::vector<api::AudioFadeConfiguration> fadeConfigurations;
+    parseFadeConfigs(fadeConfigs.front(), fadeConfigurations);
+    for (const auto& fadeConfiguration : fadeConfigurations) {
+        mFadeConfigurations.emplace(fadeConfiguration.name, fadeConfiguration);
+    }
+}
+
+void CarAudioConfigurationXmlConverter::initNonDynamicRouting() {
+    mAudioDeviceConfiguration.routingConfig =
+            api::RoutingDeviceConfiguration::DEFAULT_AUDIO_ROUTING;
+}
+
+void CarAudioConfigurationXmlConverter::initAudioDeviceConfiguration(
+        const xsd::CarAudioConfigurationType& carAudioConfigurationType) {
+    parseAudioDeviceConfigurations(carAudioConfigurationType);
+}
+
+void CarAudioConfigurationXmlConverter::parseAudioDeviceConfigurations(
+        const xsd::CarAudioConfigurationType& carAudioConfigurationType) {
+    if (!carAudioConfigurationType.hasDeviceConfigurations()) {
+        return;
+    }
+
+    mAudioDeviceConfiguration.routingConfig =
+            api::RoutingDeviceConfiguration::DYNAMIC_AUDIO_ROUTING;
+
+    const auto deviceConfigs = carAudioConfigurationType.getFirstDeviceConfigurations();
+    if (!deviceConfigs->hasDeviceConfiguration()) {
+        return;
+    }
+
+    std::vector<::android::hardware::automotive::audiocontrol::DeviceConfigurationType> configs =
+            deviceConfigs->getDeviceConfiguration();
+    const auto& parsers = getConfigsParsers();
+    for (const auto& deviceConfig : configs) {
+        if (!deviceConfig.hasName() || !deviceConfig.hasValue()) {
+            continue;
+        }
+        const auto& parser = parsers.find(deviceConfig.getName());
+        if (parser == parsers.end()) {
+            continue;
+        }
+        const auto& method = parser->second;
+        method(deviceConfig.getValue(), mAudioDeviceConfiguration);
+    }
+}
+
+void CarAudioConfigurationXmlConverter::initCarAudioConfigurations(
+        const automotive::audiocontrol::CarAudioConfigurationType& carAudioConfigurationType) {
+    if (!carAudioConfigurationType.hasZones()) {
+        mParseErrors = "Audio zones not found in file " + mAudioConfigFile;
+        initNonDynamicRouting();
+        return;
+    }
+
+    api::AudioZoneContext context;
+    if (!carAudioConfigurationType.hasOemContexts() ||
+        !parseAudioContexts(carAudioConfigurationType.getFirstOemContexts(), context)) {
+        context = getDefaultCarAudioContext();
+    }
+
+    ActivationMap activations;
+    if (carAudioConfigurationType.hasActivationVolumeConfigs()) {
+        parseVolumeGroupActivations(carAudioConfigurationType.getFirstActivationVolumeConfigs(),
+                                    activations);
+    }
+
+    if (carAudioConfigurationType.hasMirroringDevices()) {
+        parseOutputMirroringDevices(carAudioConfigurationType.getFirstMirroringDevices(),
+                                    mOutputMirroringDevices);
+    }
+
+    const auto audioZones = carAudioConfigurationType.getFirstZones();
+
+    std::string message =
+            parseAudioZones(audioZones, context, activations, mFadeConfigurations, mAudioZones);
+
+    // Assign dynamic configuration if not assigned
+    if (!mAudioZones.empty() && mAudioDeviceConfiguration.routingConfig ==
+                                        api::RoutingDeviceConfiguration::DEFAULT_AUDIO_ROUTING) {
+        mAudioDeviceConfiguration.routingConfig =
+                api::RoutingDeviceConfiguration::DYNAMIC_AUDIO_ROUTING;
+    }
+
+    if (message.empty()) {
+        return;
+    }
+    mParseErrors =
+            "Error parsing audio zone(s) in file " + mAudioConfigFile + ", message: " + message;
+    LOG(ERROR) << __func__ << " Error parsing zones: " << message;
+    initNonDynamicRouting();
+}
+
+api::AudioDeviceConfiguration CarAudioConfigurationXmlConverter::getAudioDeviceConfiguration()
+        const {
+    return mAudioDeviceConfiguration;
+}
+
+std::vector<api::AudioZone> CarAudioConfigurationXmlConverter::getAudioZones() const {
+    return mAudioZones;
+}
+
+std::vector<::aidl::android::media::audio::common::AudioPort>
+CarAudioConfigurationXmlConverter::getOutputMirroringDevices() const {
+    return mOutputMirroringDevices;
+}
+
+}  // namespace internal
+}  // namespace audiocontrol
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/automotive/audiocontrol/aidl/default/converter/test/Android.bp b/automotive/audiocontrol/aidl/default/converter/test/Android.bp
new file mode 100644
index 0000000..70d4a20
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/converter/test/Android.bp
@@ -0,0 +1,63 @@
+// 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_aaos_framework",
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+filegroup {
+    name: "simple_car_audio_configuration_xml",
+    srcs: [
+        "simple_car_audio_configuration.xml",
+        "simple_car_audio_configuration_with_device_type.xml",
+        "multi_zone_car_audio_configuration.xml",
+        "car_audio_configuration_without_configuration.xml",
+        "car_audio_configuration_with_default_context.xml",
+        "car_audio_configuration_with_missing_zones.xml",
+        "car_audio_configuration_without_audio_zone.xml",
+        "car_audio_fade_configuration.xml",
+    ],
+}
+
+cc_test {
+    name: "AudioControlConverterUnitTest",
+    vendor: true,
+    require_root: true,
+    srcs: ["*.cpp"],
+    stl: "libc++_static",
+    static_libs: [
+        "libbase",
+        "android.hardware.audiocontrol.internal",
+        "libgtest",
+        "libgmock",
+        "libutils",
+        "libaudio_aidl_conversion_common_ndk",
+    ],
+    shared_libs: ["liblog"],
+    defaults: [
+        "latest_android_hardware_audio_common_ndk_static",
+        "car.audio.configuration.xsd.default",
+        "car.fade.configuration.xsd.default",
+        "latest_android_hardware_automotive_audiocontrol_ndk_static",
+        "latest_android_media_audio_common_types_ndk_static",
+    ],
+    data: [
+        ":simple_car_audio_configuration_xml",
+    ],
+    test_suites: ["device-tests"],
+    exclude_shared_libs: [
+        "android.hardware.automotive.audiocontrol-V5-ndk",
+    ],
+}
diff --git a/automotive/audiocontrol/aidl/default/converter/test/AudioControlConverterUnitTest.cpp b/automotive/audiocontrol/aidl/default/converter/test/AudioControlConverterUnitTest.cpp
new file mode 100644
index 0000000..b6bebe5
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/converter/test/AudioControlConverterUnitTest.cpp
@@ -0,0 +1,834 @@
+/*
+ * 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-base/file.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include <CarAudioConfigurationXmlConverter.h>
+#include <aidl/android/hardware/automotive/audiocontrol/AudioDeviceConfiguration.h>
+
+namespace converter = ::android::hardware::audiocontrol::internal;
+namespace api = ::aidl::android::hardware::automotive::audiocontrol;
+
+using ::testing::ContainsRegex;
+using ::testing::UnorderedElementsAreArray;
+
+namespace {
+
+using ::aidl::android::media::audio::common::AudioAttributes;
+using ::aidl::android::media::audio::common::AudioContentType;
+using ::aidl::android::media::audio::common::AudioDevice;
+using ::aidl::android::media::audio::common::AudioDeviceAddress;
+using ::aidl::android::media::audio::common::AudioDeviceDescription;
+using ::aidl::android::media::audio::common::AudioDeviceType;
+using ::aidl::android::media::audio::common::AudioPort;
+using ::aidl::android::media::audio::common::AudioPortDeviceExt;
+using ::aidl::android::media::audio::common::AudioPortExt;
+using ::aidl::android::media::audio::common::AudioUsage;
+
+std::string getTestFilePath(const std::string& filename) {
+    static std::string baseDir = android::base::GetExecutableDirectory();
+    return baseDir + "/" + filename;
+}
+
+AudioAttributes createAudioAttributes(const AudioUsage& usage,
+                                      const AudioContentType& type = AudioContentType::UNKNOWN,
+                                      const std::string tags = "") {
+    AudioAttributes attributes;
+    attributes.usage = usage;
+    attributes.contentType = type;
+    if (!tags.empty()) {
+        attributes.tags.push_back(tags);
+    }
+    return attributes;
+}
+
+api::AudioZoneContextInfo createContextInfo(const std::string& name,
+                                            const std::vector<AudioAttributes>& attributes,
+                                            const int id = -1) {
+    api::AudioZoneContextInfo info;
+    info.name = name;
+    if (id != -1) {
+        info.id = id;
+    }
+    for (const auto& attribute : attributes) {
+        info.audioAttributes.push_back(attribute);
+    }
+    return info;
+}
+
+api::AudioZoneContextInfo createContextInfo(const std::string& name,
+                                            const std::vector<AudioUsage>& usages,
+                                            const int id = -1) {
+    std::vector<AudioAttributes> attributes;
+    attributes.reserve(usages.size());
+    for (const auto& usage : usages) {
+        attributes.push_back(createAudioAttributes(usage));
+    }
+    return createContextInfo(name, attributes, id);
+}
+
+AudioPort createAudioPort(const std::string& address, const AudioDeviceType& type,
+                          const std::string& connection = "") {
+    AudioPort port;
+    AudioDevice device;
+    device.address = AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(address);
+
+    AudioDeviceDescription description;
+    description.type = type;
+    description.connection = connection;
+    device.type = description;
+
+    port.ext = AudioPortExt::make<AudioPortExt::Tag::device>(device);
+
+    return port;
+}
+
+api::DeviceToContextEntry createRoutes(const AudioPort& port,
+                                       const std::vector<std::string>& contexts) {
+    api::DeviceToContextEntry entry;
+    entry.device = port;
+    entry.contextNames = contexts;
+    return entry;
+}
+
+api::VolumeGroupConfig createVolumeGroup(const std::string& name,
+                                         const api::VolumeActivationConfiguration& activation,
+                                         const std::vector<api::DeviceToContextEntry>& routes) {
+    api::VolumeGroupConfig config;
+    config.name = name;
+    config.activationConfiguration = activation;
+    config.carAudioRoutes = routes;
+    return config;
+}
+
+api::AudioZoneConfig createAudioZoneConfig(const std::string& name,
+                                           const api::AudioZoneFadeConfiguration& fadeConfiguration,
+                                           const std::vector<api::VolumeGroupConfig>& groups,
+                                           bool isDefault = false) {
+    api::AudioZoneConfig config;
+    config.name = name;
+    config.isDefault = isDefault;
+    config.volumeGroups = groups;
+    config.fadeConfiguration = fadeConfiguration;
+    return config;
+}
+
+api::VolumeActivationConfiguration createVolumeActivation(const std::string& name,
+                                                          const api::VolumeInvocationType& type,
+                                                          int minVolume, int maxVolume) {
+    api::VolumeActivationConfiguration activation;
+    activation.name = name;
+    api::VolumeActivationConfigurationEntry entry;
+    entry.maxActivationVolumePercentage = maxVolume;
+    entry.minActivationVolumePercentage = minVolume;
+    entry.type = type;
+    activation.volumeActivationEntries.push_back(entry);
+
+    return activation;
+}
+
+api::FadeConfiguration createFadeConfiguration(const long& fadeDurationsMillis,
+                                               const AudioAttributes& audioAttributes) {
+    api::FadeConfiguration configuration;
+    configuration.fadeDurationMillis = fadeDurationsMillis;
+    configuration.audioAttributesOrUsage
+            .set<api::FadeConfiguration::AudioAttributesOrUsage::Tag::fadeAttribute>(
+                    audioAttributes);
+    return configuration;
+}
+
+api::FadeConfiguration createFadeConfiguration(const long& fadeDurationsMillis,
+                                               const AudioUsage& audioUsage) {
+    api::FadeConfiguration configuration;
+    configuration.fadeDurationMillis = fadeDurationsMillis;
+    configuration.audioAttributesOrUsage
+            .set<api::FadeConfiguration::AudioAttributesOrUsage::Tag::usage>(audioUsage);
+    return configuration;
+}
+
+api::AudioFadeConfiguration createAudioFadeConfiguration(
+        const std::string& name, const api::FadeState& state,
+        const std::vector<AudioUsage>& fadeableUsages = std::vector<AudioUsage>(),
+        const std::optional<std::vector<AudioContentType>>& unfadeableContentTypes = std::nullopt,
+        const std::vector<AudioAttributes> unfadeableAudioAttributes =
+                std::vector<AudioAttributes>(),
+        const std::vector<api::FadeConfiguration> fadeOutConfigurations =
+                std::vector<api::FadeConfiguration>(),
+        const std::vector<api::FadeConfiguration> fadeInConfigurations =
+                std::vector<api::FadeConfiguration>(),
+        const long& fadeOutDurationMs = api::AudioFadeConfiguration::DEFAULT_FADE_OUT_DURATION_MS,
+        const long& fadeInDurationMs = api::AudioFadeConfiguration::DEFAULT_FADE_IN_DURATION_MS,
+        const long& fadeInDelayedForOffendersMs =
+                api::AudioFadeConfiguration::DEFAULT_DELAY_FADE_IN_OFFENDERS_MS) {
+    api::AudioFadeConfiguration audioZoneFadeConfiguration;
+    audioZoneFadeConfiguration.name = name;
+    audioZoneFadeConfiguration.fadeInDurationMs = fadeInDurationMs;
+    audioZoneFadeConfiguration.fadeOutDurationMs = fadeOutDurationMs;
+    audioZoneFadeConfiguration.fadeInDelayedForOffendersMs = fadeInDelayedForOffendersMs;
+    audioZoneFadeConfiguration.fadeState = state;
+    audioZoneFadeConfiguration.fadeableUsages = fadeableUsages;
+    audioZoneFadeConfiguration.unfadeableContentTypes = unfadeableContentTypes;
+    audioZoneFadeConfiguration.unfadableAudioAttributes = unfadeableAudioAttributes;
+    audioZoneFadeConfiguration.fadeOutConfigurations = fadeOutConfigurations;
+    audioZoneFadeConfiguration.fadeInConfigurations = fadeInConfigurations;
+
+    return audioZoneFadeConfiguration;
+}
+
+api::TransientFadeConfigurationEntry createTransientFadeConfiguration(
+        const api::AudioFadeConfiguration& fadeConfig, const std::vector<AudioUsage>& usages) {
+    api::TransientFadeConfigurationEntry entry;
+    entry.transientFadeConfiguration = fadeConfig;
+    entry.transientUsages = usages;
+    return entry;
+}
+
+api::AudioZoneFadeConfiguration createAudioZoneFadeConfiguration(
+        const api::AudioFadeConfiguration& defaultConfig,
+        const std::vector<api::TransientFadeConfigurationEntry>& transientConfigs) {
+    api::AudioZoneFadeConfiguration zoneFadeConfiguration;
+    zoneFadeConfiguration.defaultConfiguration = defaultConfig;
+    zoneFadeConfiguration.transientConfiguration = transientConfigs;
+    return zoneFadeConfiguration;
+}
+
+api::AudioZone createAudioZone(const std::string& name, const int zoneId,
+                               const std::vector<api::AudioZoneContextInfo>& contexts,
+                               const std::vector<api::AudioZoneConfig>& configs) {
+    api::AudioZone zone;
+    zone.name = name;
+    zone.id = zoneId;
+    zone.occupantZoneId = zoneId;
+    zone.audioZoneContext.audioContextInfos = contexts;
+    zone.audioZoneConfigs = configs;
+    return zone;
+}
+
+const std::vector<AudioUsage> kFadeableUsages = {AudioUsage::MEDIA,
+                                                 AudioUsage::GAME,
+                                                 AudioUsage::ASSISTANCE_SONIFICATION,
+                                                 AudioUsage::ASSISTANCE_ACCESSIBILITY,
+                                                 AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE,
+                                                 AudioUsage::ASSISTANT,
+                                                 AudioUsage::NOTIFICATION,
+                                                 AudioUsage::ANNOUNCEMENT};
+
+const std::vector<AudioAttributes> kUnfadeableAudioAttributes = {
+        createAudioAttributes(AudioUsage::MEDIA, AudioContentType::UNKNOWN, "oem_specific_tag1")};
+
+const std::vector<api::FadeConfiguration> kFadeOutConfigurations = {
+        createFadeConfiguration(
+                500, createAudioAttributes(AudioUsage::ASSISTANT, AudioContentType::UNKNOWN,
+                                           "oem_specific_tag2")),
+        createFadeConfiguration(500, AudioUsage::MEDIA),
+        createFadeConfiguration(500, AudioUsage::GAME),
+        createFadeConfiguration(800, AudioUsage::ASSISTANCE_SONIFICATION),
+        createFadeConfiguration(800, AudioUsage::ASSISTANCE_ACCESSIBILITY),
+        createFadeConfiguration(800, AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE),
+        createFadeConfiguration(800, AudioUsage::ASSISTANT),
+        createFadeConfiguration(800, AudioUsage::ANNOUNCEMENT),
+};
+
+const std::vector<api::FadeConfiguration> kFadeInConfigurations = {
+        createFadeConfiguration(
+                1000, createAudioAttributes(AudioUsage::ASSISTANT, AudioContentType::UNKNOWN,
+                                            "oem_specific_tag2")),
+        createFadeConfiguration(1000, AudioUsage::MEDIA),
+        createFadeConfiguration(1000, AudioUsage::GAME),
+        createFadeConfiguration(800, AudioUsage::ASSISTANCE_SONIFICATION),
+        createFadeConfiguration(800, AudioUsage::ASSISTANCE_ACCESSIBILITY),
+        createFadeConfiguration(800, AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE),
+        createFadeConfiguration(800, AudioUsage::ASSISTANT),
+        createFadeConfiguration(800, AudioUsage::ANNOUNCEMENT),
+};
+
+const api::AudioFadeConfiguration kRelaxedFading = createAudioFadeConfiguration(
+        "relaxed fading", api::FadeState::FADE_STATE_ENABLED_DEFAULT, kFadeableUsages,
+        std::optional<std::vector<AudioContentType>>(
+                {AudioContentType::SPEECH, AudioContentType::SONIFICATION}),
+        kUnfadeableAudioAttributes, kFadeOutConfigurations, kFadeInConfigurations, 800, 500, 10000);
+
+const std::vector<AudioAttributes> kAggressiveUnfadeableAudioAttributes = {
+        createAudioAttributes(AudioUsage::MEDIA, AudioContentType::UNKNOWN, "oem_specific_tag1"),
+        createAudioAttributes(AudioUsage::ASSISTANT, AudioContentType::UNKNOWN,
+                              "oem_projection_service"),
+};
+
+const std::vector<api::FadeConfiguration> kAggressiveFadeOutConfigurations = {
+        createFadeConfiguration(150, AudioUsage::MEDIA),
+        createFadeConfiguration(150, AudioUsage::GAME),
+        createFadeConfiguration(400, AudioUsage::ASSISTANCE_SONIFICATION),
+        createFadeConfiguration(400, AudioUsage::ASSISTANCE_ACCESSIBILITY),
+        createFadeConfiguration(400, AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE),
+        createFadeConfiguration(400, AudioUsage::ASSISTANT),
+        createFadeConfiguration(400, AudioUsage::ANNOUNCEMENT),
+};
+
+const std::vector<api::FadeConfiguration> kAggressiveFadeInConfigurations = {
+        createFadeConfiguration(300, AudioUsage::MEDIA),
+        createFadeConfiguration(300, AudioUsage::GAME),
+        createFadeConfiguration(550, AudioUsage::ASSISTANCE_SONIFICATION),
+        createFadeConfiguration(550, AudioUsage::ASSISTANCE_ACCESSIBILITY),
+        createFadeConfiguration(550, AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE),
+        createFadeConfiguration(550, AudioUsage::ASSISTANT),
+        createFadeConfiguration(550, AudioUsage::ANNOUNCEMENT),
+};
+
+const api::AudioFadeConfiguration kAggressiveFading = createAudioFadeConfiguration(
+        "aggressive fading", api::FadeState::FADE_STATE_ENABLED_DEFAULT, kFadeableUsages,
+        std::optional<std::vector<AudioContentType>>(
+                {AudioContentType::SPEECH, AudioContentType::MUSIC}),
+        kAggressiveUnfadeableAudioAttributes, kAggressiveFadeOutConfigurations,
+        kAggressiveFadeInConfigurations);
+
+const api::AudioFadeConfiguration kDisabledFading =
+        createAudioFadeConfiguration("disabled fading", api::FadeState::FADE_STATE_DISABLED);
+
+const std::vector<api::FadeConfiguration> kDynamicFadeOutConfigurations = {
+        createFadeConfiguration(
+                500, createAudioAttributes(AudioUsage::ASSISTANT, AudioContentType::UNKNOWN,
+                                           "oem_specific_tag2")),
+        createFadeConfiguration(800, AudioUsage::ASSISTANCE_SONIFICATION),
+        createFadeConfiguration(800, AudioUsage::ASSISTANCE_ACCESSIBILITY),
+        createFadeConfiguration(800, AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE),
+        createFadeConfiguration(800, AudioUsage::ASSISTANT),
+        createFadeConfiguration(800, AudioUsage::ANNOUNCEMENT),
+};
+
+const std::vector<api::FadeConfiguration> kDynamicFadeInConfigurations = {
+        createFadeConfiguration(
+                1000, createAudioAttributes(AudioUsage::ASSISTANT, AudioContentType::UNKNOWN,
+                                            "oem_specific_tag2")),
+        createFadeConfiguration(800, AudioUsage::ASSISTANCE_SONIFICATION),
+        createFadeConfiguration(800, AudioUsage::ASSISTANCE_ACCESSIBILITY),
+        createFadeConfiguration(800, AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE),
+        createFadeConfiguration(800, AudioUsage::ASSISTANT),
+        createFadeConfiguration(800, AudioUsage::ANNOUNCEMENT),
+};
+
+const api::AudioFadeConfiguration kDynamicFading = createAudioFadeConfiguration(
+        "dynamic fading", api::FadeState::FADE_STATE_ENABLED_DEFAULT, kFadeableUsages,
+        std::optional<std::vector<AudioContentType>>(
+                {AudioContentType::SPEECH, AudioContentType::MOVIE}),
+        kUnfadeableAudioAttributes, kDynamicFadeOutConfigurations, kDynamicFadeInConfigurations,
+        800, 500);
+
+const api::AudioZoneFadeConfiguration kDefaultAudioConfigFading = createAudioZoneFadeConfiguration(
+        kRelaxedFading,
+        {createTransientFadeConfiguration(
+                 kAggressiveFading, {AudioUsage::VOICE_COMMUNICATION, AudioUsage::ANNOUNCEMENT,
+                                     AudioUsage::VEHICLE_STATUS, AudioUsage::SAFETY}),
+         createTransientFadeConfiguration(kDisabledFading, {AudioUsage::EMERGENCY})});
+
+const api::AudioZoneFadeConfiguration kDynamicDeviceAudioConfigFading =
+        createAudioZoneFadeConfiguration(
+                kDynamicFading,
+                {createTransientFadeConfiguration(
+                         kAggressiveFading,
+                         {AudioUsage::VOICE_COMMUNICATION, AudioUsage::ANNOUNCEMENT,
+                          AudioUsage::VEHICLE_STATUS, AudioUsage::SAFETY}),
+                 createTransientFadeConfiguration(kDisabledFading, {AudioUsage::EMERGENCY})});
+
+const api::AudioZoneContextInfo kMusicContextInfo =
+        createContextInfo("oem_music", {AudioUsage::MEDIA, AudioUsage::GAME, AudioUsage::UNKNOWN});
+const api::AudioZoneContextInfo kNotificationContextInfo = createContextInfo(
+        "oem_notification", {AudioUsage::NOTIFICATION, AudioUsage::NOTIFICATION_EVENT});
+const api::AudioZoneContextInfo kVoiceContextInfo = createContextInfo(
+        "oem_voice_command", {AudioUsage::ASSISTANT, AudioUsage::ASSISTANCE_ACCESSIBILITY,
+                              AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE});
+const api::AudioZoneContextInfo kCallContextInfo =
+        createContextInfo("oem_call", {AudioUsage::VOICE_COMMUNICATION, AudioUsage::CALL_ASSISTANT,
+                                       AudioUsage::VOICE_COMMUNICATION_SIGNALLING});
+const api::AudioZoneContextInfo kRingContextInfo =
+        createContextInfo("oem_call_ring", {AudioUsage::NOTIFICATION_TELEPHONY_RINGTONE});
+const api::AudioZoneContextInfo kAlarmContextInfo =
+        createContextInfo("oem_alarm", {AudioUsage::ALARM});
+const api::AudioZoneContextInfo kSystemContextInfo = createContextInfo(
+        "oem_system_sound",
+        {AudioUsage::ASSISTANCE_SONIFICATION, AudioUsage::EMERGENCY, AudioUsage::SAFETY,
+         AudioUsage::VEHICLE_STATUS, AudioUsage::ANNOUNCEMENT});
+const api::AudioZoneContextInfo kOemContextInfo = createContextInfo(
+        "oem_context", {createAudioAttributes(AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE,
+                                              AudioContentType::SPEECH, "oem=extension_8675309")});
+
+const std::vector<api::AudioZoneContextInfo> kSimpleCarAudioConfigurationContext = {
+        kOemContextInfo,  kMusicContextInfo, kNotificationContextInfo, kVoiceContextInfo,
+        kCallContextInfo, kRingContextInfo,  kAlarmContextInfo,        kSystemContextInfo};
+
+const api::AudioZoneContextInfo kDefaultMusicContextInfo =
+        createContextInfo("music", {AudioUsage::UNKNOWN, AudioUsage::MEDIA, AudioUsage::GAME}, 1);
+const api::AudioZoneContextInfo kDefaultNavContextInfo =
+        createContextInfo("navigation", {AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE}, 2);
+const api::AudioZoneContextInfo kDefaultVoiceContextInfo = createContextInfo(
+        "voice_command", {AudioUsage::ASSISTANCE_ACCESSIBILITY, AudioUsage::ASSISTANT}, 3);
+const api::AudioZoneContextInfo kDefaultRingContextInfo =
+        createContextInfo("call_ring", {AudioUsage::NOTIFICATION_TELEPHONY_RINGTONE}, 4);
+const api::AudioZoneContextInfo kDefaultCallContextInfo =
+        createContextInfo("call",
+                          {AudioUsage::VOICE_COMMUNICATION, AudioUsage::CALL_ASSISTANT,
+                           AudioUsage::VOICE_COMMUNICATION_SIGNALLING},
+                          5);
+const api::AudioZoneContextInfo kDefaultAlarmContextInfo =
+        createContextInfo("alarm", {AudioUsage::ALARM}, 6);
+const api::AudioZoneContextInfo kDefaultNotificationContextInfo = createContextInfo(
+        "notification", {AudioUsage::NOTIFICATION, AudioUsage::NOTIFICATION_EVENT}, 7);
+const api::AudioZoneContextInfo kDefaultSystemContextInfo =
+        createContextInfo("system_sound", {AudioUsage::ASSISTANCE_SONIFICATION}, 8);
+const api::AudioZoneContextInfo kDefaultEmergencyContextInfo =
+        createContextInfo("emergency", {AudioUsage::EMERGENCY}, 9);
+const api::AudioZoneContextInfo kDefaultSafetyContextInfo =
+        createContextInfo("safety", {AudioUsage::SAFETY}, 10);
+const api::AudioZoneContextInfo kDefaultVehicleStatusContextInfo =
+        createContextInfo("vehicle_status", {AudioUsage::VEHICLE_STATUS}, 11);
+const api::AudioZoneContextInfo kDefaultAnnouncementContextInfo =
+        createContextInfo("announcement", {AudioUsage::ANNOUNCEMENT}, 12);
+
+const std::vector<api::AudioZoneContextInfo> kDefaultCarAudioConfigurationContext = {
+        kDefaultMusicContextInfo,         kDefaultNavContextInfo,
+        kDefaultVoiceContextInfo,         kDefaultRingContextInfo,
+        kDefaultCallContextInfo,          kDefaultAlarmContextInfo,
+        kDefaultNotificationContextInfo,  kDefaultSystemContextInfo,
+        kDefaultEmergencyContextInfo,     kDefaultSafetyContextInfo,
+        kDefaultVehicleStatusContextInfo, kDefaultAnnouncementContextInfo};
+
+const api::VolumeActivationConfiguration kOnBootVolumeActivation =
+        createVolumeActivation("on_boot_config", api::VolumeInvocationType::ON_BOOT, 0, 80);
+const api::VolumeActivationConfiguration kOnSourceVolumeActivation = createVolumeActivation(
+        "on_source_changed_config", api::VolumeInvocationType::ON_SOURCE_CHANGED, 20, 80);
+const api::VolumeActivationConfiguration kOnPlayVolumeActivation = createVolumeActivation(
+        "on_playback_changed_config", api::VolumeInvocationType::ON_PLAYBACK_CHANGED, 10, 90);
+
+const AudioPort kBusMediaDevice = createAudioPort("BUS00_MEDIA", AudioDeviceType::OUT_BUS);
+const AudioPort kBTMediaDevice = createAudioPort("temp", AudioDeviceType::OUT_DEVICE, "bt-a2dp");
+const AudioPort kUSBMediaDevice = createAudioPort("", AudioDeviceType::OUT_HEADSET, "usb");
+
+const AudioPort kBusNavDevice = createAudioPort("BUS02_NAV_GUIDANCE", AudioDeviceType::OUT_BUS);
+const AudioPort kBusPhoneDevice = createAudioPort("BUS03_PHONE", AudioDeviceType::OUT_BUS);
+const AudioPort kBusSysDevice = createAudioPort("BUS01_SYS_NOTIFICATION", AudioDeviceType::OUT_BUS);
+
+const AudioPort kMirrorDevice1 = createAudioPort("mirror_bus_device_1", AudioDeviceType::OUT_BUS);
+const AudioPort kMirrorDevice2 = createAudioPort("mirror_bus_device_2", AudioDeviceType::OUT_BUS);
+const std::vector<AudioPort> kMirroringDevices = {kMirrorDevice1, kMirrorDevice2};
+
+const AudioPort kMirrorDeviceThree =
+        createAudioPort("mirror_bus_device_three", AudioDeviceType::OUT_BUS);
+const AudioPort kMirrorDeviceFour =
+        createAudioPort("mirror_bus_device_four", AudioDeviceType::OUT_BUS);
+const std::vector<AudioPort> kMultiZoneMirroringDevices = {kMirrorDeviceThree, kMirrorDeviceFour};
+
+const AudioPort kInFMTunerDevice = createAudioPort("fm_tuner", AudioDeviceType::IN_FM_TUNER);
+const AudioPort kInMicDevice = createAudioPort("built_in_mic", AudioDeviceType::IN_MICROPHONE);
+const AudioPort kInBusDevice = createAudioPort("in_bus_device", AudioDeviceType::IN_BUS);
+const std::vector<AudioPort> kInputDevices{kInFMTunerDevice, kInMicDevice, kInBusDevice};
+
+const api::VolumeGroupConfig kBusMediaVolumeGroup = createVolumeGroup(
+        "entertainment", kOnBootVolumeActivation, {createRoutes(kBusMediaDevice, {"oem_music"})});
+const api::VolumeGroupConfig kUSBMediaVolumeGroup = createVolumeGroup(
+        "entertainment", kOnBootVolumeActivation, {createRoutes(kUSBMediaDevice, {"oem_music"})});
+const api::VolumeGroupConfig kBTMediaVolumeGroup = createVolumeGroup(
+        "entertainment", kOnBootVolumeActivation, {createRoutes(kBTMediaDevice, {"oem_music"})});
+const api::VolumeGroupConfig kBusNavVolumeGroup =
+        createVolumeGroup("navvoicecommand", kOnSourceVolumeActivation,
+                          {createRoutes(kBusNavDevice, {"oem_voice_command"})});
+const api::VolumeGroupConfig kBusCallVolumeGroup =
+        createVolumeGroup("telringvol", kOnPlayVolumeActivation,
+                          {createRoutes(kBusPhoneDevice, {"oem_call", "oem_call_ring"})});
+const api::VolumeGroupConfig kBusSysVolumeGroup = createVolumeGroup(
+        "systemalarm", kOnSourceVolumeActivation,
+        {createRoutes(kBusSysDevice, {"oem_alarm", "oem_system_sound", "oem_notification"})});
+
+const api::AudioZoneConfig kAllBusZoneConfig = createAudioZoneConfig(
+        "primary zone config 0", kDefaultAudioConfigFading,
+        {kBusMediaVolumeGroup, kBusNavVolumeGroup, kBusCallVolumeGroup, kBusSysVolumeGroup}, true);
+const api::AudioZoneConfig kBTMediaZoneConfig = createAudioZoneConfig(
+        "primary zone BT media", kDynamicDeviceAudioConfigFading,
+        {kBTMediaVolumeGroup, kBusNavVolumeGroup, kBusCallVolumeGroup, kBusSysVolumeGroup});
+const api::AudioZoneConfig kUsBMediaZoneConfig = createAudioZoneConfig(
+        "primary zone USB media", kDynamicDeviceAudioConfigFading,
+        {kUSBMediaVolumeGroup, kBusNavVolumeGroup, kBusCallVolumeGroup, kBusSysVolumeGroup});
+
+const std::unordered_map<std::string, api::AudioZoneConfig> kConfigNameToZoneConfig = {
+        {kAllBusZoneConfig.name, kAllBusZoneConfig},
+        {kBTMediaZoneConfig.name, kBTMediaZoneConfig},
+        {kUsBMediaZoneConfig.name, kUsBMediaZoneConfig},
+};
+
+const api::AudioZoneConfig kDriverZoneConfig = createAudioZoneConfig(
+        "driver zone config 0", kDefaultAudioConfigFading,
+        {kBusMediaVolumeGroup, kBusNavVolumeGroup, kBusCallVolumeGroup, kBusSysVolumeGroup}, true);
+
+const api::AudioZone kDriverZone =
+        createAudioZone("driver zone", api::AudioZone::PRIMARY_AUDIO_ZONE,
+                        kSimpleCarAudioConfigurationContext, {kDriverZoneConfig});
+
+const api::AudioZoneFadeConfiguration kZoneAudioConfigFading = createAudioZoneFadeConfiguration(
+        kRelaxedFading,
+        {createTransientFadeConfiguration(kDisabledFading, {AudioUsage::EMERGENCY})});
+
+const AudioPort kBusFrontDevice = createAudioPort("BUS_FRONT", AudioDeviceType::OUT_BUS);
+const api::VolumeGroupConfig kFrontVolumeGroup = createVolumeGroup(
+        "entertainment", kOnBootVolumeActivation,
+        {createRoutes(kBusFrontDevice,
+                      {"oem_music", "oem_voice_command", "oem_call", "oem_call_ring", "oem_alarm",
+                       "oem_system_sound", "oem_notification"})});
+const api::AudioZoneConfig kFrontZoneConfig = createAudioZoneConfig(
+        "front passenger config 0", kZoneAudioConfigFading, {kFrontVolumeGroup}, true);
+const api::AudioZone kFrontZone =
+        createAudioZone("front passenger zone", api::AudioZone::PRIMARY_AUDIO_ZONE + 1,
+                        kSimpleCarAudioConfigurationContext, {kFrontZoneConfig});
+
+const AudioPort kBusRearDevice = createAudioPort("BUS_REAR", AudioDeviceType::OUT_BUS);
+const api::VolumeGroupConfig kRearVolumeGroup =
+        createVolumeGroup("entertainment", kOnBootVolumeActivation,
+                          {createRoutes(kBusRearDevice, {"oem_music", "oem_voice_command",
+                                                         "oem_call", "oem_call_ring", "oem_alarm",
+                                                         "oem_system_sound", "oem_notification"})});
+const api::AudioZoneConfig kRearZoneConfig = createAudioZoneConfig(
+        "rear seat config 0", kZoneAudioConfigFading, {kRearVolumeGroup}, true);
+const api::AudioZone kRearZone =
+        createAudioZone("rear seat zone", api::AudioZone::PRIMARY_AUDIO_ZONE + 2,
+                        kSimpleCarAudioConfigurationContext, {kRearZoneConfig});
+
+std::vector<api::AudioZone> kMultiZones = {kDriverZone, kFrontZone, kRearZone};
+
+void expectSameFadeConfiguration(const api::AudioFadeConfiguration& actual,
+                                 const api::AudioFadeConfiguration& expected,
+                                 const std::string& configName) {
+    EXPECT_EQ(actual.name, expected.name) << "Audio fade configuration for config " << configName;
+    const std::string fadeConfigInfo =
+            "fade config " + actual.name + " in config name " + configName;
+    EXPECT_EQ(actual.fadeState, expected.fadeState)
+            << "Audio fade config state for " << fadeConfigInfo;
+    EXPECT_EQ(actual.fadeInDurationMs, expected.fadeInDurationMs)
+            << "Audio fade in duration for " << fadeConfigInfo;
+    EXPECT_EQ(actual.fadeOutDurationMs, expected.fadeOutDurationMs)
+            << "Audio fade out duration for " << fadeConfigInfo;
+    EXPECT_EQ(actual.fadeInDelayedForOffendersMs, expected.fadeInDelayedForOffendersMs)
+            << "Audio fade in delayed for offenders duration for " << fadeConfigInfo;
+    EXPECT_THAT(actual.fadeableUsages, UnorderedElementsAreArray(expected.fadeableUsages))
+            << "Fadeable usages for " << fadeConfigInfo;
+    EXPECT_TRUE(actual.unfadeableContentTypes.has_value() ==
+                expected.unfadeableContentTypes.has_value())
+            << "Optional unfadeable for " << fadeConfigInfo;
+    if (actual.unfadeableContentTypes.has_value() && expected.unfadeableContentTypes.has_value()) {
+        EXPECT_THAT(actual.unfadeableContentTypes.value(),
+                    UnorderedElementsAreArray(expected.unfadeableContentTypes.value()))
+                << "Unfadeable content type for " << fadeConfigInfo;
+    }
+    EXPECT_THAT(actual.unfadableAudioAttributes,
+                UnorderedElementsAreArray(expected.unfadableAudioAttributes))
+            << "Unfadeable audio attributes type for " << fadeConfigInfo;
+    EXPECT_THAT(actual.fadeOutConfigurations,
+                UnorderedElementsAreArray(expected.fadeOutConfigurations))
+            << "Fade-out configurations for " << fadeConfigInfo;
+    EXPECT_THAT(actual.fadeInConfigurations,
+                UnorderedElementsAreArray(expected.fadeInConfigurations))
+            << "Fade-in configurations for " << fadeConfigInfo;
+}
+
+void expectSameAudioZoneFadeConfiguration(
+        const std::optional<api::AudioZoneFadeConfiguration>& actual,
+        const std::optional<api::AudioZoneFadeConfiguration>& expected,
+        const std::string& configName) {
+    if (!actual.has_value() || !expected.has_value()) {
+        EXPECT_EQ(actual.has_value(), expected.has_value())
+                << "Audio zone config " << configName << " fade configuration missing";
+        return;
+    }
+    const api::AudioZoneFadeConfiguration& actualConfig = actual.value();
+    const api::AudioZoneFadeConfiguration& expectedConfig = expected.value();
+    expectSameFadeConfiguration(actualConfig.defaultConfiguration,
+                                expectedConfig.defaultConfiguration, configName);
+    EXPECT_THAT(actualConfig.transientConfiguration,
+                UnorderedElementsAreArray(expectedConfig.transientConfiguration))
+            << "Transient fade configuration for config " << configName;
+}
+
+void expectSameAudioZoneConfiguration(const api::AudioZoneConfig& actual,
+                                      const api::AudioZoneConfig& expected) {
+    EXPECT_EQ(actual.isDefault, expected.isDefault)
+            << "Zone default's status do not match for config " << actual.name;
+    EXPECT_THAT(actual.volumeGroups, UnorderedElementsAreArray(expected.volumeGroups))
+            << "Volume groups for config " << actual.name;
+    expectSameAudioZoneFadeConfiguration(actual.fadeConfiguration, expected.fadeConfiguration,
+                                         actual.name);
+}
+
+class CarAudioConfigurationTest : public testing::Test {
+  protected:
+    void SetUp() override;
+    void TearDown() override;
+
+    std::unique_ptr<converter::CarAudioConfigurationXmlConverter> converter;
+
+  protected:
+    virtual std::string getCarAudioConfiguration() = 0;
+    virtual std::string getCarFadeConfiguration() = 0;
+};
+
+void CarAudioConfigurationTest::SetUp() {
+    converter = std::make_unique<converter::CarAudioConfigurationXmlConverter>(
+            getTestFilePath(getCarAudioConfiguration()),
+            getTestFilePath(getCarFadeConfiguration()));
+}
+
+void CarAudioConfigurationTest::TearDown() {
+    converter.reset();
+}
+
+class SimpleCarAudioConfigurationTest : public CarAudioConfigurationTest {
+    virtual std::string getCarAudioConfiguration() { return "simple_car_audio_configuration.xml"; }
+
+    virtual std::string getCarFadeConfiguration() { return "car_audio_fade_configuration.xml"; }
+};
+
+TEST_F(SimpleCarAudioConfigurationTest, TestLoadSimpleConfiguration) {
+    EXPECT_EQ(converter->getErrors(), "");
+
+    const auto audioDeviceConfigs = converter->getAudioDeviceConfiguration();
+    EXPECT_EQ(audioDeviceConfigs.routingConfig,
+              api::RoutingDeviceConfiguration::DYNAMIC_AUDIO_ROUTING);
+    EXPECT_FALSE(audioDeviceConfigs.useCoreAudioVolume);
+    EXPECT_TRUE(audioDeviceConfigs.useHalDuckingSignals);
+    EXPECT_TRUE(audioDeviceConfigs.useCarVolumeGroupMuting);
+
+    const auto& mirroringDevices = converter->getOutputMirroringDevices();
+
+    EXPECT_EQ(mirroringDevices.size(), 2) << "Mirroring device size";
+    for (const auto& mirroringDevice : mirroringDevices) {
+        const auto& it =
+                std::find(kMirroringDevices.begin(), kMirroringDevices.end(), mirroringDevice);
+        EXPECT_TRUE(it != kMirroringDevices.end())
+                << "Mirroring device not found " << mirroringDevice.toString();
+    }
+
+    const auto zones = converter->getAudioZones();
+    EXPECT_EQ(zones.size(), 1);
+
+    const auto& zone = zones.front();
+    EXPECT_EQ(zone.id, api::AudioZone::PRIMARY_AUDIO_ZONE);
+    EXPECT_EQ(zone.occupantZoneId, 0);
+    EXPECT_EQ(zone.name, "primary zone");
+
+    EXPECT_EQ(zone.audioZoneContext.audioContextInfos.size(),
+              kSimpleCarAudioConfigurationContext.size());
+    for (const auto& info : zone.audioZoneContext.audioContextInfos) {
+        const auto iterator = std::find(kSimpleCarAudioConfigurationContext.begin(),
+                                        kSimpleCarAudioConfigurationContext.end(), info);
+        EXPECT_TRUE(iterator != kSimpleCarAudioConfigurationContext.end())
+                << "Context name " << info.toString() << kMusicContextInfo.toString();
+    }
+
+    for (const auto& config : zone.audioZoneConfigs) {
+        const auto& iterator = kConfigNameToZoneConfig.find(config.name);
+        EXPECT_TRUE(iterator != kConfigNameToZoneConfig.end())
+                << "Zone config not found " << config.name;
+        expectSameAudioZoneConfiguration(config, iterator->second);
+    }
+
+    const auto& inputDevices = zone.inputAudioDevices;
+    EXPECT_EQ(inputDevices.size(), 3) << "Input devices";
+    for (const auto& inputDevice : inputDevices) {
+        const auto& it = std::find(kInputDevices.begin(), kInputDevices.end(), inputDevice);
+        EXPECT_TRUE(it != kInputDevices.end())
+                << "Input device " << inputDevice.toString() << " not found";
+    }
+}
+
+class TypeDeviceCarAudioConfigurationTest : public CarAudioConfigurationTest {
+    virtual std::string getCarAudioConfiguration() {
+        return "simple_car_audio_configuration_with_device_type.xml";
+    }
+
+    virtual std::string getCarFadeConfiguration() { return "car_audio_fade_configuration.xml"; }
+};
+
+TEST_F(TypeDeviceCarAudioConfigurationTest, TestLoadConfigurationWithDeviceType) {
+    EXPECT_EQ(converter->getErrors(), "");
+
+    const auto audioDeviceConfigs = converter->getAudioDeviceConfiguration();
+    EXPECT_EQ(audioDeviceConfigs.routingConfig,
+              api::RoutingDeviceConfiguration::DYNAMIC_AUDIO_ROUTING);
+    EXPECT_FALSE(audioDeviceConfigs.useCoreAudioVolume);
+    EXPECT_TRUE(audioDeviceConfigs.useHalDuckingSignals);
+    EXPECT_TRUE(audioDeviceConfigs.useCarVolumeGroupMuting);
+
+    const auto& mirroringDevices = converter->getOutputMirroringDevices();
+
+    EXPECT_EQ(mirroringDevices.size(), 2) << "Mirroring device size";
+    for (const auto& mirroringDevice : mirroringDevices) {
+        const auto& it =
+                std::find(kMirroringDevices.begin(), kMirroringDevices.end(), mirroringDevice);
+        EXPECT_TRUE(it != kMirroringDevices.end())
+                << "Mirroring device not found " << mirroringDevice.toString();
+    }
+
+    const auto zones = converter->getAudioZones();
+    EXPECT_EQ(zones.size(), 1);
+
+    const auto& zone = zones.front();
+    EXPECT_EQ(zone.id, api::AudioZone::PRIMARY_AUDIO_ZONE);
+    EXPECT_EQ(zone.occupantZoneId, 0);
+    EXPECT_EQ(zone.name, "primary zone");
+
+    EXPECT_EQ(zone.audioZoneContext.audioContextInfos.size(),
+              kSimpleCarAudioConfigurationContext.size());
+    for (const auto& info : zone.audioZoneContext.audioContextInfos) {
+        const auto iterator = std::find(kSimpleCarAudioConfigurationContext.begin(),
+                                        kSimpleCarAudioConfigurationContext.end(), info);
+        EXPECT_TRUE(iterator != kSimpleCarAudioConfigurationContext.end())
+                << "Context name " << info.toString() << kMusicContextInfo.toString();
+    }
+
+    for (const auto& config : zone.audioZoneConfigs) {
+        const auto& iterator = kConfigNameToZoneConfig.find(config.name);
+        EXPECT_TRUE(iterator != kConfigNameToZoneConfig.end())
+                << "Zone config not found " << config.name;
+        expectSameAudioZoneConfiguration(config, iterator->second);
+    }
+
+    const auto& inputDevices = zone.inputAudioDevices;
+    EXPECT_EQ(inputDevices.size(), 3) << "Input devices";
+    for (const auto& inputDevice : inputDevices) {
+        const auto& it = std::find(kInputDevices.begin(), kInputDevices.end(), inputDevice);
+        EXPECT_TRUE(it != kInputDevices.end())
+                << "Input device " << inputDevice.toString() << " not found";
+    }
+}
+
+class CarAudioConfigurationWithDefaultContextTest : public CarAudioConfigurationTest {
+    virtual std::string getCarAudioConfiguration() {
+        return "car_audio_configuration_with_default_context.xml";
+    }
+
+    virtual std::string getCarFadeConfiguration() { return ""; }
+};
+
+TEST_F(CarAudioConfigurationWithDefaultContextTest, TestLoadConfiguration) {
+    EXPECT_EQ(converter->getErrors(), "");
+    const auto& zones = converter->getAudioZones();
+    EXPECT_EQ(zones.size(), 1) << "Default audio context zones";
+    const auto& zone = zones.front();
+    const auto& context = zone.audioZoneContext;
+    EXPECT_THAT(context.audioContextInfos,
+                UnorderedElementsAreArray(kDefaultCarAudioConfigurationContext))
+            << "Default audio contexts";
+}
+
+class MultiZoneCarAudioConfigurationTest : public CarAudioConfigurationTest {
+    std::string getCarAudioConfiguration() override {
+        return "multi_zone_car_audio_configuration.xml";
+    }
+
+    std::string getCarFadeConfiguration() override { return "car_audio_fade_configuration.xml"; }
+};
+
+TEST_F(MultiZoneCarAudioConfigurationTest, TestLoadMultiZoneConfiguration) {
+    EXPECT_EQ(converter->getErrors(), "");
+
+    const auto audioDeviceConfigs = converter->getAudioDeviceConfiguration();
+    EXPECT_EQ(audioDeviceConfigs.routingConfig,
+              api::RoutingDeviceConfiguration::CONFIGURABLE_AUDIO_ENGINE_ROUTING);
+    EXPECT_TRUE(audioDeviceConfigs.useCoreAudioVolume);
+    EXPECT_FALSE(audioDeviceConfigs.useHalDuckingSignals);
+    EXPECT_FALSE(audioDeviceConfigs.useCarVolumeGroupMuting);
+
+    const auto& mirroringDevices = converter->getOutputMirroringDevices();
+
+    EXPECT_THAT(mirroringDevices, UnorderedElementsAreArray(kMultiZoneMirroringDevices));
+
+    const auto zones = converter->getAudioZones();
+    EXPECT_THAT(zones, UnorderedElementsAreArray(kMultiZones));
+}
+
+class MalformedCarAudioConfigurationTest : public testing::Test {
+  protected:
+    void TearDown() override;
+
+    std::unique_ptr<converter::CarAudioConfigurationXmlConverter> converter;
+};
+
+void MalformedCarAudioConfigurationTest::TearDown() {
+    converter.reset();
+}
+
+TEST_F(MalformedCarAudioConfigurationTest, TestLoadEmptyConfiguration) {
+    converter =
+            std::make_unique<converter::CarAudioConfigurationXmlConverter>(getTestFilePath(""), "");
+    EXPECT_THAT(converter->getErrors(), ContainsRegex("Configuration file .+ is not readable"))
+            << "Empty configuration file";
+
+    const auto audioDeviceConfigs = converter->getAudioDeviceConfiguration();
+    EXPECT_EQ(audioDeviceConfigs.routingConfig,
+              api::RoutingDeviceConfiguration::DEFAULT_AUDIO_ROUTING)
+            << "Default configuration for empty file";
+}
+
+TEST_F(MalformedCarAudioConfigurationTest, TestLoadNonExistingConfiguration) {
+    converter = std::make_unique<converter::CarAudioConfigurationXmlConverter>(
+            getTestFilePath("non_existing_file.xml"), "");
+    EXPECT_THAT(converter->getErrors(), ContainsRegex("Configuration file .+ is not readable"))
+            << "Empty configuration file";
+
+    const auto audioDeviceConfigs = converter->getAudioDeviceConfiguration();
+    EXPECT_EQ(audioDeviceConfigs.routingConfig,
+              api::RoutingDeviceConfiguration::DEFAULT_AUDIO_ROUTING)
+            << "Default configuration for empty file";
+}
+
+TEST_F(MalformedCarAudioConfigurationTest, TestLoadMalforedConfiguration) {
+    converter = std::make_unique<converter::CarAudioConfigurationXmlConverter>(
+            getTestFilePath("car_audio_configuration_without_configuration.xml"), "");
+    EXPECT_THAT(converter->getErrors(),
+                ContainsRegex("Configuration file .+ does not have any configurations"))
+            << "Configuration file without configurations";
+
+    const auto audioDeviceConfigs = converter->getAudioDeviceConfiguration();
+    EXPECT_EQ(audioDeviceConfigs.routingConfig,
+              api::RoutingDeviceConfiguration::DEFAULT_AUDIO_ROUTING)
+            << "Default configuration for malformed file";
+}
+
+TEST_F(MalformedCarAudioConfigurationTest, TestLoadConfigurationWithoutZones) {
+    converter = std::make_unique<converter::CarAudioConfigurationXmlConverter>(
+            getTestFilePath("car_audio_configuration_without_audio_zone.xml"), "");
+    EXPECT_THAT(converter->getErrors(), ContainsRegex("Audio zones not found in file"))
+            << "Configuration file without zones";
+
+    const auto audioDeviceConfigs = converter->getAudioDeviceConfiguration();
+    EXPECT_EQ(audioDeviceConfigs.routingConfig,
+              api::RoutingDeviceConfiguration::DEFAULT_AUDIO_ROUTING)
+            << "Default configuration for file without zones";
+}
+
+TEST_F(MalformedCarAudioConfigurationTest, TestLoadConfigurationWithMissingZones) {
+    converter = std::make_unique<converter::CarAudioConfigurationXmlConverter>(
+            getTestFilePath("car_audio_configuration_with_missing_zones.xml"), "");
+    EXPECT_THAT(converter->getErrors(), ContainsRegex("Error parsing audio zone"))
+            << "Configuration file with missing zones";
+
+    const auto audioDeviceConfigs = converter->getAudioDeviceConfiguration();
+    EXPECT_EQ(audioDeviceConfigs.routingConfig,
+              api::RoutingDeviceConfiguration::DEFAULT_AUDIO_ROUTING)
+            << "Default configuration for file with missing zones";
+}
+
+}  // namespace
diff --git a/automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_with_default_context.xml b/automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_with_default_context.xml
new file mode 100644
index 0000000..80cb5cd
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_with_default_context.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<carAudioConfiguration version="4">
+    <zones>
+        <zone name="primary zone" isPrimary="true">
+            <zoneConfigs>
+                <zoneConfig name="primary zone config" isDefault="true">
+                    <volumeGroups>
+                        <group name="entertainment" >
+                            <device address="BUS00_MEDIA">
+                                <context context="MUSIC"/>
+                            </device>
+                        </group>
+                        <group name="navvoicecommand" >
+                            <device address="BUS02_NAV_GUIDANCE">
+                                <context context="NAVIGATION"/>
+                                <context context="VOICE_COMMAND"/>
+                            </device>
+                        </group>
+                        <group name="telringvol" >
+                            <device address="BUS03_PHONE">
+                                <context context="CALL"/>
+                                <context context="CALL_RING"/>
+                            </device>
+                        </group>
+                        <group name="alarm" >
+                            <device address="BUS01_NOTIFICATION">
+                                <context context="ALARM"/>
+                                <context context="NOTIFICATION"/>
+                            </device>
+                        </group>
+                        <group name="system" >
+                            <device address="BUS05_SYSTEM">
+                                <context context="SYSTEM_SOUND"/>
+                                <context context="EMERGENCY"/>
+                                <context context="SAFETY"/>
+                                <context context="VEHICLE_STATUS"/>
+                                <context context="ANNOUNCEMENT"/>
+                            </device>
+                        </group>
+                    </volumeGroups>
+                </zoneConfig>
+            </zoneConfigs>
+        </zone>
+    </zones>
+</carAudioConfiguration>
diff --git a/automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_with_missing_zones.xml b/automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_with_missing_zones.xml
new file mode 100644
index 0000000..a5880b3
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_with_missing_zones.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<carAudioConfiguration version="4">
+    <deviceConfigurations>
+        <deviceConfiguration name="useHalDuckingSignals" value="true" />
+        <deviceConfiguration name="useCoreAudioRouting" value="false" />
+        <deviceConfiguration name="useCoreAudioVolume" value="false" />
+        <deviceConfiguration name="useCarVolumeGroupMuting" value="true" />
+    </deviceConfigurations>
+    <oemContexts>
+        <oemContext name="oem_context">
+            <audioAttributes>
+                <audioAttribute usage="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"
+                    contentType="AUDIO_CONTENT_TYPE_SPEECH"
+                    tags="oem=extension_8675309" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_music">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_MEDIA" />
+                <usage value="AUDIO_USAGE_GAME" />
+                <usage value="AUDIO_USAGE_UNKNOWN" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_notification">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_NOTIFICATION" />
+                <usage value="AUDIO_USAGE_NOTIFICATION_EVENT" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_voice_command">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_ASSISTANT" />
+                <usage value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" />
+                <usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_call">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_VOICE_COMMUNICATION" />
+                <usage value="AUDIO_USAGE_CALL_ASSISTANT" />
+                <usage value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_call_ring">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_alarm">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_ALARM" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_system_sound">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" />
+                <usage value="AUDIO_USAGE_EMERGENCY" />
+                <usage value="AUDIO_USAGE_SAFETY" />
+                <usage value="AUDIO_USAGE_VEHICLE_STATUS" />
+                <usage value="AUDIO_USAGE_ANNOUNCEMENT" />
+            </audioAttributes>
+        </oemContext>
+    </oemContexts>
+    <activationVolumeConfigs>
+        <activationVolumeConfig name="on_boot_config">
+            <activationVolumeConfigEntry maxActivationVolumePercentage="80" invocationType="onBoot" />
+        </activationVolumeConfig>
+        <activationVolumeConfig name="on_source_changed_config">
+            <activationVolumeConfigEntry minActivationVolumePercentage="20" maxActivationVolumePercentage="80" invocationType="onSourceChanged" />
+        </activationVolumeConfig>
+        <activationVolumeConfig name="on_playback_changed_config">
+            <activationVolumeConfigEntry minActivationVolumePercentage="10" maxActivationVolumePercentage="90" invocationType="onPlaybackChanged" />
+        </activationVolumeConfig>
+    </activationVolumeConfigs>
+    <mirroringDevices>
+        <mirroringDevice address="mirror_bus_device_1"/>
+        <mirroringDevice address="mirror_bus_device_2"/>
+    </mirroringDevices>
+    <zones>
+    </zones>
+</carAudioConfiguration>
diff --git a/automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_without_audio_zone.xml b/automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_without_audio_zone.xml
new file mode 100644
index 0000000..1e50e6e
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_without_audio_zone.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<carAudioConfiguration version="4">
+    <deviceConfigurations>
+        <deviceConfiguration name="useHalDuckingSignals" value="true" />
+        <deviceConfiguration name="useCoreAudioRouting" value="false" />
+        <deviceConfiguration name="useCoreAudioVolume" value="false" />
+        <deviceConfiguration name="useCarVolumeGroupMuting" value="true" />
+    </deviceConfigurations>
+    <oemContexts>
+        <oemContext name="oem_context">
+            <audioAttributes>
+                <audioAttribute usage="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"
+                    contentType="AUDIO_CONTENT_TYPE_SPEECH"
+                    tags="oem=extension_8675309" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_music">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_MEDIA" />
+                <usage value="AUDIO_USAGE_GAME" />
+                <usage value="AUDIO_USAGE_UNKNOWN" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_notification">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_NOTIFICATION" />
+                <usage value="AUDIO_USAGE_NOTIFICATION_EVENT" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_voice_command">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_ASSISTANT" />
+                <usage value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" />
+                <usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_call">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_VOICE_COMMUNICATION" />
+                <usage value="AUDIO_USAGE_CALL_ASSISTANT" />
+                <usage value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_call_ring">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_alarm">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_ALARM" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_system_sound">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" />
+                <usage value="AUDIO_USAGE_EMERGENCY" />
+                <usage value="AUDIO_USAGE_SAFETY" />
+                <usage value="AUDIO_USAGE_VEHICLE_STATUS" />
+                <usage value="AUDIO_USAGE_ANNOUNCEMENT" />
+            </audioAttributes>
+        </oemContext>
+    </oemContexts>
+    <activationVolumeConfigs>
+        <activationVolumeConfig name="on_boot_config">
+            <activationVolumeConfigEntry maxActivationVolumePercentage="80" invocationType="onBoot" />
+        </activationVolumeConfig>
+        <activationVolumeConfig name="on_source_changed_config">
+            <activationVolumeConfigEntry minActivationVolumePercentage="20" maxActivationVolumePercentage="80" invocationType="onSourceChanged" />
+        </activationVolumeConfig>
+        <activationVolumeConfig name="on_playback_changed_config">
+            <activationVolumeConfigEntry minActivationVolumePercentage="10" maxActivationVolumePercentage="90" invocationType="onPlaybackChanged" />
+        </activationVolumeConfig>
+    </activationVolumeConfigs>
+    <mirroringDevices>
+        <mirroringDevice address="mirror_bus_device_1"/>
+        <mirroringDevice address="mirror_bus_device_2"/>
+    </mirroringDevices>
+</carAudioConfiguration>
diff --git a/automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_without_configuration.xml b/automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_without_configuration.xml
new file mode 100644
index 0000000..4f50ca2
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_without_configuration.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<nonCarAudioConfiguration version="4">
+
+</nonCarAudioConfiguration>
diff --git a/automotive/audiocontrol/aidl/default/converter/test/car_audio_fade_configuration.xml b/automotive/audiocontrol/aidl/default/converter/test/car_audio_fade_configuration.xml
new file mode 100644
index 0000000..249f915
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/converter/test/car_audio_fade_configuration.xml
@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<carAudioFadeConfiguration version="1">
+    <configs>
+        <config name="relaxed fading" defaultFadeOutDurationInMillis="800" defaultFadeInDurationInMillis="500" defaultFadeInDelayForOffenders="10000" >
+            <fadeState value="1" />
+            <fadeableUsages>
+                <usage value="AUDIO_USAGE_MEDIA" />
+                <usage value="AUDIO_USAGE_GAME" />
+                <usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" />
+                <usage value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" />
+                <usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" />
+                <usage value="AUDIO_USAGE_ASSISTANT" />
+                <usage value="AUDIO_USAGE_NOTIFICATION" />
+                <usage value="AUDIO_USAGE_ANNOUNCEMENT"/>
+            </fadeableUsages>
+            <unfadeableContentTypes>
+                <contentType value="AUDIO_CONTENT_TYPE_SPEECH" />
+                <contentType value="AUDIO_CONTENT_TYPE_SONIFICATION" />
+            </unfadeableContentTypes>
+            <unfadeableAudioAttributes>
+                <audioAttributes>
+                    <audioAttribute usage="AUDIO_USAGE_MEDIA" tags="oem_specific_tag1" />
+                </audioAttributes>
+            </unfadeableAudioAttributes>
+            <fadeOutConfigurations>
+                <fadeConfiguration fadeDurationMillis="500">
+                    <audioAttributes>
+                        <usage value="AUDIO_USAGE_MEDIA" />
+                        <usage value="AUDIO_USAGE_GAME" />
+                        <audioAttribute usage="AUDIO_USAGE_ASSISTANT" tags="oem_specific_tag2" />
+                    </audioAttributes>
+                </fadeConfiguration>
+                <fadeConfiguration fadeDurationMillis="800">
+                    <audioAttributes>
+                        <usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" />
+                        <usage value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" />
+                        <usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" />
+                        <usage value="AUDIO_USAGE_ASSISTANT" />
+                        <usage value="AUDIO_USAGE_ANNOUNCEMENT"/>
+                    </audioAttributes>
+                </fadeConfiguration>
+            </fadeOutConfigurations>
+            <fadeInConfigurations>
+                <fadeConfiguration fadeDurationMillis="1000">
+                    <audioAttributes>
+                        <usage value="AUDIO_USAGE_MEDIA" />
+                        <usage value="AUDIO_USAGE_GAME" />
+                        <audioAttribute usage="AUDIO_USAGE_ASSISTANT" tags="oem_specific_tag2" />
+                    </audioAttributes>
+                </fadeConfiguration>
+                <fadeConfiguration fadeDurationMillis="800">
+                    <audioAttributes>
+                        <usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" />
+                        <usage value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" />
+                        <usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" />
+                        <usage value="AUDIO_USAGE_ASSISTANT" />
+                        <usage value="AUDIO_USAGE_ANNOUNCEMENT"/>
+                    </audioAttributes>
+                </fadeConfiguration>
+            </fadeInConfigurations>
+        </config>
+        <config name="aggressive fading">
+            <fadeState value="FADE_STATE_ENABLED_DEFAULT" />
+            <fadeableUsages>
+                <usage value="AUDIO_USAGE_MEDIA" />
+                <usage value="AUDIO_USAGE_GAME" />
+                <usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" />
+                <usage value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" />
+                <usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" />
+                <usage value="AUDIO_USAGE_ASSISTANT" />
+                <usage value="AUDIO_USAGE_NOTIFICATION" />
+                <usage value="AUDIO_USAGE_ANNOUNCEMENT"/>
+            </fadeableUsages>
+            <unfadeableContentTypes>
+                <contentType value="AUDIO_CONTENT_TYPE_SPEECH" />
+                <contentType value="AUDIO_CONTENT_TYPE_MUSIC" />
+            </unfadeableContentTypes>
+            <unfadeableAudioAttributes>
+                <audioAttributes>
+                    <audioAttribute usage="AUDIO_USAGE_MEDIA" tags="oem_specific_tag1" />
+                    <audioAttribute usage="AUDIO_USAGE_ASSISTANT" tags="oem_projection_service" />
+                </audioAttributes>
+            </unfadeableAudioAttributes>
+            <fadeOutConfigurations>
+                <fadeConfiguration fadeDurationMillis="150">
+                    <audioAttributes>
+                        <usage value="AUDIO_USAGE_MEDIA" />
+                        <usage value="AUDIO_USAGE_GAME" />
+                    </audioAttributes>
+                </fadeConfiguration>
+                <fadeConfiguration fadeDurationMillis="400">
+                    <audioAttributes>
+                        <usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" />
+                        <usage value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" />
+                        <usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" />
+                        <usage value="AUDIO_USAGE_ASSISTANT" />
+                        <usage value="AUDIO_USAGE_ANNOUNCEMENT"/>
+                    </audioAttributes>
+                </fadeConfiguration>
+            </fadeOutConfigurations>
+            <fadeInConfigurations>
+                <fadeConfiguration fadeDurationMillis="300">
+                    <audioAttributes>
+                        <usage value="AUDIO_USAGE_MEDIA" />
+                        <usage value="AUDIO_USAGE_GAME" />
+                    </audioAttributes>
+                </fadeConfiguration>
+                <fadeConfiguration fadeDurationMillis="550">
+                    <audioAttributes>
+                        <usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" />
+                        <usage value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" />
+                        <usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" />
+                        <usage value="AUDIO_USAGE_ASSISTANT" />
+                        <usage value="AUDIO_USAGE_ANNOUNCEMENT"/>
+                    </audioAttributes>
+                </fadeConfiguration>
+            </fadeInConfigurations>
+        </config>
+        <config name="disabled fading">
+            <fadeState value="0" />
+        </config>
+        <config name="dynamic fading" defaultFadeOutDurationInMillis="800" defaultFadeInDurationInMillis="500">
+            <fadeState value="1" />
+            <fadeableUsages>
+                <usage value="AUDIO_USAGE_MEDIA" />
+                <usage value="AUDIO_USAGE_GAME" />
+                <usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" />
+                <usage value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" />
+                <usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" />
+                <usage value="AUDIO_USAGE_ASSISTANT" />
+                <usage value="AUDIO_USAGE_NOTIFICATION" />
+                <usage value="AUDIO_USAGE_ANNOUNCEMENT"/>
+            </fadeableUsages>
+            <unfadeableContentTypes>
+                <contentType value="AUDIO_CONTENT_TYPE_SPEECH" />
+                <contentType value="AUDIO_CONTENT_TYPE_MOVIE" />
+            </unfadeableContentTypes>
+            <unfadeableAudioAttributes>
+                <audioAttributes>
+                    <audioAttribute usage="AUDIO_USAGE_MEDIA" tags="oem_specific_tag1" />
+                </audioAttributes>
+            </unfadeableAudioAttributes>
+            <fadeOutConfigurations>
+                <fadeConfiguration fadeDurationMillis="500">
+                    <audioAttributes>
+                        <audioAttribute usage="AUDIO_USAGE_ASSISTANT" tags="oem_specific_tag2" />
+                    </audioAttributes>
+                </fadeConfiguration>
+                <fadeConfiguration fadeDurationMillis="800">
+                    <audioAttributes>
+                        <usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" />
+                        <usage value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" />
+                        <usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" />
+                        <usage value="AUDIO_USAGE_ASSISTANT" />
+                        <usage value="AUDIO_USAGE_ANNOUNCEMENT"/>
+                    </audioAttributes>
+                </fadeConfiguration>
+            </fadeOutConfigurations>
+            <fadeInConfigurations>
+                <fadeConfiguration fadeDurationMillis="1000">
+                    <audioAttributes>
+                        <audioAttribute usage="AUDIO_USAGE_ASSISTANT" tags="oem_specific_tag2" />
+                    </audioAttributes>
+                </fadeConfiguration>
+                <fadeConfiguration fadeDurationMillis="800">
+                    <audioAttributes>
+                        <usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" />
+                        <usage value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" />
+                        <usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" />
+                        <usage value="AUDIO_USAGE_ASSISTANT" />
+                        <usage value="AUDIO_USAGE_ANNOUNCEMENT"/>
+                    </audioAttributes>
+                </fadeConfiguration>
+            </fadeInConfigurations>
+        </config>
+    </configs>
+</carAudioFadeConfiguration>
diff --git a/automotive/audiocontrol/aidl/default/converter/test/multi_zone_car_audio_configuration.xml b/automotive/audiocontrol/aidl/default/converter/test/multi_zone_car_audio_configuration.xml
new file mode 100644
index 0000000..f0c9081
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/converter/test/multi_zone_car_audio_configuration.xml
@@ -0,0 +1,196 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<carAudioConfiguration version="4">
+    <deviceConfigurations>
+        <deviceConfiguration name="useHalDuckingSignals" value="false" />
+        <deviceConfiguration name="useCoreAudioRouting" value="true" />
+        <deviceConfiguration name="useCoreAudioVolume" value="true" />
+        <deviceConfiguration name="useCarVolumeGroupMuting" value="false" />
+    </deviceConfigurations>
+    <oemContexts>
+        <oemContext name="oem_context">
+            <audioAttributes>
+                <audioAttribute usage="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"
+                    contentType="AUDIO_CONTENT_TYPE_SPEECH"
+                    tags="oem=extension_8675309" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_music">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_MEDIA" />
+                <usage value="AUDIO_USAGE_GAME" />
+                <usage value="AUDIO_USAGE_UNKNOWN" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_notification">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_NOTIFICATION" />
+                <usage value="AUDIO_USAGE_NOTIFICATION_EVENT" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_voice_command">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_ASSISTANT" />
+                <usage value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" />
+                <usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_call">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_VOICE_COMMUNICATION" />
+                <usage value="AUDIO_USAGE_CALL_ASSISTANT" />
+                <usage value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_call_ring">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_alarm">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_ALARM" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_system_sound">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" />
+                <usage value="AUDIO_USAGE_EMERGENCY" />
+                <usage value="AUDIO_USAGE_SAFETY" />
+                <usage value="AUDIO_USAGE_VEHICLE_STATUS" />
+                <usage value="AUDIO_USAGE_ANNOUNCEMENT" />
+            </audioAttributes>
+        </oemContext>
+    </oemContexts>
+    <activationVolumeConfigs>
+        <activationVolumeConfig name="on_boot_config">
+            <activationVolumeConfigEntry maxActivationVolumePercentage="80" invocationType="onBoot" />
+        </activationVolumeConfig>
+        <activationVolumeConfig name="on_source_changed_config">
+            <activationVolumeConfigEntry minActivationVolumePercentage="20" maxActivationVolumePercentage="80" invocationType="onSourceChanged" />
+        </activationVolumeConfig>
+        <activationVolumeConfig name="on_playback_changed_config">
+            <activationVolumeConfigEntry minActivationVolumePercentage="10" maxActivationVolumePercentage="90" invocationType="onPlaybackChanged" />
+        </activationVolumeConfig>
+    </activationVolumeConfigs>
+    <mirroringDevices>
+        <mirroringDevice address="mirror_bus_device_three"/>
+        <mirroringDevice address="mirror_bus_device_four"/>
+    </mirroringDevices>
+    <zones>
+        <zone name="driver zone" isPrimary="true" audioZoneId="0" occupantZoneId="0">
+            <zoneConfigs>
+                <zoneConfig name="driver zone config 0" isDefault="true">
+                    <volumeGroups>
+                        <group name="entertainment" activationConfig="on_boot_config">
+                            <device address="BUS00_MEDIA">
+                                <context context="oem_music"/>
+                            </device>
+                        </group>
+                        <group name="navvoicecommand" activationConfig="on_source_changed_config">
+                            <device address="BUS02_NAV_GUIDANCE">
+                                <context context="oem_voice_command"/>
+                            </device>
+                        </group>
+                        <group name="telringvol" activationConfig="on_playback_changed_config">
+                            <device address="BUS03_PHONE">
+                                <context context="oem_call"/>
+                                <context context="oem_call_ring"/>
+                            </device>
+                        </group>
+                        <group name="systemalarm" activationConfig="on_source_changed_config">
+                            <device address="BUS01_SYS_NOTIFICATION">
+                                <context context="oem_alarm"/>
+                                <context context="oem_system_sound"/>
+                                <context context="oem_notification"/>
+                            </device>
+                        </group>
+                    </volumeGroups>
+                    <applyFadeConfigs>
+                        <fadeConfig name="relaxed fading" isDefault="true">
+                        </fadeConfig>
+                        <fadeConfig name="aggressive fading">
+                            <audioAttributes>
+                                <usage value="AUDIO_USAGE_VOICE_COMMUNICATION" />
+                                <usage value="AUDIO_USAGE_ANNOUNCEMENT" />
+                                <usage value="AUDIO_USAGE_VEHICLE_STATUS" />
+                                <usage value="AUDIO_USAGE_SAFETY" />
+                            </audioAttributes>
+                        </fadeConfig>
+                        <fadeConfig name="disabled fading">
+                            <audioAttributes>
+                                <usage value="AUDIO_USAGE_EMERGENCY" />
+                            </audioAttributes>
+                        </fadeConfig>
+                    </applyFadeConfigs>
+                </zoneConfig>
+            </zoneConfigs>
+        </zone>
+        <zone name="front passenger zone" audioZoneId="1" occupantZoneId="1">
+            <zoneConfigs>
+                <zoneConfig name="front passenger config 0" isDefault="true">
+                    <volumeGroups>
+                        <group  name="entertainment" activationConfig="on_boot_config">
+                            <device address="BUS_FRONT">
+                                <context context="oem_music"/>
+                                <context context="oem_voice_command"/>
+                                <context context="oem_call"/>
+                                <context context="oem_call_ring"/>
+                                <context context="oem_alarm"/>
+                                <context context="oem_system_sound"/>
+                                <context context="oem_notification"/>
+                            </device>
+                        </group>
+                    </volumeGroups>
+                    <applyFadeConfigs>
+                        <fadeConfig name="relaxed fading" isDefault="true">
+                        </fadeConfig>
+                        <fadeConfig name="disabled fading">
+                            <audioAttributes>
+                                <usage value="AUDIO_USAGE_EMERGENCY" />
+                            </audioAttributes>
+                        </fadeConfig>
+                    </applyFadeConfigs>
+                </zoneConfig>
+            </zoneConfigs>
+        </zone>
+        <zone name="rear seat zone" audioZoneId="2" occupantZoneId="2">
+            <zoneConfigs>
+                <zoneConfig name="rear seat config 0" isDefault="true">
+                    <volumeGroups>
+                        <group  name="entertainment" activationConfig="on_boot_config">
+                            <device address="BUS_REAR">
+                                <context context="oem_music"/>
+                                <context context="oem_voice_command"/>
+                                <context context="oem_call"/>
+                                <context context="oem_call_ring"/>
+                                <context context="oem_alarm"/>
+                                <context context="oem_system_sound"/>
+                                <context context="oem_notification"/>
+                            </device>
+                        </group>
+                    </volumeGroups>
+                    <applyFadeConfigs>
+                        <fadeConfig name="relaxed fading" isDefault="true">
+                        </fadeConfig>
+                        <fadeConfig name="disabled fading">
+                            <audioAttributes>
+                                <usage value="AUDIO_USAGE_EMERGENCY" />
+                            </audioAttributes>
+                        </fadeConfig>
+                    </applyFadeConfigs>
+                </zoneConfig>
+            </zoneConfigs>
+        </zone>
+    </zones>
+</carAudioConfiguration>
diff --git a/automotive/audiocontrol/aidl/default/converter/test/simple_car_audio_configuration.xml b/automotive/audiocontrol/aidl/default/converter/test/simple_car_audio_configuration.xml
new file mode 100644
index 0000000..a6f5317
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/converter/test/simple_car_audio_configuration.xml
@@ -0,0 +1,233 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<carAudioConfiguration version="4">
+    <deviceConfigurations>
+        <deviceConfiguration name="useHalDuckingSignals" value="true" />
+        <deviceConfiguration name="useCoreAudioRouting" value="false" />
+        <deviceConfiguration name="useCoreAudioVolume" value="false" />
+        <deviceConfiguration name="useCarVolumeGroupMuting" value="true" />
+    </deviceConfigurations>
+    <oemContexts>
+        <oemContext name="oem_context">
+            <audioAttributes>
+                <audioAttribute usage="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"
+                    contentType="AUDIO_CONTENT_TYPE_SPEECH"
+                    tags="oem=extension_8675309" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_music">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_MEDIA" />
+                <usage value="AUDIO_USAGE_GAME" />
+                <usage value="AUDIO_USAGE_UNKNOWN" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_notification">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_NOTIFICATION" />
+                <usage value="AUDIO_USAGE_NOTIFICATION_EVENT" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_voice_command">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_ASSISTANT" />
+                <usage value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" />
+                <usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_call">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_VOICE_COMMUNICATION" />
+                <usage value="AUDIO_USAGE_CALL_ASSISTANT" />
+                <usage value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_call_ring">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_alarm">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_ALARM" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_system_sound">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" />
+                <usage value="AUDIO_USAGE_EMERGENCY" />
+                <usage value="AUDIO_USAGE_SAFETY" />
+                <usage value="AUDIO_USAGE_VEHICLE_STATUS" />
+                <usage value="AUDIO_USAGE_ANNOUNCEMENT" />
+            </audioAttributes>
+        </oemContext>
+    </oemContexts>
+    <activationVolumeConfigs>
+        <activationVolumeConfig name="on_boot_config">
+            <activationVolumeConfigEntry maxActivationVolumePercentage="80" invocationType="onBoot" />
+        </activationVolumeConfig>
+        <activationVolumeConfig name="on_source_changed_config">
+            <activationVolumeConfigEntry minActivationVolumePercentage="20" maxActivationVolumePercentage="80" invocationType="onSourceChanged" />
+        </activationVolumeConfig>
+        <activationVolumeConfig name="on_playback_changed_config">
+            <activationVolumeConfigEntry minActivationVolumePercentage="10" maxActivationVolumePercentage="90" invocationType="onPlaybackChanged" />
+        </activationVolumeConfig>
+    </activationVolumeConfigs>
+    <mirroringDevices>
+        <mirroringDevice address="mirror_bus_device_1"/>
+        <mirroringDevice address="mirror_bus_device_2"/>
+    </mirroringDevices>
+    <zones>
+        <zone name="primary zone" isPrimary="true" audioZoneId="0" occupantZoneId="0">
+            <inputDevices>
+                <inputDevice address="fm_tuner" type="AUDIO_DEVICE_IN_FM_TUNER" />
+                <inputDevice address="built_in_mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" />
+                <inputDevice address="in_bus_device" type="AUDIO_DEVICE_IN_BUS" />
+            </inputDevices>
+            <zoneConfigs>
+                <zoneConfig name="primary zone config 0" isDefault="true">
+                    <volumeGroups>
+                        <group name="entertainment" activationConfig="on_boot_config">
+                            <device address="BUS00_MEDIA">
+                                <context context="oem_music"/>
+                            </device>
+                        </group>
+                        <group name="navvoicecommand" activationConfig="on_source_changed_config">
+                            <device address="BUS02_NAV_GUIDANCE">
+                                <context context="oem_voice_command"/>
+                            </device>
+                        </group>
+                        <group name="telringvol" activationConfig="on_playback_changed_config">
+                            <device address="BUS03_PHONE">
+                                <context context="oem_call"/>
+                                <context context="oem_call_ring"/>
+                            </device>
+                        </group>
+                        <group name="systemalarm" activationConfig="on_source_changed_config">
+                            <device address="BUS01_SYS_NOTIFICATION">
+                                <context context="oem_alarm"/>
+                                <context context="oem_system_sound"/>
+                                <context context="oem_notification"/>
+                            </device>
+                        </group>
+                    </volumeGroups>
+                    <applyFadeConfigs>
+                        <fadeConfig name="relaxed fading" isDefault="true">
+                        </fadeConfig>
+                        <fadeConfig name="aggressive fading">
+                            <audioAttributes>
+                                <usage value="AUDIO_USAGE_VOICE_COMMUNICATION" />
+                                <usage value="AUDIO_USAGE_ANNOUNCEMENT" />
+                                <usage value="AUDIO_USAGE_VEHICLE_STATUS" />
+                                <usage value="AUDIO_USAGE_SAFETY" />
+                            </audioAttributes>
+                        </fadeConfig>
+                        <fadeConfig name="disabled fading">
+                            <audioAttributes>
+                                <usage value="AUDIO_USAGE_EMERGENCY" />
+                            </audioAttributes>
+                        </fadeConfig>
+                    </applyFadeConfigs>
+                </zoneConfig>
+                <zoneConfig name="primary zone BT media">
+                    <volumeGroups>
+                        <group name="entertainment" activationConfig="on_boot_config">
+                            <device type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP" address="temp">
+                                <context context="oem_music"/>
+                            </device>
+                        </group>
+                        <group name="navvoicecommand" activationConfig="on_source_changed_config">
+                            <device address="BUS02_NAV_GUIDANCE">
+                                <context context="oem_voice_command"/>
+                            </device>
+                        </group>
+                        <group name="telringvol" activationConfig="on_playback_changed_config">
+                            <device address="BUS03_PHONE">
+                                <context context="oem_call"/>
+                                <context context="oem_call_ring"/>
+                            </device>
+                        </group>
+                        <group name="systemalarm" activationConfig="on_source_changed_config">
+                            <device address="BUS01_SYS_NOTIFICATION">
+                                <context context="oem_alarm"/>
+                                <context context="oem_system_sound"/>
+                                <context context="oem_notification"/>
+                            </device>
+                        </group>
+                    </volumeGroups>
+                    <applyFadeConfigs>
+                        <fadeConfig name="dynamic fading" isDefault="true">
+                        </fadeConfig>
+                        <fadeConfig name="aggressive fading">
+                            <audioAttributes>
+                                <usage value="AUDIO_USAGE_VOICE_COMMUNICATION" />
+                                <usage value="AUDIO_USAGE_ANNOUNCEMENT" />
+                                <usage value="AUDIO_USAGE_VEHICLE_STATUS" />
+                                <usage value="AUDIO_USAGE_SAFETY" />
+                            </audioAttributes>
+                        </fadeConfig>
+                        <fadeConfig name="disabled fading">
+                            <audioAttributes>
+                                <usage value="AUDIO_USAGE_EMERGENCY" />
+                            </audioAttributes>
+                        </fadeConfig>
+                    </applyFadeConfigs>
+                </zoneConfig>
+                <zoneConfig name="primary zone USB media">
+                    <volumeGroups>
+                        <group name="entertainment" activationConfig="on_boot_config">
+                            <device type="AUDIO_DEVICE_OUT_USB_HEADSET">
+                                <context context="oem_music"/>
+                            </device>
+                        </group>
+                        <group name="navvoicecommand" activationConfig="on_source_changed_config">
+                            <device address="BUS02_NAV_GUIDANCE">
+                                <context context="oem_voice_command"/>
+                            </device>
+                        </group>
+                        <group name="telringvol" activationConfig="on_playback_changed_config">
+                            <device address="BUS03_PHONE">
+                                <context context="oem_call"/>
+                                <context context="oem_call_ring"/>
+                            </device>
+                        </group>
+                        <group name="systemalarm" activationConfig="on_source_changed_config">
+                            <device address="BUS01_SYS_NOTIFICATION">
+                                <context context="oem_alarm"/>
+                                <context context="oem_system_sound"/>
+                                <context context="oem_notification"/>
+                            </device>
+                        </group>
+                    </volumeGroups>
+                    <applyFadeConfigs>
+                        <fadeConfig name="dynamic fading" isDefault="true">
+                        </fadeConfig>
+                        <fadeConfig name="aggressive fading">
+                            <audioAttributes>
+                                <usage value="AUDIO_USAGE_VOICE_COMMUNICATION" />
+                                <usage value="AUDIO_USAGE_ANNOUNCEMENT" />
+                                <usage value="AUDIO_USAGE_VEHICLE_STATUS" />
+                                <usage value="AUDIO_USAGE_SAFETY" />
+                            </audioAttributes>
+                        </fadeConfig>
+                        <fadeConfig name="disabled fading">
+                            <audioAttributes>
+                                <usage value="AUDIO_USAGE_EMERGENCY" />
+                            </audioAttributes>
+                        </fadeConfig>
+                    </applyFadeConfigs>
+                </zoneConfig>
+            </zoneConfigs>
+        </zone>
+    </zones>
+</carAudioConfiguration>
diff --git a/automotive/audiocontrol/aidl/default/converter/test/simple_car_audio_configuration_with_device_type.xml b/automotive/audiocontrol/aidl/default/converter/test/simple_car_audio_configuration_with_device_type.xml
new file mode 100644
index 0000000..eec9db9
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/converter/test/simple_car_audio_configuration_with_device_type.xml
@@ -0,0 +1,233 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<carAudioConfiguration version="4">
+    <deviceConfigurations>
+        <deviceConfiguration name="useHalDuckingSignals" value="true" />
+        <deviceConfiguration name="useCoreAudioRouting" value="false" />
+        <deviceConfiguration name="useCoreAudioVolume" value="false" />
+        <deviceConfiguration name="useCarVolumeGroupMuting" value="true" />
+    </deviceConfigurations>
+    <oemContexts>
+        <oemContext name="oem_context">
+            <audioAttributes>
+                <audioAttribute usage="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"
+                    contentType="AUDIO_CONTENT_TYPE_SPEECH"
+                    tags="oem=extension_8675309" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_music">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_MEDIA" />
+                <usage value="AUDIO_USAGE_GAME" />
+                <usage value="AUDIO_USAGE_UNKNOWN" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_notification">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_NOTIFICATION" />
+                <usage value="AUDIO_USAGE_NOTIFICATION_EVENT" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_voice_command">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_ASSISTANT" />
+                <usage value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" />
+                <usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_call">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_VOICE_COMMUNICATION" />
+                <usage value="AUDIO_USAGE_CALL_ASSISTANT" />
+                <usage value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_call_ring">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_alarm">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_ALARM" />
+            </audioAttributes>
+        </oemContext>
+        <oemContext name="oem_system_sound">
+            <audioAttributes>
+                <usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" />
+                <usage value="AUDIO_USAGE_EMERGENCY" />
+                <usage value="AUDIO_USAGE_SAFETY" />
+                <usage value="AUDIO_USAGE_VEHICLE_STATUS" />
+                <usage value="AUDIO_USAGE_ANNOUNCEMENT" />
+            </audioAttributes>
+        </oemContext>
+    </oemContexts>
+    <activationVolumeConfigs>
+        <activationVolumeConfig name="on_boot_config">
+            <activationVolumeConfigEntry maxActivationVolumePercentage="80" invocationType="onBoot" />
+        </activationVolumeConfig>
+        <activationVolumeConfig name="on_source_changed_config">
+            <activationVolumeConfigEntry minActivationVolumePercentage="20" maxActivationVolumePercentage="80" invocationType="onSourceChanged" />
+        </activationVolumeConfig>
+        <activationVolumeConfig name="on_playback_changed_config">
+            <activationVolumeConfigEntry minActivationVolumePercentage="10" maxActivationVolumePercentage="90" invocationType="onPlaybackChanged" />
+        </activationVolumeConfig>
+    </activationVolumeConfigs>
+    <mirroringDevices>
+        <mirroringDevice address="mirror_bus_device_1"/>
+        <mirroringDevice address="mirror_bus_device_2"/>
+    </mirroringDevices>
+    <zones>
+        <zone name="primary zone" isPrimary="true" audioZoneId="0" occupantZoneId="0">
+            <inputDevices>
+                <inputDevice address="fm_tuner" type="AUDIO_DEVICE_IN_FM_TUNER" />
+                <inputDevice address="built_in_mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" />
+                <inputDevice address="in_bus_device" type="AUDIO_DEVICE_IN_BUS" />
+            </inputDevices>
+            <zoneConfigs>
+                <zoneConfig name="primary zone config 0" isDefault="true">
+                    <volumeGroups>
+                        <group name="entertainment" activationConfig="on_boot_config">
+                            <device address="BUS00_MEDIA">
+                                <context context="oem_music"/>
+                            </device>
+                        </group>
+                        <group name="navvoicecommand" activationConfig="on_source_changed_config">
+                            <device address="BUS02_NAV_GUIDANCE">
+                                <context context="oem_voice_command"/>
+                            </device>
+                        </group>
+                        <group name="telringvol" activationConfig="on_playback_changed_config">
+                            <device address="BUS03_PHONE">
+                                <context context="oem_call"/>
+                                <context context="oem_call_ring"/>
+                            </device>
+                        </group>
+                        <group name="systemalarm" activationConfig="on_source_changed_config">
+                            <device address="BUS01_SYS_NOTIFICATION">
+                                <context context="oem_alarm"/>
+                                <context context="oem_system_sound"/>
+                                <context context="oem_notification"/>
+                            </device>
+                        </group>
+                    </volumeGroups>
+                    <applyFadeConfigs>
+                        <fadeConfig name="relaxed fading" isDefault="true">
+                        </fadeConfig>
+                        <fadeConfig name="aggressive fading">
+                            <audioAttributes>
+                                <usage value="AUDIO_USAGE_VOICE_COMMUNICATION" />
+                                <usage value="AUDIO_USAGE_ANNOUNCEMENT" />
+                                <usage value="AUDIO_USAGE_VEHICLE_STATUS" />
+                                <usage value="AUDIO_USAGE_SAFETY" />
+                            </audioAttributes>
+                        </fadeConfig>
+                        <fadeConfig name="disabled fading">
+                            <audioAttributes>
+                                <usage value="AUDIO_USAGE_EMERGENCY" />
+                            </audioAttributes>
+                        </fadeConfig>
+                    </applyFadeConfigs>
+                </zoneConfig>
+                <zoneConfig name="primary zone BT media">
+                    <volumeGroups>
+                        <group name="entertainment" activationConfig="on_boot_config">
+                            <device type="TYPE_BLUETOOTH_A2DP" address="temp">
+                                <context context="oem_music"/>
+                            </device>
+                        </group>
+                        <group name="navvoicecommand" activationConfig="on_source_changed_config">
+                            <device address="BUS02_NAV_GUIDANCE">
+                                <context context="oem_voice_command"/>
+                            </device>
+                        </group>
+                        <group name="telringvol" activationConfig="on_playback_changed_config">
+                            <device address="BUS03_PHONE">
+                                <context context="oem_call"/>
+                                <context context="oem_call_ring"/>
+                            </device>
+                        </group>
+                        <group name="systemalarm" activationConfig="on_source_changed_config">
+                            <device address="BUS01_SYS_NOTIFICATION">
+                                <context context="oem_alarm"/>
+                                <context context="oem_system_sound"/>
+                                <context context="oem_notification"/>
+                            </device>
+                        </group>
+                    </volumeGroups>
+                    <applyFadeConfigs>
+                        <fadeConfig name="dynamic fading" isDefault="true">
+                        </fadeConfig>
+                        <fadeConfig name="aggressive fading">
+                            <audioAttributes>
+                                <usage value="AUDIO_USAGE_VOICE_COMMUNICATION" />
+                                <usage value="AUDIO_USAGE_ANNOUNCEMENT" />
+                                <usage value="AUDIO_USAGE_VEHICLE_STATUS" />
+                                <usage value="AUDIO_USAGE_SAFETY" />
+                            </audioAttributes>
+                        </fadeConfig>
+                        <fadeConfig name="disabled fading">
+                            <audioAttributes>
+                                <usage value="AUDIO_USAGE_EMERGENCY" />
+                            </audioAttributes>
+                        </fadeConfig>
+                    </applyFadeConfigs>
+                </zoneConfig>
+                <zoneConfig name="primary zone USB media">
+                    <volumeGroups>
+                        <group name="entertainment" activationConfig="on_boot_config">
+                            <device type="TYPE_USB_HEADSET">
+                                <context context="oem_music"/>
+                            </device>
+                        </group>
+                        <group name="navvoicecommand" activationConfig="on_source_changed_config">
+                            <device address="BUS02_NAV_GUIDANCE">
+                                <context context="oem_voice_command"/>
+                            </device>
+                        </group>
+                        <group name="telringvol" activationConfig="on_playback_changed_config">
+                            <device address="BUS03_PHONE">
+                                <context context="oem_call"/>
+                                <context context="oem_call_ring"/>
+                            </device>
+                        </group>
+                        <group name="systemalarm" activationConfig="on_source_changed_config">
+                            <device address="BUS01_SYS_NOTIFICATION">
+                                <context context="oem_alarm"/>
+                                <context context="oem_system_sound"/>
+                                <context context="oem_notification"/>
+                            </device>
+                        </group>
+                    </volumeGroups>
+                    <applyFadeConfigs>
+                        <fadeConfig name="dynamic fading" isDefault="true">
+                        </fadeConfig>
+                        <fadeConfig name="aggressive fading">
+                            <audioAttributes>
+                                <usage value="AUDIO_USAGE_VOICE_COMMUNICATION" />
+                                <usage value="AUDIO_USAGE_ANNOUNCEMENT" />
+                                <usage value="AUDIO_USAGE_VEHICLE_STATUS" />
+                                <usage value="AUDIO_USAGE_SAFETY" />
+                            </audioAttributes>
+                        </fadeConfig>
+                        <fadeConfig name="disabled fading">
+                            <audioAttributes>
+                                <usage value="AUDIO_USAGE_EMERGENCY" />
+                            </audioAttributes>
+                        </fadeConfig>
+                    </applyFadeConfigs>
+                </zoneConfig>
+            </zoneConfigs>
+        </zone>
+    </zones>
+</carAudioConfiguration>
diff --git a/automotive/audiocontrol/aidl/default/loaders/config/Android.bp b/automotive/audiocontrol/aidl/default/loaders/config/Android.bp
new file mode 100644
index 0000000..0d5eb81
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/loaders/config/Android.bp
@@ -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 {
+    // 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"],
+}
+
+xsd_config {
+    name: "car_audio_configuration_xsd",
+    srcs: ["car_audio_configuration.xsd"],
+    package_name: "android.hardware.automotive.audiocontrol",
+    nullability: true,
+}
+
+cc_defaults {
+    name: "car.audio.configuration.xsd.default",
+    static_libs: [
+        "libxml2",
+    ],
+    generated_sources: [
+        "car_audio_configuration_xsd",
+    ],
+    generated_headers: [
+        "car_audio_configuration_xsd",
+    ],
+    header_libs: [
+        "libxsdc-utils",
+    ],
+}
diff --git a/automotive/audiocontrol/aidl/default/loaders/config/api/current.txt b/automotive/audiocontrol/aidl/default/loaders/config/api/current.txt
new file mode 100644
index 0000000..c87b8c6
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/loaders/config/api/current.txt
@@ -0,0 +1,331 @@
+// Signature format: 2.0
+package android.hardware.automotive.audiocontrol {
+
+  public enum ActivationType {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.hardware.automotive.audiocontrol.ActivationType onBoot;
+    enum_constant public static final android.hardware.automotive.audiocontrol.ActivationType onPlaybackChanged;
+    enum_constant public static final android.hardware.automotive.audiocontrol.ActivationType onSourceChanged;
+  }
+
+  public class ActivationVolumeConfigEntryType {
+    ctor public ActivationVolumeConfigEntryType();
+    method @Nullable public android.hardware.automotive.audiocontrol.ActivationType getInvocationType();
+    method @Nullable public String getMaxActivationVolumePercentage();
+    method @Nullable public String getMinActivationVolumePercentage();
+    method public void setInvocationType(@Nullable android.hardware.automotive.audiocontrol.ActivationType);
+    method public void setMaxActivationVolumePercentage(@Nullable String);
+    method public void setMinActivationVolumePercentage(@Nullable String);
+  }
+
+  public class ActivationVolumeConfigType {
+    ctor public ActivationVolumeConfigType();
+    method @Nullable public java.util.List<android.hardware.automotive.audiocontrol.ActivationVolumeConfigEntryType> getActivationVolumeConfigEntry();
+    method @Nullable public String getName();
+    method public void setName(@Nullable String);
+  }
+
+  public class ActivationVolumeConfigsType {
+    ctor public ActivationVolumeConfigsType();
+    method @Nullable public java.util.List<android.hardware.automotive.audiocontrol.ActivationVolumeConfigType> getActivationVolumeConfig();
+  }
+
+  public class ApplyFadeConfigType {
+    ctor public ApplyFadeConfigType();
+    method @Nullable public java.util.List<android.hardware.automotive.audiocontrol.AudioAttributeUsagesType> getAudioAttributes();
+    method @Nullable public boolean getIsDefault();
+    method @Nullable public String getName();
+    method public void setIsDefault(@Nullable boolean);
+    method public void setName(@Nullable String);
+  }
+
+  public class ApplyFadeConfigsType {
+    ctor public ApplyFadeConfigsType();
+    method @Nullable public java.util.List<android.hardware.automotive.audiocontrol.ApplyFadeConfigType> getFadeConfig();
+  }
+
+  public class AttributesType {
+    ctor public AttributesType();
+    method @Nullable public android.hardware.automotive.audiocontrol.ContentTypeEnum getContentType();
+    method @Nullable public String getTags();
+    method @Nullable public android.hardware.automotive.audiocontrol.UsageEnumType getUsage();
+    method public void setContentType(@Nullable android.hardware.automotive.audiocontrol.ContentTypeEnum);
+    method public void setTags(@Nullable String);
+    method public void setUsage(@Nullable android.hardware.automotive.audiocontrol.UsageEnumType);
+  }
+
+  public class AudioAttributeUsagesType {
+    ctor public AudioAttributeUsagesType();
+    method @Nullable public java.util.List<android.hardware.automotive.audiocontrol.UsageType> getUsage();
+  }
+
+  public class AudioAttributesUsagesType {
+    ctor public AudioAttributesUsagesType();
+    method @Nullable public java.util.List<android.hardware.automotive.audiocontrol.AttributesType> getAudioAttribute_optional();
+    method @Nullable public java.util.List<android.hardware.automotive.audiocontrol.UsageType> getUsage_optional();
+  }
+
+  public class CarAudioConfigurationType {
+    ctor public CarAudioConfigurationType();
+    method @Nullable public android.hardware.automotive.audiocontrol.ActivationVolumeConfigsType getActivationVolumeConfigs();
+    method @Nullable public android.hardware.automotive.audiocontrol.DeviceConfigurationsType getDeviceConfigurations();
+    method @Nullable public android.hardware.automotive.audiocontrol.MirroringDevicesType getMirroringDevices();
+    method @Nullable public android.hardware.automotive.audiocontrol.OemContextsType getOemContexts();
+    method @Nullable public String getVersion();
+    method @Nullable public android.hardware.automotive.audiocontrol.ZonesType getZones();
+    method public void setActivationVolumeConfigs(@Nullable android.hardware.automotive.audiocontrol.ActivationVolumeConfigsType);
+    method public void setDeviceConfigurations(@Nullable android.hardware.automotive.audiocontrol.DeviceConfigurationsType);
+    method public void setMirroringDevices(@Nullable android.hardware.automotive.audiocontrol.MirroringDevicesType);
+    method public void setOemContexts(@Nullable android.hardware.automotive.audiocontrol.OemContextsType);
+    method public void setVersion(@Nullable String);
+    method public void setZones(@Nullable android.hardware.automotive.audiocontrol.ZonesType);
+  }
+
+  public class ContentType {
+    ctor public ContentType();
+    method @Nullable public android.hardware.automotive.audiocontrol.ContentTypeEnum getValue();
+    method public void setValue(@Nullable android.hardware.automotive.audiocontrol.ContentTypeEnum);
+  }
+
+  public enum ContentTypeEnum {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.hardware.automotive.audiocontrol.ContentTypeEnum AUDIO_CONTENT_TYPE_MOVIE;
+    enum_constant public static final android.hardware.automotive.audiocontrol.ContentTypeEnum AUDIO_CONTENT_TYPE_MUSIC;
+    enum_constant public static final android.hardware.automotive.audiocontrol.ContentTypeEnum AUDIO_CONTENT_TYPE_SONIFICATION;
+    enum_constant public static final android.hardware.automotive.audiocontrol.ContentTypeEnum AUDIO_CONTENT_TYPE_SPEECH;
+    enum_constant public static final android.hardware.automotive.audiocontrol.ContentTypeEnum AUDIO_CONTENT_TYPE_UNKNOWN;
+  }
+
+  public class ContextNameType {
+    ctor public ContextNameType();
+    method @Nullable public String getContext();
+    method public void setContext(@Nullable String);
+  }
+
+  public class DeviceConfigurationType {
+    ctor public DeviceConfigurationType();
+    method @Nullable public String getName();
+    method @Nullable public String getValue();
+    method public void setName(@Nullable String);
+    method public void setValue(@Nullable String);
+  }
+
+  public class DeviceConfigurationsType {
+    ctor public DeviceConfigurationsType();
+    method @Nullable public java.util.List<android.hardware.automotive.audiocontrol.DeviceConfigurationType> getDeviceConfiguration();
+  }
+
+  public class DeviceRoutesType {
+    ctor public DeviceRoutesType();
+    method @Nullable public String getAddress();
+    method @Nullable public java.util.List<android.hardware.automotive.audiocontrol.ContextNameType> getContext();
+    method @Nullable public android.hardware.automotive.audiocontrol.OutDeviceType getType();
+    method public void setAddress(@Nullable String);
+    method public void setType(@Nullable android.hardware.automotive.audiocontrol.OutDeviceType);
+  }
+
+  public enum InDeviceType {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_AMBIENT;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_AUX_DIGITAL;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_BACK_MIC;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_BLUETOOTH_BLE;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_BUILTIN_MIC;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_BUS;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_COMMUNICATION;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_DEFAULT;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_ECHO_REFERENCE;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_FM_TUNER;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_HDMI;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_HDMI_ARC;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_IP;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_LINE;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_LOOPBACK;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_PROXY;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_SPDIF;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_STUB;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_TELEPHONY_RX;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_TV_TUNER;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_USB_ACCESSORY;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_USB_DEVICE;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_USB_HEADSET;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_VOICE_CALL;
+    enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_WIRED_HEADSET;
+  }
+
+  public class InputDeviceType {
+    ctor public InputDeviceType();
+    method @Nullable public String getAddress();
+    method @Nullable public android.hardware.automotive.audiocontrol.InDeviceType getType();
+    method public void setAddress(@Nullable String);
+    method public void setType(@Nullable android.hardware.automotive.audiocontrol.InDeviceType);
+  }
+
+  public class InputDevicesType {
+    ctor public InputDevicesType();
+    method @Nullable public java.util.List<android.hardware.automotive.audiocontrol.InputDeviceType> getInputDevice();
+  }
+
+  public class MirroringDevice {
+    ctor public MirroringDevice();
+    method @Nullable public String getAddress();
+    method public void setAddress(@Nullable String);
+  }
+
+  public class MirroringDevicesType {
+    ctor public MirroringDevicesType();
+    method @Nullable public java.util.List<android.hardware.automotive.audiocontrol.MirroringDevice> getMirroringDevice();
+  }
+
+  public class OemContextType {
+    ctor public OemContextType();
+    method @Nullable public android.hardware.automotive.audiocontrol.AudioAttributesUsagesType getAudioAttributes();
+    method @Nullable public String getId();
+    method @Nullable public String getName();
+    method public void setAudioAttributes(@Nullable android.hardware.automotive.audiocontrol.AudioAttributesUsagesType);
+    method public void setId(@Nullable String);
+    method public void setName(@Nullable String);
+  }
+
+  public class OemContextsType {
+    ctor public OemContextsType();
+    method @Nullable public java.util.List<android.hardware.automotive.audiocontrol.OemContextType> getOemContext();
+  }
+
+  public enum OutDeviceType {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_AUX_DIGITAL;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_AUX_LINE;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_BLE_BROADCAST;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_BLE_HEADSET;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_BLE_SPEAKER;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_BUS;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_DEFAULT;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_HDMI;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_HDMI_ARC;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_HDMI_EARC;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_LINE;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_SPEAKER;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_USB_ACCESSORY;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_USB_DEVICE;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_USB_HEADSET;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_WIRED_HEADSET;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_AUX_LINE;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_BLE_BROADCAST;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_BLE_HEADSET;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_BLE_SPEAKER;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_BLUETOOTH_A2DP;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_BUILTIN_SPEAKER;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_BUS;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_HDMI;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_USB_ACCESSORY;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_USB_DEVICE;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_USB_HEADSET;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_WIRED_HEADPHONES;
+    enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_WIRED_HEADSET;
+  }
+
+  public enum UsageEnumType {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_ALARM;
+    enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_ANNOUNCEMENT;
+    enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
+    enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+    enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_ASSISTANCE_SONIFICATION;
+    enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_ASSISTANT;
+    enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_CALL_ASSISTANT;
+    enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_EMERGENCY;
+    enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_GAME;
+    enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_MEDIA;
+    enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_NOTIFICATION;
+    enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED;
+    enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT;
+    enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST;
+    enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_NOTIFICATION_EVENT;
+    enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
+    enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_SAFETY;
+    enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_UNKNOWN;
+    enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_VEHICLE_STATUS;
+    enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_VIRTUAL_SOURCE;
+    enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION;
+    enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
+  }
+
+  public class UsageType {
+    ctor public UsageType();
+    method @Nullable public android.hardware.automotive.audiocontrol.UsageEnumType getValue();
+    method public void setValue(@Nullable android.hardware.automotive.audiocontrol.UsageEnumType);
+  }
+
+  public class VolumeGroupType {
+    ctor public VolumeGroupType();
+    method @Nullable public String getActivationConfig();
+    method @Nullable public java.util.List<android.hardware.automotive.audiocontrol.DeviceRoutesType> getDevice();
+    method @Nullable public String getName();
+    method public void setActivationConfig(@Nullable String);
+    method public void setName(@Nullable String);
+  }
+
+  public class VolumeGroupsType {
+    ctor public VolumeGroupsType();
+    method @Nullable public java.util.List<android.hardware.automotive.audiocontrol.VolumeGroupType> getGroup();
+  }
+
+  public class XmlParser {
+    ctor public XmlParser();
+    method @Nullable public static android.hardware.automotive.audiocontrol.CarAudioConfigurationType read(@NonNull java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method @Nullable public static String readText(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static void skip(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+  }
+
+  public class ZoneConfigType {
+    ctor public ZoneConfigType();
+    method @Nullable public android.hardware.automotive.audiocontrol.ApplyFadeConfigsType getApplyFadeConfigs();
+    method @Nullable public boolean getIsDefault();
+    method @Nullable public String getName();
+    method @Nullable public android.hardware.automotive.audiocontrol.VolumeGroupsType getVolumeGroups();
+    method public void setApplyFadeConfigs(@Nullable android.hardware.automotive.audiocontrol.ApplyFadeConfigsType);
+    method public void setIsDefault(@Nullable boolean);
+    method public void setName(@Nullable String);
+    method public void setVolumeGroups(@Nullable android.hardware.automotive.audiocontrol.VolumeGroupsType);
+  }
+
+  public class ZoneConfigsType {
+    ctor public ZoneConfigsType();
+    method @Nullable public android.hardware.automotive.audiocontrol.ZoneConfigType getZoneConfig();
+    method public void setZoneConfig(@Nullable android.hardware.automotive.audiocontrol.ZoneConfigType);
+  }
+
+  public class ZoneType {
+    ctor public ZoneType();
+    method @Nullable public String getAudioZoneId();
+    method @Nullable public android.hardware.automotive.audiocontrol.InputDevicesType getInputDevices();
+    method @Nullable public boolean getIsPrimary();
+    method @Nullable public String getName();
+    method @Nullable public String getOccupantZoneId();
+    method @Nullable public android.hardware.automotive.audiocontrol.ZoneConfigsType getZoneConfigs();
+    method public void setAudioZoneId(@Nullable String);
+    method public void setInputDevices(@Nullable android.hardware.automotive.audiocontrol.InputDevicesType);
+    method public void setIsPrimary(@Nullable boolean);
+    method public void setName(@Nullable String);
+    method public void setOccupantZoneId(@Nullable String);
+    method public void setZoneConfigs(@Nullable android.hardware.automotive.audiocontrol.ZoneConfigsType);
+  }
+
+  public class ZonesType {
+    ctor public ZonesType();
+    method @Nullable public java.util.List<android.hardware.automotive.audiocontrol.ZoneType> getZone();
+  }
+
+}
+
diff --git a/automotive/audiocontrol/aidl/default/loaders/config/api/last_current.txt b/automotive/audiocontrol/aidl/default/loaders/config/api/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/loaders/config/api/last_current.txt
diff --git a/automotive/audiocontrol/aidl/default/loaders/config/api/last_removed.txt b/automotive/audiocontrol/aidl/default/loaders/config/api/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/loaders/config/api/last_removed.txt
diff --git a/automotive/audiocontrol/aidl/default/loaders/config/api/removed.txt b/automotive/audiocontrol/aidl/default/loaders/config/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/loaders/config/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/automotive/audiocontrol/aidl/default/loaders/config/car_audio_configuration.xsd b/automotive/audiocontrol/aidl/default/loaders/config/car_audio_configuration.xsd
new file mode 100644
index 0000000..634aeda
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/loaders/config/car_audio_configuration.xsd
@@ -0,0 +1,248 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<xs:schema version="2.0" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+    <xs:element name="carAudioConfiguration" type="CarAudioConfigurationType" minOccurs="1" maxOccurs="1" />
+    <xs:complexType name="CarAudioConfigurationType">
+        <xs:attribute name="version" type="xs:string" use="required" />
+        <xs:sequence>
+            <xs:element name="mirroringDevices" type="MirroringDevicesType" minOccurs="0" />
+            <xs:element name="deviceConfigurations" type="DeviceConfigurationsType" minOccurs="0" />
+            <xs:element name="oemContexts" type="OemContextsType" />
+            <xs:element name="activationVolumeConfigs" type="ActivationVolumeConfigsType" minOccurs="0" />
+            <xs:element name="zones" type="ZonesType" />
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="ZonesType">
+        <xs:element name="zone" type="ZoneType" minOccurs="1" maxOccurs="unbounded" />
+    </xs:complexType>
+    <xs:complexType name="ActivationVolumeConfigsType">
+        <xs:element name="activationVolumeConfig" type="ActivationVolumeConfigType" maxOccurs="unbounded" />
+    </xs:complexType>
+    <xs:complexType name="OemContextsType">
+        <xs:element name="oemContext" type="OemContextType" minOccurs="1" maxOccurs="unbounded" />
+    </xs:complexType>
+    <xs:complexType name="DeviceConfigurationsType">
+        <xs:element name="deviceConfiguration" type="DeviceConfigurationType" minOccurs="0" maxOccurs="unbounded" />
+    </xs:complexType>
+    <xs:complexType name="ZoneType">
+        <xs:attribute name="name" type="xs:string" />
+        <xs:attribute name="audioZoneId" type="xs:string" use="required" />
+        <xs:attribute name="isPrimary" type="xs:boolean" />
+        <xs:attribute name="occupantZoneId" type="xs:string" />
+        <xs:element name="inputDevices" type="InputDevicesType" />
+        <xs:element name="zoneConfigs" type="ZoneConfigsType" />
+    </xs:complexType>
+    <xs:complexType name="ZoneConfigsType">
+        <xs:element name="zoneConfig" type="ZoneConfigType"/>
+    </xs:complexType>
+    <xs:complexType name="ZoneConfigType">
+        <xs:attribute name="name" type="xs:string" />
+        <xs:attribute name="isDefault" type="xs:boolean" />
+        <xs:element name="volumeGroups" type="VolumeGroupsType" />
+        <xs:element name="applyFadeConfigs" type="ApplyFadeConfigsType" />
+    </xs:complexType>
+    <xs:complexType name="ApplyFadeConfigsType">
+        <xs:element name="fadeConfig" type="ApplyFadeConfigType" minOccurs="0" maxOccurs="unbounded" />
+    </xs:complexType>
+    <xs:complexType name="ApplyFadeConfigType">
+        <xs:attribute name="name" type="xs:string" />
+        <xs:attribute name="isDefault" type="xs:boolean" />
+        <xs:element name="audioAttributes" type="AudioAttributeUsagesType" minOccurs="0" maxOccurs="unbounded" />
+    </xs:complexType>
+    <xs:complexType name="AudioAttributeUsagesType">
+        <xs:element name="usage" type="UsageType" maxOccurs="unbounded" />
+    </xs:complexType>
+    <xs:complexType name="VolumeGroupsType">
+        <xs:element name="group"  type="VolumeGroupType" minOccurs="1" maxOccurs="unbounded" />
+    </xs:complexType>
+    <xs:complexType name="VolumeGroupType">
+        <xs:attribute name="name" type="xs:string" />
+        <xs:attribute name="activationConfig" type="xs:string" />
+        <xs:element name="device" type="DeviceRoutesType" minOccurts="1" maxOccurs="unbounded" />
+    </xs:complexType>
+    <xs:complexType name="DeviceRoutesType" >
+        <xs:attribute name="address" type="xs:string" />
+        <xs:attribute name="type" type="OutDeviceType" />
+        <xs:element name="context" type="ContextNameType" mixOccurs="1" maxOccurs="unbounded" />
+    </xs:complexType>
+    <xs:complexType name="ContextNameType">
+        <xs:attribute name="context" type="xs:string"/>
+    </xs:complexType>
+    <xs:complexType name="OemContextType">
+        <xs:attribute name="name" type="xs:string" />
+        <xs:attribute name="id" type="xs:string" />
+        <xs:element name="audioAttributes" type="AudioAttributesUsagesType" minOccurs="1" maxOccurs="1" />
+    </xs:complexType>
+    <xs:complexType name="AudioAttributesUsagesType" >
+        <xs:choice minOccurs="0" maxOccurs="unbounded" >
+            <xs:element name="audioAttribute" type="AttributesType" />
+            <xs:element name="usage" type="UsageType" />
+        </xs:choice>
+    </xs:complexType>
+    <xs:complexType name="AttributesType">
+        <xs:attribute name="contentType" type="contentTypeEnum" />
+        <xs:attribute name="usage" type="usageEnumType" />
+        <xs:attribute name="tags" type="xs:string" />
+    </xs:complexType>
+    <xs:complexType name="DeviceConfigurationType">
+        <xs:attribute name="name" type="xs:string" />
+        <xs:attribute name="value" type="xs:string" />
+    </xs:complexType>
+    <xs:complexType name="ContentType" >
+        <xs:attribute name="value" type="contentTypeEnum" use="required" />
+    </xs:complexType>
+    <xs:complexType name="UsageType">
+        <xs:attribute name="value" type="usageEnumType" use="required" />
+    </xs:complexType>
+    <xs:simpleType name="contentTypeEnum">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_CONTENT_TYPE_UNKNOWN"/>
+            <xs:enumeration value="AUDIO_CONTENT_TYPE_SPEECH"/>
+            <xs:enumeration value="AUDIO_CONTENT_TYPE_MUSIC"/>
+            <xs:enumeration value="AUDIO_CONTENT_TYPE_MOVIE"/>
+            <xs:enumeration value="AUDIO_CONTENT_TYPE_SONIFICATION"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="usageEnumType">
+      <xs:restriction base="xs:string">
+          <xs:enumeration value="AUDIO_USAGE_UNKNOWN"/>
+          <xs:enumeration value="AUDIO_USAGE_MEDIA"/>
+          <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION"/>
+          <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING"/>
+          <xs:enumeration value="AUDIO_USAGE_ALARM"/>
+          <xs:enumeration value="AUDIO_USAGE_NOTIFICATION"/>
+          <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE"/>
+          <!-- Note: the following 3 values were deprecated in Android T (13) SDK -->
+          <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST"/>
+          <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT"/>
+          <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED"/>
+          <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_EVENT"/>
+          <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY"/>
+          <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/>
+          <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_SONIFICATION"/>
+          <xs:enumeration value="AUDIO_USAGE_GAME"/>
+          <xs:enumeration value="AUDIO_USAGE_VIRTUAL_SOURCE"/>
+          <xs:enumeration value="AUDIO_USAGE_ASSISTANT"/>
+          <xs:enumeration value="AUDIO_USAGE_CALL_ASSISTANT"/>
+          <xs:enumeration value="AUDIO_USAGE_EMERGENCY" />
+          <xs:enumeration value="AUDIO_USAGE_SAFETY" />
+          <xs:enumeration value="AUDIO_USAGE_VEHICLE_STATUS" />
+          <xs:enumeration value="AUDIO_USAGE_ANNOUNCEMENT" />
+      </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="ActivationVolumeConfigType">
+        <xs:attribute name="name" type="xs:string" />
+        <xs:element name="activationVolumeConfigEntry" type="ActivationVolumeConfigEntryType" maxOccurs="unbounded" />
+    </xs:complexType>
+    <xs:complexType name="ActivationVolumeConfigEntryType">
+          <xs:attribute name="maxActivationVolumePercentage" type="xs:string" />
+          <xs:attribute name="minActivationVolumePercentage" type="xs:string" />
+          <xs:attribute name="invocationType" type="ActivationType" />
+    </xs:complexType>
+    <xs:simpleType name="ActivationType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="onBoot"/>
+            <xs:enumeration value="onSourceChanged"/>
+            <xs:enumeration value="onPlaybackChanged"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="OutDeviceType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADPHONE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI_EARC"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_DIGITAL"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_USB_ACCESSORY"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_USB_DEVICE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_LINE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI_ARC"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_LINE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER_SAFE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BUS"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_USB_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLE_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLE_SPEAKER"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLE_BROADCAST"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_DEFAULT"/>
+            <!-- Added to support legacy files -->
+            <xs:enumeration value="TYPE_BUILTIN_SPEAKER"/>
+            <xs:enumeration value="TYPE_WIRED_HEADSET"/>
+            <xs:enumeration value="TYPE_WIRED_HEADPHONES"/>
+            <xs:enumeration value="TYPE_BLUETOOTH_A2DP"/>
+            <xs:enumeration value="TYPE_HDMI"/>
+            <xs:enumeration value="TYPE_USB_ACCESSORY"/>
+            <xs:enumeration value="TYPE_USB_DEVICE"/>
+            <xs:enumeration value="TYPE_USB_HEADSET"/>
+            <xs:enumeration value="TYPE_AUX_LINE"/>
+            <xs:enumeration value="TYPE_BUS"/>
+            <xs:enumeration value="TYPE_BLE_HEADSET"/>
+            <xs:enumeration value="TYPE_BLE_SPEAKER"/>
+            <xs:enumeration value="TYPE_BLE_BROADCAST"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="MirroringDevicesType">
+        <xs:element name="mirroringDevice" type="MirroringDevice" maxOccurs="unbounded" />
+    </xs:complexType>
+    <xs:complexType name="MirroringDevice">
+        <xs:attribute name="address" type="xs:string" />
+    </xs:complexType>
+    <xs:complexType name="InputDevicesType">
+        <xs:element name="inputDevice" type="InputDeviceType" maxOccurs="unbounded" />
+    </xs:complexType>
+    <xs:complexType name="InputDeviceType">
+        <xs:attribute name="address" type="xs:string" />
+        <xs:attribute name="type" type="InDeviceType" />
+    </xs:complexType>
+    <xs:simpleType name="InDeviceType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_DEVICE_IN_COMMUNICATION"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_AMBIENT"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BUILTIN_MIC"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_WIRED_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_AUX_DIGITAL"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_HDMI"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_VOICE_CALL"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_TELEPHONY_RX"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BACK_MIC"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_REMOTE_SUBMIX"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_USB_ACCESSORY"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_USB_DEVICE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_FM_TUNER"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_TV_TUNER"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_LINE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_SPDIF"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_A2DP"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_LOOPBACK"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_IP"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BUS"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_PROXY"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_USB_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_BLE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_HDMI_ARC"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_ECHO_REFERENCE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_DEFAULT"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_STUB"/>
+        </xs:restriction>
+    </xs:simpleType>
+</xs:schema>
diff --git a/automotive/audiocontrol/aidl/default/loaders/fade/Android.bp b/automotive/audiocontrol/aidl/default/loaders/fade/Android.bp
new file mode 100644
index 0000000..3dbc2f1
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/loaders/fade/Android.bp
@@ -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 {
+    // 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"],
+}
+
+xsd_config {
+    name: "car_fade_audio_configuration_xsd",
+    srcs: ["car_fade_audio_configuration.xsd"],
+    package_name: "android.hardware.automotive.audiocontrol.fade",
+    nullability: true,
+}
+
+cc_defaults {
+    name: "car.fade.configuration.xsd.default",
+    static_libs: [
+        "libxml2",
+    ],
+    generated_sources: [
+        "car_fade_audio_configuration_xsd",
+    ],
+    generated_headers: [
+        "car_fade_audio_configuration_xsd",
+    ],
+    header_libs: [
+        "libxsdc-utils",
+    ],
+}
diff --git a/automotive/audiocontrol/aidl/default/loaders/fade/api/current.txt b/automotive/audiocontrol/aidl/default/loaders/fade/api/current.txt
new file mode 100644
index 0000000..f40f1be
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/loaders/fade/api/current.txt
@@ -0,0 +1,160 @@
+// Signature format: 2.0
+package android.hardware.automotive.audiocontrol.fade {
+
+  public class AttributesType {
+    ctor public AttributesType();
+    method @Nullable public android.hardware.automotive.audiocontrol.fade.ContentTypeEnum getContentType();
+    method @Nullable public String getTags();
+    method @Nullable public android.hardware.automotive.audiocontrol.fade.UsageEnumType getUsage();
+    method public void setContentType(@Nullable android.hardware.automotive.audiocontrol.fade.ContentTypeEnum);
+    method public void setTags(@Nullable String);
+    method public void setUsage(@Nullable android.hardware.automotive.audiocontrol.fade.UsageEnumType);
+  }
+
+  public class AudioAttributesUsagesType {
+    ctor public AudioAttributesUsagesType();
+    method @Nullable public java.util.List<android.hardware.automotive.audiocontrol.fade.AttributesType> getAudioAttribute_optional();
+    method @Nullable public java.util.List<android.hardware.automotive.audiocontrol.fade.UsageType> getUsage_optional();
+  }
+
+  public class CarAudioFadeConfigurationType {
+    ctor public CarAudioFadeConfigurationType();
+    method @Nullable public android.hardware.automotive.audiocontrol.fade.FadeConfigurationConfigs getConfigs();
+    method public void setConfigs(@Nullable android.hardware.automotive.audiocontrol.fade.FadeConfigurationConfigs);
+  }
+
+  public class ContentType {
+    ctor public ContentType();
+    method @Nullable public android.hardware.automotive.audiocontrol.fade.ContentTypeEnum getValue();
+    method public void setValue(@Nullable android.hardware.automotive.audiocontrol.fade.ContentTypeEnum);
+  }
+
+  public enum ContentTypeEnum {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.ContentTypeEnum AUDIO_CONTENT_TYPE_MOVIE;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.ContentTypeEnum AUDIO_CONTENT_TYPE_MUSIC;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.ContentTypeEnum AUDIO_CONTENT_TYPE_SONIFICATION;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.ContentTypeEnum AUDIO_CONTENT_TYPE_SPEECH;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.ContentTypeEnum AUDIO_CONTENT_TYPE_UNKNOWN;
+  }
+
+  public class FadeConfigurationConfig {
+    ctor public FadeConfigurationConfig();
+    method @Nullable public String getDefaultFadeInDelayForOffenders();
+    method @Nullable public String getDefaultFadeInDurationInMillis();
+    method @Nullable public String getDefaultFadeOutDurationInMillis();
+    method @Nullable public android.hardware.automotive.audiocontrol.fade.FadeInConfigurationsType getFadeInConfigurations();
+    method @Nullable public android.hardware.automotive.audiocontrol.fade.FadeOutConfigurationsType getFadeOutConfigurations();
+    method @Nullable public android.hardware.automotive.audiocontrol.fade.FadeStateType getFadeState();
+    method @Nullable public android.hardware.automotive.audiocontrol.fade.FadeableUsagesType getFadeableUsages();
+    method @Nullable public String getName();
+    method @Nullable public android.hardware.automotive.audiocontrol.fade.UnfadeableAudioAttributesType getUnfadeableAudioAttributes();
+    method @Nullable public android.hardware.automotive.audiocontrol.fade.UnfadeableContentTypesType getUnfadeableContentTypes();
+    method public void setDefaultFadeInDelayForOffenders(@Nullable String);
+    method public void setDefaultFadeInDurationInMillis(@Nullable String);
+    method public void setDefaultFadeOutDurationInMillis(@Nullable String);
+    method public void setFadeInConfigurations(@Nullable android.hardware.automotive.audiocontrol.fade.FadeInConfigurationsType);
+    method public void setFadeOutConfigurations(@Nullable android.hardware.automotive.audiocontrol.fade.FadeOutConfigurationsType);
+    method public void setFadeState(@Nullable android.hardware.automotive.audiocontrol.fade.FadeStateType);
+    method public void setFadeableUsages(@Nullable android.hardware.automotive.audiocontrol.fade.FadeableUsagesType);
+    method public void setName(@Nullable String);
+    method public void setUnfadeableAudioAttributes(@Nullable android.hardware.automotive.audiocontrol.fade.UnfadeableAudioAttributesType);
+    method public void setUnfadeableContentTypes(@Nullable android.hardware.automotive.audiocontrol.fade.UnfadeableContentTypesType);
+  }
+
+  public class FadeConfigurationConfigs {
+    ctor public FadeConfigurationConfigs();
+    method @Nullable public java.util.List<android.hardware.automotive.audiocontrol.fade.FadeConfigurationConfig> getConfig();
+  }
+
+  public class FadeConfigurationType {
+    ctor public FadeConfigurationType();
+    method @Nullable public android.hardware.automotive.audiocontrol.fade.AudioAttributesUsagesType getAudioAttributes();
+    method @Nullable public String getFadeDurationMillis();
+    method public void setAudioAttributes(@Nullable android.hardware.automotive.audiocontrol.fade.AudioAttributesUsagesType);
+    method public void setFadeDurationMillis(@Nullable String);
+  }
+
+  public class FadeInConfigurationsType {
+    ctor public FadeInConfigurationsType();
+    method @Nullable public android.hardware.automotive.audiocontrol.fade.FadeConfigurationType getFadeConfiguration();
+    method public void setFadeConfiguration(@Nullable android.hardware.automotive.audiocontrol.fade.FadeConfigurationType);
+  }
+
+  public class FadeOutConfigurationsType {
+    ctor public FadeOutConfigurationsType();
+    method @Nullable public android.hardware.automotive.audiocontrol.fade.FadeConfigurationType getFadeConfiguration();
+    method public void setFadeConfiguration(@Nullable android.hardware.automotive.audiocontrol.fade.FadeConfigurationType);
+  }
+
+  public enum FadeStateEnumType {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.FadeStateEnumType FADE_STATE_DISABLED;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.FadeStateEnumType FADE_STATE_ENABLED_DEFAULT;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.FadeStateEnumType _0;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.FadeStateEnumType _1;
+  }
+
+  public class FadeStateType {
+    ctor public FadeStateType();
+    method @Nullable public android.hardware.automotive.audiocontrol.fade.FadeStateEnumType getValue();
+    method public void setValue(@Nullable android.hardware.automotive.audiocontrol.fade.FadeStateEnumType);
+  }
+
+  public class FadeableUsagesType {
+    ctor public FadeableUsagesType();
+    method @Nullable public java.util.List<android.hardware.automotive.audiocontrol.fade.UsageType> getUsage();
+  }
+
+  public class UnfadeableAudioAttributesType {
+    ctor public UnfadeableAudioAttributesType();
+    method @Nullable public android.hardware.automotive.audiocontrol.fade.AudioAttributesUsagesType getAudioAttributes();
+    method public void setAudioAttributes(@Nullable android.hardware.automotive.audiocontrol.fade.AudioAttributesUsagesType);
+  }
+
+  public class UnfadeableContentTypesType {
+    ctor public UnfadeableContentTypesType();
+    method @Nullable public java.util.List<android.hardware.automotive.audiocontrol.fade.ContentType> getContentType();
+  }
+
+  public enum UsageEnumType {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_ALARM;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_ANNOUNCEMENT;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_ASSISTANCE_SONIFICATION;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_ASSISTANT;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_CALL_ASSISTANT;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_EMERGENCY;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_GAME;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_MEDIA;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_NOTIFICATION;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_NOTIFICATION_EVENT;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_SAFETY;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_UNKNOWN;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_VEHICLE_STATUS;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_VIRTUAL_SOURCE;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION;
+    enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
+  }
+
+  public class UsageType {
+    ctor public UsageType();
+    method @Nullable public android.hardware.automotive.audiocontrol.fade.UsageEnumType getValue();
+    method public void setValue(@Nullable android.hardware.automotive.audiocontrol.fade.UsageEnumType);
+  }
+
+  public class XmlParser {
+    ctor public XmlParser();
+    method @Nullable public static android.hardware.automotive.audiocontrol.fade.CarAudioFadeConfigurationType read(@NonNull java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method @Nullable public static String readText(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static void skip(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+  }
+
+}
+
diff --git a/automotive/audiocontrol/aidl/default/loaders/fade/api/last_current.txt b/automotive/audiocontrol/aidl/default/loaders/fade/api/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/loaders/fade/api/last_current.txt
diff --git a/automotive/audiocontrol/aidl/default/loaders/fade/api/last_removed.txt b/automotive/audiocontrol/aidl/default/loaders/fade/api/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/loaders/fade/api/last_removed.txt
diff --git a/automotive/audiocontrol/aidl/default/loaders/fade/api/removed.txt b/automotive/audiocontrol/aidl/default/loaders/fade/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/loaders/fade/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/automotive/audiocontrol/aidl/default/loaders/fade/car_fade_audio_configuration.xsd b/automotive/audiocontrol/aidl/default/loaders/fade/car_fade_audio_configuration.xsd
new file mode 100644
index 0000000..051be7e
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/loaders/fade/car_fade_audio_configuration.xsd
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" version="2.0">
+    <xs:element name="carAudioFadeConfiguration" type="CarAudioFadeConfigurationType" />
+    <xs:complexType name="CarAudioFadeConfigurationType">
+        <xs:element name="configs" type="FadeConfigurationConfigs" />
+    </xs:complexType>
+    <xs:complexType name="FadeConfigurationConfigs">
+        <xs:element name="config" type="FadeConfigurationConfig" maxOccurs="unbounded" />
+    </xs:complexType>
+    <xs:complexType name="FadeConfigurationConfig">
+        <xs:attribute name="name" type="xs:string" />
+        <xs:attribute name="defaultFadeOutDurationInMillis" type="xs:string" />
+        <xs:attribute name="defaultFadeInDurationInMillis" type="xs:string" />
+        <xs:attribute name="defaultFadeInDelayForOffenders" type="xs:string" />
+        <xs:element name="fadeState" type="FadeStateType" />
+        <xs:element name="fadeableUsages" type="FadeableUsagesType" />
+        <xs:element name="unfadeableContentTypes" type="UnfadeableContentTypesType" />
+        <xs:element name="unfadeableAudioAttributes" type="UnfadeableAudioAttributesType" />
+        <xs:element name="fadeOutConfigurations" type="FadeOutConfigurationsType" />
+        <xs:element name="fadeInConfigurations" type="FadeInConfigurationsType" />
+    </xs:complexType>
+    <xs:complexType name="FadeStateType">
+        <xs:attribute name="value" type="fadeStateEnumType" />
+    </xs:complexType>
+    <xs:simpleType name="fadeStateEnumType" >
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="0" />
+            <xs:enumeration value="1" />
+            <xs:enumeration value="FADE_STATE_DISABLED" />
+            <xs:enumeration value="FADE_STATE_ENABLED_DEFAULT" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="FadeableUsagesType">
+        <xs:element name="usage" type="UsageType" maxOccurs="unbounded" />
+    </xs:complexType>
+    <xs:complexType name="UsageType">
+        <xs:attribute name="value" type="usageEnumType" />
+    </xs:complexType>
+    <xs:simpleType name="usageEnumType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_USAGE_UNKNOWN"/>
+            <xs:enumeration value="AUDIO_USAGE_MEDIA"/>
+            <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION"/>
+            <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING"/>
+            <xs:enumeration value="AUDIO_USAGE_ALARM"/>
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION"/>
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE"/>
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST"/>
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT"/>
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED"/>
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_EVENT"/>
+            <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY"/>
+            <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/>
+            <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_SONIFICATION"/>
+            <xs:enumeration value="AUDIO_USAGE_GAME"/>
+            <xs:enumeration value="AUDIO_USAGE_VIRTUAL_SOURCE"/>
+            <xs:enumeration value="AUDIO_USAGE_ASSISTANT"/>
+            <xs:enumeration value="AUDIO_USAGE_CALL_ASSISTANT"/>
+            <xs:enumeration value="AUDIO_USAGE_EMERGENCY" />
+            <xs:enumeration value="AUDIO_USAGE_SAFETY" />
+            <xs:enumeration value="AUDIO_USAGE_VEHICLE_STATUS" />
+            <xs:enumeration value="AUDIO_USAGE_ANNOUNCEMENT" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="UnfadeableContentTypesType">
+        <xs:element name="contentType" type="ContentType" maxOccurs="unbounded" />
+    </xs:complexType>
+    <xs:complexType name="ContentType">
+        <xs:attribute name="value" type="contentTypeEnum" />
+    </xs:complexType>
+    <xs:simpleType name="contentTypeEnum">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_CONTENT_TYPE_UNKNOWN"/>
+            <xs:enumeration value="AUDIO_CONTENT_TYPE_SPEECH"/>
+            <xs:enumeration value="AUDIO_CONTENT_TYPE_MUSIC"/>
+            <xs:enumeration value="AUDIO_CONTENT_TYPE_MOVIE"/>
+            <xs:enumeration value="AUDIO_CONTENT_TYPE_SONIFICATION"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="UnfadeableAudioAttributesType">
+        <xs:element name="audioAttributes" type="AudioAttributesUsagesType" />
+    </xs:complexType>
+    <xs:complexType name="AudioAttributesUsagesType" >
+        <xs:choice minOccurs="0" maxOccurs="unbounded" >
+            <xs:element name="audioAttribute" type="AttributesType" />
+            <xs:element name="usage" type="UsageType" />
+        </xs:choice>
+    </xs:complexType>
+    <xs:complexType name="AttributesType">
+        <xs:attribute name="contentType" type="contentTypeEnum" />
+        <xs:attribute name="usage" type="usageEnumType" />
+        <xs:attribute name="tags" type="xs:string" />
+    </xs:complexType>
+    <xs:complexType name="FadeOutConfigurationsType">
+        <xs:element name="fadeConfiguration" type="FadeConfigurationType" />
+    </xs:complexType>
+    <xs:complexType name="FadeConfigurationType">
+        <xs:attribute name="fadeDurationMillis" type="xs:string" />
+        <xs:element name="audioAttributes" type="AudioAttributesUsagesType" />
+    </xs:complexType>
+    <xs:complexType name="FadeInConfigurationsType">
+        <xs:element name="fadeConfiguration" type="FadeConfigurationType" />
+    </xs:complexType>
+</xs:schema>
diff --git a/automotive/audiocontrol/aidl/rust_impl/Android.bp b/automotive/audiocontrol/aidl/rust_impl/Android.bp
index 062d989..f9d07b2 100644
--- a/automotive/audiocontrol/aidl/rust_impl/Android.bp
+++ b/automotive/audiocontrol/aidl/rust_impl/Android.bp
@@ -15,7 +15,7 @@
  */
 
 rust_binary {
-    name: "android.hardware.automotive.audiocontrol-V4-rust-service",
+    name: "android.hardware.automotive.audiocontrol-rust-service",
     relative_install_path: "hw",
     vendor: true,
     srcs: ["src/*.rs"],
@@ -23,6 +23,7 @@
     defaults: [
         "latest_android_hardware_automotive_audiocontrol_rust",
         "latest_android_hardware_audio_common_rust",
+        "latest_android_media_audio_common_types_rust",
     ],
     vintf_fragments: ["audiocontrol-rust-service.xml"],
     init_rc: ["audiocontrol-rust-service.rc"],
diff --git a/automotive/audiocontrol/aidl/rust_impl/README.md b/automotive/audiocontrol/aidl/rust_impl/README.md
index ed22356..b68daf3 100644
--- a/automotive/audiocontrol/aidl/rust_impl/README.md
+++ b/automotive/audiocontrol/aidl/rust_impl/README.md
@@ -6,7 +6,7 @@
 This folder contains a skeleton audio control HAL implementation in Rust to
 demonstrate  how vendor may implement a Rust audio control HAL. To run this
 audio control HAL, include
-`android.hardware.automotive.audiocontrol-V4-rust-service` in your image.
+`android.hardware.automotive.audiocontrol-rust-service` in your image.
 
 This implementation returns `StatusCode::UNKNOWN_ERROR` for all operations
 and does not pass VTS/CTS. Vendor must replace the logic in
diff --git a/automotive/audiocontrol/aidl/rust_impl/src/default_audio_control_hal.rs b/automotive/audiocontrol/aidl/rust_impl/src/default_audio_control_hal.rs
index ba0ca23..8184c43 100644
--- a/automotive/audiocontrol/aidl/rust_impl/src/default_audio_control_hal.rs
+++ b/automotive/audiocontrol/aidl/rust_impl/src/default_audio_control_hal.rs
@@ -23,8 +23,15 @@
     IModuleChangeCallback::IModuleChangeCallback,
     MutingInfo::MutingInfo,
     Reasons::Reasons,
+    AudioDeviceConfiguration::AudioDeviceConfiguration,
+    AudioZone::AudioZone
 };
-use android_hardware_audio_common::aidl::android::hardware::audio::common::PlaybackTrackMetadata::PlaybackTrackMetadata;
+use android_hardware_audio_common::aidl::android::hardware::audio::common::{
+    PlaybackTrackMetadata::PlaybackTrackMetadata,
+};
+use android_media_audio_common_types::aidl::android::media::audio::common::{
+    AudioPort::AudioPort,
+};
 use binder::{Interface, Result as BinderResult, StatusCode, Strong};
 
 /// This struct is defined to implement IAudioControl AIDL interface.
@@ -81,4 +88,16 @@
     fn clearModuleChangeCallback(&self) -> BinderResult<()> {
         Err(StatusCode::UNKNOWN_ERROR.into())
     }
+
+    fn getAudioDeviceConfiguration(&self) -> std::result::Result<AudioDeviceConfiguration, binder::Status> {
+        Err(binder::StatusCode::UNKNOWN_ERROR.into())
+    }
+
+    fn getOutputMirroringDevices(&self) -> std::result::Result<std::vec::Vec<AudioPort>, binder::Status> {
+        Err(binder::StatusCode::UNKNOWN_ERROR.into())
+    }
+
+    fn getCarAudioZones(&self) -> std::result::Result<std::vec::Vec<AudioZone>, binder::Status> {
+        Err(binder::StatusCode::UNKNOWN_ERROR.into())
+    }
 }
diff --git a/automotive/audiocontrol/aidl/vts/Android.bp b/automotive/audiocontrol/aidl/vts/Android.bp
index d94ad55..57c6ae4 100644
--- a/automotive/audiocontrol/aidl/vts/Android.bp
+++ b/automotive/audiocontrol/aidl/vts/Android.bp
@@ -22,6 +22,25 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
+cc_library {
+    name: "AudioControlHalTestUtils",
+    srcs: [
+        "src/AudioControlTestUtils.cpp",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+    defaults: [
+        "latest_android_hardware_audio_common_cpp_static",
+        "latest_android_hardware_automotive_audiocontrol_cpp_static",
+        "latest_android_media_audio_common_types_cpp_static",
+    ],
+    shared_libs: [
+        "libbase",
+        "libutils",
+    ],
+}
+
 cc_test {
     name: "VtsAidlHalAudioControlTest",
     defaults: [
@@ -39,9 +58,11 @@
         "libbinder",
         "libbase",
         "libxml2",
+        "libutils",
     ],
     static_libs: [
         "libgmock",
+        "AudioControlHalTestUtils",
     ],
     test_suites: [
         "general-tests",
diff --git a/automotive/audiocontrol/aidl/vts/VtsHalAudioControlTargetTest.cpp b/automotive/audiocontrol/aidl/vts/VtsHalAudioControlTargetTest.cpp
index 4e7e963..c01c0d6 100644
--- a/automotive/audiocontrol/aidl/vts/VtsHalAudioControlTargetTest.cpp
+++ b/automotive/audiocontrol/aidl/vts/VtsHalAudioControlTargetTest.cpp
@@ -18,6 +18,8 @@
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
 #include <gmock/gmock.h>
+#include <utils/String16.h>
+#include <set>
 
 #include <android/hardware/automotive/audiocontrol/BnAudioGainCallback.h>
 #include <android/hardware/automotive/audiocontrol/BnFocusListener.h>
@@ -26,24 +28,49 @@
 #include <android/log.h>
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
+#include <include/AudioControlTestUtils.h>
 
 using android::ProcessState;
 using android::sp;
 using android::String16;
 using android::binder::Status;
+using android::hardware::automotive::audiocontrol::AudioDeviceConfiguration;
+using android::hardware::automotive::audiocontrol::AudioFadeConfiguration;
 using android::hardware::automotive::audiocontrol::AudioFocusChange;
 using android::hardware::automotive::audiocontrol::AudioGainConfigInfo;
+using android::hardware::automotive::audiocontrol::AudioZone;
+using android::hardware::automotive::audiocontrol::AudioZoneConfig;
+using android::hardware::automotive::audiocontrol::AudioZoneContextInfo;
+using android::hardware::automotive::audiocontrol::AudioZoneFadeConfiguration;
 using android::hardware::automotive::audiocontrol::BnAudioGainCallback;
 using android::hardware::automotive::audiocontrol::BnFocusListener;
 using android::hardware::automotive::audiocontrol::BnModuleChangeCallback;
+using android::hardware::automotive::audiocontrol::DeviceToContextEntry;
 using android::hardware::automotive::audiocontrol::DuckingInfo;
+using android::hardware::automotive::audiocontrol::FadeConfiguration;
 using android::hardware::automotive::audiocontrol::IAudioControl;
 using android::hardware::automotive::audiocontrol::IModuleChangeCallback;
 using android::hardware::automotive::audiocontrol::MutingInfo;
 using android::hardware::automotive::audiocontrol::Reasons;
+using android::hardware::automotive::audiocontrol::VolumeActivationConfiguration;
+using android::hardware::automotive::audiocontrol::VolumeActivationConfigurationEntry;
+using android::hardware::automotive::audiocontrol::VolumeGroupConfig;
+using android::hardware::automotive::audiocontrol::RoutingDeviceConfiguration::
+        CONFIGURABLE_AUDIO_ENGINE_ROUTING;
+using android::hardware::automotive::audiocontrol::RoutingDeviceConfiguration::
+        DEFAULT_AUDIO_ROUTING;
+using android::hardware::automotive::audiocontrol::VolumeActivationConfigurationEntry::
+        DEFAULT_MAX_ACTIVATION_VALUE;
+using android::hardware::automotive::audiocontrol::VolumeActivationConfigurationEntry::
+        DEFAULT_MIN_ACTIVATION_VALUE;
 using ::testing::AnyOf;
 using ::testing::Eq;
 
+using ::testing::Not;
+using ::testing::UnorderedElementsAreArray;
+
+using android::internal::ToString;
+
 #include "android_audio_policy_configuration_V7_0.h"
 
 namespace xsd {
@@ -52,11 +79,219 @@
 
 namespace audiohalcommon = android::hardware::audio::common;
 namespace audiomediacommon = android::media::audio::common;
+namespace testutils = android::hardware::audiocontrol::testutils;
 
 namespace {
 constexpr int32_t kAidlVersionThree = 3;
+constexpr int32_t kAidlVersionFive = 5;
+
+bool hasValidVolumeGroupActivation(const VolumeActivationConfiguration& activation,
+                                   std::string& message) {
+    if (activation.volumeActivationEntries.empty()) {
+        message = "Volume group activation must have at least one volume activation entry";
+        return false;
+    }
+    for (const auto& entry : activation.volumeActivationEntries) {
+        int32_t max = entry.maxActivationVolumePercentage;
+        int32_t min = entry.minActivationVolumePercentage;
+        if (min > DEFAULT_MAX_ACTIVATION_VALUE || min < DEFAULT_MIN_ACTIVATION_VALUE) {
+            message = "Invalid minActivationVolumePercentage, must be between " +
+                      std::to_string(DEFAULT_MIN_ACTIVATION_VALUE) + " and " +
+                      std::to_string(DEFAULT_MAX_ACTIVATION_VALUE);
+            return false;
+        }
+        if (max > DEFAULT_MAX_ACTIVATION_VALUE || max < DEFAULT_MIN_ACTIVATION_VALUE) {
+            message = "Invalid maxActivationVolumePercentage, must be between " +
+                      std::to_string(DEFAULT_MIN_ACTIVATION_VALUE) + " and " +
+                      std::to_string(DEFAULT_MAX_ACTIVATION_VALUE);
+            return false;
+        }
+        if (min >= max) {
+            message =
+                    "Invalid maxActivationVolumePercentage and minActivationVolumePercentage "
+                    "combination, minActivationVolumePercentage must be less than "
+                    "maxActivationVolumePercentage";
+            return false;
+        }
+    }
+    return true;
 }
 
+bool hasValidAudioRoute(const DeviceToContextEntry& entry, std::string& message,
+                        std::set<std::string>& groupDevices) {
+    if (entry.contextNames.empty()) {
+        message = " Contexts can not be empty for DeviceToContextEntry";
+        return false;
+    }
+    std::set<std::string> contextInRoute;
+    for (const auto& context : entry.contextNames) {
+        std::string contextString = ToString(context);
+        if (contextInRoute.contains(contextString)) {
+            message = " Context " + contextString + " repeats for DeviceToContextEntry";
+            return false;
+        }
+        groupDevices.insert(contextString);
+    }
+    audiomediacommon::AudioDeviceDescription description;
+    if (!testutils::getAudioPortDeviceDescriptor(entry.device, description)) {
+        message = " DeviceToContextEntry must have a valid device port";
+        return false;
+    }
+    // BUS type also has empty connection
+    // Note: OUT_BUS is also mapped to OUT_DEVICE
+    if (description.type != audiomediacommon::AudioDeviceType::OUT_BUS &&
+        !description.connection.empty()) {
+        return true;
+    }
+    std::string address;
+    if (!testutils::getAddressForAudioPort(entry.device, address) || address.empty()) {
+        message = " Address can not be empty for BUS devices";
+        return false;
+    }
+    if (groupDevices.contains(address)) {
+        message = " Audio device address can not repeat in the same volume group";
+        return false;
+    }
+    groupDevices.insert(address);
+    return true;
+}
+
+inline bool hasValidTimeout(int64_t timeout) {
+    return timeout > 0;
+}
+bool hasValidFadeConfiguration(const FadeConfiguration& fadeConfiguration,
+                               const std::string& prefix, std::string& message) {
+    if (!hasValidTimeout(fadeConfiguration.fadeDurationMillis)) {
+        message = prefix + " duration must be greater than 0";
+        return false;
+    }
+    return true;
+}
+bool hadValidAudioFadeConfiguration(const AudioFadeConfiguration& fadeConfiguration,
+                                    std::string& message) {
+    if (!hasValidTimeout(fadeConfiguration.fadeInDurationMs)) {
+        message = "Fade-in duration must be greater than 0";
+        return false;
+    }
+    if (!hasValidTimeout(fadeConfiguration.fadeOutDurationMs)) {
+        message = "Fade-out duration must be greater than 0";
+        return false;
+    }
+    if (!hasValidTimeout(fadeConfiguration.fadeInDelayedForOffendersMs)) {
+        message = "Fade-in delayed for offenders duration must be greater than 0";
+        return false;
+    }
+    for (const auto& fadeOutConfig : fadeConfiguration.fadeOutConfigurations) {
+        if (!hasValidFadeConfiguration(fadeOutConfig, "Fade-out", message)) {
+            return false;
+        }
+    }
+    for (const auto& fadeOutConfig : fadeConfiguration.fadeInConfigurations) {
+        if (!hasValidFadeConfiguration(fadeOutConfig, "Fade-in", message)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+void validateVolumeGroupInfo(const AudioZoneConfig& audioZoneConfig,
+                             const VolumeGroupConfig& volumeGroupConfig,
+                             const AudioDeviceConfiguration& deviceConfig) {
+    std::string zoneConfigName = testutils::toAlphaNumeric(ToString(audioZoneConfig.name));
+    std::string volumeGroupName = testutils::toAlphaNumeric(ToString(volumeGroupConfig.name));
+    std::string volumeGroupInfo =
+            "Audio zone config " + zoneConfigName + " volume group " + volumeGroupName;
+    ALOGI("%s test", volumeGroupInfo.c_str());
+
+    EXPECT_FALSE(volumeGroupConfig.carAudioRoutes.empty())
+            << volumeGroupInfo << " must have at least one audio route";
+    if (deviceConfig.routingConfig == CONFIGURABLE_AUDIO_ENGINE_ROUTING) {
+        EXPECT_FALSE(volumeGroupConfig.name.empty())
+                << volumeGroupInfo << " must have a non-empty volume name";
+    }
+    std::set<std::string> groupDevices;
+    for (const auto& audioRoute : volumeGroupConfig.carAudioRoutes) {
+        std::string routeMessage;
+        EXPECT_TRUE(hasValidAudioRoute(audioRoute, routeMessage, groupDevices))
+                << volumeGroupInfo << " Volume route message: " << routeMessage;
+    }
+    if (volumeGroupConfig.activationConfiguration.has_value()) {
+        std::string activationMessage;
+        EXPECT_TRUE(hasValidVolumeGroupActivation(volumeGroupConfig.activationConfiguration.value(),
+                                                  activationMessage))
+                << volumeGroupInfo << " Activation message: " << activationMessage;
+    }
+}
+
+void validateAudioZoneFadeConfiguration(const AudioZoneFadeConfiguration& fadeConfiguration) {
+    ALOGI("Fade configuration test");
+    std::set<audiomediacommon::AudioUsage> usages;
+    std::string defaultValidationMessage;
+    EXPECT_TRUE(hadValidAudioFadeConfiguration(fadeConfiguration.defaultConfiguration,
+                                               defaultValidationMessage))
+            << "Default configuration validation failed: " << defaultValidationMessage;
+    for (const auto& entry : fadeConfiguration.transientConfiguration) {
+        ALOGI("Transient fade configuration test");
+        std::string transientFadeConfigurationMessage;
+        EXPECT_TRUE(hadValidAudioFadeConfiguration(entry.transientFadeConfiguration,
+                                                   transientFadeConfigurationMessage))
+                << "Transient fade configuration validation failed: "
+                << transientFadeConfigurationMessage;
+        EXPECT_FALSE(entry.transientUsages.empty())
+                << "Transient fade configuration must have at least one audio usage";
+        for (const auto& usage : entry.transientUsages) {
+            EXPECT_FALSE(usages.contains(usage)) << "Audio usages " << ToString(usage)
+                                                 << " repeat in transient fade configuration";
+        }
+    }
+}
+
+void validateAudioZoneConfiguration(const AudioZone& carAudioZone,
+                                    const AudioZoneConfig& audioZoneConfig,
+                                    const AudioDeviceConfiguration& deviceConfig) {
+    std::string zoneConfigName = testutils::toAlphaNumeric(ToString(audioZoneConfig.name));
+    ALOGI("Zone config name %s test", zoneConfigName.c_str());
+    std::set<std::string> contextInfoNames;
+    EXPECT_FALSE(audioZoneConfig.volumeGroups.empty())
+            << "Volume groups for zone config " << zoneConfigName.c_str();
+    for (const auto& volumeGroup : audioZoneConfig.volumeGroups) {
+        ALOGI("Zone config name %s volume group test %s", zoneConfigName.c_str(),
+              ToString(volumeGroup.name).c_str());
+        std::vector<std::string> groupContexts =
+                testutils::getContextInfoNamesForVolumeGroup(volumeGroup);
+        for (const auto& context : groupContexts) {
+            EXPECT_FALSE(contextInfoNames.contains(context))
+                    << "Context " << context << " repeats in zone config " << zoneConfigName;
+            contextInfoNames.insert(context);
+        }
+        validateVolumeGroupInfo(audioZoneConfig, volumeGroup, deviceConfig);
+    }
+    const auto& audioZoneContexts = carAudioZone.audioZoneContext.audioContextInfos;
+    std::map<std::string, AudioZoneContextInfo> infoNameToInfo;
+    std::transform(audioZoneContexts.begin(), audioZoneContexts.end(),
+                   std::inserter(infoNameToInfo, infoNameToInfo.end()),
+                   [&](const AudioZoneContextInfo& context) {
+                       return std::make_pair(ToString(context.name), context);
+                   });
+    std::vector<AudioZoneContextInfo> configContextInfos;
+    for (const auto& contextName : contextInfoNames) {
+        const auto& pair = infoNameToInfo.find(contextName);
+        if (pair == infoNameToInfo.end()) {
+            continue;
+        }
+        configContextInfos.push_back(pair->second);
+    }
+    std::string message;
+    EXPECT_TRUE(testutils::contextInfosContainAllAudioAttributeUsages(configContextInfos, message))
+            << "Config " << zoneConfigName << " message: " << message;
+
+    if (audioZoneConfig.fadeConfiguration.has_value()) {
+        validateAudioZoneFadeConfiguration(audioZoneConfig.fadeConfiguration.value());
+    }
+}
+
+}  // namespace
+
 class AudioControlAidl : public testing::TestWithParam<std::string> {
   public:
     virtual void SetUp() override {
@@ -292,12 +527,193 @@
                 AnyOf(Eq(Status::EX_ILLEGAL_ARGUMENT), Eq(Status::EX_UNSUPPORTED_OPERATION)));
 }
 
+class AudioControlVersionFiveAndAbove : public AudioControlAidl {
+  public:
+    virtual void SetUp() override {
+        AudioControlAidl::SetUp();
+        if (isAidlVersionAtleast(kAidlVersionFive)) {
+            return;
+        }
+        GTEST_SKIP() << " Version is lower than " << std::to_string(kAidlVersionFive);
+    }
+};
+
+class AudioControlWithAudioConfiguration : public AudioControlVersionFiveAndAbove {
+  public:
+    virtual void SetUp() override {
+        AudioControlVersionFiveAndAbove::SetUp();
+
+        if (IsSkipped()) {
+            return;
+        }
+
+        const auto& configStatus =
+                audioControl->getAudioDeviceConfiguration(&audioDeviceConfiguration);
+
+        EXPECT_THAT(configStatus.exceptionCode(),
+                    AnyOf(Eq(Status::EX_NONE), Eq(Status::EX_UNSUPPORTED_OPERATION)));
+        if (!configStatus.isOk()) {
+            GTEST_SKIP() << "Device does not support audio configurations APIs";
+        }
+        ALOGD("Audio device info: %s", audioDeviceConfiguration.toString().c_str());
+    }
+
+    AudioDeviceConfiguration audioDeviceConfiguration;
+};
+
+TEST_P(AudioControlWithAudioConfiguration, DefaultAudioRoutingConfiguration) {
+    if (audioDeviceConfiguration.routingConfig != DEFAULT_AUDIO_ROUTING) {
+        GTEST_SKIP() << "Default audio routing not supported";
+    }
+    std::vector<AudioZone> zones;
+
+    const auto& zoneStatus = audioControl->getCarAudioZones(&zones);
+
+    EXPECT_THAT(zoneStatus.exceptionCode(),
+                AnyOf(Eq(Status::EX_NONE), Eq(Status::EX_UNSUPPORTED_OPERATION)))
+            << "Default routing can be implemented or unsupported";
+    if (!zoneStatus.isOk()) return;
+    EXPECT_TRUE(zones.empty()) << "Zones must be empty for default routing";
+}
+
+class AudioControlWithDynamicConfiguration : public AudioControlWithAudioConfiguration {
+  public:
+    virtual void SetUp() override {
+        AudioControlWithAudioConfiguration::SetUp();
+        if (IsSkipped()) {
+            return;
+        }
+        if (audioDeviceConfiguration.routingConfig == DEFAULT_AUDIO_ROUTING) {
+            GTEST_SKIP() << "Dynamic/core audio routing not supported";
+        }
+        const auto& zoneStatus = audioControl->getCarAudioZones(&audioZones);
+        EXPECT_EQ(zoneStatus.exceptionCode(), Status::EX_NONE)
+                << "Zones API must be supported for core/dynamic routing";
+    }
+
+    std::vector<AudioZone> audioZones;
+};
+
+TEST_P(AudioControlWithDynamicConfiguration, DynamicAudioRoutingConfiguration) {
+    EXPECT_FALSE(audioZones.empty()) << "Zones must not be empty for core/dynamic routing";
+}
+
+class AudioControlWithAudioZoneInfo : public AudioControlWithDynamicConfiguration {
+  public:
+    virtual void SetUp() override {
+        AudioControlWithDynamicConfiguration::SetUp();
+        if (IsSkipped()) {
+            return;
+        }
+        EXPECT_TRUE(!audioZones.empty()) << "Zones must exist for core/dynamic routing";
+    }
+};
+
+TEST_P(AudioControlWithAudioZoneInfo, AudioZonesRequirements) {
+    bool primaryZoneFound = false;
+    std::set<int> zoneIds;
+    std::set<int> occupantIds;
+    std::set<android::String16> zoneNames;
+    std::set<std::string> deviceAddresses;
+    for (const auto& zone : audioZones) {
+        if (zone.id == AudioZone::PRIMARY_AUDIO_ZONE) {
+            EXPECT_FALSE(primaryZoneFound) << "There can only be one primary zone";
+            primaryZoneFound = true;
+        }
+        EXPECT_FALSE(zoneIds.contains(zone.id)) << "Zone " << std::to_string(zone.id) << " repeats";
+        zoneIds.insert(zone.id);
+        if (!zone.name.empty()) {
+            EXPECT_FALSE(zoneNames.contains(zone.name)) << "Zone " << zone.name << " repeats";
+            zoneNames.insert(zone.name);
+        }
+        if (zone.occupantZoneId != AudioZone::UNASSIGNED_OCCUPANT) {
+            EXPECT_FALSE(occupantIds.contains(zone.occupantZoneId))
+                    << "Occupant zone id " << zone.occupantZoneId << " repeats";
+            occupantIds.insert(zone.occupantZoneId);
+        }
+        const auto& zoneAddresses = testutils::getDeviceAddressesForZone(zone);
+        for (const auto& address : zoneAddresses) {
+            EXPECT_FALSE(deviceAddresses.contains(address))
+                    << "Device address " << address << " in zone " << zone.name << " repeats";
+        }
+        // Add after zone comparison is done since devices may repeat within a zone for different
+        // configurations
+        deviceAddresses.insert(zoneAddresses.begin(), zoneAddresses.end());
+    }
+    EXPECT_TRUE(primaryZoneFound) << "Primary zone must exist";
+}
+
+TEST_P(AudioControlWithAudioZoneInfo, AudioZoneInfoRequirements) {
+    for (const auto& carAudioZone : audioZones) {
+        ALOGI("Zone id %d test", carAudioZone.id);
+        std::string missingContextMessage;
+        EXPECT_TRUE(testutils::contextContainsAllAudioAttributeUsages(carAudioZone.audioZoneContext,
+                                                                      missingContextMessage))
+                << "Audio zone context for zone id " << std::to_string(carAudioZone.id)
+                << missingContextMessage;
+        EXPECT_FALSE(carAudioZone.audioZoneConfigs.empty())
+                << "Audio zone zone id " << std::to_string(carAudioZone.id)
+                << " missing zone configs";
+        std::set<android::String16> configNames;
+        bool defaultConfigFound = false;
+        for (const auto& config : carAudioZone.audioZoneConfigs) {
+            ALOGI("Zone id %d config name %s test", carAudioZone.id, ToString(config.name).c_str());
+            if (config.isDefault) {
+                EXPECT_FALSE(defaultConfigFound)
+                        << "Config name " << config.name
+                        << " repeats default config value in zone id " << carAudioZone.id;
+                defaultConfigFound = true;
+            }
+            EXPECT_FALSE(configNames.contains(config.name))
+                    << "Config name " << config.name << " repeats in " << carAudioZone.id;
+        }
+        EXPECT_TRUE(defaultConfigFound)
+                << "Audio zone " << carAudioZone.id << " must contain default config";
+        std::set<audiomediacommon::AudioPort> inputPorts;
+        ALOGI("Zone id %d input devices test", carAudioZone.id);
+        for (const auto& audioPort : carAudioZone.inputAudioDevices) {
+            std::string address;
+            const auto hasAddress = testutils::getAddressForAudioPort(audioPort, address);
+            EXPECT_FALSE(inputPorts.contains(audioPort))
+                    << "Repeating input device for " << carAudioZone.id << ", device address "
+                    << (hasAddress ? address : "empty address");
+            inputPorts.insert(audioPort);
+        }
+    }
+}
+
+TEST_P(AudioControlWithAudioZoneInfo, AudioZoneConfigInfoRequirements) {
+    for (const auto& carAudioZone : audioZones) {
+        for (const auto& audioZoneConfig : carAudioZone.audioZoneConfigs) {
+            validateAudioZoneConfiguration(carAudioZone, audioZoneConfig, audioDeviceConfiguration);
+        }
+    }
+}
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioControlAidl);
 INSTANTIATE_TEST_SUITE_P(
         Audiocontrol, AudioControlAidl,
         testing::ValuesIn(android::getAidlHalInstanceNames(IAudioControl::descriptor)),
         android::PrintInstanceNameToString);
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioControlWithAudioConfiguration);
+INSTANTIATE_TEST_SUITE_P(
+        Audiocontrol, AudioControlWithAudioConfiguration,
+        testing::ValuesIn(android::getAidlHalInstanceNames(IAudioControl::descriptor)),
+        android::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioControlWithDynamicConfiguration);
+INSTANTIATE_TEST_SUITE_P(
+        Audiocontrol, AudioControlWithDynamicConfiguration,
+        testing::ValuesIn(android::getAidlHalInstanceNames(IAudioControl::descriptor)),
+        android::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioControlWithAudioZoneInfo);
+INSTANTIATE_TEST_SUITE_P(
+        Audiocontrol, AudioControlWithAudioZoneInfo,
+        testing::ValuesIn(android::getAidlHalInstanceNames(IAudioControl::descriptor)),
+        android::PrintInstanceNameToString);
+
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
     ProcessState::self()->setThreadPoolMaxThreadCount(1);
diff --git a/automotive/audiocontrol/aidl/vts/include/AudioControlTestUtils.h b/automotive/audiocontrol/aidl/vts/include/AudioControlTestUtils.h
new file mode 100644
index 0000000..46fdce2
--- /dev/null
+++ b/automotive/audiocontrol/aidl/vts/include/AudioControlTestUtils.h
@@ -0,0 +1,67 @@
+/*
+ * 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 MAIN8_AUDIOCONTROLTESTUTILS_H
+#define MAIN8_AUDIOCONTROLTESTUTILS_H
+
+#include <android/hardware/automotive/audiocontrol/IAudioControl.h>
+#include <string>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace audiocontrol {
+namespace testutils {
+
+std::string toAlphaNumeric(const std::string& info);
+
+bool getAudioPortDeviceDescriptor(
+        const android::media::audio::common::AudioPort& audioPort,
+        android::media::audio::common::AudioDeviceDescription& description);
+
+bool getAddressForAudioPort(const android::media::audio::common::AudioPort& audioPort,
+                            std::string& address);
+
+bool getAddressForAudioDevice(
+        const android::hardware::automotive::audiocontrol::DeviceToContextEntry& device,
+        std::string& address);
+
+std::vector<std::string> getDeviceAddressesForVolumeGroup(
+        const android::hardware::automotive::audiocontrol::VolumeGroupConfig& config);
+
+std::vector<std::string> getDeviceAddressesForZoneConfig(
+        const android::hardware::automotive::audiocontrol::AudioZoneConfig& config);
+
+std::vector<std::string> getDeviceAddressesForZone(
+        const android::hardware::automotive::audiocontrol::AudioZone& config);
+
+bool contextInfosContainAllAudioAttributeUsages(
+        const std::vector<android::hardware::automotive::audiocontrol::AudioZoneContextInfo>& infos,
+        std::string& message);
+
+bool contextContainsAllAudioAttributeUsages(
+        const android::hardware::automotive::audiocontrol::AudioZoneContext& context,
+        std::string& message);
+
+std::vector<std::string> getContextInfoNamesForVolumeGroup(
+        const android::hardware::automotive::audiocontrol::VolumeGroupConfig& group);
+
+}  // namespace testutils
+}  // namespace audiocontrol
+}  // namespace hardware
+}  // namespace android
+
+#endif  // MAIN8_AUDIOCONTROLTESTUTILS_H
diff --git a/automotive/audiocontrol/aidl/vts/src/AudioControlTestUtils.cpp b/automotive/audiocontrol/aidl/vts/src/AudioControlTestUtils.cpp
new file mode 100644
index 0000000..7b7c896
--- /dev/null
+++ b/automotive/audiocontrol/aidl/vts/src/AudioControlTestUtils.cpp
@@ -0,0 +1,203 @@
+/*
+ * 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 "../include/AudioControlTestUtils.h"
+
+#include <set>
+
+using android::hardware::automotive::audiocontrol::AudioZone;
+using android::hardware::automotive::audiocontrol::AudioZoneConfig;
+using android::hardware::automotive::audiocontrol::AudioZoneContext;
+using android::hardware::automotive::audiocontrol::AudioZoneContextInfo;
+using android::hardware::automotive::audiocontrol::DeviceToContextEntry;
+using android::hardware::automotive::audiocontrol::VolumeGroupConfig;
+
+namespace audiomediacommon = android::media::audio::common;
+
+namespace android {
+namespace hardware {
+namespace audiocontrol {
+namespace testutils {
+
+std::string toAlphaNumeric(const std::string& info) {
+    std::string name = info;
+    for (size_t i = 0; i < name.size(); i++) {
+        // gtest test names must only contain alphanumeric characters
+        if (!std::isalnum(name[i])) name[i] = '_';
+    }
+
+    return name;
+}
+
+bool getAudioPortDeviceDescriptor(const audiomediacommon::AudioPort& audioPort,
+                                  audiomediacommon::AudioDeviceDescription& description) {
+    if (audioPort.ext.getTag() != audiomediacommon::AudioPortExt::Tag::device) {
+        return false;
+    }
+    const auto& audioDevice =
+            audioPort.ext.get<audiomediacommon::AudioPortExt::Tag::device>().device;
+    description = audioDevice.type;
+    return true;
+}
+
+bool getAddressForAudioPort(const android::media::audio::common::AudioPort& audioPort,
+                            std::string& address) {
+    if (audioPort.ext.getTag() != audiomediacommon::AudioPortExt::Tag::device) {
+        return false;
+    }
+    const auto& audioDevice =
+            audioPort.ext.get<audiomediacommon::AudioPortExt::Tag::device>().device;
+
+    switch (audioDevice.address.getTag()) {
+        case audiomediacommon::AudioDeviceAddress::Tag::id:
+            address = audioDevice.address.get<audiomediacommon::AudioDeviceAddress::Tag::id>();
+            return true;
+        case audiomediacommon::AudioDeviceAddress::Tag::alsa:
+            address = android::internal::ToString(
+                    audioDevice.address.get<audiomediacommon::AudioDeviceAddress::Tag::alsa>());
+            return true;
+        case audiomediacommon::AudioDeviceAddress::Tag::mac:
+            address = android::internal::ToString(
+                    audioDevice.address.get<audiomediacommon::AudioDeviceAddress::Tag::mac>());
+            return true;
+        case audiomediacommon::AudioDeviceAddress::Tag::ipv4:
+            address = android::internal::ToString(
+                    audioDevice.address.get<audiomediacommon::AudioDeviceAddress::Tag::ipv4>());
+            return true;
+        case audiomediacommon::AudioDeviceAddress::Tag::ipv6:
+            address = android::internal::ToString(
+                    audioDevice.address.get<audiomediacommon::AudioDeviceAddress::Tag::ipv6>());
+            return true;
+        default:
+            address = audioDevice.address.toString();
+            return true;
+    }
+}
+
+bool getAddressForAudioDevice(const DeviceToContextEntry& device, std::string& address) {
+    if (device.device.flags.getTag() == audiomediacommon::AudioIoFlags::input ||
+        device.device.ext.getTag() != audiomediacommon::AudioPortExt::Tag::device) {
+        return false;
+    }
+    return getAddressForAudioPort(device.device, address);
+}
+
+std::vector<std::string> getDeviceAddressesForVolumeGroup(const VolumeGroupConfig& config) {
+    std::vector<std::string> addresses;
+    for (const auto& route : config.carAudioRoutes) {
+        std::string address;
+        if (!getAddressForAudioDevice(route, address)) {
+            continue;
+        }
+        addresses.push_back(address);
+    }
+    return addresses;
+}
+
+std::vector<std::string> getDeviceAddressesForZoneConfig(const AudioZoneConfig& config) {
+    std::vector<std::string> addresses;
+    for (const auto& volumeGroup : config.volumeGroups) {
+        const auto groupAddresses = getDeviceAddressesForVolumeGroup(volumeGroup);
+        addresses.insert(addresses.begin(), groupAddresses.begin(), groupAddresses.end());
+    }
+    return addresses;
+}
+
+std::vector<std::string> getDeviceAddressesForZone(const AudioZone& config) {
+    std::vector<std::string> addresses;
+    for (const auto& zoneConfig : config.audioZoneConfigs) {
+        const auto groupAddresses = getDeviceAddressesForZoneConfig(zoneConfig);
+        addresses.insert(addresses.begin(), groupAddresses.begin(), groupAddresses.end());
+    }
+    return addresses;
+}
+
+static void addContextUsages(const AudioZoneContextInfo& info,
+                             std::set<audiomediacommon::AudioUsage>& contextUsages) {
+    for (const auto& audioAttribute : info.audioAttributes) {
+        contextUsages.insert(audioAttribute.usage);
+    }
+}
+
+bool contextInfosContainAllAudioAttributeUsages(const std::vector<AudioZoneContextInfo>& infos,
+                                                std::string& message) {
+    static const std::vector<audiomediacommon::AudioUsage> audioUsages{
+            audiomediacommon::AudioUsage::UNKNOWN,
+            audiomediacommon::AudioUsage::MEDIA,
+            audiomediacommon::AudioUsage::VOICE_COMMUNICATION,
+            audiomediacommon::AudioUsage::VOICE_COMMUNICATION_SIGNALLING,
+            audiomediacommon::AudioUsage::ALARM,
+            audiomediacommon::AudioUsage::NOTIFICATION,
+            audiomediacommon::AudioUsage::NOTIFICATION_TELEPHONY_RINGTONE,
+            audiomediacommon::AudioUsage::NOTIFICATION_EVENT,
+            audiomediacommon::AudioUsage::ASSISTANCE_ACCESSIBILITY,
+            audiomediacommon::AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE,
+            audiomediacommon::AudioUsage::ASSISTANCE_SONIFICATION,
+            audiomediacommon::AudioUsage::GAME,
+            audiomediacommon::AudioUsage::ASSISTANT,
+            audiomediacommon::AudioUsage::CALL_ASSISTANT,
+            audiomediacommon::AudioUsage::EMERGENCY,
+            audiomediacommon::AudioUsage::SAFETY,
+            audiomediacommon::AudioUsage::VEHICLE_STATUS,
+            audiomediacommon::AudioUsage::ANNOUNCEMENT,
+    };
+
+    std::set<audiomediacommon::AudioUsage> contextUsages;
+    for (const auto& contextInfo : infos) {
+        addContextUsages(contextInfo, contextUsages);
+    }
+
+    bool allUsagesPresent = true;
+    for (const auto& usage : audioUsages) {
+        if (contextUsages.contains(usage)) {
+            continue;
+        }
+        if (message.empty()) {
+            message = " Missing usage(s): ";
+        }
+        message += audiomediacommon::toString(usage) + ", ";
+        allUsagesPresent = false;
+    }
+    return allUsagesPresent;
+}
+
+bool contextContainsAllAudioAttributeUsages(const AudioZoneContext& context, std::string& message) {
+    return contextInfosContainAllAudioAttributeUsages(context.audioContextInfos, message);
+}
+
+std::vector<std::string> getContextInfoNamesForAudioRoute(const DeviceToContextEntry& route) {
+    std::vector<std::string> contextInfoNames;
+    contextInfoNames.reserve(route.contextNames.size());
+    for (const auto& contextName : route.contextNames) {
+        contextInfoNames.push_back(android::internal::ToString(contextName));
+    }
+    return contextInfoNames;
+}
+
+std::vector<std::string> getContextInfoNamesForVolumeGroup(const VolumeGroupConfig& group) {
+    std::vector<std::string> contextInfoNames;
+    for (const auto& route : group.carAudioRoutes) {
+        std::vector<std::string> routeContexts = getContextInfoNamesForAudioRoute(route);
+        contextInfoNames.insert(contextInfoNames.begin(), routeContexts.begin(),
+                                routeContexts.end());
+    }
+    return contextInfoNames;
+}
+
+}  // namespace testutils
+}  // namespace audiocontrol
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/automotive/can/1.0/default/libnetdevice/Android.bp b/automotive/can/1.0/default/libnetdevice/Android.bp
index 653e773..affbeee 100644
--- a/automotive/can/1.0/default/libnetdevice/Android.bp
+++ b/automotive/can/1.0/default/libnetdevice/Android.bp
@@ -26,6 +26,7 @@
 cc_library_static {
     name: "android.hardware.automotive.can@libnetdevice",
     defaults: ["android.hardware.automotive.can@defaults"],
+    host_supported: true,
     vendor_available: true,
     srcs: [
         "can.cpp",
diff --git a/automotive/can/1.0/default/libnetdevice/can.cpp b/automotive/can/1.0/default/libnetdevice/can.cpp
index 2a0545a..9cf0253 100644
--- a/automotive/can/1.0/default/libnetdevice/can.cpp
+++ b/automotive/can/1.0/default/libnetdevice/can.cpp
@@ -33,7 +33,7 @@
 
 static constexpr can_err_mask_t kErrMask = CAN_ERR_MASK;
 
-base::unique_fd socket(const std::string& ifname) {
+base::unique_fd socket(std::string_view ifname) {
     sockaddr_can addr = {};
     addr.can_family = AF_CAN;
     addr.can_ifindex = nametoindex(ifname);
@@ -66,11 +66,11 @@
     return sock;
 }
 
-bool setBitrate(std::string ifname, uint32_t bitrate) {
+bool setBitrate(std::string_view ifname, uint32_t bitrate) {
     can_bittiming bt = {};
     bt.bitrate = bitrate;
 
-    nl::MessageFactory<ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK);
+    nl::MessageFactory<ifinfomsg> req(RTM_NEWLINK);
 
     req->ifi_index = nametoindex(ifname);
     if (req->ifi_index == 0) {
diff --git a/automotive/can/1.0/default/libnetdevice/common.cpp b/automotive/can/1.0/default/libnetdevice/common.cpp
index 28e50af..22add65 100644
--- a/automotive/can/1.0/default/libnetdevice/common.cpp
+++ b/automotive/can/1.0/default/libnetdevice/common.cpp
@@ -22,8 +22,8 @@
 
 namespace android::netdevice {
 
-unsigned int nametoindex(const std::string& ifname) {
-    const auto ifidx = if_nametoindex(ifname.c_str());
+unsigned int nametoindex(std::string_view ifname) {
+    const auto ifidx = if_nametoindex(std::string(ifname).c_str());
     if (ifidx != 0) return ifidx;
 
     if (errno != ENODEV) {
diff --git a/automotive/can/1.0/default/libnetdevice/common.h b/automotive/can/1.0/default/libnetdevice/common.h
index 661e3f8..e73c581 100644
--- a/automotive/can/1.0/default/libnetdevice/common.h
+++ b/automotive/can/1.0/default/libnetdevice/common.h
@@ -32,6 +32,6 @@
  * \param ifname Interface to check
  * \return Interface index, or 0 if the interface doesn't exist
  */
-unsigned int nametoindex(const std::string& ifname);
+unsigned int nametoindex(std::string_view ifname);
 
 }  // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/ethtool.cpp b/automotive/can/1.0/default/libnetdevice/ethtool.cpp
index 762ef5c..b0f88c7 100644
--- a/automotive/can/1.0/default/libnetdevice/ethtool.cpp
+++ b/automotive/can/1.0/default/libnetdevice/ethtool.cpp
@@ -19,27 +19,28 @@
 #include "ifreqs.h"
 
 #include <linux/ethtool.h>
+#include <linux/sockios.h>
 
 namespace android::netdevice::ethtool {
 
-std::optional<uint32_t> getValue(const std::string& ifname, uint32_t command) {
+std::optional<uint32_t> getValue(std::string_view ifname, uint32_t command) {
     struct ethtool_value valueop = {};
     valueop.cmd = command;
 
     auto ifr = ifreqs::fromName(ifname);
-    ifr.ifr_data = &valueop;
+    ifr.ifr_data = reinterpret_cast<caddr_t>(&valueop);
 
     if (!ifreqs::send(SIOCETHTOOL, ifr)) return std::nullopt;
     return valueop.data;
 }
 
-bool setValue(const std::string& ifname, uint32_t command, uint32_t value) {
+bool setValue(std::string_view ifname, uint32_t command, uint32_t value) {
     struct ethtool_value valueop = {};
     valueop.cmd = command;
     valueop.data = value;
 
     auto ifr = ifreqs::fromName(ifname);
-    ifr.ifr_data = &valueop;
+    ifr.ifr_data = reinterpret_cast<caddr_t>(&valueop);
 
     return ifreqs::send(SIOCETHTOOL, ifr);
 }
diff --git a/automotive/can/1.0/default/libnetdevice/ifreqs.cpp b/automotive/can/1.0/default/libnetdevice/ifreqs.cpp
index 8471173..2e6ad41 100644
--- a/automotive/can/1.0/default/libnetdevice/ifreqs.cpp
+++ b/automotive/can/1.0/default/libnetdevice/ifreqs.cpp
@@ -21,6 +21,8 @@
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
 
+#include <sys/ioctl.h>
+
 #include <map>
 
 namespace android::netdevice::ifreqs {
@@ -68,9 +70,11 @@
     return true;
 }
 
-struct ifreq fromName(const std::string& ifname) {
+struct ifreq fromName(std::string_view ifname) {
     struct ifreq ifr = {};
-    strlcpy(ifr.ifr_name, ifname.c_str(), IF_NAMESIZE);
+    // memcpy: last \0 initialized with ifreq above
+    memcpy(ifr.ifr_name, ifname.data(),
+           std::min(ifname.size(), static_cast<size_t>(IF_NAMESIZE - 1)));
     return ifr;
 }
 
diff --git a/automotive/can/1.0/default/libnetdevice/ifreqs.h b/automotive/can/1.0/default/libnetdevice/ifreqs.h
index aa7030b..f9d8d3b 100644
--- a/automotive/can/1.0/default/libnetdevice/ifreqs.h
+++ b/automotive/can/1.0/default/libnetdevice/ifreqs.h
@@ -52,6 +52,6 @@
  * \param ifname Interface to initialize request with
  * \return Interface request with ifr_name field set to ifname
  */
-struct ifreq fromName(const std::string& ifname);
+struct ifreq fromName(std::string_view ifname);
 
 }  // namespace android::netdevice::ifreqs
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h
index 3886acf..6045733 100644
--- a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h
@@ -28,7 +28,7 @@
  * \param ifname Interface to open a socket against
  * \return Socket's FD or -1 in case of failure
  */
-base::unique_fd socket(const std::string& ifname);
+base::unique_fd socket(std::string_view ifname);
 
 /**
  * Sets CAN interface bitrate.
@@ -36,6 +36,6 @@
  * \param ifname Interface for which the bitrate is to be set
  * \return true on success, false on failure
  */
-bool setBitrate(std::string ifname, uint32_t bitrate);
+bool setBitrate(std::string_view ifname, uint32_t bitrate);
 
 }  // namespace android::netdevice::can
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/ethtool.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/ethtool.h
index 26bfdce..416108f 100644
--- a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/ethtool.h
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/ethtool.h
@@ -29,7 +29,7 @@
  * \param command Fetch command (ETHTOOL_G*)
  * \return value, or nullopt if fetch failed
  */
-std::optional<uint32_t> getValue(const std::string& ifname, uint32_t command);
+std::optional<uint32_t> getValue(std::string_view ifname, uint32_t command);
 
 /**
  * Set a single value with ethtool_value.
@@ -40,6 +40,6 @@
  * \param value New value
  * \return true if succeeded, false otherwise
  */
-bool setValue(const std::string& ifname, uint32_t command, uint32_t value);
+bool setValue(std::string_view ifname, uint32_t command, uint32_t value);
 
 }  // namespace android::netdevice::ethtool
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
index 657f9b2..75655d5 100644
--- a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
@@ -43,7 +43,7 @@
  * \param ifname Interface to check
  * \return true if it exists, false otherwise
  */
-bool exists(std::string ifname);
+bool exists(std::string_view ifname);
 
 /**
  * Checks if network interface is up.
@@ -51,7 +51,7 @@
  * \param ifname Interface to check
  * \return true/false if the check succeeded, nullopt otherwise
  */
-std::optional<bool> isUp(std::string ifname);
+std::optional<bool> isUp(std::string_view ifname);
 
 /**
  * Interface condition to wait for.
@@ -101,7 +101,7 @@
  * \param ifname Interface to bring up
  * \return true in case of success, false otherwise
  */
-bool up(std::string ifname);
+bool up(std::string_view ifname);
 
 /**
  * Brings network interface down.
@@ -109,7 +109,38 @@
  * \param ifname Interface to bring down
  * \return true in case of success, false otherwise
  */
-bool down(std::string ifname);
+bool down(std::string_view ifname);
+
+/**
+ * Retrieves all IPv4 addresses of a given interface.
+ *
+ * \param ifname Interface to query
+ * \return list of IPv4 addresses of this interface
+ */
+std::set<std::string> getAllAddr4(std::string_view ifname);
+
+/**
+ * Set IPv4 address on a given interface.
+ *
+ * This function will overwrite any other existing IPv4 addresses.
+ *
+ * \param ifname Interface to modify
+ * \param addr IPv4 address to set
+ * \return true in case of success, false otherwise
+ */
+bool setAddr4(std::string_view ifname, std::string_view addr);
+
+/**
+ * Add new IPv4 address to a given interface.
+ *
+ * Please note this doesn't remove existing IPv4 addresses.
+ *
+ * \param ifname Interface to modify
+ * \param addr IPv4 address to add
+ * \param prefixlen IPv4 netmask length
+ * \return true in case of success, false otherwise
+ */
+bool addAddr4(std::string_view ifname, std::string_view addr, uint8_t prefixlen = 24);
 
 /**
  * Adds virtual link.
@@ -118,7 +149,7 @@
  * \param type the type of the new device
  * \return true in case of success, false otherwise
  */
-bool add(std::string dev, std::string type);
+bool add(std::string_view dev, std::string_view type);
 
 /**
  * Deletes virtual link.
@@ -126,7 +157,7 @@
  * \param dev the name of the device to remove
  * \return true in case of success, false otherwise
  */
-bool del(std::string dev);
+bool del(std::string_view dev);
 
 /**
  * Fetches interface's hardware address.
@@ -134,7 +165,7 @@
  * \param ifname Interface name
  * \return Hardware address (MAC address) or nullopt if the lookup failed
  */
-std::optional<hwaddr_t> getHwAddr(const std::string& ifname);
+std::optional<hwaddr_t> getHwAddr(std::string_view ifname);
 
 /**
  * Changes interface's hardware address.
@@ -142,7 +173,7 @@
  * \param ifname Interface name
  * \param hwaddr New hardware address to set
  */
-bool setHwAddr(const std::string& ifname, hwaddr_t hwaddr);
+bool setHwAddr(std::string_view ifname, hwaddr_t hwaddr);
 
 }  // namespace android::netdevice
 
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/vlan.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/vlan.h
index 3e1b736..884b704 100644
--- a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/vlan.h
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/vlan.h
@@ -20,6 +20,6 @@
 
 namespace android::netdevice::vlan {
 
-bool add(const std::string& eth, const std::string& vlan, uint16_t id);
+bool add(std::string_view eth, std::string_view vlan, uint16_t id);
 
 }  // namespace android::netdevice::vlan
diff --git a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
index 413b4b1..1830633 100644
--- a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
+++ b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
@@ -23,9 +23,13 @@
 #include <libnl++/MessageFactory.h>
 #include <libnl++/Socket.h>
 
+#include <arpa/inet.h>
+#include <ifaddrs.h>
 #include <linux/can.h>
 #include <linux/rtnetlink.h>
 #include <net/if.h>
+#include <netdb.h>
+#include <sys/ioctl.h>
 
 #include <algorithm>
 #include <iterator>
@@ -37,27 +41,85 @@
     ifreqs::socketDomain = domain;
 }
 
-bool exists(std::string ifname) {
+bool exists(std::string_view ifname) {
     return nametoindex(ifname) != 0;
 }
 
-bool up(std::string ifname) {
+bool up(std::string_view ifname) {
     auto ifr = ifreqs::fromName(ifname);
     if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return false;
+    if (ifr.ifr_flags & IFF_UP) return true;
     ifr.ifr_flags |= IFF_UP;
     return ifreqs::send(SIOCSIFFLAGS, ifr);
 }
 
-bool down(std::string ifname) {
+bool down(std::string_view ifname) {
     auto ifr = ifreqs::fromName(ifname);
     if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return false;
+    if (!(ifr.ifr_flags & IFF_UP)) return true;
     ifr.ifr_flags &= ~IFF_UP;
     return ifreqs::send(SIOCSIFFLAGS, ifr);
 }
 
-bool add(std::string dev, std::string type) {
-    nl::MessageFactory<ifinfomsg> req(RTM_NEWLINK,
-                                      NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK);
+static std::string toString(const sockaddr* addr) {
+    char host[NI_MAXHOST];
+    socklen_t addrlen = (addr->sa_family == AF_INET) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);
+    auto res = getnameinfo(addr, addrlen, host, sizeof(host), nullptr, 0, NI_NUMERICHOST);
+    CHECK(res == 0) << "getnameinfo failed: " << gai_strerror(res);
+    return host;
+}
+
+static std::unique_ptr<ifaddrs, decltype(&freeifaddrs)> getifaddrs() {
+    ifaddrs* addrs = nullptr;
+    CHECK(getifaddrs(&addrs) == 0) << "getifaddrs failed: " << strerror(errno);
+    return {addrs, freeifaddrs};
+}
+
+std::set<std::string> getAllAddr4(std::string_view ifname) {
+    std::set<std::string> addresses;
+    auto addrs = getifaddrs();
+    for (ifaddrs* addr = addrs.get(); addr != nullptr; addr = addr->ifa_next) {
+        if (ifname != addr->ifa_name) continue;
+        if (addr->ifa_addr == nullptr) continue;
+        if (addr->ifa_addr->sa_family != AF_INET) continue;
+        addresses.insert(toString(addr->ifa_addr));
+    }
+    return addresses;
+}
+
+static in_addr_t inetAddr(std::string_view addr) {
+    auto addrn = inet_addr(std::string(addr).c_str());
+    CHECK(addrn != INADDR_NONE) << "Invalid address " << addr;
+    return addrn;
+}
+
+bool setAddr4(std::string_view ifname, std::string_view addr) {
+    auto ifr = ifreqs::fromName(ifname);
+
+    struct sockaddr_in* ifrAddr = reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr);
+    ifrAddr->sin_family = AF_INET;
+    ifrAddr->sin_addr.s_addr = inetAddr(addr);
+
+    return ifreqs::send(SIOCSIFADDR, ifr);
+}
+
+bool addAddr4(std::string_view ifname, std::string_view addr, uint8_t prefixlen) {
+    nl::MessageFactory<ifaddrmsg> req(RTM_NEWADDR, nl::kCreateFlags);
+    req->ifa_family = AF_INET;
+    req->ifa_prefixlen = prefixlen;
+    req->ifa_flags = IFA_F_SECONDARY;
+    req->ifa_index = nametoindex(ifname);
+
+    auto addrn = inetAddr(addr);
+    req.add(IFLA_ADDRESS, addrn);
+    req.add(IFLA_BROADCAST, addrn);
+
+    nl::Socket sock(NETLINK_ROUTE);
+    return sock.send(req) && sock.receiveAck(req);
+}
+
+bool add(std::string_view dev, std::string_view type) {
+    nl::MessageFactory<ifinfomsg> req(RTM_NEWLINK, nl::kCreateFlags);
     req.add(IFLA_IFNAME, dev);
 
     {
@@ -69,15 +131,15 @@
     return sock.send(req) && sock.receiveAck(req);
 }
 
-bool del(std::string dev) {
-    nl::MessageFactory<ifinfomsg> req(RTM_DELLINK, NLM_F_REQUEST | NLM_F_ACK);
+bool del(std::string_view dev) {
+    nl::MessageFactory<ifinfomsg> req(RTM_DELLINK);
     req.add(IFLA_IFNAME, dev);
 
     nl::Socket sock(NETLINK_ROUTE);
     return sock.send(req) && sock.receiveAck(req);
 }
 
-std::optional<hwaddr_t> getHwAddr(const std::string& ifname) {
+std::optional<hwaddr_t> getHwAddr(std::string_view ifname) {
     auto ifr = ifreqs::fromName(ifname);
     if (!ifreqs::send(SIOCGIFHWADDR, ifr)) return std::nullopt;
 
@@ -86,7 +148,7 @@
     return hwaddr;
 }
 
-bool setHwAddr(const std::string& ifname, hwaddr_t hwaddr) {
+bool setHwAddr(std::string_view ifname, hwaddr_t hwaddr) {
     auto ifr = ifreqs::fromName(ifname);
 
     // fetch sa_family
@@ -96,13 +158,13 @@
     return ifreqs::send(SIOCSIFHWADDR, ifr);
 }
 
-std::optional<bool> isUp(std::string ifname) {
+std::optional<bool> isUp(std::string_view ifname) {
     auto ifr = ifreqs::fromName(ifname);
     if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return std::nullopt;
     return ifr.ifr_flags & IFF_UP;
 }
 
-static bool hasIpv4(std::string ifname) {
+static bool hasIpv4(std::string_view ifname) {
     auto ifr = ifreqs::fromName(ifname);
     switch (ifreqs::trySend(SIOCGIFADDR, ifr)) {
         case 0:
diff --git a/automotive/can/1.0/default/libnetdevice/vlan.cpp b/automotive/can/1.0/default/libnetdevice/vlan.cpp
index 35b21b8..e5b5a61 100644
--- a/automotive/can/1.0/default/libnetdevice/vlan.cpp
+++ b/automotive/can/1.0/default/libnetdevice/vlan.cpp
@@ -26,15 +26,14 @@
 
 namespace android::netdevice::vlan {
 
-bool add(const std::string& eth, const std::string& vlan, uint16_t id) {
+bool add(std::string_view eth, std::string_view vlan, uint16_t id) {
     const auto ethidx = nametoindex(eth);
     if (ethidx == 0) {
         LOG(ERROR) << "Ethernet interface " << eth << " doesn't exist";
         return false;
     }
 
-    nl::MessageFactory<ifinfomsg> req(RTM_NEWLINK,
-                                      NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK);
+    nl::MessageFactory<ifinfomsg> req(RTM_NEWLINK, nl::kCreateFlags);
     req.add(IFLA_IFNAME, vlan);
     req.add<uint32_t>(IFLA_LINK, ethidx);
 
diff --git a/automotive/can/1.0/default/libnl++/Android.bp b/automotive/can/1.0/default/libnl++/Android.bp
index 01c1e55..5e3168a 100644
--- a/automotive/can/1.0/default/libnl++/Android.bp
+++ b/automotive/can/1.0/default/libnl++/Android.bp
@@ -26,6 +26,7 @@
 cc_library_static {
     name: "libnl++",
     defaults: ["android.hardware.automotive.can@defaults"],
+    host_supported: true,
     vendor_available: true,
     srcs: [
         "protocols/common/Empty.cpp",
diff --git a/automotive/can/1.0/default/libnl++/Socket.cpp b/automotive/can/1.0/default/libnl++/Socket.cpp
index 221063d..a5a782c 100644
--- a/automotive/can/1.0/default/libnl++/Socket.cpp
+++ b/automotive/can/1.0/default/libnl++/Socket.cpp
@@ -20,6 +20,9 @@
 
 #include <android-base/logging.h>
 
+// Should be in sys/socket.h or linux/socket.h
+#define SOL_NETLINK 270
+
 namespace android::nl {
 
 /**
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/MessageFactory.h b/automotive/can/1.0/default/libnl++/include/libnl++/MessageFactory.h
index a5a425e..f65f055 100644
--- a/automotive/can/1.0/default/libnl++/include/libnl++/MessageFactory.h
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/MessageFactory.h
@@ -26,6 +26,9 @@
 
 namespace android::nl {
 
+static constexpr uint16_t kDefaultFlags = NLM_F_REQUEST | NLM_F_ACK;
+static constexpr uint16_t kCreateFlags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
+
 class MessageFactoryBase {
   protected:
     static nlattr* add(nlmsghdr* msg, size_t maxLen, nlattrtype_t type, const void* data,
@@ -54,7 +57,7 @@
      * \param type Message type (such as RTM_NEWLINK).
      * \param flags Message flags (such as NLM_F_REQUEST).
      */
-    MessageFactory(nlmsgtype_t type, uint16_t flags)
+    MessageFactory(nlmsgtype_t type, uint16_t flags = kDefaultFlags)
         : header(mMessage.header), data(mMessage.data) {
         mMessage.header.nlmsg_len = offsetof(Message, attributesBuffer);
         mMessage.header.nlmsg_type = type;
diff --git a/automotive/can/1.0/default/libnl++/printer.cpp b/automotive/can/1.0/default/libnl++/printer.cpp
index d540482..8c7c476 100644
--- a/automotive/can/1.0/default/libnl++/printer.cpp
+++ b/automotive/can/1.0/default/libnl++/printer.cpp
@@ -26,6 +26,12 @@
 #include <iomanip>
 #include <sstream>
 
+// should be in linux/netlink.h
+#define NLM_F_DUMP_FILTERED 0x20
+#define NLM_F_NONREC 0x100
+#define NLM_F_CAPPED 0x100
+#define NLM_F_ACK_TLVS 0x200
+
 namespace android::nl {
 
 static void flagsToStream(std::stringstream& ss, __u16 nlmsg_flags, protocols::MessageGenre genre) {
diff --git a/automotive/can/1.0/default/libnl++/protocols/common/Error.cpp b/automotive/can/1.0/default/libnl++/protocols/common/Error.cpp
index 77451ed..277f19d 100644
--- a/automotive/can/1.0/default/libnl++/protocols/common/Error.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/common/Error.cpp
@@ -22,6 +22,17 @@
 
 #include <map>
 
+#include <linux/netlink.h>
+#ifndef _UAPI__LINUX_NETLINK_H
+// linux_glibc (host) includes source headers instead of uapi headers
+enum nlmsgerr_attrs {
+    NLMSGERR_ATTR_UNUSED,
+    NLMSGERR_ATTR_MSG,
+    NLMSGERR_ATTR_OFFS,
+    NLMSGERR_ATTR_COOKIE,
+};
+#endif
+
 namespace android::nl::protocols::base {
 
 using DataType = AttributeDefinition::DataType;
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/FamilyTracker.cpp b/automotive/can/1.0/default/libnl++/protocols/generic/FamilyTracker.cpp
index 3ad101e..eebd1f1 100644
--- a/automotive/can/1.0/default/libnl++/protocols/generic/FamilyTracker.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/FamilyTracker.cpp
@@ -18,6 +18,9 @@
 
 #include <android-base/logging.h>
 
+// should be in linux/genetlink.h
+#define GENL_START_ALLOC (NLMSG_MIN_TYPE + 3)
+
 namespace android::nl::generic {
 
 bool FamilyTracker::track(const Buffer<nlmsghdr>& buffer) {
diff --git a/automotive/can/1.0/default/libnl++/protocols/route/Addr.cpp b/automotive/can/1.0/default/libnl++/protocols/route/Addr.cpp
index 024d389..5bd6262 100644
--- a/automotive/can/1.0/default/libnl++/protocols/route/Addr.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/route/Addr.cpp
@@ -20,6 +20,12 @@
 #include "attributes.h"
 #include "structs.h"
 
+// should be in linux/if_addr.h
+#define IFA_F_MANAGETEMPADDR 0x100
+#define IFA_F_NOPREFIXROUTE 0x200
+#define IFA_F_MCAUTOJOIN 0x400
+#define IFA_F_STABLE_PRIVACY 0x800
+
 namespace android::nl::protocols::route {
 
 using DataType = AttributeDefinition::DataType;
diff --git a/automotive/can/1.0/default/libnl++/protocols/route/attributes.cpp b/automotive/can/1.0/default/libnl++/protocols/route/attributes.cpp
index 69d9b81..c81ee27 100644
--- a/automotive/can/1.0/default/libnl++/protocols/route/attributes.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/route/attributes.cpp
@@ -22,6 +22,54 @@
 #include <linux/rtnetlink.h>
 #include <net/if.h>
 
+#include <linux/if_link.h>
+#ifndef _UAPI_LINUX_IF_LINK_H
+enum {
+    IFLA_INFO_SLAVE_KIND = IFLA_INFO_XSTATS + 1,
+    IFLA_INFO_SLAVE_DATA,
+};
+enum {
+    IFLA_INET6_TOKEN = IFLA_INET6_ICMP6STATS + 1,
+    IFLA_INET6_ADDR_GEN_MODE,
+    IFLA_INET6_RA_MTU,
+};
+enum {
+    IFLA_CARRIER = IFLA_NUM_RX_QUEUES + 1,
+    IFLA_PHYS_PORT_ID,
+    IFLA_CARRIER_CHANGES,
+    IFLA_PHYS_SWITCH_ID,
+    IFLA_LINK_NETNSID,
+    IFLA_PHYS_PORT_NAME,
+    IFLA_PROTO_DOWN,
+    IFLA_GSO_MAX_SEGS,
+    IFLA_GSO_MAX_SIZE,
+    IFLA_PAD,
+    IFLA_XDP,
+    IFLA_EVENT,
+    IFLA_NEW_NETNSID,
+    IFLA_TARGET_NETNSID,
+    IFLA_CARRIER_UP_COUNT,
+    IFLA_CARRIER_DOWN_COUNT,
+    IFLA_NEW_IFINDEX,
+    IFLA_MIN_MTU,
+    IFLA_MAX_MTU,
+    IFLA_PROP_LIST,
+    IFLA_ALT_IFNAME,
+    IFLA_PERM_ADDRESS,
+    IFLA_PROTO_DOWN_REASON,
+    IFLA_PARENT_DEV_NAME,
+    IFLA_PARENT_DEV_BUS_NAME,
+    IFLA_GRO_MAX_SIZE,
+    IFLA_TSO_MAX_SIZE,
+    IFLA_TSO_MAX_SEGS,
+    IFLA_ALLMULTI,
+    IFLA_DEVLINK_PORT,
+    IFLA_GSO_IPV4_MAX_SIZE,
+    IFLA_GRO_IPV4_MAX_SIZE,
+    IFLA_DPLL_PIN,
+};
+#endif
+
 namespace android::nl::protocols::route {
 
 using DataType = AttributeDefinition::DataType;
diff --git a/automotive/can/1.0/default/libnl++/protocols/route/structs.h b/automotive/can/1.0/default/libnl++/protocols/route/structs.h
index c969a6c..410c42e 100644
--- a/automotive/can/1.0/default/libnl++/protocols/route/structs.h
+++ b/automotive/can/1.0/default/libnl++/protocols/route/structs.h
@@ -64,8 +64,8 @@
        << data.tx_heartbeat_errors << ','  //
        << data.tx_window_errors << ','     //
        << data.rx_compressed << ','        //
-       << data.tx_compressed << ','        //
-       << data.rx_nohandler << '}';
+       << data.tx_compressed << '}';
+    // Not printed (due to portability): rx_nohandler, rx_otherhost_dropped
 }
 
 }  // namespace android::nl::protocols::route
diff --git a/automotive/evs/aidl/Android.bp b/automotive/evs/aidl/Android.bp
index dfb15c6..75eb924 100644
--- a/automotive/evs/aidl/Android.bp
+++ b/automotive/evs/aidl/Android.bp
@@ -28,9 +28,11 @@
         "android/hardware/automotive/evs/*.aidl",
     ],
     stability: "vintf",
+    defaults: [
+        "android.hardware.graphics.common-latest",
+    ],
     imports: [
         "android.hardware.common-V2",
-        "android.hardware.graphics.common-V5",
     ],
     backend: {
         java: {
@@ -44,6 +46,9 @@
         ndk: {
             min_sdk_version: "29",
         },
+        rust: {
+            enabled: true,
+        },
     },
     versions_with_info: [
         {
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/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/test/DefaultVehicleHalTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
index 11a8fc7..ad34a4c 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) {
@@ -1790,6 +1849,12 @@
     std::this_thread::sleep_for(std::chrono::seconds(3));
 
     auto maybeResults = getCallback()->nextOnPropertyEventResults();
+    size_t retryCount = 0;
+    // Add a 1s (100ms * 10) buffer time.
+    while (!maybeResults.has_value() && retryCount < 10) {
+        retryCount++;
+        std::this_thread::sleep_for(std::chrono::milliseconds(100));
+    }
     ASSERT_TRUE(maybeResults.has_value()) << "no results in callback";
     ASSERT_EQ(maybeResults.value().payloads.size(), static_cast<size_t>(1));
     VehiclePropValue gotValue = maybeResults.value().payloads[0];
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/tools/translate_aidl_enums.py b/automotive/vehicle/tools/translate_aidl_enums.py
index a7c1808..53afef3 100644
--- a/automotive/vehicle/tools/translate_aidl_enums.py
+++ b/automotive/vehicle/tools/translate_aidl_enums.py
@@ -21,14 +21,16 @@
    ENUM_NAMETest.java files in cts/tests/tests/car/src/android/car/cts and
    packages/services/Car/tests/android_car_api_test/src/android/car/apitest
 
+   Also needs a flag name e.g. FLAG_ANDROID_VIC_VEHICLE_PROPERTIES
+
    Usage:
-   $ python translate_aidl_enums.py ENUM_NAME.aidl
+   $ python translate_aidl_enums.py ENUM_NAME.aidl FLAG_NAME
 """
 import os
 import sys
 
 LICENSE = """/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -45,15 +47,20 @@
 """
 
 class EnumParser:
-    def __init__(self, file_path, file_name):
+    def __init__(self, file_path, file_name, flag_name):
         self.filePath = file_path
         self.fileName = file_name
+        self.flagName = flag_name
         self.lowerFileName = self.fileName[0].lower() + self.fileName[1:]
+        self.enumNames = []
         self.enums = []
         self.outputMsg = []
         self.outputMsg.append(LICENSE)
         self.outputMsg.append("\npackage android.car.hardware.property;\n")
         self.outputMsg.append("""
+import static android.car.feature.Flags.{};
+
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 
@@ -61,26 +68,61 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-""")
+""".format(self.flagName))
+
+        comment_block = []
+        in_comment = False
 
         with open(self.filePath, 'r') as f:
-            for line in f.readlines()[16:]:
-                if line in ["package android.hardware.automotive.vehicle;\n",
-                            "@VintfStability\n",
-                            '@Backing(type="int")\n']:
+            lines = f.readlines()
+            for line in lines:
+                line = line.rstrip('\n')
+                if line.strip() in ["package android.hardware.automotive.vehicle;",
+                                    "@VintfStability",
+                                    '@Backing(type="int")']:
                     continue
 
-                msg = line
+                if line.strip().startswith('/**') or line.strip().startswith('/*'):
+                    in_comment = True
+                    comment_block.append(line + '\n')
+                    continue
+                elif in_comment:
+                    comment_block.append(line + '\n')
+                    if line.strip().endswith('*/'):
+                        in_comment = False
+                    continue
+                elif line.strip().startswith('*'):
+                    comment_block.append(line + '\n')
+                    continue
+
+                msg = line + '\n'
                 msgSplit = msg.strip().split()
                 if len(msgSplit) > 0 and msgSplit[0] == "enum":
+                    if comment_block:
+                        self.outputMsg.extend(comment_block)
+                        comment_block = []
+                    self.outputMsg.append("@FlaggedApi({})\n".format(self.flagName))
                     msgSplit[0] = "public final class"
                     msg = " ".join(msgSplit) + "\n"
+                    self.outputMsg.append(msg)
                 elif len(msgSplit) > 1 and msgSplit[1] == '=':
+                    if comment_block:
+                        indented_comment_block = [line for line in comment_block]
+                        self.outputMsg.extend(indented_comment_block)
+                        comment_block = []
                     msgSplit.insert(0, "    public static final int")
-                    self.enums.append(msgSplit[1])
-                    msgSplit[-1] = msgSplit[-1][:-1] + ";\n"
-                    msg = " ".join(msgSplit)
-                elif msg == "}\n":
+                    enum_name = msgSplit[1].strip()
+                    self.enumNames.append(enum_name)
+                    enum = msgSplit[3].strip(",")
+                    self.enums.append(enum)
+                    if msgSplit[-1].endswith(','):
+                        msgSplit[-1] = msgSplit[-1][:-1] + ";"
+                    msg = " ".join(msgSplit) + "\n"
+                    self.outputMsg.append(msg)
+                elif line.strip() == '}':
+                    if comment_block:
+                        self.outputMsg.extend(comment_block)
+                        comment_block = []
                     self.outputMsg.append("""
     private {2}() {{}}
 
@@ -101,17 +143,23 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface {2}Int {{}}\n""".format(self.lowerFileName, "{" + ", ".join(self.enums) + "}",
                                               self.fileName))
-                self.outputMsg.append(msg)
-        self.outputMsg.append("TODO: delete this line and manually update this file with app-facing documentation and necessary tags.\n")
+        self.outputMsg.append("}")
 
         self.outputMsgApiTest = []
         self.outputMsgApiTest.append(LICENSE)
         self.outputMsgApiTest.append("""package android.car.apitest;
 
+import static android.car.feature.Flags.{1};
+
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+
 import androidx.test.filters.SmallTest;
 
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -122,6 +170,8 @@
 @SmallTest
 @RunWith(Parameterized.class)
 public class {0}Test {{
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
     private final int mJavaConstantValue;
     private final int mHalConstantValue;
 
@@ -133,56 +183,68 @@
     @Parameterized.Parameters
     public static Collection constantValues() {{
         return Arrays.asList(
-                new Object[][] {{""".format(self.fileName))
-        for enum in self.enums:
+                new Object[][] {{""".format(self.fileName, self.flagName))
+        for enum in self.enumNames:
             self.outputMsgApiTest.append("""
                         {{
                                 android.car.hardware.property.{0}.{1},
                                 android.hardware.automotive.vehicle.{0}.{1}
                         }},""".format(self.fileName, enum))
         self.outputMsgApiTest.append("""
-                });
-    }
+                }});
+    }}
 
     @Test
-    public void testMatchWithVehicleHal() {
+    @RequiresFlagsEnabled({})
+    public void testMatchWithVehicleHal() {{
         assertWithMessage("Java constant")
                 .that(mJavaConstantValue)
                 .isEqualTo(mHalConstantValue);
-    }
-}
-""")
+    }}
+}}
+""".format(self.flagName))
 
         self.outputMsgCtsTest = []
         self.outputMsgCtsTest.append(LICENSE)
         self.outputMsgCtsTest.append("""
 package android.car.cts;
 
+import static android.car.feature.Flags.{1};
+
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import android.car.cts.utils.VehiclePropertyUtils;
 import android.car.hardware.property.{0};
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 
+import org.junit.Rule;
 import org.junit.Test;
 
 import java.util.List;
 
 public class {0}Test {{
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
 
     @Test
-    public void testToString() {{""".format(self.fileName))
-        for enum in self.enums:
+    @RequiresFlagsEnabled({1})
+    public void testToString() {{""".format(self.fileName, self.flagName))
+        for enum in self.enumNames:
             self.outputMsgCtsTest.append("""
         assertThat({0}.toString(
                 {0}.{1}))
                 .isEqualTo("{1}");""".format(self.fileName, enum))
+        max_enum_value = len(self.enums)
         self.outputMsgCtsTest.append("""
         assertThat({0}.toString({1})).isEqualTo("{2}");
         assertThat({0}.toString(12)).isEqualTo("0xc");
     }}
 
     @Test
+    @RequiresFlagsEnabled({4})
     public void testAll{0}sAreMappedInToString() {{
         List<Integer> {3}s =
                 VehiclePropertyUtils.getIntegersFromDataEnums({0}.class);
@@ -194,11 +256,11 @@
         }}
     }}
 }}
-""".format(self.fileName, len(self.enums), hex(len(self.enums)), self.lowerFileName))
+""".format(self.fileName, len(self.enums), hex(len(self.enums)), self.lowerFileName, self.flagName))
 
 def main():
-    if len(sys.argv) != 2:
-        print("Usage: {} enum_aidl_file".format(sys.argv[0]))
+    if len(sys.argv) != 3:
+        print("Usage: {} enum_aidl_file ALL_CAPS_FLAG_NAME".format(sys.argv[0]))
         sys.exit(1)
     print("WARNING: This file only generates the base enum values in the framework layer. The "
           + "generated files must be reviewed by you and edited if any additional changes are "
@@ -207,12 +269,14 @@
           + "the new property is system API")
     file_path = sys.argv[1]
     file_name = file_path.split('/')[-1][:-5]
-    parser = EnumParser(file_path, file_name)
+    flag_name = sys.argv[2]
+    parser = EnumParser(file_path, file_name, flag_name)
 
     android_top = os.environ['ANDROID_BUILD_TOP']
     if not android_top:
         print('ANDROID_BUILD_TOP is not in environmental variable, please run source and lunch '
               + 'at the android root')
+        sys.exit(1)
 
     with open(android_top + "/packages/services/Car/car-lib/src/android/car/hardware/property/"
               + file_name + ".java", 'w') as f:
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..bed0405 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,80 @@
     ],
     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_fragments: ["face-default.xml"],
+    shared_libs: [
+        "libbinder_ndk",
+        "liblog",
+        "libnativewindow",
+    ],
+    whole_static_libs: [
+        "android.hardware.biometrics.face-service.lib",
+    ],
 }
 
 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 +106,7 @@
         "tests/FakeFaceEngineTest.cpp",
         "FakeFaceEngine.cpp",
         "FakeLockoutTracker.cpp",
+        "FaceConfig.cpp",
     ],
     shared_libs: [
         "libbase",
@@ -81,6 +122,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 +135,7 @@
     srcs: [
         "tests/FakeLockoutTrackerTest.cpp",
         "FakeLockoutTracker.cpp",
+        "FaceConfig.cpp",
     ],
     shared_libs: [
         "libbase",
@@ -107,8 +151,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/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/biometrics/face/aidl/default/FaceConfig.h
similarity index 62%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
copy to biometrics/face/aidl/default/FaceConfig.h
index c7be950..64b62e0 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ b/biometrics/face/aidl/default/FaceConfig.h
@@ -14,22 +14,14 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+#pragma once
 
-import android.hardware.biometrics.fingerprint.AcquiredInfo;
+#include "config/Config.h"
 
-/**
- * @hide
- */
-@VintfStability
-union AcquiredInfoAndVendorCode {
-    /**
-     * Acquired info as specified in AcqauiredInfo.aidl
-     */
-    AcquiredInfo acquiredInfo = AcquiredInfo.UNKNOWN;
+namespace aidl::android::hardware::biometrics::face {
 
-    /**
-     * Vendor specific code
-     */
-    int vendorCode;
-}
+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/AcquiredInfoAndVendorCode.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
deleted file mode 100644
index c1dc51c..0000000
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ /dev/null
@@ -1,40 +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
-union AcquiredInfoAndVendorCode {
-  android.hardware.biometrics.fingerprint.AcquiredInfo acquiredInfo = android.hardware.biometrics.fingerprint.AcquiredInfo.UNKNOWN;
-  int vendorCode;
-}
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..faaa9c6 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,80 @@
         "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_fragments: ["fingerprint-default.xml"],
+    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",
+    ],
 }
 
 cc_test {
@@ -63,14 +120,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 +147,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 +172,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 +199,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 +231,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 +244,6 @@
             cflags: ["-DFPS_DEBUGGABLE"],
         },
     },
-    vendor: true,
     test_suites: ["general-tests"],
     require_root: true,
 }
@@ -198,39 +251,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/broadcastradio/aidl/Android.bp b/broadcastradio/aidl/Android.bp
index 82ee949..081bae3 100644
--- a/broadcastradio/aidl/Android.bp
+++ b/broadcastradio/aidl/Android.bp
@@ -51,12 +51,12 @@
         },
 
     ],
-    frozen: true,
+    frozen: false,
 
 }
 
 // Note: This should always be one version ahead of the last frozen version
-latest_android_hardware_broadcastradio = "android.hardware.broadcastradio-V2"
+latest_android_hardware_broadcastradio = "android.hardware.broadcastradio-V3"
 
 cc_defaults {
     name: "latest_android_hardware_broadcastradio_ndk_static",
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Alert.aidl
similarity index 84%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Alert.aidl
index 173ac17..7e02f70 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Alert.aidl
@@ -31,10 +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.biometrics.fingerprint;
-/* @hide */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.broadcastradio;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable Alert {
+  android.hardware.broadcastradio.AlertStatus status;
+  android.hardware.broadcastradio.AlertMessageType messageType;
+  android.hardware.broadcastradio.AlertInfo[] infoArray;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AlertArea.aidl
similarity index 87%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AlertArea.aidl
index 173ac17..aa828d0 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AlertArea.aidl
@@ -31,10 +31,9 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.broadcastradio;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable AlertArea {
+  android.hardware.broadcastradio.Polygon[] polygons;
+  android.hardware.broadcastradio.Geocode[] geocodes;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AlertCategory.aidl
similarity index 86%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AlertCategory.aidl
index 173ac17..f493e75 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AlertCategory.aidl
@@ -31,10 +31,19 @@
 // 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
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.broadcastradio;
+@Backing(type="int") @JavaDerive(equals=true, toString=true) @VintfStability
+enum AlertCategory {
+  GEO,
+  MET,
+  SAFETY,
+  SECURITY,
+  RESCUE,
+  FIRE,
+  HEALTH,
+  ENV,
+  TRANSPORT,
+  INFRA,
+  CBRNE,
+  OTHER,
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AlertCertainty.aidl
similarity index 87%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AlertCertainty.aidl
index 173ac17..dcf283a 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AlertCertainty.aidl
@@ -31,10 +31,12 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.broadcastradio;
+@Backing(type="int") @JavaDerive(equals=true, toString=true) @VintfStability
+enum AlertCertainty {
+  OBSERVED,
+  LIKELY,
+  POSSIBLE,
+  UNLIKELY,
+  UNKNOWN,
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/NextEnrollment.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AlertInfo.aidl
similarity index 78%
rename from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/NextEnrollment.aidl
rename to broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AlertInfo.aidl
index 75ed070..da08c9a 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/NextEnrollment.aidl
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AlertInfo.aidl
@@ -31,11 +31,14 @@
 // 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
-parcelable NextEnrollment {
-  int id;
-  android.hardware.biometrics.fingerprint.EnrollmentProgressStep[] progressSteps;
-  boolean result = true;
+package android.hardware.broadcastradio;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable AlertInfo {
+  android.hardware.broadcastradio.AlertCategory[] categoryArray;
+  android.hardware.broadcastradio.AlertUrgency urgency;
+  android.hardware.broadcastradio.AlertSeverity severity;
+  android.hardware.broadcastradio.AlertCertainty certainty;
+  String description;
+  android.hardware.broadcastradio.AlertArea[] areas;
+  @nullable String language;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AlertMessageType.aidl
similarity index 87%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AlertMessageType.aidl
index 173ac17..2b89c92 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AlertMessageType.aidl
@@ -31,10 +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.biometrics.fingerprint;
-/* @hide */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.broadcastradio;
+@Backing(type="int") @JavaDerive(equals=true, toString=true) @VintfStability
+enum AlertMessageType {
+  ALERT,
+  UPDATE,
+  CANCEL,
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AlertSeverity.aidl
similarity index 87%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AlertSeverity.aidl
index 173ac17..5c91abd 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AlertSeverity.aidl
@@ -31,10 +31,12 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.broadcastradio;
+@Backing(type="int") @JavaDerive(equals=true, toString=true) @VintfStability
+enum AlertSeverity {
+  EXTREME,
+  SEVERE,
+  MODERATE,
+  MINOR,
+  UNKNOWN,
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AlertStatus.aidl
similarity index 87%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AlertStatus.aidl
index 173ac17..8ce69b5 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AlertStatus.aidl
@@ -31,10 +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.biometrics.fingerprint;
-/* @hide */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.broadcastradio;
+@Backing(type="int") @JavaDerive(equals=true, toString=true) @VintfStability
+enum AlertStatus {
+  ACTUAL,
+  EXERCISE,
+  TEST,
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AlertUrgency.aidl
similarity index 87%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AlertUrgency.aidl
index 173ac17..fd0491d 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AlertUrgency.aidl
@@ -31,10 +31,12 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.broadcastradio;
+@Backing(type="int") @JavaDerive(equals=true, toString=true) @VintfStability
+enum AlertUrgency {
+  IMMEDIATE,
+  EXPECTED,
+  FUTURE,
+  PAST,
+  UNKNOWN,
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Coordinate.aidl
similarity index 87%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Coordinate.aidl
index 173ac17..b303986 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Coordinate.aidl
@@ -31,10 +31,9 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.broadcastradio;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable Coordinate {
+  double latitude;
+  double longitude;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Geocode.aidl
similarity index 87%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Geocode.aidl
index 173ac17..a07e1c0 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Geocode.aidl
@@ -31,10 +31,9 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.broadcastradio;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable Geocode {
+  String valueName;
+  String value;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Polygon.aidl
similarity index 87%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Polygon.aidl
index 173ac17..4d4d78d 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Polygon.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 */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.broadcastradio;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable Polygon {
+  android.hardware.broadcastradio.Coordinate[] coordinates;
 }
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ProgramInfo.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ProgramInfo.aidl
index 997cdd7..dd57901 100644
--- a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ProgramInfo.aidl
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ProgramInfo.aidl
@@ -42,6 +42,7 @@
   int signalQuality;
   android.hardware.broadcastradio.Metadata[] metadata;
   android.hardware.broadcastradio.VendorKeyValue[] vendorInfo;
+  @nullable android.hardware.broadcastradio.Alert emergencyAlert;
   const int FLAG_LIVE = (1 << 0) /* 1 */;
   const int FLAG_MUTED = (1 << 1) /* 2 */;
   const int FLAG_TRAFFIC_PROGRAM = (1 << 2) /* 4 */;
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/Alert.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/Alert.aidl
new file mode 100644
index 0000000..a307ccc
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/Alert.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.broadcastradio;
+
+import android.hardware.broadcastradio.AlertInfo;
+import android.hardware.broadcastradio.AlertMessageType;
+import android.hardware.broadcastradio.AlertStatus;
+
+/**
+ * Emergency Alert Message.
+ *
+ * <p>Alert message can be sent from a radio station of technologies such as HD radio to
+ * the radio users for some emergency events (see ITU-T X.1303 bis for more info).
+ */
+@VintfStability
+@JavaDerive(equals=true, toString=true)
+parcelable Alert {
+    /**
+     * The status of the alert message.
+     */
+    AlertStatus status;
+
+    /**
+     * The message type of the alert message.
+     */
+    AlertMessageType messageType;
+
+    /**
+     * Array of alert information.
+     */
+    AlertInfo[] infoArray;
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/AlertArea.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/AlertArea.aidl
new file mode 100644
index 0000000..b3f07b3
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/AlertArea.aidl
@@ -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.
+ */
+
+package android.hardware.broadcastradio;
+
+import android.hardware.broadcastradio.Geocode;
+import android.hardware.broadcastradio.Polygon;
+
+/**
+ * The geographic area that delineates the affected area of the alert message
+ *
+ * <p>(see ITU-T X.1303 bis for more info).
+ */
+@VintfStability
+@JavaDerive(equals=true, toString=true)
+parcelable AlertArea {
+    /**
+     * Polygons that delineate the affected area of the alert message.
+     */
+    Polygon[] polygons;
+
+    /**
+     * Geographic code delineating the affected area of the alert message.
+     */
+    Geocode[] geocodes;
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/AlertCategory.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/AlertCategory.aidl
new file mode 100644
index 0000000..a24361a
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/AlertCategory.aidl
@@ -0,0 +1,88 @@
+/*
+ * 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.broadcastradio;
+
+/**
+ * The category of the subject event of the emergency alert message.
+ *
+ * <p>(see ITU-T X.1303 bis for more info).
+ */
+@VintfStability
+@Backing(type="int")
+@JavaDerive(equals=true, toString=true)
+enum AlertCategory {
+    /**
+     * Alert category related to geophysical (inc. landslide).
+     */
+    GEO,
+
+    /**
+     * Alert category related to meteorological (inc. flood).
+     */
+    MET,
+
+    /**
+     * Alert category related to general emergency and public safety.
+     */
+    SAFETY,
+
+    /**
+     * Alert category related to law enforcement, military, homeland and local/private security.
+     */
+    SECURITY,
+
+    /**
+     * Alert category related to rescue and recovery.
+     */
+    RESCUE,
+
+    /**
+     * Alert category related to fire suppression and rescue.
+     */
+    FIRE,
+
+    /**
+     * Alert category related to medical and public health.
+     */
+    HEALTH,
+
+    /**
+     * Alert category related to pollution and other environmental.
+     */
+    ENV,
+
+    /**
+     * Alert category related to public and private transportation.
+     */
+    TRANSPORT,
+
+    /**
+     * Utility, telecommunication, other non-transport infrastructure.
+     */
+    INFRA,
+
+    /**
+     * Alert category related to chemical, biological, radiological, nuclear or high-yield
+     * explosive threat or attack.
+     */
+    CBRNE,
+
+    /**
+     * Alert category related to other events.
+     */
+    OTHER,
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/AlertCertainty.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/AlertCertainty.aidl
new file mode 100644
index 0000000..11f069e
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/AlertCertainty.aidl
@@ -0,0 +1,52 @@
+/*
+ * 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.broadcastradio;
+
+/**
+ * The certainty of the subject event of the emergency alert message
+ *
+ * <p>(see ITU-T X.1303 bis for more info).
+ */
+@VintfStability
+@Backing(type="int")
+@JavaDerive(equals=true, toString=true)
+enum AlertCertainty {
+    /**
+     * Certainty indicating that the event is determined to have occurred or to be ongoing.
+     */
+    OBSERVED,
+
+    /**
+     * Certainty indicating that the event is likely (probability > ~50%).
+     */
+    LIKELY,
+
+    /**
+     * Certainty indicating that the event is possible but not likely (probability <= ~50%).
+     */
+    POSSIBLE,
+
+    /**
+     * Certainty indicating that the event is not expected to occur (probability ~ 0).
+     */
+    UNLIKELY,
+
+    /**
+     * Unknown certainty.
+     */
+    UNKNOWN,
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/AlertInfo.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/AlertInfo.aidl
new file mode 100644
index 0000000..ab2e6f7
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/AlertInfo.aidl
@@ -0,0 +1,77 @@
+/*
+ * 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.broadcastradio;
+
+import android.hardware.broadcastradio.AlertArea;
+import android.hardware.broadcastradio.AlertCategory;
+import android.hardware.broadcastradio.AlertCertainty;
+import android.hardware.broadcastradio.AlertSeverity;
+import android.hardware.broadcastradio.AlertUrgency;
+
+/**
+ * Alert information.
+ *
+ * <p>(see ITU-T X.1303 bis for more info).
+ */
+@VintfStability
+@JavaDerive(equals=true, toString=true)
+parcelable AlertInfo {
+    /**
+     * Array of categories of the subject event of the alert info.
+     *
+     * <p>According to ITU-T X.1303, a single alert info block may contains multiple categories.
+     */
+    AlertCategory[] categoryArray;
+
+    /**
+     * The urgency of the subject event of the alert info.
+     *
+     * <p>Urgency represents the time available to prepare for the alert.
+     */
+    AlertUrgency urgency;
+
+    /**
+     * The severity of the subject event of the alert info.
+     *
+     * <p>Severity represents the intensity of impact.
+     */
+    AlertSeverity severity;
+
+    /**
+     * The certainty of the subject event of the alert info.
+     *
+     * <p>Certainty represents confidence in the observation or prediction.
+     */
+    AlertCertainty certainty;
+
+    /**
+     * Textual descriptions of the subject event.
+     */
+    String description;
+
+    /**
+     * The array of geographic areas to which the alert info segment in which it appears applies.
+     */
+    AlertArea[] areas;
+
+    /**
+     * The IETF RFC 3066 language code donating the language of the alert message.
+     *
+     * <p>This field is optional.
+     */
+    @nullable String language;
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/AlertMessageType.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/AlertMessageType.aidl
new file mode 100644
index 0000000..1dd4e2b
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/AlertMessageType.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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.broadcastradio;
+
+/**
+ * The emergency alert message type
+ *
+ * <p>The message type indicates the emergency alert message nature.
+ * (see ITU-T X.1303 bis for more info).
+ */
+@VintfStability
+@Backing(type="int")
+@JavaDerive(equals=true, toString=true)
+enum AlertMessageType {
+    /**
+     * Initial information requiring attention by targeted recipients.
+     */
+    ALERT,
+
+    /**
+     * Updates and supersedes the earlier message(s).
+     */
+    UPDATE,
+
+    /**
+     * Cancels the earlier message(s).
+     */
+    CANCEL,
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/AlertSeverity.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/AlertSeverity.aidl
new file mode 100644
index 0000000..acc11c4
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/AlertSeverity.aidl
@@ -0,0 +1,52 @@
+/*
+ * 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.broadcastradio;
+
+/**
+ * The severity of the subject event of the emergency alert message
+ *
+ * <p>(see ITU-T X.1303 bis for more info).
+ */
+@VintfStability
+@Backing(type="int")
+@JavaDerive(equals=true, toString=true)
+enum AlertSeverity {
+    /**
+     * Severity indicating extraordinary threat to life or property.
+     */
+    EXTREME,
+
+    /**
+     * Severity indicating significant threat to life or property.
+     */
+    SEVERE,
+
+    /**
+     * Severity indicating possible threat to life or property.
+     */
+    MODERATE,
+
+    /**
+     * Severity indicating minimal to no known threat to life or property.
+     */
+    MINOR,
+
+    /**
+     * Unknown severity.
+     */
+    UNKNOWN,
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/AlertStatus.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/AlertStatus.aidl
new file mode 100644
index 0000000..8b0c917
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/AlertStatus.aidl
@@ -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.
+ */
+
+package android.hardware.broadcastradio;
+
+/**
+ * The status of the alert message
+ *
+ * <p>Status is the appropriate handling of the alert message (see ITU-T X.1303 bis for more info).
+ */
+@VintfStability
+@Backing(type="int")
+@JavaDerive(equals=true, toString=true)
+enum AlertStatus {
+    /**
+     * Actionable by all targeted recipients.
+     */
+    ACTUAL,
+
+    /**
+     * Actionable only by designated exercise participants.
+     */
+    EXERCISE,
+
+    /**
+     * Technical testing only, all recipients disregard.
+     */
+    TEST,
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/AlertUrgency.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/AlertUrgency.aidl
new file mode 100644
index 0000000..a0ef4a9
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/AlertUrgency.aidl
@@ -0,0 +1,52 @@
+/*
+ * 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.broadcastradio;
+
+/**
+ * The severity of the subject event of the emergency alert message.
+ *
+ * <p>(see ITU-T X.1303 bis for more info).
+ */
+@VintfStability
+@Backing(type="int")
+@JavaDerive(equals=true, toString=true)
+enum AlertUrgency {
+    /**
+     * Urgency indicating that responsive action should be taken immediately.
+     */
+    IMMEDIATE,
+
+    /**
+     * Urgency indicating that responsive action should be taken soon.
+     */
+    EXPECTED,
+
+    /**
+     * Urgency indicating that responsive action should be taken in the near future.
+     */
+    FUTURE,
+
+    /**
+     * Urgency indicating that responsive action is no longer required.
+     */
+    PAST,
+
+    /**
+     * Unknown rgency.
+     */
+    UNKNOWN,
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/Coordinate.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/Coordinate.aidl
new file mode 100644
index 0000000..b881534
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/Coordinate.aidl
@@ -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 android.hardware.broadcastradio;
+
+/**
+ * Coordinate reprensenting the geographic location in alert message
+ *
+ * <p>(see ITU-T X.1303 bis for more info).
+ */
+@VintfStability
+@JavaDerive(equals=true, toString=true)
+parcelable Coordinate {
+    /**
+     * Latitude of the cooridinate.
+     *
+     * <p>Latitude is in the range of -90 to 90.
+     */
+    double latitude;
+
+    /**
+     * Longitude of the cooridinate.
+     *
+     * <p>Longitude is in the range of -90 to 90.
+     */
+    double longitude;
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/Geocode.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/Geocode.aidl
new file mode 100644
index 0000000..f0162ca
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/Geocode.aidl
@@ -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.
+ */
+
+package android.hardware.broadcastradio;
+
+/**
+ * Geographic code reprensenting location in alert message
+ *
+ * <p>(see ITU-T X.1303 bis for more info).
+ */
+@VintfStability
+@JavaDerive(equals=true, toString=true)
+parcelable Geocode {
+    /**
+     * Value name of a geographic code.
+     *
+     * <p>Value name are acronyms should be represented in all capital
+     * letters without periods (e.g., SAME, FIPS, ZIP).
+     */
+    String valueName;
+
+    /**
+     * Value of a geographic code.
+     */
+    String value;
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/Polygon.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/Polygon.aidl
new file mode 100644
index 0000000..12bd2cd
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/Polygon.aidl
@@ -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 android.hardware.broadcastradio;
+
+import android.hardware.broadcastradio.Coordinate;
+
+/**
+ * The array of coordinates defining a polygon
+ *
+ * <p>(see ITU-T X.1303 bis for more info).
+ */
+@VintfStability
+@JavaDerive(equals=true, toString=true)
+parcelable Polygon {
+    /**
+     * Cooridinates of points defining a polygon.
+     *
+     * <p>A minimum of 4 coordinates MUST be present and the first and last
+     * coordinates must be the same. See WGS 84 for more information.
+     */
+    Coordinate[] coordinates;
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/ProgramInfo.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramInfo.aidl
index d4ccd01..0b5abe2 100644
--- a/broadcastradio/aidl/android/hardware/broadcastradio/ProgramInfo.aidl
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramInfo.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.broadcastradio;
 
+import android.hardware.broadcastradio.Alert;
 import android.hardware.broadcastradio.Metadata;
 import android.hardware.broadcastradio.ProgramIdentifier;
 import android.hardware.broadcastradio.ProgramSelector;
@@ -192,4 +193,12 @@
      * for example: paid-service=true; bitrate=320kbps.
      */
     VendorKeyValue[] vendorInfo;
+
+    /**
+     * Emergency alert message.
+     *
+     * <p>Alert message can be sent from a radio station of technologies such as HD radio to
+     * the radio users for some emergency events.
+     */
+    @nullable Alert emergencyAlert;
 }
diff --git a/broadcastradio/aidl/default/BroadcastRadio.cpp b/broadcastradio/aidl/default/BroadcastRadio.cpp
index 4d6d81d..015cae0 100644
--- a/broadcastradio/aidl/default/BroadcastRadio.cpp
+++ b/broadcastradio/aidl/default/BroadcastRadio.cpp
@@ -17,11 +17,9 @@
 #include "BroadcastRadio.h"
 #include <broadcastradio-utils-aidl/Utils.h>
 #include <broadcastradio-utils-aidl/UtilsV2.h>
+#include <broadcastradio-utils-aidl/UtilsV3.h>
 #include "resources.h"
 
-#include <aidl/android/hardware/broadcastradio/IdentifierType.h>
-#include <aidl/android/hardware/broadcastradio/Result.h>
-
 #include <android-base/logging.h>
 #include <android-base/strings.h>
 
@@ -47,6 +45,8 @@
 inline constexpr std::chrono::milliseconds kTuneDelayTimeMs = 150ms;
 inline constexpr std::chrono::seconds kListDelayTimeS = 1s;
 
+const string kAlertAreaDelimiter = "+";
+const string kAlertCoordinateGeocodeDelimiter = ",";
 // clang-format off
 const AmFmBandRange kFmFullBandRange = {65000, 108000, 10, 0};
 const AmFmBandRange kAmFullBandRange = {150, 30000, 1, 0};
@@ -142,6 +142,30 @@
     return info;
 }
 
+static Alert createSampleAlert() {
+    Polygon polygon = {{{-38.47, -120.14},
+                        {38.34, -119.95},
+                        {38.52, -119.74},
+                        {38.62, -119.89},
+                        {-38.47, -120.14}}};
+    AlertArea alertArea1 = {{polygon}, {{"SAME", "006109"}, {"SAME", "006209"}}};
+    AlertArea alertArea2 = {{}, {{"SAME", "006009"}}};
+    AlertInfo alertInfo;
+    alertInfo.categoryArray = {AlertCategory::GEO, AlertCategory::TRANSPORT};
+    alertInfo.urgency = AlertUrgency::FUTURE;
+    alertInfo.severity = AlertSeverity::SEVERE;
+    alertInfo.certainty = AlertCertainty::POSSIBLE;
+    alertInfo.description = "Sample radio alert.";
+    alertInfo.language = "en-US";
+    alertInfo.areas.push_back(alertArea1);
+    alertInfo.areas.push_back(alertArea2);
+    Alert alert;
+    alert.status = AlertStatus::ACTUAL;
+    alert.messageType = AlertMessageType::ALERT;
+    alert.infoArray.push_back(alertInfo);
+    return alert;
+}
+
 static bool checkDumpCallerHasWritePermissions(int fd) {
     uid_t uid = AIBinder_getCallingUid();
     if (uid == AID_ROOT || uid == AID_SHELL || uid == AID_SYSTEM) {
@@ -151,6 +175,87 @@
     return false;
 }
 
+static bool parseGeocode(int fd, const string& geocodeString, Geocode& parsedGeocode) {
+    vector<string> geocodeStringPair =
+            ::android::base::Split(geocodeString, kAlertCoordinateGeocodeDelimiter);
+    if (geocodeStringPair.size() != 2) {
+        dprintf(fd, "Geocode is not of \"VALUE_NAME,VALUE\" format: %s\n", geocodeString.c_str());
+        return false;
+    }
+    parsedGeocode.valueName = geocodeStringPair[0];
+    parsedGeocode.value = geocodeStringPair[1];
+    return true;
+}
+
+static bool parsePolygon(int fd, const string& polygonString, Polygon& parsedPolygon) {
+    vector<Coordinate> coordinates;
+    vector<string> coordinateStrings =
+            ::android::base::Split(polygonString, kAlertCoordinateGeocodeDelimiter);
+    if (coordinateStrings.size() % 2) {
+        dprintf(fd, "Incomplete \"LATITUDE,LONGITUDE\" coordinate pairs separated by \",\": %s\n",
+                polygonString.c_str());
+        return false;
+    }
+    for (size_t i = 0; i < coordinateStrings.size(); i += 2) {
+        double latitude;
+        double longitude;
+        if (!utils::parseArgDouble(coordinateStrings[i], &latitude) ||
+            !utils::parseArgDouble(coordinateStrings[i + 1], &longitude)) {
+            dprintf(fd, "Value of \"LATITUDE,LONGITUDE\" coordinate pair is not double-type: %s\n",
+                    coordinateStrings[i].c_str());
+            return false;
+        }
+        coordinates.push_back(Coordinate(latitude, longitude));
+    }
+    parsedPolygon.coordinates = coordinates;
+    return true;
+}
+
+static bool parseAreaString(int fd, const string& areaString, AlertArea& parsedAlertArea) {
+    vector<string> areaEntryStrings = ::android::base::Split(areaString, "_");
+    for (const auto& areaEntryString : areaEntryStrings) {
+        vector<string> areaTypeValuePair = ::android::base::Split(areaEntryString, ":");
+        if (areaTypeValuePair.size() != 2) {
+            dprintf(fd, "Area is not of \"<TYPE>:<VALUE>\" format: %s\n", areaEntryString.c_str());
+            return false;
+        }
+        if (EqualsIgnoreCase(areaTypeValuePair[0], "polygon")) {
+            Polygon parsedPolygon;
+            if (!parsePolygon(fd, areaTypeValuePair[1], parsedPolygon)) {
+                return false;
+            }
+            parsedAlertArea.polygons.push_back(parsedPolygon);
+        } else if (EqualsIgnoreCase(areaTypeValuePair[0], "geocode")) {
+            Geocode parsedGeocode;
+            if (!parseGeocode(fd, areaTypeValuePair[1], parsedGeocode)) {
+                return false;
+            }
+            parsedAlertArea.geocodes.push_back(parsedGeocode);
+        } else {
+            dprintf(fd, "Invalid area <TYPE> other than \"polygon\" and \"geocode\": %s\n",
+                    areaTypeValuePair[0].c_str());
+            return false;
+        }
+    }
+    return true;
+}
+
+static bool parseAreaListString(int fd, const string& areaListString,
+                                vector<AlertArea>& parsedAlertAreas) {
+    if (EqualsIgnoreCase(areaListString, kAlertAreaDelimiter)) {
+        return true;
+    }
+    vector<string> areaStrings = ::android::base::Split(areaListString, kAlertAreaDelimiter);
+    for (const auto& areaString : areaStrings) {
+        AlertArea parsedArea;
+        if (!parseAreaString(fd, areaString, parsedArea)) {
+            return false;
+        }
+        parsedAlertAreas.push_back(parsedArea);
+    }
+    return true;
+}
+
 }  // namespace
 
 BroadcastRadio::BroadcastRadio(const VirtualRadio& virtualRadio)
@@ -162,9 +267,9 @@
         ProgramSelector sel = utils::makeSelectorAmfm(ranges[0].lowerBound);
         VirtualProgram virtualProgram = {};
         if (mVirtualRadio.getProgram(sel, &virtualProgram)) {
-            mCurrentProgram = virtualProgram.selector;
+            mCurrentProgramSelector = virtualProgram.selector;
         } else {
-            mCurrentProgram = sel;
+            mCurrentProgramSelector = sel;
         }
         adjustAmFmRangeLocked();
     }
@@ -230,13 +335,13 @@
             isDigitalProgramAllowed(sel, isConfigFlagSetLocked(ConfigFlag::FORCE_ANALOG_FM),
                                     isConfigFlagSetLocked(ConfigFlag::FORCE_ANALOG_AM));
     if (isProgramAllowed && mVirtualRadio.getProgram(sel, &virtualProgram)) {
-        mCurrentProgram = virtualProgram.selector;
+        mCurrentProgramSelector = virtualProgram.selector;
         programInfo = virtualProgram;
     } else {
         if (!isProgramAllowed) {
-            mCurrentProgram = utils::makeSelectorAmfm(utils::getAmFmFrequency(sel));
+            mCurrentProgramSelector = utils::makeSelectorAmfm(utils::getAmFmFrequency(sel));
         } else {
-            mCurrentProgram = sel;
+            mCurrentProgramSelector = sel;
         }
         programInfo = makeSampleProgramInfo(sel);
     }
@@ -277,6 +382,10 @@
 void BroadcastRadio::handleProgramInfoUpdateRadioCallback(
         ProgramInfo programInfo, const std::shared_ptr<ITunerCallback>& callback) {
     callback->onCurrentProgramInfoChanged(programInfo);
+    {
+        lock_guard<mutex> lk(mMutex);
+        mCurrentProgramInfo = programInfo;
+    }
     if (programInfo.selector.primaryId.type != IdentifierType::HD_STATION_ID_EXT) {
         return;
     }
@@ -285,12 +394,14 @@
     programInfo.infoFlags |= ProgramInfo::FLAG_HD_SIS_ACQUISITION;
     auto sisAcquiredTask = [this, callback, programInfo, cancelTask]() {
         callback->onCurrentProgramInfoChanged(programInfo);
+        mCurrentProgramInfo = programInfo;
         auto audioAcquiredTask = [this, callback, programInfo]() {
             ProgramInfo hdProgramInfoWithAudio = programInfo;
             hdProgramInfoWithAudio.infoFlags |= ProgramInfo::FLAG_HD_AUDIO_ACQUISITION;
             callback->onCurrentProgramInfoChanged(hdProgramInfoWithAudio);
             lock_guard<mutex> lk(mMutex);
             mIsTuneCompleted = true;
+            mCurrentProgramInfo = hdProgramInfoWithAudio;
         };
         lock_guard<mutex> lk(mMutex);
         mTuningThread->schedule(audioAcquiredTask, cancelTask, kTuneDelayTimeMs);
@@ -481,7 +592,8 @@
     auto cancelTask = [callback]() { callback->onTuneFailed(Result::CANCELED, {}); };
 
     VirtualProgram nextProgram = {};
-    bool foundNext = findNextLocked(mCurrentProgram, directionUp, skipSubChannel, &nextProgram);
+    bool foundNext =
+            findNextLocked(mCurrentProgramSelector, directionUp, skipSubChannel, &nextProgram);
     mIsTuneCompleted = false;
     if (!foundNext) {
         auto task = [callback]() {
@@ -520,10 +632,10 @@
     cancelLocked();
 
     int64_t stepTo;
-    if (utils::hasId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY_KHZ)) {
-        stepTo = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY_KHZ);
-    } else if (mCurrentProgram.primaryId.type == IdentifierType::HD_STATION_ID_EXT) {
-        stepTo = utils::getHdFrequency(mCurrentProgram);
+    if (utils::hasId(mCurrentProgramSelector, IdentifierType::AMFM_FREQUENCY_KHZ)) {
+        stepTo = utils::getId(mCurrentProgramSelector, IdentifierType::AMFM_FREQUENCY_KHZ);
+    } else if (mCurrentProgramSelector.primaryId.type == IdentifierType::HD_STATION_ID_EXT) {
+        stepTo = utils::getHdFrequency(mCurrentProgramSelector);
     } else {
         LOG(WARNING) << __func__ << ": can't step in anything else than AM/FM";
         return ScopedAStatus::fromServiceSpecificErrorWithMessage(
@@ -568,7 +680,7 @@
     LOG(DEBUG) << __func__ << ": cancelling current tuning operations...";
 
     mTuningThread->cancelAll();
-    if (mCurrentProgram.primaryId.type != IdentifierType::INVALID) {
+    if (mCurrentProgramSelector.primaryId.type != IdentifierType::INVALID) {
         mIsTuneCompleted = true;
     }
 }
@@ -692,13 +804,13 @@
 
 bool BroadcastRadio::adjustAmFmRangeLocked() {
     bool hasBandBefore = mCurrentAmFmBandRange.has_value();
-    if (!utils::hasAmFmFrequency(mCurrentProgram)) {
+    if (!utils::hasAmFmFrequency(mCurrentProgramSelector)) {
         LOG(WARNING) << __func__ << ": current program does not has AMFM_FREQUENCY_KHZ identifier";
         mCurrentAmFmBandRange.reset();
         return hasBandBefore;
     }
 
-    int32_t freq = static_cast<int32_t>(utils::getAmFmFrequency(mCurrentProgram));
+    int32_t freq = static_cast<int32_t>(utils::getAmFmFrequency(mCurrentProgramSelector));
     for (const auto& range : mAmFmConfig.ranges) {
         if (range.lowerBound <= freq && range.upperBound >= freq) {
             bool isBandChanged = hasBandBefore ? *mCurrentAmFmBandRange != range : true;
@@ -711,6 +823,24 @@
     return !hasBandBefore;
 }
 
+void BroadcastRadio::updateCurrentProgramInfoWithAlert(std::optional<Alert>& alert) {
+    std::shared_ptr<ITunerCallback> callback;
+    ProgramInfo currentProgramInfo;
+    {
+        lock_guard<mutex> lk(mMutex);
+        if (mCallback == nullptr) {
+            return;
+        }
+        if (mCurrentProgramInfo.selector.primaryId.type == IdentifierType::INVALID) {
+            return;
+        }
+        callback = mCallback;
+        currentProgramInfo = mCurrentProgramInfo;
+    }
+    currentProgramInfo.emergencyAlert = alert.value();
+    callback->onCurrentProgramInfoChanged(currentProgramInfo);
+}
+
 ScopedAStatus BroadcastRadio::registerAnnouncementListener(
         [[maybe_unused]] const std::shared_ptr<IAnnouncementListener>& listener,
         const vector<AnnouncementType>& enabled, std::shared_ptr<ICloseHandle>* returnCloseHandle) {
@@ -745,6 +875,8 @@
         return cmdStartProgramListUpdates(fd, args, numArgs);
     } else if (EqualsIgnoreCase(option, "--stopProgramListUpdates")) {
         return cmdStopProgramListUpdates(fd, numArgs);
+    } else if (EqualsIgnoreCase(option, "--simulateAlert")) {
+        return cmdSimulateAlert(fd, args, numArgs);
     }
     dprintf(fd, "Invalid option: %s\n", option.c_str());
     return STATUS_BAD_VALUE;
@@ -767,7 +899,7 @@
     } else {
         dprintf(fd, "ITunerCallback registered\n");
     }
-    dprintf(fd, "CurrentProgram: %s \n", mCurrentProgram.toString().c_str());
+    dprintf(fd, "CurrentProgram: %s \n", mCurrentProgramSelector.toString().c_str());
     return STATUS_OK;
 }
 
@@ -798,13 +930,41 @@
             "excludeModifications (string, should be either \"true\" or \"false\")\n");
     dprintf(fd, "--stopProgramListUpdates: stop current pending program list updates\n");
     dprintf(fd,
-            "Note on <TYPE> for --startProgramList command: it is int for identifier type. "
+            "\t<TYPE>: it is int for identifier type. "
             "Please see broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl "
             "for its definition.\n");
     dprintf(fd,
-            "Note on <VALUE> for --startProgramList command: it is long type for identifier value. "
+            "\t<VALUE>: it is long type for identifier value. "
             "Please see broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl "
             "for its value.\n");
+    dprintf(fd,
+            "--simulateAlert <STATUS> <MESSAGE_TYPE> <CATEGORIES> <URGENCY> <SEVERITY> "
+            "<CERTAINTY> <DESCRIPTION> <LANGUAGE> <AREAS>: simulate emergency alert on current "
+            "program; if no arguments following \"--simulateAlert\", the default alert message"
+            "is applied.\n");
+    dprintf(fd, "\t<STATUS>: string representation of alert scope.\n");
+    dprintf(fd, "\t<MESSAGE_TYPE>: string representation of alert message type.\n");
+    dprintf(fd,
+            "\t<CATEGORIES>: string representation of alert categories separated by "
+            "\",\".\n");
+    dprintf(fd, "\t<URGENCY>: string representation of alert urgency type.\n");
+    dprintf(fd, "\t<SEVERITY>: string representation of alert severity type.\n");
+    dprintf(fd, "\t<CERTAINTY>: string representation of alert certainty type.\n");
+    dprintf(fd, "\t<DESCRIPTION>: description of alert message within quotation mark(\"\").\n");
+    dprintf(fd, "\t<LANGUAGE>: language code of alert message, \"null\" if unspecified.\n");
+    dprintf(fd,
+            "\t<AREAS>: <TYPE>:<VALUE>_<TYPE>:<VALUE>_...+<TYPE>:<VALUE>_<TYPE>:<VALUE>_... "
+            "which represents list of affected areas of the alert separated by \"|\". "
+            "If no area, this field should be: |\n"
+            "Each area may contains multiple entries separated by \";\" where "
+            "<TYPE> can be either \"polygon\" or \"geocode\". If <TYPE> is polygon, <VALUE> is a "
+            "series of coordinates of \"LATITUDE,LONGITUDE\" format separated by \",\"; if "
+            "<TYPE> is geocode, <VALUE> is of \"VALUE_NAME,VALUE\" format.\n");
+    dprintf(fd,
+            "Example: --simulateAlert actual alert geo,transport future severe"
+            " possible \"alert message for testing\" en-US geocode:SAME,006109_geocode:SAME,006209"
+            "_polygon:-38.47,-120.14,38.34,-119.95,38.52,-119.74,38.62,-119.89,-38.47,-120.14"
+            "+geocode:SAME,006009\n");
 
     return STATUS_OK;
 }
@@ -1038,4 +1198,71 @@
     return STATUS_OK;
 }
 
+binder_status_t BroadcastRadio::cmdSimulateAlert(int fd, const char** args, uint32_t numArgs) {
+    if (!checkDumpCallerHasWritePermissions(fd)) {
+        return STATUS_PERMISSION_DENIED;
+    }
+    std::optional<Alert> alertOpt;
+    if (numArgs == 1) {
+        alertOpt.emplace(createSampleAlert());
+        updateCurrentProgramInfoWithAlert(alertOpt);
+        return STATUS_OK;
+    }
+    if (numArgs != 10) {
+        dprintf(fd,
+                "Invalid number of arguments: please provide --simulateAlert "
+                "<STATUS> <MESSAGE_TYPE> <CATEGORIES> <URGENCY> "
+                "<SEVERITY> <CERTAINTY> <DESCRIPTION> <LANGUAGE> <AREAS>, provided: %d\n",
+                numArgs);
+        return STATUS_BAD_VALUE;
+    }
+    Alert parsedAlert;
+    if (!utils::parseAlertStatus(args[1], parsedAlert.status)) {
+        dprintf(fd, "Unknown alert status type: %s\n", args[2]);
+        return STATUS_BAD_VALUE;
+    }
+    if (!utils::parseAlertMessageType(args[2], parsedAlert.messageType)) {
+        dprintf(fd, "Unknown alert message type: %s\n", args[3]);
+        return STATUS_BAD_VALUE;
+    }
+    AlertInfo parsedAlertInfo;
+    vector<string> categoryStrings = ::android::base::Split(args[3], ",");
+    for (const auto& categoryString : categoryStrings) {
+        AlertCategory category;
+        if (!utils::parseAlertCategory(categoryString, category)) {
+            dprintf(fd, "Unknown alert category type: %s\n", args[3]);
+            return STATUS_BAD_VALUE;
+        }
+        parsedAlertInfo.categoryArray.push_back(category);
+    }
+    if (!utils::parseAlertUrgency(args[4], parsedAlertInfo.urgency)) {
+        dprintf(fd, "Unknown alert urgency type: %s\n", args[4]);
+        return STATUS_BAD_VALUE;
+    }
+    if (!utils::parseAlertSeverity(args[5], parsedAlertInfo.severity)) {
+        dprintf(fd, "Unknown alert severity type: %s\n", args[5]);
+        return STATUS_BAD_VALUE;
+    }
+    if (!utils::parseAlertCertainty(args[6], parsedAlertInfo.certainty)) {
+        dprintf(fd, "Unknown alert certainty type: %s\n", args[6]);
+        return STATUS_BAD_VALUE;
+    }
+    parsedAlertInfo.description = string(args[7]);
+    string languageStr = string(args[8]);
+    if (!EqualsIgnoreCase(languageStr, "null")) {
+        parsedAlertInfo.language.emplace(languageStr);
+    }
+    string areaListString = string(args[9]);
+    vector<AlertArea> areaList;
+    if (!parseAreaListString(fd, areaListString, areaList)) {
+        return STATUS_BAD_VALUE;
+    }
+    parsedAlertInfo.areas = areaList;
+    parsedAlert.infoArray = {parsedAlertInfo};
+    LOG(INFO) << "Simulate alert: " << parsedAlert.toString().c_str();
+    alertOpt.emplace(parsedAlert);
+    updateCurrentProgramInfoWithAlert(alertOpt);
+    return STATUS_OK;
+}
+
 }  // namespace aidl::android::hardware::broadcastradio
diff --git a/broadcastradio/aidl/default/BroadcastRadio.h b/broadcastradio/aidl/default/BroadcastRadio.h
index 60ea907..a4cba3b 100644
--- a/broadcastradio/aidl/default/BroadcastRadio.h
+++ b/broadcastradio/aidl/default/BroadcastRadio.h
@@ -78,7 +78,8 @@
             std::unique_ptr<::android::WorkerThread>(new ::android::WorkerThread());
     bool mIsTuneCompleted GUARDED_BY(mMutex) = true;
     Properties mProperties GUARDED_BY(mMutex);
-    ProgramSelector mCurrentProgram GUARDED_BY(mMutex) = {};
+    ProgramSelector mCurrentProgramSelector GUARDED_BY(mMutex) = {};
+    ProgramInfo mCurrentProgramInfo GUARDED_BY(mMutex) = {};
     std::vector<VirtualProgram> mProgramList GUARDED_BY(mMutex) = {};
     std::optional<AmFmBandRange> mCurrentAmFmBandRange GUARDED_BY(mMutex);
     std::shared_ptr<ITunerCallback> mCallback GUARDED_BY(mMutex);
@@ -99,6 +100,7 @@
     void jumpToFirstSubChannelLocked(std::vector<VirtualProgram>::const_iterator& it) const
             REQUIRES(mMutex);
     bool isConfigFlagSetLocked(ConfigFlag flag) const REQUIRES(mMutex);
+    void updateCurrentProgramInfoWithAlert(std::optional<Alert>& alert);
 
     binder_status_t cmdHelp(int fd) const;
     binder_status_t cmdTune(int fd, const char** args, uint32_t numArgs);
@@ -107,6 +109,7 @@
     binder_status_t cmdCancel(int fd, uint32_t numArgs);
     binder_status_t cmdStartProgramListUpdates(int fd, const char** args, uint32_t numArgs);
     binder_status_t cmdStopProgramListUpdates(int fd, uint32_t numArgs);
+    binder_status_t cmdSimulateAlert(int fd, const char** args, uint32_t numArgs);
 
     binder_status_t dumpsys(int fd) EXCLUDES(mMutex);
 };
diff --git a/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp b/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp
index ee0c639..7e9e458 100644
--- a/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp
+++ b/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp
@@ -16,6 +16,7 @@
 
 #define EGMOCK_VERBOSE 1
 
+#include <aidl/android/hardware/broadcastradio/Alert.h>
 #include <aidl/android/hardware/broadcastradio/BnAnnouncementListener.h>
 #include <aidl/android/hardware/broadcastradio/BnTunerCallback.h>
 #include <aidl/android/hardware/broadcastradio/ConfigFlag.h>
@@ -76,12 +77,13 @@
 
 constexpr int32_t kAidlVersion1 = 1;
 constexpr int32_t kAidlVersion2 = 2;
+constexpr int32_t kAidlVersion3 = 3;
 
 bool isValidAmFmFreq(int64_t freq, int aidlVersion) {
     ProgramIdentifier id = bcutils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, freq);
     if (aidlVersion == kAidlVersion1) {
         return bcutils::isValid(id);
-    } else if (aidlVersion == kAidlVersion2) {
+    } else if (aidlVersion >= kAidlVersion2) {
         return bcutils::isValidV2(id);
     }
     LOG(ERROR) << "Unknown AIDL version " << aidlVersion;
@@ -105,6 +107,41 @@
     return false;
 }
 
+void validateMetadata(const ProgramInfo& info, int32_t aidlVersion) {
+    for (const auto& metadataItem : info.metadata) {
+        bool validMetadata = false;
+        if (aidlVersion == kAidlVersion1) {
+            validMetadata = bcutils::isValidMetadata(metadataItem);
+        } else {
+            validMetadata = bcutils::isValidMetadataV2(metadataItem);
+        }
+        EXPECT_TRUE(validMetadata) << "Invalid metadata " << metadataItem.toString().c_str();
+    }
+}
+
+void validateAlert(const ProgramInfo& info, int32_t aidlVersion) {
+    if (aidlVersion < kAidlVersion3 || !info.emergencyAlert.has_value()) {
+        return;
+    }
+    Alert alert = info.emergencyAlert.value();
+    ASSERT_FALSE(alert.infoArray.empty());
+    for (const auto& alertInfo : alert.infoArray) {
+        ASSERT_FALSE(alertInfo.categoryArray.empty());
+        if (alertInfo.areas.empty()) {
+            continue;
+        }
+        for (const auto& area : alertInfo.areas) {
+            if (area.polygons.empty()) {
+                continue;
+            }
+            for (const auto& polygon : area.polygons) {
+                ASSERT_GE(polygon.coordinates.size(), 4);
+                EXPECT_EQ(polygon.coordinates.front(), polygon.coordinates.back());
+            }
+        }
+    }
+}
+
 }  // namespace
 
 class CallbackFlag final {
@@ -250,15 +287,9 @@
         }
     }
 
-    for (const auto& metadataItem : info.metadata) {
-        bool validMetadata = false;
-        if (mCallbackAidlVersion == kAidlVersion1) {
-            validMetadata = bcutils::isValidMetadata(metadataItem);
-        } else {
-            validMetadata = bcutils::isValidMetadataV2(metadataItem);
-        }
-        EXPECT_TRUE(validMetadata) << "Invalid metadata " << metadataItem.toString().c_str();
-    }
+    validateMetadata(info, mCallbackAidlVersion);
+
+    validateAlert(info, mCallbackAidlVersion);
 
     {
         std::lock_guard<std::mutex> lk(mLock);
@@ -349,7 +380,7 @@
     // get AIDL HAL version
     ASSERT_TRUE(mModule->getInterfaceVersion(&mAidlVersion).isOk());
     EXPECT_GE(mAidlVersion, kAidlVersion1);
-    EXPECT_LE(mAidlVersion, kAidlVersion2);
+    EXPECT_LE(mAidlVersion, kAidlVersion3);
 
     // set callback
     mCallback = SharedRefBase::make<TunerCallbackImpl>(mAidlVersion);
@@ -1122,12 +1153,22 @@
  * Verifies that:
  * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
  * - the complete list is fetched within kProgramListScanTimeoutMs;
- * - stopProgramListUpdates does not crash.
+ * - stopProgramListUpdates does not crash;
+ * - metadata of program info in the program list is valid;
+ * - alert message is valid if it exists in the program list.
  */
 TEST_P(BroadcastRadioHalTest, GetProgramListFromEmptyFilter) {
     LOG(DEBUG) << "GetProgramListFromEmptyFilter Test";
 
-    getProgramList();
+    std::optional<bcutils::ProgramInfoSet> completeList = getProgramList();
+
+    if (!completeList || mAidlVersion < kAidlVersion3) {
+        return;
+    }
+    for (const auto& program : *completeList) {
+        validateMetadata(program, mAidlVersion);
+        validateAlert(program, mAidlVersion);
+    }
 }
 
 /**
diff --git a/broadcastradio/common/utilsaidl/Android.bp b/broadcastradio/common/utilsaidl/Android.bp
index d88081f..2245492 100644
--- a/broadcastradio/common/utilsaidl/Android.bp
+++ b/broadcastradio/common/utilsaidl/Android.bp
@@ -24,7 +24,7 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
-cc_library_static {
+cc_library {
     name: "android.hardware.broadcastradio@common-utils-aidl-lib",
     defaults: [
         "BroadcastRadioUtilsDefaults",
@@ -34,7 +34,7 @@
     ],
 }
 
-cc_library_static {
+cc_library {
     name: "android.hardware.broadcastradio@common-utils-aidl-lib-V2",
     defaults: [
         "BroadcastRadioUtilsDefaults",
@@ -47,7 +47,21 @@
     ],
 }
 
-cc_library_static {
+cc_library {
+    name: "android.hardware.broadcastradio@common-utils-aidl-lib-V3",
+    defaults: [
+        "BroadcastRadioUtilsDefaults",
+    ],
+    srcs: [
+        "src/UtilsV2.cpp",
+        "src/UtilsV3.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.broadcastradio-V3-ndk",
+    ],
+}
+
+cc_library {
     name: "android.hardware.broadcastradio@common-utils-aidl-lib-latest",
     defaults: [
         "BroadcastRadioUtilsDefaults",
@@ -55,6 +69,7 @@
     ],
     srcs: [
         "src/UtilsV2.cpp",
+        "src/UtilsV3.cpp",
     ],
 }
 
diff --git a/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h b/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h
index a34ee10..f5b71b2 100644
--- a/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h
+++ b/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h
@@ -197,6 +197,8 @@
 
 bool parseArgLong(const std::string& s, long* out);
 
+bool parseArgDouble(const std::string& s, double* out);
+
 bool parseArgBool(const std::string& s, bool* out);
 
 bool parseArgDirection(const std::string& s, bool* out);
diff --git a/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/UtilsV3.h b/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/UtilsV3.h
new file mode 100644
index 0000000..250e217
--- /dev/null
+++ b/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/UtilsV3.h
@@ -0,0 +1,37 @@
+/*
+ * 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/broadcastradio/ProgramInfo.h>
+
+namespace aidl::android::hardware::broadcastradio {
+
+namespace utils {
+
+bool parseAlertStatus(const std::string& s, AlertStatus& out);
+
+bool parseAlertMessageType(const std::string& s, AlertMessageType& out);
+
+bool parseAlertCategory(const std::string& s, AlertCategory& out);
+
+bool parseAlertUrgency(const std::string& s, AlertUrgency& out);
+
+bool parseAlertSeverity(const std::string& s, AlertSeverity& out);
+
+bool parseAlertCertainty(const std::string& s, AlertCertainty& out);
+}  // namespace utils
+}  // namespace aidl::android::hardware::broadcastradio
\ No newline at end of file
diff --git a/broadcastradio/common/utilsaidl/src/Utils.cpp b/broadcastradio/common/utilsaidl/src/Utils.cpp
index 3de1866..bfa93a5 100644
--- a/broadcastradio/common/utilsaidl/src/Utils.cpp
+++ b/broadcastradio/common/utilsaidl/src/Utils.cpp
@@ -19,6 +19,7 @@
 #include "broadcastradio-utils-aidl/Utils.h"
 
 #include <android-base/logging.h>
+#include <android-base/parsedouble.h>
 #include <android-base/parseint.h>
 #include <android-base/strings.h>
 
@@ -631,6 +632,10 @@
     return ::android::base::ParseInt(s, out);
 }
 
+bool parseArgDouble(const std::string& s, double* out) {
+    return ::android::base::ParseDouble(s, out);
+}
+
 bool parseArgBool(const std::string& s, bool* out) {
     if (EqualsIgnoreCase(s, "true")) {
         *out = true;
diff --git a/broadcastradio/common/utilsaidl/src/UtilsV3.cpp b/broadcastradio/common/utilsaidl/src/UtilsV3.cpp
new file mode 100644
index 0000000..bf694da
--- /dev/null
+++ b/broadcastradio/common/utilsaidl/src/UtilsV3.cpp
@@ -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.
+ */
+
+#define LOG_TAG "BcRadioAidlDef.utilsV3"
+
+#include "broadcastradio-utils-aidl/Utils.h"
+
+#include <android-base/strings.h>
+
+namespace aidl::android::hardware::broadcastradio {
+
+namespace utils {
+
+namespace {
+
+using ::android::base::EqualsIgnoreCase;
+using ::std::vector;
+}  // namespace
+
+bool parseAlertStatus(const std::string& s, AlertStatus& out) {
+    if (EqualsIgnoreCase(s, toString(AlertStatus::ACTUAL))) {
+        out = AlertStatus::ACTUAL;
+    } else if (EqualsIgnoreCase(s, toString(AlertStatus::EXERCISE))) {
+        out = AlertStatus::EXERCISE;
+    } else if (EqualsIgnoreCase(s, toString(AlertStatus::TEST))) {
+        out = AlertStatus::TEST;
+    } else {
+        return false;
+    }
+    return true;
+}
+
+bool parseAlertMessageType(const std::string& s, AlertMessageType& out) {
+    if (EqualsIgnoreCase(s, toString(AlertMessageType::ALERT))) {
+        out = AlertMessageType::ALERT;
+    } else if (EqualsIgnoreCase(s, toString(AlertMessageType::UPDATE))) {
+        out = AlertMessageType::UPDATE;
+    } else if (EqualsIgnoreCase(s, toString(AlertMessageType::CANCEL))) {
+        out = AlertMessageType::CANCEL;
+    } else {
+        return false;
+    }
+    return true;
+}
+
+bool parseAlertCategory(const std::string& s, AlertCategory& out) {
+    if (EqualsIgnoreCase(s, toString(AlertCategory::GEO))) {
+        out = AlertCategory::GEO;
+    } else if (EqualsIgnoreCase(s, toString(AlertCategory::MET))) {
+        out = AlertCategory::MET;
+    } else if (EqualsIgnoreCase(s, toString(AlertCategory::SAFETY))) {
+        out = AlertCategory::SAFETY;
+    } else if (EqualsIgnoreCase(s, toString(AlertCategory::SECURITY))) {
+        out = AlertCategory::SECURITY;
+    } else if (EqualsIgnoreCase(s, toString(AlertCategory::RESCUE))) {
+        out = AlertCategory::RESCUE;
+    } else if (EqualsIgnoreCase(s, toString(AlertCategory::FIRE))) {
+        out = AlertCategory::FIRE;
+    } else if (EqualsIgnoreCase(s, toString(AlertCategory::HEALTH))) {
+        out = AlertCategory::HEALTH;
+    } else if (EqualsIgnoreCase(s, toString(AlertCategory::ENV))) {
+        out = AlertCategory::ENV;
+    } else if (EqualsIgnoreCase(s, toString(AlertCategory::TRANSPORT))) {
+        out = AlertCategory::TRANSPORT;
+    } else if (EqualsIgnoreCase(s, toString(AlertCategory::INFRA))) {
+        out = AlertCategory::INFRA;
+    } else if (EqualsIgnoreCase(s, toString(AlertCategory::CBRNE))) {
+        out = AlertCategory::CBRNE;
+    } else if (EqualsIgnoreCase(s, toString(AlertCategory::OTHER))) {
+        out = AlertCategory::OTHER;
+    } else {
+        return false;
+    }
+    return true;
+}
+
+bool parseAlertUrgency(const std::string& s, AlertUrgency& out) {
+    if (EqualsIgnoreCase(s, toString(AlertUrgency::IMMEDIATE))) {
+        out = AlertUrgency::IMMEDIATE;
+    } else if (EqualsIgnoreCase(s, toString(AlertUrgency::EXPECTED))) {
+        out = AlertUrgency::EXPECTED;
+    } else if (EqualsIgnoreCase(s, toString(AlertUrgency::FUTURE))) {
+        out = AlertUrgency::FUTURE;
+    } else if (EqualsIgnoreCase(s, toString(AlertUrgency::PAST))) {
+        out = AlertUrgency::PAST;
+    } else if (EqualsIgnoreCase(s, toString(AlertUrgency::UNKNOWN))) {
+        out = AlertUrgency::UNKNOWN;
+    } else {
+        return false;
+    }
+    return true;
+}
+
+bool parseAlertSeverity(const std::string& s, AlertSeverity& out) {
+    if (EqualsIgnoreCase(s, toString(AlertSeverity::EXTREME))) {
+        out = AlertSeverity::EXTREME;
+    } else if (EqualsIgnoreCase(s, toString(AlertSeverity::SEVERE))) {
+        out = AlertSeverity::SEVERE;
+    } else if (EqualsIgnoreCase(s, toString(AlertSeverity::MODERATE))) {
+        out = AlertSeverity::MODERATE;
+    } else if (EqualsIgnoreCase(s, toString(AlertSeverity::MINOR))) {
+        out = AlertSeverity::MINOR;
+    } else if (EqualsIgnoreCase(s, toString(AlertSeverity::UNKNOWN))) {
+        out = AlertSeverity::UNKNOWN;
+    } else {
+        return false;
+    }
+    return true;
+}
+
+bool parseAlertCertainty(const std::string& s, AlertCertainty& out) {
+    if (EqualsIgnoreCase(s, toString(AlertCertainty::OBSERVED))) {
+        out = AlertCertainty::OBSERVED;
+    } else if (EqualsIgnoreCase(s, toString(AlertCertainty::LIKELY))) {
+        out = AlertCertainty::LIKELY;
+    } else if (EqualsIgnoreCase(s, toString(AlertCertainty::POSSIBLE))) {
+        out = AlertCertainty::POSSIBLE;
+    } else if (EqualsIgnoreCase(s, toString(AlertCertainty::UNLIKELY))) {
+        out = AlertCertainty::UNLIKELY;
+    } else if (EqualsIgnoreCase(s, toString(AlertCertainty::UNKNOWN))) {
+        out = AlertCertainty::UNKNOWN;
+    } else {
+        return false;
+    }
+    return true;
+}
+
+}  // namespace utils
+}  // namespace aidl::android::hardware::broadcastradio
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 78aefac..48ae34e 100644
--- a/camera/device/aidl/Android.bp
+++ b/camera/device/aidl/Android.bp
@@ -10,16 +10,19 @@
 
 aidl_interface {
     name: "android.hardware.camera.device",
+    host_supported: true,
     vendor_available: true,
     srcs: ["android/hardware/camera/device/*.aidl"],
     frozen: true,
     stability: "vintf",
+    defaults: [
+        "android.hardware.graphics.common-latest",
+    ],
     imports: [
         "android.hardware.common-V2",
         "android.hardware.common.fmq-V1",
         "android.hardware.camera.common-V1",
         "android.hardware.camera.metadata-V3",
-        "android.hardware.graphics.common-V5",
     ],
     backend: {
         cpp: {
@@ -29,6 +32,9 @@
             sdk_version: "module_current",
             enabled: false,
         },
+        rust: {
+            enabled: true,
+        },
     },
     versions_with_info: [
         {
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..d7303fc 100644
--- a/camera/metadata/aidl/Android.bp
+++ b/camera/metadata/aidl/Android.bp
@@ -10,9 +10,10 @@
 
 aidl_interface {
     name: "android.hardware.camera.metadata",
+    host_supported: true,
     vendor_available: true,
     srcs: ["android/hardware/camera/metadata/*.aidl"],
-    frozen: true,
+    frozen: false,
     stability: "vintf",
     backend: {
         cpp: {
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
index 9321ec0..8387c81 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
@@ -43,6 +43,10 @@
   ANDROID_COLOR_CORRECTION_GAINS,
   ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
   ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
+  ANDROID_COLOR_CORRECTION_COLOR_TEMPERATURE,
+  ANDROID_COLOR_CORRECTION_COLOR_TINT,
+  ANDROID_COLOR_CORRECTION_COLOR_TEMPERATURE_RANGE,
+  ANDROID_COLOR_CORRECTION_AVAILABLE_MODES,
   ANDROID_CONTROL_AE_ANTIBANDING_MODE = android.hardware.camera.metadata.CameraMetadataSectionStart.ANDROID_CONTROL_START /* 65536 */,
   ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
   ANDROID_CONTROL_AE_LOCK,
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ColorCorrectionMode.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ColorCorrectionMode.aidl
index 2381605..69f0f5f 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ColorCorrectionMode.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ColorCorrectionMode.aidl
@@ -41,4 +41,5 @@
   ANDROID_COLOR_CORRECTION_MODE_TRANSFORM_MATRIX,
   ANDROID_COLOR_CORRECTION_MODE_FAST,
   ANDROID_COLOR_CORRECTION_MODE_HIGH_QUALITY,
+  ANDROID_COLOR_CORRECTION_MODE_CCT,
 }
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
index 236bcaf..98897a2 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
@@ -70,6 +70,38 @@
      */
     ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
     /**
+     * android.colorCorrection.colorTemperature [dynamic, int32, public]
+     *
+     * <p>Specifies the color temperature for CCT mode in Kelvin
+     * to adjust the white balance of the image.</p>
+     */
+    ANDROID_COLOR_CORRECTION_COLOR_TEMPERATURE,
+    /**
+     * android.colorCorrection.colorTint [dynamic, int32, public]
+     *
+     * <p>Specifies the color tint for CCT mode to adjust the white
+     * balance of the image.</p>
+     */
+    ANDROID_COLOR_CORRECTION_COLOR_TINT,
+    /**
+     * android.colorCorrection.colorTemperatureRange [static, int32[], public]
+     *
+     * <p>The range of supported color temperature values for
+     * ANDROID_COLOR_CORRECTION_COLOR_TEMPERATURE.</p>
+     *
+     * @see ANDROID_COLOR_CORRECTION_COLOR_TEMPERATURE
+     */
+    ANDROID_COLOR_CORRECTION_COLOR_TEMPERATURE_RANGE,
+    /**
+     * android.colorCorrection.availableModes [static, byte[], public]
+     *
+     * <p>List of color correction modes for ANDROID_COLOR_CORRECTION_MODE that are
+     * supported by this camera device.</p>
+     *
+     * @see ANDROID_COLOR_CORRECTION_MODE
+     */
+    ANDROID_COLOR_CORRECTION_AVAILABLE_MODES,
+    /**
      * android.control.aeAntibandingMode [dynamic, enum, public]
      *
      * <p>The desired setting for the camera device's auto-exposure
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/ColorCorrectionMode.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/ColorCorrectionMode.aidl
index 2a51bfc..f12b6f6 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/ColorCorrectionMode.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/ColorCorrectionMode.aidl
@@ -33,4 +33,5 @@
     ANDROID_COLOR_CORRECTION_MODE_TRANSFORM_MATRIX,
     ANDROID_COLOR_CORRECTION_MODE_FAST,
     ANDROID_COLOR_CORRECTION_MODE_HIGH_QUALITY,
+    ANDROID_COLOR_CORRECTION_MODE_CCT,
 }
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..44af306 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());
 
@@ -2596,8 +2590,7 @@
         return ret;
     }
 
-    if (flags::session_hal_buf_manager() &&
-        (bufferManagerType == BufferManagerType::SESSION && interfaceVersion >= 3)) {
+    if (bufferManagerType == BufferManagerType::SESSION && interfaceVersion >= 3) {
         ret = session->configureStreamsV2(config, &aidl_return);
     } else {
         ret = session->configureStreams(config, halStreams);
@@ -2605,12 +2598,11 @@
     if (!ret.isOk()) {
         return ret;
     }
-    if (flags::session_hal_buf_manager() && bufferManagerType == BufferManagerType::SESSION) {
+    if (bufferManagerType == BufferManagerType::SESSION) {
         *halStreams = std::move(aidl_return.halStreams);
     }
     for (const auto& halStream : *halStreams) {
-        if ((flags::session_hal_buf_manager() && bufferManagerType == BufferManagerType::SESSION &&
-             halStream.enableHalBufferManager) ||
+        if ((bufferManagerType == BufferManagerType::SESSION && halStream.enableHalBufferManager) ||
             bufferManagerType == BufferManagerType::HAL) {
             halBufManagedStreamIds->insert(halStream.id);
         }
diff --git a/compatibility_matrices/compatibility_matrix.202504.xml b/compatibility_matrices/compatibility_matrix.202504.xml
index ced86a0..9f6e283 100644
--- a/compatibility_matrices/compatibility_matrix.202504.xml
+++ b/compatibility_matrices/compatibility_matrix.202504.xml
@@ -163,7 +163,7 @@
     </hal>
     <hal format="aidl">
         <name>android.hardware.broadcastradio</name>
-        <version>1-2</version>
+        <version>1-3</version>
         <interface>
             <name>IBroadcastRadio</name>
             <regex-instance>.*</regex-instance>
@@ -194,7 +194,7 @@
     </hal>
     <hal format="aidl">
         <name>android.hardware.contexthub</name>
-        <version>3</version>
+        <version>3-4</version>
         <interface>
             <name>IContextHub</name>
             <instance>default</instance>
@@ -241,7 +241,7 @@
     </hal>
     <hal format="aidl">
         <name>android.hardware.graphics.composer3</name>
-        <version>3</version>
+        <version>4</version>
         <interface>
             <name>IComposer</name>
             <instance>default</instance>
@@ -313,7 +313,7 @@
     </hal>
     <hal format="aidl" updatable-via-apex="true">
         <name>android.hardware.security.keymint</name>
-        <version>1-3</version>
+        <version>1-4</version>
         <interface>
             <name>IKeyMintDevice</name>
             <instance>default</instance>
@@ -372,7 +372,7 @@
     </hal>
     <hal format="aidl">
         <name>android.hardware.power</name>
-        <version>5</version>
+        <version>5-6</version>
         <interface>
             <name>IPower</name>
             <instance>default</instance>
@@ -551,7 +551,7 @@
     </hal>
     <hal format="aidl">
         <name>android.hardware.thermal</name>
-        <version>2</version>
+        <version>3</version>
         <interface>
             <name>IThermal</name>
             <instance>default</instance>
@@ -591,7 +591,7 @@
     </hal>
     <hal format="aidl">
         <name>android.hardware.tv.tuner</name>
-        <version>1-2</version>
+        <version>1-3</version>
         <interface>
             <name>ITuner</name>
             <instance>default</instance>
@@ -622,7 +622,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,7 +630,7 @@
     </hal>
     <hal format="aidl">
         <name>android.hardware.vibrator</name>
-        <version>1-2</version>
+        <version>1-3</version>
         <interface>
             <name>IVibratorManager</name>
             <instance>default</instance>
@@ -646,7 +646,7 @@
     </hal>
     <hal format="aidl" updatable-via-apex="true">
         <name>android.hardware.wifi</name>
-        <version>1-2</version>
+        <version>2-3</version>
         <interface>
             <name>IWifi</name>
             <instance>default</instance>
@@ -662,7 +662,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,12 +670,20 @@
     </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>
         </interface>
     </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.tv.mediaquality</name>
+        <version>1</version>
+        <interface>
+            <name>IMediaQuality</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
     <!-- The native mapper HAL must exist on the device -->
     <hal format="native">
         <name>mapper</name>
diff --git a/compatibility_matrices/exclude/fcm_exclude.cpp b/compatibility_matrices/exclude/fcm_exclude.cpp
index b86f399..e7a31e6 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.",
diff --git a/confirmationui/aidl/Android.bp b/confirmationui/aidl/Android.bp
index 51bde0a..1f17866 100644
--- a/confirmationui/aidl/Android.bp
+++ b/confirmationui/aidl/Android.bp
@@ -19,8 +19,8 @@
 aidl_interface {
     name: "android.hardware.confirmationui",
     vendor_available: true,
-    imports: [
-        "android.hardware.security.keymint-V3",
+    defaults: [
+        "android.hardware.security.keymint-latest-defaults",
     ],
     srcs: ["android/hardware/confirmationui/*.aidl"],
     stability: "vintf",
@@ -38,7 +38,7 @@
     versions_with_info: [
         {
             version: "1",
-            imports: ["android.hardware.security.keymint-V3"],
+            imports: ["android.hardware.security.keymint-V4"],
         },
     ],
     frozen: true,
diff --git a/contexthub/aidl/Android.bp b/contexthub/aidl/Android.bp
index 202813c..eaa47c6 100644
--- a/contexthub/aidl/Android.bp
+++ b/contexthub/aidl/Android.bp
@@ -52,8 +52,6 @@
             version: "3",
             imports: [],
         },
-
     ],
-    frozen: true,
-
+    frozen: false,
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/EndpointId.aidl
similarity index 88%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/EndpointId.aidl
index 173ac17..a70065d 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/EndpointId.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.contexthub;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable EndpointId {
+  long id;
+  long hubId;
+  const long ENDPOINT_ID_INVALID = 0;
+  const long ENDPOINT_ID_RESERVED = (-1) /* -1 */;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/EndpointInfo.aidl
similarity index 78%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/EndpointInfo.aidl
index 173ac17..43e5ec3 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/EndpointInfo.aidl
@@ -31,10 +31,22 @@
 // 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.contexthub;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable EndpointInfo {
+  android.hardware.contexthub.EndpointId id;
+  android.hardware.contexthub.EndpointInfo.EndpointType type;
+  String name;
+  int version;
+  @nullable String tag;
+  String[] requiredPermissions;
+  android.hardware.contexthub.Service[] services;
+  @Backing(type="int") @VintfStability
+  enum EndpointType {
+    FRAMEWORK = 1,
+    APP = 2,
+    NATIVE = 3,
+    NANOAPP = 4,
+    GENERIC = 5,
+  }
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/HubInfo.aidl
similarity index 81%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/HubInfo.aidl
index 173ac17..cac441a 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/HubInfo.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.contexthub;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable HubInfo {
+  long hubId;
+  android.hardware.contexthub.HubInfo.HubDetails hubDetails;
+  const long HUB_ID_INVALID = 0;
+  const long HUB_ID_RESERVED = (-1) /* -1 */;
+  union HubDetails {
+    android.hardware.contexthub.ContextHubInfo contextHubInfo;
+    android.hardware.contexthub.VendorHubInfo vendorHubInfo;
+  }
 }
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
index 7341e0e..93b8ff5 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
@@ -49,5 +49,16 @@
   void onNanSessionStateChanged(in android.hardware.contexthub.NanSessionStateUpdate update);
   void setTestMode(in boolean enable);
   void sendMessageDeliveryStatusToHub(in int contextHubId, in android.hardware.contexthub.MessageDeliveryStatus messageDeliveryStatus);
+  List<android.hardware.contexthub.HubInfo> getHubs();
+  List<android.hardware.contexthub.EndpointInfo> getEndpoints();
+  void registerEndpoint(in android.hardware.contexthub.EndpointInfo endpoint);
+  void unregisterEndpoint(in android.hardware.contexthub.EndpointInfo endpoint);
+  void registerEndpointCallback(in android.hardware.contexthub.IEndpointCallback callback);
+  int[] requestSessionIdRange(int size);
+  void openEndpointSession(int sessionId, in android.hardware.contexthub.EndpointId destination, in android.hardware.contexthub.EndpointId initiator, in @nullable String serviceDescriptor);
+  void sendMessageToEndpoint(int sessionId, in android.hardware.contexthub.Message msg);
+  void sendMessageDeliveryStatusToEndpoint(int sessionId, in android.hardware.contexthub.MessageDeliveryStatus msgStatus);
+  void closeEndpointSession(int sessionId, in android.hardware.contexthub.Reason reason);
+  void endpointSessionOpenComplete(int sessionId);
   const int EX_CONTEXT_HUB_UNSPECIFIED = (-1) /* -1 */;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IEndpointCallback.aidl
similarity index 66%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IEndpointCallback.aidl
index 173ac17..c0bb744 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IEndpointCallback.aidl
@@ -31,10 +31,14 @@
 // 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.contexthub;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+interface IEndpointCallback {
+  void onEndpointStarted(in android.hardware.contexthub.EndpointInfo[] endpointInfos);
+  void onEndpointStopped(in android.hardware.contexthub.EndpointId[] endpointIds, android.hardware.contexthub.Reason reason);
+  void onMessageReceived(int sessionId, in android.hardware.contexthub.Message msg);
+  void onMessageDeliveryStatusReceived(int sessionId, in android.hardware.contexthub.MessageDeliveryStatus msgStatus);
+  void onEndpointSessionOpenRequest(int sessionId, in android.hardware.contexthub.EndpointId destination, in android.hardware.contexthub.EndpointId initiator, in @nullable String serviceDescriptor);
+  void onCloseEndpointSession(int sessionId, in android.hardware.contexthub.Reason reason);
+  void onEndpointSessionOpenComplete(int sessionId);
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/Message.aidl
similarity index 88%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/Message.aidl
index 173ac17..ef117c3 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/Message.aidl
@@ -31,10 +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.contexthub;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable Message {
+  int flags;
+  int sequenceNumber;
+  String[] permissions;
+  int type;
+  byte[] content;
+  const int FLAG_REQUIRES_DELIVERY_STATUS = 1;
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevel.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/Reason.aidl
similarity index 82%
copy from drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevel.aidl
copy to contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/Reason.aidl
index 5704fb0..a315438 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevel.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/Reason.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,15 +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.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,
+package android.hardware.contexthub;
+@Backing(type="byte") @VintfStability
+enum Reason {
+  UNSPECIFIED = 0,
+  OUT_OF_MEMORY,
+  TIMEOUT,
+  OPEN_ENDPOINT_SESSION_REQUEST_REJECTED,
+  CLOSE_ENDPOINT_SESSION_REQUESTED,
+  ENDPOINT_INVALID,
+  ENDPOINT_GONE,
+  ENDPOINT_CRASHED,
+  HUB_RESET,
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/Service.aidl
similarity index 83%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/Service.aidl
index 173ac17..e3d94c8 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/Service.aidl
@@ -31,10 +31,18 @@
 // 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.contexthub;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable Service {
+  android.hardware.contexthub.Service.RpcFormat format;
+  String serviceDescriptor;
+  int majorVersion;
+  int minorVersion;
+  ParcelableHolder extendedInfo;
+  @Backing(type="int") @VintfStability
+  enum RpcFormat {
+    CUSTOM = 0,
+    AIDL = 1,
+    PW_RPC_PROTOBUF = 2,
+  }
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/VendorHubInfo.aidl
similarity index 88%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/VendorHubInfo.aidl
index 173ac17..db64ec7 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/VendorHubInfo.aidl
@@ -31,10 +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.biometrics.fingerprint;
-/* @hide */
+package android.hardware.contexthub;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable VendorHubInfo {
+  String name;
+  int version;
+  ParcelableHolder extendedInfo;
 }
diff --git a/contexthub/aidl/android/hardware/contexthub/EndpointId.aidl b/contexthub/aidl/android/hardware/contexthub/EndpointId.aidl
new file mode 100644
index 0000000..2075e73
--- /dev/null
+++ b/contexthub/aidl/android/hardware/contexthub/EndpointId.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.contexthub;
+
+/* This structure is a unique identifier for an endpoint */
+@VintfStability
+parcelable EndpointId {
+    /**
+     * Invalid endpoint ID.
+     */
+    const long ENDPOINT_ID_INVALID = 0;
+
+    /**
+     * Reserved endpoint ID.
+     */
+    const long ENDPOINT_ID_RESERVED = -1;
+
+    /**
+     * Nanoapp ID or randomly generated ID (depending on type). This value uniquely identifies the
+     * endpoint within a single hub.
+     *
+     * ENDPOINT_ID_INVALID(0) is an invalid id and should never be used.
+     * ENDPOINT_ID_RESERVED(-1) is reserved for future use.
+     * For static/compile-time-generated IDs, topmost bit should be 0.
+     * For dynamic/runtime-generated IDs, topmost bit should be 1.
+     */
+    long id;
+
+    /**
+     * Hub ID of the hub hosting this endpoint. A pair of (hubId, id) uniquely identifies the
+     * endpoint globally.
+     */
+    long hubId;
+}
diff --git a/contexthub/aidl/android/hardware/contexthub/EndpointInfo.aidl b/contexthub/aidl/android/hardware/contexthub/EndpointInfo.aidl
new file mode 100644
index 0000000..53a41fc
--- /dev/null
+++ b/contexthub/aidl/android/hardware/contexthub/EndpointInfo.aidl
@@ -0,0 +1,101 @@
+/*
+ * 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.contexthub;
+
+import android.hardware.contexthub.EndpointId;
+import android.hardware.contexthub.Service;
+
+/* This structure is a unified superset of NanoAppInfo and HostEndpointInfo. */
+@VintfStability
+parcelable EndpointInfo {
+    /** Unique identifier of this endpoint. */
+    EndpointId id;
+
+    /** Type of this endpoint. */
+    EndpointType type;
+
+    /**
+     * Name of this endpoint. Endpoint may use this field to identify the initiator of the session
+     * request.
+     *
+     * Depending on type of the endpoint, the following values are used:
+     *  - Framework: package name of the process registering this endpoint
+     *  - App: package name of the process registering this endpoint
+     *  - Native: name of the process registering this endpoint, supplied by client for debugging
+     *            purpose.
+     *  - Nanoapp: name of the nanoapp, for debugging purpose
+     *  - Generic: name of the generic endpoint, for debugging purpose
+     */
+    String name;
+
+    /**
+     * Monotonically increasing version number. The two sides of an endpoint session can use this
+     * version number to identify the other side and determine compatibility with each other.
+     * The interpretation of the version number is specific to the implementation of an endpoint.
+     * The version number should not be used to compare endpoints implementation freshness for
+     * different endpoint types.
+     *
+     * Depending on type of the endpoint, the following values are used:
+     *  - Framework: android.os.Build.VERSION.SDK_INT_FULL (populated by ContextHubService)
+     *  - App: versionCode (populated by ContextHubService)
+     *  - Native: unspecified format (supplied by endpoint code)
+     *  - Nanoapp: nanoapp version, typically following 0xMMmmpppp scheme where
+     *             MM = major version, mm = minor version, pppp = patch version
+     *  - Generic: unspecified format (supplied by endpoint code), following nanoapp versioning
+     *             scheme is recommended
+     */
+    int version;
+
+    /**
+     * Tag for this particular endpoint. Optional string that further identifies the submodule
+     * that created this endpoint.
+     */
+    @nullable String tag;
+
+    /**
+     * Represents the minimally required permissions in order to message this endpoint. Further
+     * permissions may be required on a message-by-message basis.
+     */
+    String[] requiredPermissions;
+
+    /**
+     * List of services provided by this endpoint. Service list should be fixed for the
+     * lifetime of an endpoint.
+     */
+    Service[] services;
+
+    @VintfStability
+    @Backing(type="int")
+    enum EndpointType {
+        /**
+         * This endpoint is from the Android framework
+         */
+        FRAMEWORK = 1,
+
+        /** This endpoint is an Android app. */
+        APP = 2,
+
+        /** This endpoint is from an Android native program. */
+        NATIVE = 3,
+
+        /** This endpoint is from a nanoapp. */
+        NANOAPP = 4,
+
+        /** This endpoint is a generic endpoint (not from a nanoapp). */
+        GENERIC = 5,
+    }
+}
diff --git a/contexthub/aidl/android/hardware/contexthub/HubInfo.aidl b/contexthub/aidl/android/hardware/contexthub/HubInfo.aidl
new file mode 100644
index 0000000..3d0a76e
--- /dev/null
+++ b/contexthub/aidl/android/hardware/contexthub/HubInfo.aidl
@@ -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.
+ */
+
+package android.hardware.contexthub;
+
+import android.hardware.contexthub.ContextHubInfo;
+import android.hardware.contexthub.VendorHubInfo;
+
+@VintfStability
+parcelable HubInfo {
+    /**
+     * Invalid hub ID.
+     */
+    const long HUB_ID_INVALID = 0;
+
+    /**
+     * Reserved hub ID.
+     */
+    const long HUB_ID_RESERVED = -1;
+
+    /**
+     * Hub ID (depending on type). This is a globally unique identifier.
+     *
+     * HUB_ID_INVALID(0) is an invalid id and should never be used.
+     * HUB_ID_RESERVED(-1) is reserved for future use.
+     */
+    long hubId;
+
+    /**
+     * A hub can be either a ContextHub or a VendorHub.
+     */
+    union HubDetails {
+        ContextHubInfo contextHubInfo;
+        VendorHubInfo vendorHubInfo;
+    }
+
+    /**
+     * Detail information about the hub.
+     */
+    HubDetails hubDetails;
+}
diff --git a/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl b/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
index b146ff8..24192a1 100644
--- a/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
@@ -18,12 +18,19 @@
 
 import android.hardware.contexthub.ContextHubInfo;
 import android.hardware.contexthub.ContextHubMessage;
+import android.hardware.contexthub.EndpointId;
+import android.hardware.contexthub.EndpointInfo;
 import android.hardware.contexthub.HostEndpointInfo;
+import android.hardware.contexthub.HubInfo;
 import android.hardware.contexthub.IContextHubCallback;
+import android.hardware.contexthub.IEndpointCallback;
+import android.hardware.contexthub.Message;
 import android.hardware.contexthub.MessageDeliveryStatus;
 import android.hardware.contexthub.NanSessionStateUpdate;
 import android.hardware.contexthub.NanoappBinary;
 import android.hardware.contexthub.NanoappInfo;
+import android.hardware.contexthub.Reason;
+import android.hardware.contexthub.Service;
 import android.hardware.contexthub.Setting;
 
 @VintfStability
@@ -221,7 +228,7 @@
     void onNanSessionStateChanged(in NanSessionStateUpdate update);
 
     /**
-     * Puts the context hub in and out of test mode. Test mode is a clean state
+     * Puts the Context Hub in and out of test mode. Test mode is a clean state
      * where tests can be executed in the same environment. If enable is true,
      * this will enable test mode by unloading all nanoapps. If enable is false,
      * this will disable test mode and reverse the actions of enabling test mode
@@ -231,7 +238,7 @@
      * @TestApi or development tools. This should not be used in a production
      * environment.
      *
-     * @param enable If true, put the context hub in test mode. If false, disable
+     * @param enable If true, put the Context Hub in test mode. If false, disable
      *               test mode.
      */
     void setTestMode(in boolean enable);
@@ -256,4 +263,136 @@
      * value EX_SERVICE_SPECIFIC.
      */
     const int EX_CONTEXT_HUB_UNSPECIFIED = -1;
+
+    /** Lists all the hubs, including the Context Hub and generic hubs. */
+    List<HubInfo> getHubs();
+
+    /** Lists all the endpoints, including the Context Hub nanoapps and generic endpoints. */
+    List<EndpointInfo> getEndpoints();
+
+    /**
+     * Publishes an endpoint from the calling side (e.g. Android). Endpoints must be registered
+     * prior to starting a session.
+     */
+    void registerEndpoint(in EndpointInfo endpoint);
+
+    /**
+     * Teardown an endpoint from the calling side (e.g. Android). This endpoint must have already
+     * been published via registerEndpoint().
+     */
+    void unregisterEndpoint(in EndpointInfo endpoint);
+
+    /**
+     * Attaches a callback interface to receive events targeted at endpoints registered by the
+     * caller.
+     */
+    void registerEndpointCallback(in IEndpointCallback callback);
+
+    /**
+     * Request a range of session IDs for the caller to use when initiating sessions. This may be
+     * called more than once, but typical usage is to request a large enough range to accommodate
+     * the maximum expected number of concurrent sessions, but not overly large as to limit other
+     * clients.
+     *
+     * @param size The number of sessionId reserved for host-initiated sessions. This number should
+     *         be less than or equal to 1024.
+     *
+     * @return An array with two elements representing the smallest and largest possible session id
+     *         available for host.
+     *
+     * @throws EX_ILLEGAL_ARGUMENT if the size is invalid.
+     * @throws EX_SERVICE_SPECIFIC if the id range requested cannot be allocated.
+     */
+    int[] requestSessionIdRange(int size);
+
+    /**
+     * Request to open a session for communication between an endpoint previously registered by the
+     * caller and a target endpoint found in getEndpoints(), optionally scoped to a service
+     * published by the target endpoint.
+     *
+     * Upon returning from this function, the session is in pending state, and the final result will
+     * be given by an asynchronous call to onEndpointSessionOpenComplete() on success, or
+     * onCloseEndpointSession() on failure.
+     *
+     * @param sessionId Caller-allocated session identifier, which must be unique across all active
+     *         sessions, and must fall in a range allocated via requestSessionIdRange().
+     * @param destination The EndpointId representing the destination side of the session.
+     * @param initiator The EndpointId representing the initiating side of the session, which
+     *         must've already been published through registerEndpoint().
+     * @param serviceDescriptor Descriptor for the service specification for scoping this session
+     *         (nullable). Null indicates a fully custom marshalling scheme. The value should match
+     *         a published descriptor for both destination and initiator.
+     *
+     * @return An integer identifying the session, the integer can be used to present
+     *         the tuple of (destination, initiator, serviceDescriptor).
+     *
+     * @throws EX_ILLEGAL_ARGUMENT if any of the arguments are invalid, or the combination of the
+     *         arguments is invalid.
+     * @throws EX_SERVICE_SPECIFIC on other errors
+     *         - EX_CONTEXT_HUB_UNSPECIFIED if the request failed for other reasons.
+     */
+    void openEndpointSession(int sessionId, in EndpointId destination, in EndpointId initiator,
+            in @nullable String serviceDescriptor);
+
+    /**
+     * Send a message from one endpoint to another on the (currently open) session.
+     *
+     * @param sessionId The integer representing the communication session, previously set in
+     *         openEndpointSession() or onEndpointSessionOpenRequest().
+     * @param msg The Message object representing a message to endpoint from the endpoint on host.
+     *
+     * @throws EX_ILLEGAL_ARGUMENT if any of the arguments are invalid, or the combination of the
+     *         arguments is invalid.
+     * @throws EX_SERVICE_SPECIFIC on other errors
+     *         - EX_CONTEXT_HUB_UNSPECIFIED if the request failed for other reasons.
+     */
+    void sendMessageToEndpoint(int sessionId, in Message msg);
+
+    /**
+     * Sends a message delivery status to the endpoint in response to receiving a Message with flag
+     * FLAG_REQUIRES_DELIVERY_STATUS. Each message with the flag should have a MessageDeliveryStatus
+     * response. This method sends the message delivery status back to the remote endpoint for a
+     * session.
+     *
+     * @param sessionId The integer representing the communication session, previously set in
+     *         openEndpointSession() or onEndpointSessionOpenRequest().
+     * @param msgStatus The MessageDeliveryStatus object representing the delivery status for a
+     *         specific message (identified by the sequenceNumber) within the session.
+     *
+     * @throws EX_UNSUPPORTED_OPERATION if ContextHubInfo.supportsReliableMessages is false for
+     *          the hub involved in this session.
+     */
+    void sendMessageDeliveryStatusToEndpoint(int sessionId, in MessageDeliveryStatus msgStatus);
+
+    /**
+     * Closes a session previously opened by openEndpointSession() or requested via
+     * onEndpointSessionOpenRequest(). Processing of session closure must be ordered/synchronized
+     * with message delivery, such that if this session was open, any messages previously passed to
+     * sendMessageToEndpoint() that are still in-flight must still be delivered before the session
+     * is closed. Any in-flight messages to the endpoint that requested to close the session will
+     * not be delivered.
+     *
+     * @param sessionId The integer representing the communication session, previously set in
+     *         openEndpointSession() or onEndpointSessionOpenRequest().
+     * @param reason The reason for this close endpoint session request.
+     *
+     * @throws EX_ILLEGAL_ARGUMENT if any of the arguments are invalid, or the combination of the
+     *         arguments is invalid.
+     * @throws EX_SERVICE_SPECIFIC on other errors
+     *         - EX_CONTEXT_HUB_UNSPECIFIED if the request failed for other reasons.
+     */
+    void closeEndpointSession(int sessionId, in Reason reason);
+
+    /**
+     * Notifies the HAL that the session requested by onEndpointSessionOpenRequest is ready to use.
+     *
+     * @param sessionId The integer representing the communication session, previously set in
+     *         onEndpointSessionOpenRequest(). This id is assigned by the HAL.
+     *
+     * @throws EX_ILLEGAL_ARGUMENT if any of the arguments are invalid, or the combination of the
+     *         arguments is invalid.
+     * @throws EX_SERVICE_SPECIFIC on other errors
+     *         - EX_CONTEXT_HUB_UNSPECIFIED if the request failed for other reasons.
+     */
+    void endpointSessionOpenComplete(int sessionId);
 }
diff --git a/contexthub/aidl/android/hardware/contexthub/IEndpointCallback.aidl b/contexthub/aidl/android/hardware/contexthub/IEndpointCallback.aidl
new file mode 100644
index 0000000..972853b
--- /dev/null
+++ b/contexthub/aidl/android/hardware/contexthub/IEndpointCallback.aidl
@@ -0,0 +1,118 @@
+/*
+ * 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.contexthub;
+
+import android.hardware.contexthub.EndpointId;
+import android.hardware.contexthub.EndpointInfo;
+import android.hardware.contexthub.Message;
+import android.hardware.contexthub.MessageDeliveryStatus;
+import android.hardware.contexthub.Reason;
+import android.hardware.contexthub.Service;
+
+@VintfStability
+interface IEndpointCallback {
+    /**
+     * Lifecycle event notification for endpoint starting from remote side. There is no need to
+     * report already started endpoint prior to the registration of an EndpointLifecycleCallbacks
+     * object. The EndpointInfo reported here should be consistent with values from getEndpoints().
+     *
+     * Endpoints added by registerEndpoint should not be included. registerEndpoint() should not
+     * cause this call.
+     *
+     * @param endpointInfos An array of EndpointInfo representing endpoints that just started.
+     */
+    void onEndpointStarted(in EndpointInfo[] endpointInfos);
+
+    /**
+     * Lifecycle event notification for endpoint stopping from remote side. There is no need to
+     * report already stopped endpoint prior to the registration of an EndpointLifecycleCallbacks
+     * object. The EndpointId reported here should represent a previously started Endpoint.
+     *
+     * When a hub crashes or restart, events should be batched into be a single call (containing all
+     * the EndpointId that were impacted).
+     *
+     * Endpoints added by registerEndpoint should not be included. unregisterEndpoint() should not
+     * cause this call.
+     *
+     * @param endpointIds An array of EndpointId representing endpoints that just stopped.
+     * @param reason The reason for why the endpoints stopped.
+     */
+    void onEndpointStopped(in EndpointId[] endpointIds, Reason reason);
+
+    /**
+     * Invoked when an endpoint sends message to another endpoint (on host) on the (currently open)
+     * session.
+     *
+     * @param sessionId The integer representing the communication session, previously set in
+     *         openEndpointSession() or onEndpointSessionOpenRequest().
+     * @param msg The Message object representing a message from endpoint to an endpoint on host.
+     */
+    void onMessageReceived(int sessionId, in Message msg);
+
+    /**
+     * Invoked when an endpoint sends the response for a message that requires delivery status.
+     *
+     * The response is the message delivery status of a recently sent message within a session. See
+     * sendMessageDeliveryStatusToEndpoint() for more details.
+     *
+     * @param sessionId The integer representing the communication session, previously set in
+     *         openEndpointSession() or onEndpointSessionOpenRequest().
+     * @param msgStatus The MessageDeliveryStatus object representing the delivery status for a
+     *         specific message (identified by the sequenceNumber) within the session.
+     */
+    void onMessageDeliveryStatusReceived(int sessionId, in MessageDeliveryStatus msgStatus);
+
+    /**
+     * Invoked when session initiation is requested by a remote endpoint. The receiving host client
+     * must later call endpointSessionOpenComplete() to indicate successful connection and
+     * acceptance of the session, or closeEndpointSession() to indicate failure.
+     *
+     * @param sessionId Caller-allocated session identifier, which must be unique across all active
+     *         sessions, and must not fall in a range allocated via requestSessionIdRange().
+     * @param destination The EndpointId representing the destination side of the session, which
+     *         must've already been published through registerEndpoint().
+     * @param initiator The EndpointId representing the initiating side of the session.
+     * @param serviceDescriptor Descriptor for the service specification for scoping this session
+     *         (nullable). Null indicates a fully custom marshalling scheme. The value should match
+     *         a published descriptor for both endpoints.
+     *
+     * @throws EX_ILLEGAL_ARGUMENT if any of the arguments are invalid, or the combination of the
+     *         arguments is invalid.
+     */
+    void onEndpointSessionOpenRequest(int sessionId, in EndpointId destination,
+            in EndpointId initiator, in @nullable String serviceDescriptor);
+
+    /**
+     * Invoked when a session has either failed to open, or has been closed by the remote side.
+     * Upon receiving this callback, the session is closed and further messages on it will not be
+     * delivered.
+     *
+     * @param sessionId The integer representing the communication session, previously set in
+     *         openEndpointSession() or onEndpointSessionOpenRequest().
+     * @param reason The reason for this close endpoint session notification.
+     */
+    void onCloseEndpointSession(int sessionId, in Reason reason);
+
+    /**
+     * Callback when a session is opened. This callback is the status callback for a previous
+     * openEndpointSession().
+     *
+     * @param sessionId The integer representing the communication session, previously set in
+     *         onEndpointSessionOpenRequest(). This id is assigned by the host.
+     */
+    void onEndpointSessionOpenComplete(int sessionId);
+}
diff --git a/contexthub/aidl/android/hardware/contexthub/Message.aidl b/contexthub/aidl/android/hardware/contexthub/Message.aidl
new file mode 100644
index 0000000..fc81ab0
--- /dev/null
+++ b/contexthub/aidl/android/hardware/contexthub/Message.aidl
@@ -0,0 +1,51 @@
+/*
+ * 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.contexthub;
+
+@VintfStability
+parcelable Message {
+    /**
+     * Bitmask for flags field if this message requires a MessageDeliveryStatus for the
+     * sequenceNumber within 1 second.
+     */
+    const int FLAG_REQUIRES_DELIVERY_STATUS = 1;
+
+    /** Bitset of flags */
+    int flags;
+
+    /** Sequence number of this message */
+    int sequenceNumber;
+
+    /**
+     * Per message permission (used for app-op permission attribution).
+     */
+    String[] permissions;
+
+    /**
+     * The type of this message payload, following a scheme specific to the service or sending
+     * endpoint's communication protocol. This value can be used to distinguish the handling of
+     * content (e.g. for decoding). This could also be used as the complete content of the message
+     * if no additional payload is needed.
+     */
+    int type;
+
+    /**
+     * Content (payload) of the message. The format of the message is specific to the context of the
+     * message: the service or endpoints involved in the session, and the message type.
+     */
+    byte[] content;
+}
diff --git a/contexthub/aidl/android/hardware/contexthub/MessageDeliveryStatus.aidl b/contexthub/aidl/android/hardware/contexthub/MessageDeliveryStatus.aidl
index ae425b3..4129981 100644
--- a/contexthub/aidl/android/hardware/contexthub/MessageDeliveryStatus.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/MessageDeliveryStatus.aidl
@@ -21,7 +21,8 @@
 @VintfStability
 parcelable MessageDeliveryStatus {
     /**
-     * The messageSequenceNumber of the ContextHubMessage to which this status applies.
+     * The messageSequenceNumber of the ContextHubMessage or Message to which this status is
+     * required.
      */
     int messageSequenceNumber;
 
diff --git a/contexthub/aidl/android/hardware/contexthub/Reason.aidl b/contexthub/aidl/android/hardware/contexthub/Reason.aidl
new file mode 100644
index 0000000..65d9f8a
--- /dev/null
+++ b/contexthub/aidl/android/hardware/contexthub/Reason.aidl
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.contexthub;
+
+@VintfStability
+@Backing(type="byte")
+enum Reason {
+    /**
+     * Unspecified reason.
+     */
+    UNSPECIFIED = 0,
+
+    /**
+     * Out of memory. There's not enough memory to perform this operation.
+     */
+    OUT_OF_MEMORY,
+
+    /**
+     * Timeout. This operation timed out.
+     */
+    TIMEOUT,
+
+    /**
+     * Endpoint rejected this openEndpointSession request.
+     */
+    OPEN_ENDPOINT_SESSION_REQUEST_REJECTED,
+
+    /**
+     * Endpoint requested closeEndpointSession.
+     */
+    CLOSE_ENDPOINT_SESSION_REQUESTED,
+
+    /**
+     * Invalid endpoint.
+     */
+    ENDPOINT_INVALID,
+
+    /**
+     * Endpoint is now stopped.
+     */
+    ENDPOINT_GONE,
+
+    /**
+     * Endpoint crashed.
+     */
+    ENDPOINT_CRASHED,
+
+    /**
+     * Hub was reset or is resetting.
+     */
+    HUB_RESET,
+}
diff --git a/contexthub/aidl/android/hardware/contexthub/Service.aidl b/contexthub/aidl/android/hardware/contexthub/Service.aidl
new file mode 100644
index 0000000..fd748c3
--- /dev/null
+++ b/contexthub/aidl/android/hardware/contexthub/Service.aidl
@@ -0,0 +1,67 @@
+/*
+ * 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.contexthub;
+
+@VintfStability
+parcelable Service {
+    /**
+     * Type of the Service. This field defines the messaging format used for this service.
+     * The format refers to how the data would be marhsalled in messages between host endpoint (on
+     * Android) and endpoint on the Context Hub or generic hub.
+     */
+    RpcFormat format;
+
+    /**
+     * Uniquely identifies the interface (scoped to type). Conventions depend on interface type.
+     * Examples:
+     *   1. AOSP-defined AIDL: android.hardware.something.IFoo/default
+     *   2. Vendor-defined AIDL: com.example.something.IBar/default
+     *   3. Pigweed RPC with Protobuf: com.example.proto.ExampleService
+     */
+    String serviceDescriptor;
+
+    /** Breaking changes should be a major version bump. */
+    int majorVersion;
+    /** Monotonically increasing minor version. */
+    int minorVersion;
+
+    /** Hook for additional detail in vendor-specific type */
+    ParcelableHolder extendedInfo;
+
+    /**
+     * Supported messaging format for the service between the host and the hubs.
+     */
+    @VintfStability
+    @Backing(type="int")
+    enum RpcFormat {
+        /**
+         * Customized format for messaging. Fully customized and opaque messaging format.
+         */
+        CUSTOM = 0,
+        /**
+         * Binder-based messaging. The host endpoint is defining this service in Stable AIDL.
+         * Messages between endpoints that uses this service will be using the binder marhsalling
+         * format.
+         */
+        AIDL = 1,
+        /**
+         * Pigweed RPC messaging with Protobuf. This endpoint is a Pigweed RPC. Messages between
+         * endpoints will use Pigweed RPC marshalling format (protobuf).
+         */
+        PW_RPC_PROTOBUF = 2,
+    }
+}
diff --git a/contexthub/aidl/android/hardware/contexthub/VendorHubInfo.aidl b/contexthub/aidl/android/hardware/contexthub/VendorHubInfo.aidl
new file mode 100644
index 0000000..524c7e8
--- /dev/null
+++ b/contexthub/aidl/android/hardware/contexthub/VendorHubInfo.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.contexthub;
+
+/**
+ * A representation of a vendor-specific hub providing endpoints (with services). The hub does not
+ * run the Context Hub Runtime Environment, but exposes a similar messaging API.
+ */
+@VintfStability
+parcelable VendorHubInfo {
+    /** Descriptive name of the basic hub */
+    String name;
+
+    /** Version of the hub */
+    int version;
+
+    /** Hook for additional detail in vendor-specific type */
+    ParcelableHolder extendedInfo;
+}
diff --git a/contexthub/aidl/default/Android.bp b/contexthub/aidl/default/Android.bp
index 2960746..da173f9 100644
--- a/contexthub/aidl/default/Android.bp
+++ b/contexthub/aidl/default/Android.bp
@@ -30,7 +30,7 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.contexthub-V3-ndk",
+        "android.hardware.contexthub-V4-ndk",
     ],
     export_include_dirs: ["include"],
     srcs: [
@@ -51,7 +51,7 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.contexthub-V3-ndk",
+        "android.hardware.contexthub-V4-ndk",
     ],
     static_libs: [
         "libcontexthubexampleimpl",
diff --git a/contexthub/aidl/default/ContextHub.cpp b/contexthub/aidl/default/ContextHub.cpp
index bd483d7..5713a1b 100644
--- a/contexthub/aidl/default/ContextHub.cpp
+++ b/contexthub/aidl/default/ContextHub.cpp
@@ -136,4 +136,83 @@
     return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
+ScopedAStatus ContextHub::getHubs(std::vector<HubInfo>* _aidl_return) {
+    ContextHubInfo hub = {};
+    hub.name = "Mock Context Hub";
+    hub.vendor = "AOSP";
+    hub.toolchain = "n/a";
+    hub.id = kMockHubId;
+    hub.peakMips = 1;
+    hub.maxSupportedMessageLengthBytes = 4096;
+    hub.chrePlatformId = UINT64_C(0x476f6f6754000000);
+    hub.chreApiMajorVersion = 1;
+    hub.chreApiMinorVersion = 6;
+    hub.supportsReliableMessages = false;
+
+    HubInfo hubInfo1 = {};
+    hubInfo1.hubId = hub.chrePlatformId;
+    hubInfo1.hubDetails = HubInfo::HubDetails::make<HubInfo::HubDetails::Tag::contextHubInfo>(hub);
+
+    VendorHubInfo vendorHub = {};
+    vendorHub.name = "Mock Vendor Hub";
+    vendorHub.version = 42;
+
+    HubInfo hubInfo2 = {};
+    hubInfo1.hubId = UINT64_C(0x1234567812345678);
+    hubInfo1.hubDetails =
+            HubInfo::HubDetails::make<HubInfo::HubDetails::Tag::vendorHubInfo>(vendorHub);
+
+    _aidl_return->push_back(hubInfo1);
+    _aidl_return->push_back(hubInfo2);
+
+    return ScopedAStatus::ok();
+};
+
+ScopedAStatus ContextHub::getEndpoints(std::vector<EndpointInfo>* /* _aidl_return */) {
+    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
+ScopedAStatus ContextHub::registerEndpoint(const EndpointInfo& /* in_endpoint */) {
+    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
+ScopedAStatus ContextHub::unregisterEndpoint(const EndpointInfo& /* in_endpoint */) {
+    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
+ScopedAStatus ContextHub::registerEndpointCallback(
+        const std::shared_ptr<IEndpointCallback>& /* in_callback */) {
+    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
+ScopedAStatus ContextHub::requestSessionIdRange(int32_t /* in_size */,
+                                                std::vector<int32_t>* /* _aidl_return */) {
+    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
+ScopedAStatus ContextHub::openEndpointSession(
+        int32_t /* in_sessionId */, const EndpointId& /* in_destination */,
+        const EndpointId& /* in_initiator */,
+        const std::optional<std::string>& /* in_serviceDescriptor */) {
+    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
+ScopedAStatus ContextHub::sendMessageToEndpoint(int32_t /* in_sessionId */,
+                                                const Message& /* in_msg */) {
+    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
+ScopedAStatus ContextHub::sendMessageDeliveryStatusToEndpoint(
+        int32_t /* in_sessionId */, const MessageDeliveryStatus& /* in_msgStatus */) {
+    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
+ScopedAStatus ContextHub::closeEndpointSession(int32_t /* in_sessionId */, Reason /* in_reason */) {
+    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
+ScopedAStatus ContextHub::endpointSessionOpenComplete(int32_t /* in_sessionId */) {
+    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
 }  // namespace aidl::android::hardware::contexthub
diff --git a/contexthub/aidl/default/contexthub-default.xml b/contexthub/aidl/default/contexthub-default.xml
index 2f8ddc8..359bb0a 100644
--- a/contexthub/aidl/default/contexthub-default.xml
+++ b/contexthub/aidl/default/contexthub-default.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.contexthub</name>
-        <version>3</version>
+        <version>4</version>
         <interface>
             <name>IContextHub</name>
             <instance>default</instance>
diff --git a/contexthub/aidl/default/include/contexthub-impl/ContextHub.h b/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
index 72e8b3b..5680a77 100644
--- a/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
+++ b/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
@@ -53,6 +53,24 @@
             int32_t in_contextHubId,
             const MessageDeliveryStatus& in_messageDeliveryStatus) override;
 
+    ::ndk::ScopedAStatus getHubs(std::vector<HubInfo>* _aidl_return) override;
+    ::ndk::ScopedAStatus getEndpoints(std::vector<EndpointInfo>* _aidl_return) override;
+    ::ndk::ScopedAStatus registerEndpoint(const EndpointInfo& in_endpoint) override;
+    ::ndk::ScopedAStatus unregisterEndpoint(const EndpointInfo& in_endpoint) override;
+    ::ndk::ScopedAStatus registerEndpointCallback(
+            const std::shared_ptr<IEndpointCallback>& in_callback) override;
+    ::ndk::ScopedAStatus requestSessionIdRange(int32_t in_size,
+                                               std::vector<int32_t>* _aidl_return) override;
+    ::ndk::ScopedAStatus openEndpointSession(
+            int32_t in_sessionId, const EndpointId& in_destination, const EndpointId& in_initiator,
+            const std::optional<std::string>& in_serviceDescriptor) override;
+    ::ndk::ScopedAStatus sendMessageToEndpoint(int32_t in_sessionId,
+                                               const Message& in_msg) override;
+    ::ndk::ScopedAStatus sendMessageDeliveryStatusToEndpoint(
+            int32_t in_sessionId, const MessageDeliveryStatus& in_msgStatus) override;
+    ::ndk::ScopedAStatus closeEndpointSession(int32_t in_sessionId, Reason in_reason) override;
+    ::ndk::ScopedAStatus endpointSessionOpenComplete(int32_t in_sessionId) override;
+
   private:
     static constexpr uint32_t kMockHubId = 0;
     std::shared_ptr<IContextHubCallback> mCallback;
diff --git a/drm/aidl/Android.bp b/drm/aidl/Android.bp
index c42e723..827621c 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: {
@@ -31,7 +32,10 @@
     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/gatekeeper/aidl/Android.bp b/gatekeeper/aidl/Android.bp
index 169a7d5..88c10b7 100644
--- a/gatekeeper/aidl/Android.bp
+++ b/gatekeeper/aidl/Android.bp
@@ -10,8 +10,8 @@
 aidl_interface {
     name: "android.hardware.gatekeeper",
     vendor_available: true,
-    imports: [
-        "android.hardware.security.keymint-V3",
+    defaults: [
+        "android.hardware.security.keymint-latest-defaults",
     ],
     srcs: ["android/hardware/gatekeeper/*.aidl"],
     stability: "vintf",
@@ -32,7 +32,7 @@
     versions_with_info: [
         {
             version: "1",
-            imports: ["android.hardware.security.keymint-V3"],
+            imports: ["android.hardware.security.keymint-V4"],
         },
     ],
     frozen: true,
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 cae5292..d768ecf 100644
--- a/graphics/Android.bp
+++ b/graphics/Android.bp
@@ -16,11 +16,32 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
+aidl_interface_defaults {
+    name: "android.hardware.graphics.allocator-latest",
+    imports: [
+        "android.hardware.graphics.allocator-V2",
+    ],
+}
+
+rust_defaults {
+    name: "android.hardware.graphics.allocator-latest-rust",
+    rustlibs: [
+        "android.hardware.graphics.allocator-V2-rust",
+    ],
+    defaults: [
+        "android.hardware.graphics.common-latest-rust",
+    ],
+}
+
 cc_defaults {
     name: "android.hardware.graphics.allocator-ndk_static",
-    static_libs: [
-        "android.hardware.graphics.allocator-V2-ndk",
-    ],
+    target: {
+        linux: {
+            static_libs: [
+                "android.hardware.graphics.allocator-V2-ndk",
+            ],
+        },
+    },
     defaults: [
         "android.hardware.graphics.common-ndk_static",
     ],
@@ -28,38 +49,81 @@
 
 cc_defaults {
     name: "android.hardware.graphics.allocator-ndk_shared",
-    shared_libs: [
-        "android.hardware.graphics.allocator-V2-ndk",
-    ],
+    target: {
+        linux: {
+            shared_libs: [
+                "android.hardware.graphics.allocator-V2-ndk",
+            ],
+        },
+    },
     defaults: [
         "android.hardware.graphics.common-ndk_shared",
     ],
 }
 
-cc_defaults {
-    name: "android.hardware.graphics.common-ndk_static",
-    static_libs: [
-        "android.hardware.graphics.common-V5-ndk",
+aidl_interface_defaults {
+    name: "android.hardware.graphics.common-latest",
+    imports: [
+        "android.hardware.graphics.common-V5",
+    ],
+}
+
+rust_defaults {
+    name: "android.hardware.graphics.common-latest-rust",
+    rustlibs: [
+        "android.hardware.graphics.common-V5-rust",
     ],
 }
 
 cc_defaults {
+    name: "android.hardware.graphics.common-ndk_static",
+    target: {
+        linux: {
+            static_libs: [
+                "android.hardware.graphics.common-V5-ndk",
+            ],
+        },
+    },
+}
+
+cc_defaults {
     name: "android.hardware.graphics.common-ndk_shared",
-    shared_libs: [
-        "android.hardware.graphics.common-V5-ndk",
+    target: {
+        linux: {
+            shared_libs: [
+                "android.hardware.graphics.common-V5-ndk",
+            ],
+        },
+    },
+}
+
+aidl_interface_defaults {
+    name: "android.hardware.graphics.composer3-latest",
+    imports: [
+        "android.hardware.graphics.composer3-V4",
     ],
 }
 
 cc_defaults {
     name: "android.hardware.graphics.composer3-ndk_static",
-    static_libs: [
-        "android.hardware.graphics.composer3-V3-ndk",
-    ],
+    target: {
+        linux: {
+            static_libs: [
+                "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",
-    ],
+    target: {
+        linux: {
+            shared_libs: [
+                "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 7bb6b50..30b341c 100644
--- a/graphics/allocator/aidl/Android.bp
+++ b/graphics/allocator/aidl/Android.bp
@@ -13,9 +13,11 @@
     vendor_available: true,
     double_loadable: true,
     srcs: ["android/hardware/graphics/allocator/*.aidl"],
+    defaults: [
+        "android.hardware.graphics.common-latest",
+    ],
     imports: [
         "android.hardware.common-V2",
-        "android.hardware.graphics.common-V5",
     ],
     stability: "vintf",
     backend: {
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/DisplayHotplugEvent.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/DisplayHotplugEvent.aidl
index 63dca0a..b18d2be 100644
--- a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/DisplayHotplugEvent.aidl
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/DisplayHotplugEvent.aidl
@@ -39,4 +39,5 @@
   ERROR_UNKNOWN = (-1) /* -1 */,
   ERROR_INCOMPATIBLE_CABLE = (-2) /* -2 */,
   ERROR_TOO_MANY_DISPLAYS = (-3) /* -3 */,
+  ERROR_LINK_UNSTABLE = (-4) /* -4 */,
 }
diff --git a/graphics/common/aidl/android/hardware/graphics/common/DisplayHotplugEvent.aidl b/graphics/common/aidl/android/hardware/graphics/common/DisplayHotplugEvent.aidl
index b35ada5..c807ffd 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/DisplayHotplugEvent.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/DisplayHotplugEvent.aidl
@@ -43,4 +43,11 @@
      * displays that can be simultaneously connected
      */
     ERROR_TOO_MANY_DISPLAYS = -3,
+
+    /**
+     * Display link is unstable, e.g. link training failure (negotiation
+     * of connection speed failed), and the display needs to be
+     * reconfigured
+     */
+    ERROR_LINK_UNSTABLE = -4,
 }
diff --git a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
index 8cfdae6..e4da890 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
@@ -282,7 +282,7 @@
      * When it is encoded into a byte stream, the total number of Rects is written using
      * 8 bytes in little endian. It is followed by each Rect.
      *
-     * To encode a Rect, write the following fields in this order each as 8 bytes in little endian:
+     * To encode a Rect, write the following fields in this order each as 4 bytes in little endian:
      * left, top, right and bottom.
      */
     CROP = 16,
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 c4e6878..bba41da 100644
--- a/graphics/composer/aidl/Android.bp
+++ b/graphics/composer/aidl/Android.bp
@@ -29,14 +29,17 @@
     host_supported: true,
     vendor_available: true,
     double_loadable: true,
-    frozen: true,
+    frozen: false,
     srcs: [
         "android/hardware/graphics/composer3/*.aidl",
     ],
     stability: "vintf",
+    defaults: [
+        "android.hardware.graphics.common-latest",
+    ],
     imports: [
-        "android.hardware.graphics.common-V5",
         "android.hardware.common-V2",
+        "android.hardware.drm.common-V1",
     ],
     backend: {
         cpp: {
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/EnrollmentProgressStep.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayLuts.aidl
similarity index 83%
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/DisplayLuts.aidl
index 173ac17..4263140 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/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,10 +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 EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable DisplayLuts {
+  long display;
+  android.hardware.graphics.composer3.DisplayLuts.LayerLut[] layerLuts;
+  parcelable LayerLut {
+    long layer;
+    android.hardware.graphics.composer3.Luts luts;
+  }
 }
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/IComposerClient.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl
index bc27cc7..c71c010 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl
@@ -97,5 +97,6 @@
   const int EX_UNSUPPORTED = 8;
   const int EX_SEAMLESS_NOT_ALLOWED = 9;
   const int EX_SEAMLESS_NOT_POSSIBLE = 10;
+  const int EX_CONFIG_FAILED = 11;
   const int INVALID_CONFIGURATION = 0x7fffffff;
 }
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..87c0e1e 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.Luts 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/LutProperties.aidl
similarity index 79%
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/LutProperties.aidl
index 173ac17..6a4593a 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/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,10 +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 EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable LutProperties {
+  android.hardware.graphics.composer3.LutProperties.Dimension dimension;
+  int 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/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/Luts.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/Luts.aidl
index 173ac17..2890365 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/Luts.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,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.biometrics.fingerprint;
-/* @hide */
+package android.hardware.graphics.composer3;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable Luts {
+  @nullable ParcelFileDescriptor pfd;
+  @nullable int[] offsets;
+  android.hardware.graphics.composer3.LutProperties[] lutProperties;
 }
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..6b59a6f
--- /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.Luts;
+
+/**
+ * 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;
+        /**
+         * Lut(s) specified by the HWC for given HDR layers that don't have Luts provided.
+         */
+        Luts luts;
+    }
+
+    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/IComposerClient.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
index 213e8e9..9650334 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
@@ -93,6 +93,10 @@
      * Seamless requirements cannot be met Exception
      */
     const int EX_SEAMLESS_NOT_POSSIBLE = 10;
+    /**
+     * Proposed configuration failed for undisclosed reasons
+     */
+    const int EX_CONFIG_FAILED = 11;
 
     /**
      * Integer.MAX_VALUE is reserved for the invalid configuration.
@@ -558,6 +562,7 @@
      * @exception EX_BAD_DISPLAY when an invalid display handle was passed in.
      * @exception EX_BAD_CONFIG when the configuration handle passed in is not valid
      *                    for this display.
+     * @exception EX_CONFIG_FAILED when the config failed for undisclosed reasons.
      */
     void setActiveConfig(long display, int config);
 
@@ -583,6 +588,7 @@
      * achieve the vsync period change without a noticeable visual artifact. When the conditions
      * change and it may be possible to change the vsync period seamlessly, onSeamlessPossible
      * callback must be called to indicate that caller should retry.
+     * @exception EX_CONFIG_FAILED when the config failed for undisclosed reasons.
      *
      * @return is the timeline for the vsync period change.
      */
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl
index e961c48..c89887d 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.Luts;
 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 Luts luts;
 }
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..1c6fd18
--- /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.
+     */
+    int 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/Luts.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/Luts.aidl
new file mode 100644
index 0000000..5f55f1c
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/Luts.aidl
@@ -0,0 +1,65 @@
+/*
+ * 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 Luts {
+    /**
+     * 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 `ashmem_create_region` 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 offsets store the starting point of each Lut memory of the Lut buffer.
+     *
+     * Multiple Luts can be packed into one same `pfd`, and `offsets` is used to pinpoint
+     * the starting point of each Lut.
+     */
+    @nullable int[] offsets;
+
+    /**
+     * The properties list of the Luts.
+     */
+    LutProperties[] lutProperties;
+}
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..07c9c6d 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& [layerId, luts] : displayLuts.layerLuts) {
+            if (luts.pfd.get() >= 0) {
+                data.layerLuts.push_back(
+                        {layerId, Luts{ndk::ScopedFileDescriptor(luts.pfd.release()), luts.offsets,
+                                       luts.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..036460e 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/Luts.h>
 #include <aidl/android/hardware/graphics/composer3/PerFrameMetadata.h>
 #include <aidl/android/hardware/graphics/composer3/PerFrameMetadataBlob.h>
 
@@ -245,6 +246,10 @@
         getLayerCommand(display, layer).blockingRegion.emplace(blocking.begin(), blocking.end());
     }
 
+    void setLayerLuts(int64_t display, int64_t layer, Luts& luts) {
+        getLayerCommand(display, layer).luts.emplace(std::move(luts));
+    }
+
     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/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/Android.bp b/graphics/mapper/stable-c/Android.bp
index 82306be..f4196b9 100644
--- a/graphics/mapper/stable-c/Android.bp
+++ b/graphics/mapper/stable-c/Android.bp
@@ -111,7 +111,7 @@
         "VtsHalTargetTestDefaults",
         "use_libaidlvintf_gtest_helper_static",
         "android.hardware.graphics.allocator-ndk_shared",
-        "android.hardware.graphics.common-ndk_shared",
+        "android.hardware.graphics.common-ndk_static",
     ],
     srcs: [
         "vts/VtsHalGraphicsMapperStableC_TargetTest.cpp",
diff --git a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
index 1e0c427..3e2f2ac 100644
--- a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
+++ b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
@@ -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) {
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/aidl/Android.bp b/neuralnetworks/aidl/Android.bp
index c9242ca..9589750 100644
--- a/neuralnetworks/aidl/Android.bp
+++ b/neuralnetworks/aidl/Android.bp
@@ -16,9 +16,11 @@
         "android/hardware/neuralnetworks/*.aidl",
     ],
     stability: "vintf",
+    defaults: [
+        "android.hardware.graphics.common-latest",
+    ],
     imports: [
         "android.hardware.common-V2",
-        "android.hardware.graphics.common-V5",
     ],
     backend: {
         java: {
diff --git a/power/aidl/Android.bp b/power/aidl/Android.bp
index dc57613..2c80aab 100644
--- a/power/aidl/Android.bp
+++ b/power/aidl/Android.bp
@@ -69,46 +69,53 @@
                 "android.hardware.common-V2",
             ],
         },
-
     ],
-    frozen: true,
-
+    frozen: false,
 }
 
+power_version = "android.hardware.power-V6"
+
 cc_defaults {
     name: "android.hardware.power-ndk_shared",
     shared_libs: [
-        "android.hardware.power-V5-ndk",
+        power_version + "-ndk",
     ],
 }
 
 cc_defaults {
     name: "android.hardware.power-ndk_export_shared",
     shared_libs: [
-        "android.hardware.power-V5-ndk",
+        power_version + "-ndk",
     ],
     export_shared_lib_headers: [
-        "android.hardware.power-V5-ndk",
+        power_version + "-ndk",
     ],
 }
 
 cc_defaults {
     name: "android.hardware.power-ndk_static",
     static_libs: [
-        "android.hardware.power-V5-ndk",
+        power_version + "-ndk",
     ],
 }
 
 java_defaults {
     name: "android.hardware.power-java_shared",
     libs: [
-        "android.hardware.power-V5-java",
+        power_version + "-java",
     ],
 }
 
 java_defaults {
     name: "android.hardware.power-java_static",
     static_libs: [
-        "android.hardware.power-V5-java",
+        power_version + "-java",
+    ],
+}
+
+aidl_interface_defaults {
+    name: "android.hardware.power-aidl",
+    imports: [
+        power_version,
     ],
 }
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPower.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPower.aidl
index 8acdaf2..8d8fb88 100644
--- a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPower.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPower.aidl
@@ -43,4 +43,5 @@
   android.hardware.power.IPowerHintSession createHintSessionWithConfig(in int tgid, in int uid, in int[] threadIds, in long durationNanos, in android.hardware.power.SessionTag tag, out android.hardware.power.SessionConfig config);
   android.hardware.power.ChannelConfig getSessionChannel(in int tgid, in int uid);
   oneway void closeSessionChannel(in int tgid, in int uid);
+  android.hardware.power.SupportInfo getSupportInfo();
 }
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionTag.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionTag.aidl
index 862fbc5..71da2d4 100644
--- a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionTag.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionTag.aidl
@@ -39,4 +39,5 @@
   HWUI,
   GAME,
   APP,
+  SYSUI,
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SupportInfo.aidl
similarity index 88%
rename from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
rename to power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SupportInfo.aidl
index 173ac17..85da2fc 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SupportInfo.aidl
@@ -31,10 +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.power;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable SupportInfo {
+  boolean usesSessions;
+  long boosts;
+  long modes;
+  long sessionHints;
+  long sessionModes;
+  long sessionTags;
 }
diff --git a/power/aidl/android/hardware/power/IPower.aidl b/power/aidl/android/hardware/power/IPower.aidl
index e25714f..2f15648 100644
--- a/power/aidl/android/hardware/power/IPower.aidl
+++ b/power/aidl/android/hardware/power/IPower.aidl
@@ -22,6 +22,7 @@
 import android.hardware.power.Mode;
 import android.hardware.power.SessionConfig;
 import android.hardware.power.SessionTag;
+import android.hardware.power.SupportInfo;
 
 @VintfStability
 interface IPower {
@@ -144,4 +145,14 @@
      * @param   uid The UID to be associated with this channel.
      */
     oneway void closeSessionChannel(in int tgid, in int uid);
+
+    /**
+     * Called to get detailed information on the support status of various PowerHAL
+     * features, such as hint sessions and specific boosts.
+     *
+     * @return  a SupportInfo giving detailed support information, or
+     *          EX_UNSUPPORTED_OPERATION if detailed support checking is itself
+     *          not supported.
+     */
+    SupportInfo getSupportInfo();
 }
diff --git a/power/aidl/android/hardware/power/SessionTag.aidl b/power/aidl/android/hardware/power/SessionTag.aidl
index 27bf3e3..e98cc77 100644
--- a/power/aidl/android/hardware/power/SessionTag.aidl
+++ b/power/aidl/android/hardware/power/SessionTag.aidl
@@ -46,4 +46,9 @@
      * instead.
      */
     APP,
+
+    /**
+     * This tag is used to mark hint sessions created by the system UI.
+     */
+    SYSUI,
 }
diff --git a/power/aidl/android/hardware/power/SupportInfo.aidl b/power/aidl/android/hardware/power/SupportInfo.aidl
new file mode 100644
index 0000000..46bcdd3
--- /dev/null
+++ b/power/aidl/android/hardware/power/SupportInfo.aidl
@@ -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.
+ */
+
+package android.hardware.power;
+
+import android.hardware.power.Boost;
+import android.hardware.power.Mode;
+import android.hardware.power.SessionHint;
+import android.hardware.power.SessionMode;
+
+/**
+ * Tells clients the status of various PowerHAL features in a single call.
+ * SupportInfo consists of several bitsets, where each bit from the left
+ * corresponds to the support status of that same value of that enum index.
+ *
+ * For "Boost", having the first bit set would mean "INTERACTION"
+ * boost is supported, having the second bit set would mean
+ * "DISPLAY_UPDATE_IMMINENT" is supported, and so on. The expectation
+ * is that a client should be able to index the bitset like
+ * "(supportInfo.boosts >> Boost::AUDIO_LAUNCH) % 2" and it should return
+ * the support value of Boost::AUDIO_LAUNCH. This pattern is the same for
+ * all four support bitsets.
+ */
+@VintfStability
+parcelable SupportInfo {
+    /**
+     * Boolean representing whether hint sessions are supported on this device
+     */
+    boolean usesSessions;
+
+    /**
+     * The set of "Boost" enum values that are supported by this device
+     * Each bit should correspond to a value of the "Boost.aidl" enum
+     */
+    long boosts;
+
+    /**
+     * The set of "Mode" enum values that are supported by this device
+     * Each bit should correspond to a value of the "Mode.aidl" enum
+     */
+    long modes;
+
+    /**
+     * The set of "SessionHint" enum values that are supported by this device
+     * Each bit should correspond to a value of the "SessionHint.aidl" enum
+     */
+    long sessionHints;
+
+    /**
+     * The set of "SessionMode" enum values that are supported by this device
+     * Each bit should correspond to a value of the "SessionMode.aidl" enum
+     */
+    long sessionModes;
+
+    /**
+     * The set of "SessionTag" enum values that are supported by this device
+     * Each bit should correspond to a value of the "SessionTag.aidl" enum
+     */
+    long sessionTags;
+}
diff --git a/power/aidl/default/Power.cpp b/power/aidl/default/Power.cpp
index 64294e5..36d0055 100644
--- a/power/aidl/default/Power.cpp
+++ b/power/aidl/default/Power.cpp
@@ -41,6 +41,11 @@
                                      ndk::enum_range<Boost>().end()};
 const std::vector<Mode> MODE_RANGE{ndk::enum_range<Mode>().begin(), ndk::enum_range<Mode>().end()};
 
+template <class T>
+constexpr size_t enum_size() {
+    return static_cast<size_t>(*(ndk::enum_range<T>().end() - 1)) + 1;
+}
+
 ScopedAStatus Power::setMode(Mode type, bool enabled) {
     LOG(VERBOSE) << "Power setMode: " << static_cast<int32_t>(type) << " to: " << enabled;
     return ScopedAStatus::ok();
@@ -105,11 +110,30 @@
     return ndk::ScopedAStatus::ok();
 }
 
-ScopedAStatus Power::getHintSessionPreferredRate(int64_t* outNanoseconds) {
+ndk::ScopedAStatus Power::getHintSessionPreferredRate(int64_t* outNanoseconds) {
     *outNanoseconds = std::chrono::nanoseconds(1ms).count();
     return ScopedAStatus::ok();
 }
 
+template <class E>
+int64_t bitsForEnum() {
+    return static_cast<int64_t>(std::bitset<enum_size<E>()>().set().to_ullong());
+}
+
+ndk::ScopedAStatus Power::getSupportInfo(SupportInfo* _aidl_return) {
+    static SupportInfo supportInfo = {
+            .usesSessions = false,
+            .modes = bitsForEnum<Mode>(),
+            .boosts = bitsForEnum<Boost>(),
+            .sessionHints = 0,
+            .sessionModes = 0,
+            .sessionTags = 0,
+    };
+    // Copy the support object into the binder
+    *_aidl_return = supportInfo;
+    return ndk::ScopedAStatus::ok();
+}
+
 }  // namespace example
 }  // namespace impl
 }  // namespace power
diff --git a/power/aidl/default/Power.h b/power/aidl/default/Power.h
index baabaa7..ef524e1 100644
--- a/power/aidl/default/Power.h
+++ b/power/aidl/default/Power.h
@@ -44,6 +44,7 @@
     ndk::ScopedAStatus getSessionChannel(int32_t tgid, int32_t uid,
                                          ChannelConfig* _aidl_return) override;
     ndk::ScopedAStatus closeSessionChannel(int32_t tgid, int32_t uid) override;
+    ndk::ScopedAStatus getSupportInfo(SupportInfo* _aidl_return) override;
 
   private:
     std::vector<std::shared_ptr<IPowerHintSession>> mPowerHintSessions;
diff --git a/power/aidl/default/power-default.xml b/power/aidl/default/power-default.xml
index 418fb83..1bb73f3 100644
--- a/power/aidl/default/power-default.xml
+++ b/power/aidl/default/power-default.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.power</name>
-        <version>5</version>
+        <version>6</version>
         <fqname>IPower/default</fqname>
     </hal>
 </manifest>
diff --git a/power/aidl/vts/VtsHalPowerTargetTest.cpp b/power/aidl/vts/VtsHalPowerTargetTest.cpp
index 272674f..9684c38 100644
--- a/power/aidl/vts/VtsHalPowerTargetTest.cpp
+++ b/power/aidl/vts/VtsHalPowerTargetTest.cpp
@@ -45,6 +45,7 @@
 using android::hardware::power::Mode;
 using android::hardware::power::SessionHint;
 using android::hardware::power::SessionMode;
+using android::hardware::power::SupportInfo;
 using android::hardware::power::WorkDuration;
 using ChannelMessageContents = ChannelMessage::ChannelMessageContents;
 using ModeSetter = ChannelMessage::ChannelMessageContents::SessionModeSetter;
@@ -83,6 +84,16 @@
         static_cast<SessionMode>(static_cast<int32_t>(kSessionModes.back()) + 1),
 };
 
+template <class T>
+constexpr size_t enum_size() {
+    return static_cast<size_t>(*(ndk::enum_range<T>().end() - 1)) + 1;
+}
+
+template <class E>
+bool supportFromBitset(int64_t& supportInt, E type) {
+    return (supportInt >> static_cast<int>(type)) % 2;
+}
+
 class DurationWrapper : public WorkDuration {
   public:
     DurationWrapper(int64_t dur, int64_t time) {
@@ -288,6 +299,21 @@
     ASSERT_TRUE(supported);
 }
 
+TEST_P(PowerAidl, hasSupportInfo) {
+    SupportInfo config;
+    ASSERT_TRUE(power->getSupportInfo(&config).isOk());
+    for (Mode mode : kModes) {
+        bool supported;
+        power->isModeSupported(mode, &supported);
+        ASSERT_EQ(supported, supportFromBitset(config.modes, mode));
+    }
+    for (Boost boost : kBoosts) {
+        bool supported;
+        power->isBoostSupported(boost, &supported);
+        ASSERT_EQ(supported, supportFromBitset(config.boosts, boost));
+    }
+}
+
 TEST_P(HintSessionAidl, createAndCloseHintSession) {
     if (!mSessionSupport) {
         GTEST_SKIP() << "DEVICE not support Hint Session.";
diff --git a/radio/aidl/android/hardware/radio/network/CellIdentityLte.aidl b/radio/aidl/android/hardware/radio/network/CellIdentityLte.aidl
index c4c76cf..6912e02 100644
--- a/radio/aidl/android/hardware/radio/network/CellIdentityLte.aidl
+++ b/radio/aidl/android/hardware/radio/network/CellIdentityLte.aidl
@@ -33,7 +33,7 @@
      */
     String mnc;
     /**
-     * 28-bit Cell Identity described in TS TS 27.007, INT_MAX if unknown
+     * 28-bit Cell Identity described in TS 27.007, INT_MAX if unknown
      */
     int ci;
     /**
diff --git a/radio/aidl/android/hardware/radio/sim/IRadioSimResponse.aidl b/radio/aidl/android/hardware/radio/sim/IRadioSimResponse.aidl
index cf08bad..8666e03 100644
--- a/radio/aidl/android/hardware/radio/sim/IRadioSimResponse.aidl
+++ b/radio/aidl/android/hardware/radio/sim/IRadioSimResponse.aidl
@@ -381,6 +381,7 @@
      *   RadioError:INVALID_MODEM_STATE
      *   RadioError:SIM_ERR
      *   RadioError:INVALID_ARGUMENTS
+     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void requestIccSimAuthenticationResponse(in RadioResponseInfo info, in IccIoResult result);
 
diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
index 914cad0..3d24165 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -609,6 +609,11 @@
         }
     }
 
+    if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+        GTEST_SKIP() << "Skipping setSignalStrengthReportingCriteria_Cdma2000 "
+                        "due to undefined FEATURE_TELEPHONY_CDMA";
+    }
+
     serial = GetRandomSerialNumber();
 
     SignalThresholdInfo signalThresholdInfo;
@@ -824,9 +829,12 @@
     signalThresholdInfoNgran.isEnabled = true;
     signalThresholdInfoNgran.ran = AccessNetwork::NGRAN;
 
-    const static std::vector<SignalThresholdInfo> candidateSignalThresholdInfos = {
+    std::vector<SignalThresholdInfo> candidateSignalThresholdInfos = {
             signalThresholdInfoGeran, signalThresholdInfoUtran, signalThresholdInfoEutran,
-            signalThresholdInfoCdma2000, signalThresholdInfoNgran};
+            signalThresholdInfoNgran};
+    if (deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+        candidateSignalThresholdInfos.push_back(signalThresholdInfoCdma2000);
+    }
 
     std::vector<SignalThresholdInfo> supportedSignalThresholdInfos;
     for (size_t i = 0; i < candidateSignalThresholdInfos.size(); i++) {
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.bp b/security/keymint/aidl/Android.bp
index e346610..a2e58ac 100644
--- a/security/keymint/aidl/Android.bp
+++ b/security/keymint/aidl/Android.bp
@@ -17,7 +17,7 @@
         "android.hardware.security.secureclock-V1",
     ],
     stability: "vintf",
-    frozen: true,
+    frozen: false,
     backend: {
         java: {
             platform_apis: true,
@@ -51,34 +51,42 @@
 
 }
 
+// An aidl_interface_defaults that includes the latest KeyMint AIDL interface.
+// aidl_interface modules that depend on KeyMint directly can include this
+// aidl_interface_defaults to avoid managing dependency versions explicitly.
+aidl_interface_defaults {
+    name: "android.hardware.security.keymint-latest-defaults",
+    imports: ["android.hardware.security.keymint-V4"],
+}
+
 // cc_defaults that includes the latest KeyMint AIDL library.
 // Modules that depend on KeyMint directly can include this cc_defaults to avoid
 // managing dependency versions explicitly.
 cc_defaults {
     name: "keymint_use_latest_hal_aidl_ndk_static",
     static_libs: [
-        "android.hardware.security.keymint-V3-ndk",
+        "android.hardware.security.keymint-V4-ndk",
     ],
 }
 
 cc_defaults {
     name: "keymint_use_latest_hal_aidl_ndk_shared",
     shared_libs: [
-        "android.hardware.security.keymint-V3-ndk",
+        "android.hardware.security.keymint-V4-ndk",
     ],
 }
 
 cc_defaults {
     name: "keymint_use_latest_hal_aidl_cpp_static",
     static_libs: [
-        "android.hardware.security.keymint-V3-cpp",
+        "android.hardware.security.keymint-V4-cpp",
     ],
 }
 
 cc_defaults {
     name: "keymint_use_latest_hal_aidl_cpp_shared",
     shared_libs: [
-        "android.hardware.security.keymint-V3-cpp",
+        "android.hardware.security.keymint-V4-cpp",
     ],
 }
 
@@ -88,6 +96,6 @@
 rust_defaults {
     name: "keymint_use_latest_hal_aidl_rust",
     rustlibs: [
-        "android.hardware.security.keymint-V3-rust",
+        "android.hardware.security.keymint-V4-rust",
     ],
 }
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl
index b05a0f3..71d3651 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl
@@ -36,90 +36,91 @@
 @Backing(type="int") @VintfStability
 enum ErrorCode {
   OK = 0,
-  ROOT_OF_TRUST_ALREADY_SET = -1,
-  UNSUPPORTED_PURPOSE = -2,
-  INCOMPATIBLE_PURPOSE = -3,
-  UNSUPPORTED_ALGORITHM = -4,
-  INCOMPATIBLE_ALGORITHM = -5,
-  UNSUPPORTED_KEY_SIZE = -6,
-  UNSUPPORTED_BLOCK_MODE = -7,
-  INCOMPATIBLE_BLOCK_MODE = -8,
-  UNSUPPORTED_MAC_LENGTH = -9,
-  UNSUPPORTED_PADDING_MODE = -10,
-  INCOMPATIBLE_PADDING_MODE = -11,
-  UNSUPPORTED_DIGEST = -12,
-  INCOMPATIBLE_DIGEST = -13,
-  INVALID_EXPIRATION_TIME = -14,
-  INVALID_USER_ID = -15,
-  INVALID_AUTHORIZATION_TIMEOUT = -16,
-  UNSUPPORTED_KEY_FORMAT = -17,
-  INCOMPATIBLE_KEY_FORMAT = -18,
-  UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM = -19,
-  UNSUPPORTED_KEY_VERIFICATION_ALGORITHM = -20,
-  INVALID_INPUT_LENGTH = -21,
-  KEY_EXPORT_OPTIONS_INVALID = -22,
-  DELEGATION_NOT_ALLOWED = -23,
-  KEY_NOT_YET_VALID = -24,
-  KEY_EXPIRED = -25,
-  KEY_USER_NOT_AUTHENTICATED = -26,
-  OUTPUT_PARAMETER_NULL = -27,
-  INVALID_OPERATION_HANDLE = -28,
-  INSUFFICIENT_BUFFER_SPACE = -29,
-  VERIFICATION_FAILED = -30,
-  TOO_MANY_OPERATIONS = -31,
-  UNEXPECTED_NULL_POINTER = -32,
-  INVALID_KEY_BLOB = -33,
-  IMPORTED_KEY_NOT_ENCRYPTED = -34,
-  IMPORTED_KEY_DECRYPTION_FAILED = -35,
-  IMPORTED_KEY_NOT_SIGNED = -36,
-  IMPORTED_KEY_VERIFICATION_FAILED = -37,
-  INVALID_ARGUMENT = -38,
-  UNSUPPORTED_TAG = -39,
-  INVALID_TAG = -40,
-  MEMORY_ALLOCATION_FAILED = -41,
-  IMPORT_PARAMETER_MISMATCH = -44,
-  SECURE_HW_ACCESS_DENIED = -45,
-  OPERATION_CANCELLED = -46,
-  CONCURRENT_ACCESS_CONFLICT = -47,
-  SECURE_HW_BUSY = -48,
-  SECURE_HW_COMMUNICATION_FAILED = -49,
-  UNSUPPORTED_EC_FIELD = -50,
-  MISSING_NONCE = -51,
-  INVALID_NONCE = -52,
-  MISSING_MAC_LENGTH = -53,
-  KEY_RATE_LIMIT_EXCEEDED = -54,
-  CALLER_NONCE_PROHIBITED = -55,
-  KEY_MAX_OPS_EXCEEDED = -56,
-  INVALID_MAC_LENGTH = -57,
-  MISSING_MIN_MAC_LENGTH = -58,
-  UNSUPPORTED_MIN_MAC_LENGTH = -59,
-  UNSUPPORTED_KDF = -60,
-  UNSUPPORTED_EC_CURVE = -61,
-  KEY_REQUIRES_UPGRADE = -62,
-  ATTESTATION_CHALLENGE_MISSING = -63,
-  KEYMINT_NOT_CONFIGURED = -64,
-  ATTESTATION_APPLICATION_ID_MISSING = -65,
-  CANNOT_ATTEST_IDS = -66,
-  ROLLBACK_RESISTANCE_UNAVAILABLE = -67,
-  HARDWARE_TYPE_UNAVAILABLE = -68,
-  PROOF_OF_PRESENCE_REQUIRED = -69,
-  CONCURRENT_PROOF_OF_PRESENCE_REQUESTED = -70,
-  NO_USER_CONFIRMATION = -71,
-  DEVICE_LOCKED = -72,
-  EARLY_BOOT_ENDED = -73,
-  ATTESTATION_KEYS_NOT_PROVISIONED = -74,
-  ATTESTATION_IDS_NOT_PROVISIONED = -75,
-  INVALID_OPERATION = -76,
-  STORAGE_KEY_UNSUPPORTED = -77,
-  INCOMPATIBLE_MGF_DIGEST = -78,
-  UNSUPPORTED_MGF_DIGEST = -79,
-  MISSING_NOT_BEFORE = -80,
-  MISSING_NOT_AFTER = -81,
-  MISSING_ISSUER_SUBJECT = -82,
-  INVALID_ISSUER_SUBJECT = -83,
-  BOOT_LEVEL_EXCEEDED = -84,
-  HARDWARE_NOT_YET_AVAILABLE = -85,
-  UNIMPLEMENTED = -100,
-  VERSION_MISMATCH = -101,
-  UNKNOWN_ERROR = -1000,
+  ROOT_OF_TRUST_ALREADY_SET = (-1) /* -1 */,
+  UNSUPPORTED_PURPOSE = (-2) /* -2 */,
+  INCOMPATIBLE_PURPOSE = (-3) /* -3 */,
+  UNSUPPORTED_ALGORITHM = (-4) /* -4 */,
+  INCOMPATIBLE_ALGORITHM = (-5) /* -5 */,
+  UNSUPPORTED_KEY_SIZE = (-6) /* -6 */,
+  UNSUPPORTED_BLOCK_MODE = (-7) /* -7 */,
+  INCOMPATIBLE_BLOCK_MODE = (-8) /* -8 */,
+  UNSUPPORTED_MAC_LENGTH = (-9) /* -9 */,
+  UNSUPPORTED_PADDING_MODE = (-10) /* -10 */,
+  INCOMPATIBLE_PADDING_MODE = (-11) /* -11 */,
+  UNSUPPORTED_DIGEST = (-12) /* -12 */,
+  INCOMPATIBLE_DIGEST = (-13) /* -13 */,
+  INVALID_EXPIRATION_TIME = (-14) /* -14 */,
+  INVALID_USER_ID = (-15) /* -15 */,
+  INVALID_AUTHORIZATION_TIMEOUT = (-16) /* -16 */,
+  UNSUPPORTED_KEY_FORMAT = (-17) /* -17 */,
+  INCOMPATIBLE_KEY_FORMAT = (-18) /* -18 */,
+  UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM = (-19) /* -19 */,
+  UNSUPPORTED_KEY_VERIFICATION_ALGORITHM = (-20) /* -20 */,
+  INVALID_INPUT_LENGTH = (-21) /* -21 */,
+  KEY_EXPORT_OPTIONS_INVALID = (-22) /* -22 */,
+  DELEGATION_NOT_ALLOWED = (-23) /* -23 */,
+  KEY_NOT_YET_VALID = (-24) /* -24 */,
+  KEY_EXPIRED = (-25) /* -25 */,
+  KEY_USER_NOT_AUTHENTICATED = (-26) /* -26 */,
+  OUTPUT_PARAMETER_NULL = (-27) /* -27 */,
+  INVALID_OPERATION_HANDLE = (-28) /* -28 */,
+  INSUFFICIENT_BUFFER_SPACE = (-29) /* -29 */,
+  VERIFICATION_FAILED = (-30) /* -30 */,
+  TOO_MANY_OPERATIONS = (-31) /* -31 */,
+  UNEXPECTED_NULL_POINTER = (-32) /* -32 */,
+  INVALID_KEY_BLOB = (-33) /* -33 */,
+  IMPORTED_KEY_NOT_ENCRYPTED = (-34) /* -34 */,
+  IMPORTED_KEY_DECRYPTION_FAILED = (-35) /* -35 */,
+  IMPORTED_KEY_NOT_SIGNED = (-36) /* -36 */,
+  IMPORTED_KEY_VERIFICATION_FAILED = (-37) /* -37 */,
+  INVALID_ARGUMENT = (-38) /* -38 */,
+  UNSUPPORTED_TAG = (-39) /* -39 */,
+  INVALID_TAG = (-40) /* -40 */,
+  MEMORY_ALLOCATION_FAILED = (-41) /* -41 */,
+  IMPORT_PARAMETER_MISMATCH = (-44) /* -44 */,
+  SECURE_HW_ACCESS_DENIED = (-45) /* -45 */,
+  OPERATION_CANCELLED = (-46) /* -46 */,
+  CONCURRENT_ACCESS_CONFLICT = (-47) /* -47 */,
+  SECURE_HW_BUSY = (-48) /* -48 */,
+  SECURE_HW_COMMUNICATION_FAILED = (-49) /* -49 */,
+  UNSUPPORTED_EC_FIELD = (-50) /* -50 */,
+  MISSING_NONCE = (-51) /* -51 */,
+  INVALID_NONCE = (-52) /* -52 */,
+  MISSING_MAC_LENGTH = (-53) /* -53 */,
+  KEY_RATE_LIMIT_EXCEEDED = (-54) /* -54 */,
+  CALLER_NONCE_PROHIBITED = (-55) /* -55 */,
+  KEY_MAX_OPS_EXCEEDED = (-56) /* -56 */,
+  INVALID_MAC_LENGTH = (-57) /* -57 */,
+  MISSING_MIN_MAC_LENGTH = (-58) /* -58 */,
+  UNSUPPORTED_MIN_MAC_LENGTH = (-59) /* -59 */,
+  UNSUPPORTED_KDF = (-60) /* -60 */,
+  UNSUPPORTED_EC_CURVE = (-61) /* -61 */,
+  KEY_REQUIRES_UPGRADE = (-62) /* -62 */,
+  ATTESTATION_CHALLENGE_MISSING = (-63) /* -63 */,
+  KEYMINT_NOT_CONFIGURED = (-64) /* -64 */,
+  ATTESTATION_APPLICATION_ID_MISSING = (-65) /* -65 */,
+  CANNOT_ATTEST_IDS = (-66) /* -66 */,
+  ROLLBACK_RESISTANCE_UNAVAILABLE = (-67) /* -67 */,
+  HARDWARE_TYPE_UNAVAILABLE = (-68) /* -68 */,
+  PROOF_OF_PRESENCE_REQUIRED = (-69) /* -69 */,
+  CONCURRENT_PROOF_OF_PRESENCE_REQUESTED = (-70) /* -70 */,
+  NO_USER_CONFIRMATION = (-71) /* -71 */,
+  DEVICE_LOCKED = (-72) /* -72 */,
+  EARLY_BOOT_ENDED = (-73) /* -73 */,
+  ATTESTATION_KEYS_NOT_PROVISIONED = (-74) /* -74 */,
+  ATTESTATION_IDS_NOT_PROVISIONED = (-75) /* -75 */,
+  INVALID_OPERATION = (-76) /* -76 */,
+  STORAGE_KEY_UNSUPPORTED = (-77) /* -77 */,
+  INCOMPATIBLE_MGF_DIGEST = (-78) /* -78 */,
+  UNSUPPORTED_MGF_DIGEST = (-79) /* -79 */,
+  MISSING_NOT_BEFORE = (-80) /* -80 */,
+  MISSING_NOT_AFTER = (-81) /* -81 */,
+  MISSING_ISSUER_SUBJECT = (-82) /* -82 */,
+  INVALID_ISSUER_SUBJECT = (-83) /* -83 */,
+  BOOT_LEVEL_EXCEEDED = (-84) /* -84 */,
+  HARDWARE_NOT_YET_AVAILABLE = (-85) /* -85 */,
+  MODULE_HASH_ALREADY_SET = (-86) /* -86 */,
+  UNIMPLEMENTED = (-100) /* -100 */,
+  VERSION_MISMATCH = (-101) /* -101 */,
+  UNKNOWN_ERROR = (-1000) /* -1000 */,
 }
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/HardwareAuthenticatorType.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/HardwareAuthenticatorType.aidl
index dfc98f0..eb4f621 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/HardwareAuthenticatorType.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/HardwareAuthenticatorType.aidl
@@ -36,7 +36,7 @@
 @Backing(type="int") @VintfStability
 enum HardwareAuthenticatorType {
   NONE = 0,
-  PASSWORD = 1,
-  FINGERPRINT = 2,
-  ANY = -1,
+  PASSWORD = (1 << 0) /* 1 */,
+  FINGERPRINT = (1 << 1) /* 2 */,
+  ANY = 0xFFFFFFFF,
 }
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
index dcc22c4..2945dab 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -52,5 +52,6 @@
   byte[16] getRootOfTrustChallenge();
   byte[] getRootOfTrust(in byte[16] challenge);
   void sendRootOfTrust(in byte[] rootOfTrust);
+  void setAdditionalAttestationInfo(in android.hardware.security.keymint.KeyParameter[] info);
   const int AUTH_TOKEN_MAC_LENGTH = 32;
 }
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl
index 6ae2369..79341ee 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl
@@ -36,69 +36,70 @@
 @Backing(type="int") @VintfStability
 enum Tag {
   INVALID = 0,
-  PURPOSE = 536870913,
-  ALGORITHM = 268435458,
-  KEY_SIZE = 805306371,
-  BLOCK_MODE = 536870916,
-  DIGEST = 536870917,
-  PADDING = 536870918,
-  CALLER_NONCE = 1879048199,
-  MIN_MAC_LENGTH = 805306376,
-  EC_CURVE = 268435466,
-  RSA_PUBLIC_EXPONENT = 1342177480,
-  INCLUDE_UNIQUE_ID = 1879048394,
-  RSA_OAEP_MGF_DIGEST = 536871115,
-  BOOTLOADER_ONLY = 1879048494,
-  ROLLBACK_RESISTANCE = 1879048495,
-  HARDWARE_TYPE = 268435760,
-  EARLY_BOOT_ONLY = 1879048497,
-  ACTIVE_DATETIME = 1610613136,
-  ORIGINATION_EXPIRE_DATETIME = 1610613137,
-  USAGE_EXPIRE_DATETIME = 1610613138,
-  MIN_SECONDS_BETWEEN_OPS = 805306771,
-  MAX_USES_PER_BOOT = 805306772,
-  USAGE_COUNT_LIMIT = 805306773,
-  USER_ID = 805306869,
-  USER_SECURE_ID = -1610612234,
-  NO_AUTH_REQUIRED = 1879048695,
-  USER_AUTH_TYPE = 268435960,
-  AUTH_TIMEOUT = 805306873,
-  ALLOW_WHILE_ON_BODY = 1879048698,
-  TRUSTED_USER_PRESENCE_REQUIRED = 1879048699,
-  TRUSTED_CONFIRMATION_REQUIRED = 1879048700,
-  UNLOCKED_DEVICE_REQUIRED = 1879048701,
-  APPLICATION_ID = -1879047591,
-  APPLICATION_DATA = -1879047492,
-  CREATION_DATETIME = 1610613437,
-  ORIGIN = 268436158,
-  ROOT_OF_TRUST = -1879047488,
-  OS_VERSION = 805307073,
-  OS_PATCHLEVEL = 805307074,
-  UNIQUE_ID = -1879047485,
-  ATTESTATION_CHALLENGE = -1879047484,
-  ATTESTATION_APPLICATION_ID = -1879047483,
-  ATTESTATION_ID_BRAND = -1879047482,
-  ATTESTATION_ID_DEVICE = -1879047481,
-  ATTESTATION_ID_PRODUCT = -1879047480,
-  ATTESTATION_ID_SERIAL = -1879047479,
-  ATTESTATION_ID_IMEI = -1879047478,
-  ATTESTATION_ID_MEID = -1879047477,
-  ATTESTATION_ID_MANUFACTURER = -1879047476,
-  ATTESTATION_ID_MODEL = -1879047475,
-  VENDOR_PATCHLEVEL = 805307086,
-  BOOT_PATCHLEVEL = 805307087,
-  DEVICE_UNIQUE_ATTESTATION = 1879048912,
-  IDENTITY_CREDENTIAL_KEY = 1879048913,
-  STORAGE_KEY = 1879048914,
-  ATTESTATION_ID_SECOND_IMEI = -1879047469,
-  ASSOCIATED_DATA = -1879047192,
-  NONCE = -1879047191,
-  MAC_LENGTH = 805307371,
-  RESET_SINCE_ID_ROTATION = 1879049196,
-  CONFIRMATION_TOKEN = -1879047187,
-  CERTIFICATE_SERIAL = -2147482642,
-  CERTIFICATE_SUBJECT = -1879047185,
-  CERTIFICATE_NOT_BEFORE = 1610613744,
-  CERTIFICATE_NOT_AFTER = 1610613745,
-  MAX_BOOT_LEVEL = 805307378,
+  PURPOSE = (android.hardware.security.keymint.TagType.ENUM_REP | 1) /* 536870913 */,
+  ALGORITHM = (android.hardware.security.keymint.TagType.ENUM | 2) /* 268435458 */,
+  KEY_SIZE = (android.hardware.security.keymint.TagType.UINT | 3) /* 805306371 */,
+  BLOCK_MODE = (android.hardware.security.keymint.TagType.ENUM_REP | 4) /* 536870916 */,
+  DIGEST = (android.hardware.security.keymint.TagType.ENUM_REP | 5) /* 536870917 */,
+  PADDING = (android.hardware.security.keymint.TagType.ENUM_REP | 6) /* 536870918 */,
+  CALLER_NONCE = (android.hardware.security.keymint.TagType.BOOL | 7) /* 1879048199 */,
+  MIN_MAC_LENGTH = (android.hardware.security.keymint.TagType.UINT | 8) /* 805306376 */,
+  EC_CURVE = (android.hardware.security.keymint.TagType.ENUM | 10) /* 268435466 */,
+  RSA_PUBLIC_EXPONENT = (android.hardware.security.keymint.TagType.ULONG | 200) /* 1342177480 */,
+  INCLUDE_UNIQUE_ID = (android.hardware.security.keymint.TagType.BOOL | 202) /* 1879048394 */,
+  RSA_OAEP_MGF_DIGEST = (android.hardware.security.keymint.TagType.ENUM_REP | 203) /* 536871115 */,
+  BOOTLOADER_ONLY = (android.hardware.security.keymint.TagType.BOOL | 302) /* 1879048494 */,
+  ROLLBACK_RESISTANCE = (android.hardware.security.keymint.TagType.BOOL | 303) /* 1879048495 */,
+  HARDWARE_TYPE = (android.hardware.security.keymint.TagType.ENUM | 304) /* 268435760 */,
+  EARLY_BOOT_ONLY = (android.hardware.security.keymint.TagType.BOOL | 305) /* 1879048497 */,
+  ACTIVE_DATETIME = (android.hardware.security.keymint.TagType.DATE | 400) /* 1610613136 */,
+  ORIGINATION_EXPIRE_DATETIME = (android.hardware.security.keymint.TagType.DATE | 401) /* 1610613137 */,
+  USAGE_EXPIRE_DATETIME = (android.hardware.security.keymint.TagType.DATE | 402) /* 1610613138 */,
+  MIN_SECONDS_BETWEEN_OPS = (android.hardware.security.keymint.TagType.UINT | 403) /* 805306771 */,
+  MAX_USES_PER_BOOT = (android.hardware.security.keymint.TagType.UINT | 404) /* 805306772 */,
+  USAGE_COUNT_LIMIT = (android.hardware.security.keymint.TagType.UINT | 405) /* 805306773 */,
+  USER_ID = (android.hardware.security.keymint.TagType.UINT | 501) /* 805306869 */,
+  USER_SECURE_ID = (android.hardware.security.keymint.TagType.ULONG_REP | 502) /* -1610612234 */,
+  NO_AUTH_REQUIRED = (android.hardware.security.keymint.TagType.BOOL | 503) /* 1879048695 */,
+  USER_AUTH_TYPE = (android.hardware.security.keymint.TagType.ENUM | 504) /* 268435960 */,
+  AUTH_TIMEOUT = (android.hardware.security.keymint.TagType.UINT | 505) /* 805306873 */,
+  ALLOW_WHILE_ON_BODY = (android.hardware.security.keymint.TagType.BOOL | 506) /* 1879048698 */,
+  TRUSTED_USER_PRESENCE_REQUIRED = (android.hardware.security.keymint.TagType.BOOL | 507) /* 1879048699 */,
+  TRUSTED_CONFIRMATION_REQUIRED = (android.hardware.security.keymint.TagType.BOOL | 508) /* 1879048700 */,
+  UNLOCKED_DEVICE_REQUIRED = (android.hardware.security.keymint.TagType.BOOL | 509) /* 1879048701 */,
+  APPLICATION_ID = (android.hardware.security.keymint.TagType.BYTES | 601) /* -1879047591 */,
+  APPLICATION_DATA = (android.hardware.security.keymint.TagType.BYTES | 700) /* -1879047492 */,
+  CREATION_DATETIME = (android.hardware.security.keymint.TagType.DATE | 701) /* 1610613437 */,
+  ORIGIN = (android.hardware.security.keymint.TagType.ENUM | 702) /* 268436158 */,
+  ROOT_OF_TRUST = (android.hardware.security.keymint.TagType.BYTES | 704) /* -1879047488 */,
+  OS_VERSION = (android.hardware.security.keymint.TagType.UINT | 705) /* 805307073 */,
+  OS_PATCHLEVEL = (android.hardware.security.keymint.TagType.UINT | 706) /* 805307074 */,
+  UNIQUE_ID = (android.hardware.security.keymint.TagType.BYTES | 707) /* -1879047485 */,
+  ATTESTATION_CHALLENGE = (android.hardware.security.keymint.TagType.BYTES | 708) /* -1879047484 */,
+  ATTESTATION_APPLICATION_ID = (android.hardware.security.keymint.TagType.BYTES | 709) /* -1879047483 */,
+  ATTESTATION_ID_BRAND = (android.hardware.security.keymint.TagType.BYTES | 710) /* -1879047482 */,
+  ATTESTATION_ID_DEVICE = (android.hardware.security.keymint.TagType.BYTES | 711) /* -1879047481 */,
+  ATTESTATION_ID_PRODUCT = (android.hardware.security.keymint.TagType.BYTES | 712) /* -1879047480 */,
+  ATTESTATION_ID_SERIAL = (android.hardware.security.keymint.TagType.BYTES | 713) /* -1879047479 */,
+  ATTESTATION_ID_IMEI = (android.hardware.security.keymint.TagType.BYTES | 714) /* -1879047478 */,
+  ATTESTATION_ID_MEID = (android.hardware.security.keymint.TagType.BYTES | 715) /* -1879047477 */,
+  ATTESTATION_ID_MANUFACTURER = (android.hardware.security.keymint.TagType.BYTES | 716) /* -1879047476 */,
+  ATTESTATION_ID_MODEL = (android.hardware.security.keymint.TagType.BYTES | 717) /* -1879047475 */,
+  VENDOR_PATCHLEVEL = (android.hardware.security.keymint.TagType.UINT | 718) /* 805307086 */,
+  BOOT_PATCHLEVEL = (android.hardware.security.keymint.TagType.UINT | 719) /* 805307087 */,
+  DEVICE_UNIQUE_ATTESTATION = (android.hardware.security.keymint.TagType.BOOL | 720) /* 1879048912 */,
+  IDENTITY_CREDENTIAL_KEY = (android.hardware.security.keymint.TagType.BOOL | 721) /* 1879048913 */,
+  STORAGE_KEY = (android.hardware.security.keymint.TagType.BOOL | 722) /* 1879048914 */,
+  ATTESTATION_ID_SECOND_IMEI = (android.hardware.security.keymint.TagType.BYTES | 723) /* -1879047469 */,
+  MODULE_HASH = (android.hardware.security.keymint.TagType.BYTES | 724) /* -1879047468 */,
+  ASSOCIATED_DATA = (android.hardware.security.keymint.TagType.BYTES | 1000) /* -1879047192 */,
+  NONCE = (android.hardware.security.keymint.TagType.BYTES | 1001) /* -1879047191 */,
+  MAC_LENGTH = (android.hardware.security.keymint.TagType.UINT | 1003) /* 805307371 */,
+  RESET_SINCE_ID_ROTATION = (android.hardware.security.keymint.TagType.BOOL | 1004) /* 1879049196 */,
+  CONFIRMATION_TOKEN = (android.hardware.security.keymint.TagType.BYTES | 1005) /* -1879047187 */,
+  CERTIFICATE_SERIAL = (android.hardware.security.keymint.TagType.BIGNUM | 1006) /* -2147482642 */,
+  CERTIFICATE_SUBJECT = (android.hardware.security.keymint.TagType.BYTES | 1007) /* -1879047185 */,
+  CERTIFICATE_NOT_BEFORE = (android.hardware.security.keymint.TagType.DATE | 1008) /* 1610613744 */,
+  CERTIFICATE_NOT_AFTER = (android.hardware.security.keymint.TagType.DATE | 1009) /* 1610613745 */,
+  MAX_BOOT_LEVEL = (android.hardware.security.keymint.TagType.UINT | 1010) /* 805307378 */,
 }
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/TagType.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/TagType.aidl
index a7d1de5..ca19e7e 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/TagType.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/TagType.aidl
@@ -35,15 +35,15 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum TagType {
-  INVALID = 0,
-  ENUM = 268435456,
-  ENUM_REP = 536870912,
-  UINT = 805306368,
-  UINT_REP = 1073741824,
-  ULONG = 1342177280,
-  DATE = 1610612736,
-  BOOL = 1879048192,
-  BIGNUM = -2147483648,
-  BYTES = -1879048192,
-  ULONG_REP = -1610612736,
+  INVALID = (0 << 28) /* 0 */,
+  ENUM = (1 << 28) /* 268435456 */,
+  ENUM_REP = (2 << 28) /* 536870912 */,
+  UINT = (3 << 28) /* 805306368 */,
+  UINT_REP = (4 << 28) /* 1073741824 */,
+  ULONG = (5 << 28) /* 1342177280 */,
+  DATE = (6 << 28) /* 1610612736 */,
+  BOOL = (7 << 28) /* 1879048192 */,
+  BIGNUM = (8 << 28) /* -2147483648 */,
+  BYTES = (9 << 28) /* -1879048192 */,
+  ULONG_REP = (10 << 28) /* -1610612736 */,
 }
diff --git a/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl b/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl
index 137e6b6..72fa773 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl
@@ -108,6 +108,7 @@
     INVALID_ISSUER_SUBJECT = -83,
     BOOT_LEVEL_EXCEEDED = -84,
     HARDWARE_NOT_YET_AVAILABLE = -85,
+    MODULE_HASH_ALREADY_SET = -86,
 
     UNIMPLEMENTED = -100,
     VERSION_MISMATCH = -101,
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index 4ebafee..e8eed71 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -959,4 +959,17 @@
      * not implemented.  TEE KeyMint implementations must return ErrorCode::UNIMPLEMENTED.
      */
     void sendRootOfTrust(in byte[] rootOfTrust);
+
+    /**
+     * Called by Android to deliver additional attestation information to the IKeyMintDevice.
+     *
+     * IKeyMintDevice must ignore KeyParameters with tags not included in the following list:
+     *
+     * o Tag::MODULE_HASH: holds a hash that must be included in attestations in the moduleHash
+     *   field of the software enforced authorization list. If Tag::MODULE_HASH is included in more
+     *   than one setAdditionalAttestationInfo call, the implementation should compare the initial
+     *   KeyParamValue with the more recent one. If they differ, the implementation should fail with
+     *   ErrorCode::MODULE_HASH_ALREADY_SET. If they are the same, no action needs to be taken.
+     */
+    void setAdditionalAttestationInfo(in KeyParameter[] info);
 }
diff --git a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
index 996e4e3..e56c193 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
@@ -901,6 +901,17 @@
     ATTESTATION_ID_SECOND_IMEI = TagType.BYTES | 723,
 
     /**
+     * Tag::MODULE_HASH specifies the SHA-256 hash of the DER-encoded module information (see
+     * KeyCreationResult.aidl for the ASN.1 schema).
+     *
+     * This tag is never provided or returned from KeyMint in the key characteristics. It exists
+     * only to define the tag for use in the attestation record.
+     *
+     * Must never appear in KeyCharacteristics.
+     */
+    MODULE_HASH = TagType.BYTES | 724,
+
+    /**
      * OBSOLETE: Do not use.
      *
      * This tag value is included for historical reasons -- in Keymaster it was used to hold
diff --git a/security/keymint/aidl/default/android.hardware.hardware_keystore.xml b/security/keymint/aidl/default/android.hardware.hardware_keystore.xml
index 4c75596..1ab2133 100644
--- a/security/keymint/aidl/default/android.hardware.hardware_keystore.xml
+++ b/security/keymint/aidl/default/android.hardware.hardware_keystore.xml
@@ -14,5 +14,5 @@
      limitations under the License.
 -->
 <permissions>
-  <feature name="android.hardware.hardware_keystore" version="300" />
+  <feature name="android.hardware.hardware_keystore" version="400" />
 </permissions>
diff --git a/security/keymint/aidl/default/android.hardware.security.keymint-service.xml b/security/keymint/aidl/default/android.hardware.security.keymint-service.xml
index 0568ae6..6bdd33e 100644
--- a/security/keymint/aidl/default/android.hardware.security.keymint-service.xml
+++ b/security/keymint/aidl/default/android.hardware.security.keymint-service.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.security.keymint</name>
-        <version>3</version>
+        <version>4</version>
         <fqname>IKeyMintDevice/default</fqname>
     </hal>
     <hal format="aidl">
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/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/aidl/Android.bp b/thermal/aidl/Android.bp
index 597a166..db77783 100644
--- a/thermal/aidl/Android.bp
+++ b/thermal/aidl/Android.bp
@@ -48,8 +48,7 @@
             version: "2",
             imports: [],
         },
-
     ],
-    frozen: true,
+    frozen: false,
 
 }
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermalChangedCallback.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermalChangedCallback.aidl
index 5e1d753..779544b 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermalChangedCallback.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermalChangedCallback.aidl
@@ -36,4 +36,5 @@
 @VintfStability
 interface IThermalChangedCallback {
   oneway void notifyThrottling(in android.hardware.thermal.Temperature temperature);
+  oneway void notifyThresholdChanged(in android.hardware.thermal.TemperatureThreshold threshold);
 }
diff --git a/thermal/aidl/android/hardware/thermal/IThermalChangedCallback.aidl b/thermal/aidl/android/hardware/thermal/IThermalChangedCallback.aidl
index 105f085..1ff4b7a 100644
--- a/thermal/aidl/android/hardware/thermal/IThermalChangedCallback.aidl
+++ b/thermal/aidl/android/hardware/thermal/IThermalChangedCallback.aidl
@@ -17,6 +17,7 @@
 package android.hardware.thermal;
 
 import android.hardware.thermal.Temperature;
+import android.hardware.thermal.TemperatureThreshold;
 
 /**
  * IThermalChangedCallback send throttling notification to clients.
@@ -25,11 +26,19 @@
 @VintfStability
 interface IThermalChangedCallback {
     /**
-     * Send a thermal throttling event to all ThermalHAL
+     * Send a thermal throttling event to all Thermal HAL
      * thermal event listeners.
      *
      * @param temperature The temperature associated with the
      *    throttling event.
      */
     oneway void notifyThrottling(in Temperature temperature);
+
+    /**
+     * Send a thermal threshold change event to all Thermal HAL
+     * thermal event listeners.
+     *
+     * @param threshold The temperature threshold that changed.
+     */
+    oneway void notifyThresholdChanged(in TemperatureThreshold threshold);
 }
diff --git a/thermal/aidl/default/Android.bp b/thermal/aidl/default/Android.bp
index 9fe62ce..9d89903 100644
--- a/thermal/aidl/default/Android.bp
+++ b/thermal/aidl/default/Android.bp
@@ -27,7 +27,7 @@
     vendor: true,
     stl: "c++_static",
     static_libs: [
-        "android.hardware.thermal-V2-ndk",
+        "android.hardware.thermal-V3-ndk",
         "libbase",
     ],
     shared_libs: [
diff --git a/thermal/aidl/default/thermal-example.xml b/thermal/aidl/default/thermal-example.xml
index 08dc68c..148ddbf 100644
--- a/thermal/aidl/default/thermal-example.xml
+++ b/thermal/aidl/default/thermal-example.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.thermal</name>
-        <version>2</version>
+        <version>3</version>
         <fqname>IThermal/default</fqname>
     </hal>
 </manifest>
diff --git a/thermal/aidl/vts/Android.bp b/thermal/aidl/vts/Android.bp
index 35f7649..18cb051 100644
--- a/thermal/aidl/vts/Android.bp
+++ b/thermal/aidl/vts/Android.bp
@@ -33,7 +33,7 @@
         "libbinder_ndk",
     ],
     static_libs: [
-        "android.hardware.thermal-V2-ndk",
+        "android.hardware.thermal-V3-ndk",
     ],
     test_suites: [
         "vts",
diff --git a/thermal/aidl/vts/VtsHalThermalTargetTest.cpp b/thermal/aidl/vts/VtsHalThermalTargetTest.cpp
index 7f33e2d..066e773 100644
--- a/thermal/aidl/vts/VtsHalThermalTargetTest.cpp
+++ b/thermal/aidl/vts/VtsHalThermalTargetTest.cpp
@@ -93,6 +93,10 @@
         return ndk::ScopedAStatus::ok();
     }
 
+    ndk::ScopedAStatus notifyThresholdChanged(const TemperatureThreshold&) {
+        return ndk::ScopedAStatus::ok();
+    }
+
     template <typename R, typename P>
     [[nodiscard]] bool waitForCallback(std::chrono::duration<R, P> duration) {
         std::unique_lock<std::mutex> lock(mMutex);
diff --git a/tv/mediaquality/OWNERS b/tv/mediaquality/OWNERS
new file mode 100644
index 0000000..35ca732
--- /dev/null
+++ b/tv/mediaquality/OWNERS
@@ -0,0 +1,3 @@
+quxiangfang@google.com
+shubang@google.com
+haofanw@google.com
\ No newline at end of file
diff --git a/tv/mediaquality/aidl/Android.bp b/tv/mediaquality/aidl/Android.bp
new file mode 100644
index 0000000..0084248
--- /dev/null
+++ b/tv/mediaquality/aidl/Android.bp
@@ -0,0 +1,38 @@
+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.tv.mediaquality",
+    vendor_available: true,
+    owner: "haofanw",
+    srcs: [
+        "android/hardware/tv/mediaquality/*.aidl",
+    ],
+    imports: [
+        "android.hardware.graphics.common-V5",
+    ],
+    stability: "vintf",
+    backend: {
+        java: {
+            enabled: true,
+            platform_apis: true,
+        },
+        ndk: {
+            enabled: true,
+            min_sdk_version: "29",
+        },
+        rust: {
+            enabled: true,
+        },
+        cpp: {
+            enabled: false,
+        },
+    },
+    frozen: false,
+}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/tv/mediaquality/aidl/aidl_api/android.hardware.tv.mediaquality/current/android/hardware/tv/mediaquality/AmbientBacklightCompressAlgorithm.aidl
similarity index 88%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to tv/mediaquality/aidl/aidl_api/android.hardware.tv.mediaquality/current/android/hardware/tv/mediaquality/AmbientBacklightCompressAlgorithm.aidl
index 173ac17..d441370 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/tv/mediaquality/aidl/aidl_api/android.hardware.tv.mediaquality/current/android/hardware/tv/mediaquality/AmbientBacklightCompressAlgorithm.aidl
@@ -31,10 +31,9 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
+package android.hardware.tv.mediaquality;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+enum AmbientBacklightCompressAlgorithm {
+  NONE = 0,
+  RLE = 1,
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/tv/mediaquality/aidl/aidl_api/android.hardware.tv.mediaquality/current/android/hardware/tv/mediaquality/AmbientBacklightEvent.aidl
similarity index 88%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to tv/mediaquality/aidl/aidl_api/android.hardware.tv.mediaquality/current/android/hardware/tv/mediaquality/AmbientBacklightEvent.aidl
index 173ac17..2fc2cc6 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/tv/mediaquality/aidl/aidl_api/android.hardware.tv.mediaquality/current/android/hardware/tv/mediaquality/AmbientBacklightEvent.aidl
@@ -31,10 +31,9 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
+package android.hardware.tv.mediaquality;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+union AmbientBacklightEvent {
+  boolean enabled;
+  android.hardware.tv.mediaquality.AmbientBacklightMetadata metadata;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/tv/mediaquality/aidl/aidl_api/android.hardware.tv.mediaquality/current/android/hardware/tv/mediaquality/AmbientBacklightMetadata.aidl
similarity index 86%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to tv/mediaquality/aidl/aidl_api/android.hardware.tv.mediaquality/current/android/hardware/tv/mediaquality/AmbientBacklightMetadata.aidl
index 173ac17..bbdfd62 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/tv/mediaquality/aidl/aidl_api/android.hardware.tv.mediaquality/current/android/hardware/tv/mediaquality/AmbientBacklightMetadata.aidl
@@ -31,10 +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.biometrics.fingerprint;
-/* @hide */
+package android.hardware.tv.mediaquality;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable AmbientBacklightMetadata {
+  android.hardware.tv.mediaquality.AmbientBacklightSettings settings;
+  android.hardware.tv.mediaquality.AmbientBacklightCompressAlgorithm compressAlgorithm;
+  int[] zonesColors;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/tv/mediaquality/aidl/aidl_api/android.hardware.tv.mediaquality/current/android/hardware/tv/mediaquality/AmbientBacklightSettings.aidl
similarity index 83%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to tv/mediaquality/aidl/aidl_api/android.hardware.tv.mediaquality/current/android/hardware/tv/mediaquality/AmbientBacklightSettings.aidl
index 173ac17..ffbae26 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/tv/mediaquality/aidl/aidl_api/android.hardware.tv.mediaquality/current/android/hardware/tv/mediaquality/AmbientBacklightSettings.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.tv.mediaquality;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable AmbientBacklightSettings {
+  String packageName;
+  android.hardware.tv.mediaquality.AmbientBacklightSource source;
+  int maxFramerate;
+  android.hardware.graphics.common.PixelFormat colorFormat;
+  int hZonesNumber;
+  int vZonesNumber;
+  boolean hasLetterbox;
+  int threshold;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/tv/mediaquality/aidl/aidl_api/android.hardware.tv.mediaquality/current/android/hardware/tv/mediaquality/AmbientBacklightSource.aidl
similarity index 88%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to tv/mediaquality/aidl/aidl_api/android.hardware.tv.mediaquality/current/android/hardware/tv/mediaquality/AmbientBacklightSource.aidl
index 173ac17..22912f4 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/tv/mediaquality/aidl/aidl_api/android.hardware.tv.mediaquality/current/android/hardware/tv/mediaquality/AmbientBacklightSource.aidl
@@ -31,10 +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.biometrics.fingerprint;
-/* @hide */
+package android.hardware.tv.mediaquality;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+enum AmbientBacklightSource {
+  NONE = 0,
+  AUDIO = 1,
+  VIDEO = 2,
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/tv/mediaquality/aidl/aidl_api/android.hardware.tv.mediaquality/current/android/hardware/tv/mediaquality/IMediaQuality.aidl
similarity index 81%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to tv/mediaquality/aidl/aidl_api/android.hardware.tv.mediaquality/current/android/hardware/tv/mediaquality/IMediaQuality.aidl
index 173ac17..d2b2bc3 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/tv/mediaquality/aidl/aidl_api/android.hardware.tv.mediaquality/current/android/hardware/tv/mediaquality/IMediaQuality.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.tv.mediaquality;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+interface IMediaQuality {
+  void setCallback(in android.hardware.tv.mediaquality.IMediaQualityCallback callback);
+  void setAmbientBacklightDetector(in android.hardware.tv.mediaquality.AmbientBacklightSettings settings);
+  void setAmbientBacklightDetectionEnabled(in boolean enabled);
+  boolean getAmbientBacklightDetectionEnabled();
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/tv/mediaquality/aidl/aidl_api/android.hardware.tv.mediaquality/current/android/hardware/tv/mediaquality/IMediaQualityCallback.aidl
similarity index 88%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to tv/mediaquality/aidl/aidl_api/android.hardware.tv.mediaquality/current/android/hardware/tv/mediaquality/IMediaQualityCallback.aidl
index 173ac17..014bf58 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/tv/mediaquality/aidl/aidl_api/android.hardware.tv.mediaquality/current/android/hardware/tv/mediaquality/IMediaQualityCallback.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.tv.mediaquality;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+interface IMediaQualityCallback {
+  oneway void notifyAmbientBacklightEvent(in android.hardware.tv.mediaquality.AmbientBacklightEvent event);
 }
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/tv/mediaquality/aidl/android/hardware/tv/mediaquality/AmbientBacklightCompressAlgorithm.aidl
similarity index 67%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
copy to tv/mediaquality/aidl/android/hardware/tv/mediaquality/AmbientBacklightCompressAlgorithm.aidl
index c7be950..e1c68b3 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ b/tv/mediaquality/aidl/android/hardware/tv/mediaquality/AmbientBacklightCompressAlgorithm.aidl
@@ -14,22 +14,16 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+package android.hardware.tv.mediaquality;
 
-import android.hardware.biometrics.fingerprint.AcquiredInfo;
-
-/**
- * @hide
- */
 @VintfStability
-union AcquiredInfoAndVendorCode {
+enum AmbientBacklightCompressAlgorithm {
     /**
-     * Acquired info as specified in AcqauiredInfo.aidl
+     * The compress algorithm is disabled.
      */
-    AcquiredInfo acquiredInfo = AcquiredInfo.UNKNOWN;
-
+    NONE = 0,
     /**
-     * Vendor specific code
+     * The compress algorithm is enabled for RLE (Run-Length Encoding).
      */
-    int vendorCode;
+    RLE = 1,
 }
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/tv/mediaquality/aidl/android/hardware/tv/mediaquality/AmbientBacklightEvent.aidl
similarity index 63%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
copy to tv/mediaquality/aidl/android/hardware/tv/mediaquality/AmbientBacklightEvent.aidl
index c7be950..237e531 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ b/tv/mediaquality/aidl/android/hardware/tv/mediaquality/AmbientBacklightEvent.aidl
@@ -14,22 +14,19 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+package android.hardware.tv.mediaquality;
 
-import android.hardware.biometrics.fingerprint.AcquiredInfo;
+import android.hardware.tv.mediaquality.AmbientBacklightMetadata;
 
-/**
- * @hide
- */
 @VintfStability
-union AcquiredInfoAndVendorCode {
+union AmbientBacklightEvent {
     /**
-     * Acquired info as specified in AcqauiredInfo.aidl
+     * This field is relevant when the event signifies that ambient backlight is enabled.
      */
-    AcquiredInfo acquiredInfo = AcquiredInfo.UNKNOWN;
+    boolean enabled;
 
     /**
-     * Vendor specific code
+     * This field is relevant when the event includes ambient backlight metadata.
      */
-    int vendorCode;
+    AmbientBacklightMetadata metadata;
 }
diff --git a/tv/mediaquality/aidl/android/hardware/tv/mediaquality/AmbientBacklightMetadata.aidl b/tv/mediaquality/aidl/android/hardware/tv/mediaquality/AmbientBacklightMetadata.aidl
new file mode 100644
index 0000000..49b3a28
--- /dev/null
+++ b/tv/mediaquality/aidl/android/hardware/tv/mediaquality/AmbientBacklightMetadata.aidl
@@ -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.
+ */
+
+package android.hardware.tv.mediaquality;
+
+import android.hardware.tv.mediaquality.AmbientBacklightCompressAlgorithm;
+import android.hardware.tv.mediaquality.AmbientBacklightSettings;
+
+@VintfStability
+parcelable AmbientBacklightMetadata {
+    /**
+     * The settings which are used to generate the colors.
+     */
+    AmbientBacklightSettings settings;
+
+    /**
+     * The compress algorithm of the ambient backlight colors.
+     */
+    AmbientBacklightCompressAlgorithm compressAlgorithm;
+
+    /**
+     * The colors for the zones. Format of the color will be indicated in the
+     * AmbientBacklightSettings::colorFormat.
+     */
+    int[] zonesColors;
+}
diff --git a/tv/mediaquality/aidl/android/hardware/tv/mediaquality/AmbientBacklightSettings.aidl b/tv/mediaquality/aidl/android/hardware/tv/mediaquality/AmbientBacklightSettings.aidl
new file mode 100644
index 0000000..b6a26ee
--- /dev/null
+++ b/tv/mediaquality/aidl/android/hardware/tv/mediaquality/AmbientBacklightSettings.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.tv.mediaquality;
+
+import android.hardware.graphics.common.PixelFormat;
+import android.hardware.tv.mediaquality.AmbientBacklightSource;
+
+@VintfStability
+parcelable AmbientBacklightSettings {
+    /**
+     * The package name of the ambient backlight control application.
+     */
+    String packageName;
+
+    /**
+     * The source of the ambient backlight.
+     */
+    AmbientBacklightSource source;
+
+    /**
+     * The maximum framerate for the ambient backlight.
+     */
+    int maxFramerate;
+
+    /**
+     * The color format for the ambient backlight.
+     */
+    PixelFormat colorFormat;
+
+    /**
+     * The number of zones in horizontal direction.
+     */
+    int hZonesNumber;
+
+    /**
+     * The number of zones in vertical direction.
+     */
+    int vZonesNumber;
+
+    /**
+     * When a video has a different aspect ratio than the display people
+     * watching it on, they often get black bars at the top and bottom
+     * (or sometimes the sides). These black bars are called "letterboxing".
+     * It's a way to show the entire video without distortion, but it means
+     * some of the screen space is unused. This configuration determines
+     * whether to ignore the black bar used for padding.
+     */
+    boolean hasLetterbox;
+
+    /**
+     * The color threshold for the ambient backlight. The units of the color deopends on
+     * the colorFormat. For example, RGB888, where the values of R/G/B range from 0 to 255,
+     * and the threshold is a positive number within the same range.
+     */
+    int threshold;
+}
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/tv/mediaquality/aidl/android/hardware/tv/mediaquality/AmbientBacklightSource.aidl
similarity index 67%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
copy to tv/mediaquality/aidl/android/hardware/tv/mediaquality/AmbientBacklightSource.aidl
index c7be950..8051fb6 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ b/tv/mediaquality/aidl/android/hardware/tv/mediaquality/AmbientBacklightSource.aidl
@@ -14,22 +14,20 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+package android.hardware.tv.mediaquality;
 
-import android.hardware.biometrics.fingerprint.AcquiredInfo;
-
-/**
- * @hide
- */
 @VintfStability
-union AcquiredInfoAndVendorCode {
+enum AmbientBacklightSource {
     /**
-     * Acquired info as specified in AcqauiredInfo.aidl
+     * The detection is disabled.
      */
-    AcquiredInfo acquiredInfo = AcquiredInfo.UNKNOWN;
-
+    NONE = 0,
     /**
-     * Vendor specific code
+     * The detection is enabled for audio.
      */
-    int vendorCode;
+    AUDIO = 1,
+    /**
+     * The detection is enabled for video.
+     */
+    VIDEO = 2,
 }
diff --git a/tv/mediaquality/aidl/android/hardware/tv/mediaquality/IMediaQuality.aidl b/tv/mediaquality/aidl/android/hardware/tv/mediaquality/IMediaQuality.aidl
new file mode 100644
index 0000000..def9e39
--- /dev/null
+++ b/tv/mediaquality/aidl/android/hardware/tv/mediaquality/IMediaQuality.aidl
@@ -0,0 +1,59 @@
+/*
+ * 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.tv.mediaquality;
+
+import android.hardware.tv.mediaquality.AmbientBacklightSettings;
+import android.hardware.tv.mediaquality.IMediaQualityCallback;
+
+/**
+ * Interface for the media quality service
+ */
+@VintfStability
+interface IMediaQuality {
+    /**
+     * Sets a callback for events.
+     *
+     * @param callback Callback object to pass events.
+     */
+    void setCallback(in IMediaQualityCallback callback);
+
+    /**
+     * Sets the ambient backlight detector settings.
+     *
+     * @param settings Ambient backlight detector settings.
+     */
+    void setAmbientBacklightDetector(in AmbientBacklightSettings settings);
+
+    /**
+     * Sets the ambient backlight detection enabled or disabled. The ambient backlight is the
+     * projection of light against the wall driven by the current content playing. Enable will
+     * detects the Ambient backlight metadata and ambient control app can control the related
+     * device as configured before.
+     *
+     * @param enabled True to enable the ambient backlight detection, false to disable.
+     */
+    void setAmbientBacklightDetectionEnabled(in boolean enabled);
+
+    /**
+     * Gets the ambient backlight detection enabled status. The ambient backlight is enabled by
+     * calling setAmbientBacklightDetectionEnabled(in boolean enabled). True to enable the
+     * ambient light detection and False to disable the ambient backlight detection.
+     *
+     * @return True if the ambient backlight detection is enabled, false otherwise.
+     */
+    boolean getAmbientBacklightDetectionEnabled();
+}
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/tv/mediaquality/aidl/android/hardware/tv/mediaquality/IMediaQualityCallback.aidl
similarity index 61%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
copy to tv/mediaquality/aidl/android/hardware/tv/mediaquality/IMediaQualityCallback.aidl
index c7be950..31ab255 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ b/tv/mediaquality/aidl/android/hardware/tv/mediaquality/IMediaQualityCallback.aidl
@@ -14,22 +14,17 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+package android.hardware.tv.mediaquality;
 
-import android.hardware.biometrics.fingerprint.AcquiredInfo;
+import android.hardware.tv.mediaquality.AmbientBacklightEvent;
 
-/**
- * @hide
- */
 @VintfStability
-union AcquiredInfoAndVendorCode {
+oneway interface IMediaQualityCallback {
     /**
-     * Acquired info as specified in AcqauiredInfo.aidl
+     * Notifies the client that an ambient backlight event has occurred. For possible
+     * event types, check AmbientBacklightEventType.
+     *
+     * @param event Event passed to the client.
      */
-    AcquiredInfo acquiredInfo = AcquiredInfo.UNKNOWN;
-
-    /**
-     * Vendor specific code
-     */
-    int vendorCode;
+    void notifyAmbientBacklightEvent(in AmbientBacklightEvent event);
 }
diff --git a/tv/mediaquality/aidl/default/Android.bp b/tv/mediaquality/aidl/default/Android.bp
new file mode 100644
index 0000000..e25b01f
--- /dev/null
+++ b/tv/mediaquality/aidl/default/Android.bp
@@ -0,0 +1,24 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+rust_binary {
+    name: "android.hardware.tv.mediaquality-service.example",
+    relative_install_path: "hw",
+    init_rc: ["mediaquality-default.rc"],
+    vintf_fragments: ["mediaquality-default.xml"],
+    vendor: true,
+    rustlibs: [
+        "libandroid_logger",
+        "liblogger",
+        "liblog_rust",
+        "libbinder_rs",
+        "android.hardware.tv.mediaquality-V1-rust",
+    ],
+    srcs: ["main.rs"],
+}
diff --git a/tv/mediaquality/aidl/default/hal/media_quality_hal_impl.rs b/tv/mediaquality/aidl/default/hal/media_quality_hal_impl.rs
new file mode 100644
index 0000000..8769804
--- /dev/null
+++ b/tv/mediaquality/aidl/default/hal/media_quality_hal_impl.rs
@@ -0,0 +1,114 @@
+/*
+ * 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 module implements the IMediaQuality AIDL interface.
+
+use android_hardware_tv_mediaquality::aidl::android::hardware::tv::mediaquality::{
+    IMediaQuality::IMediaQuality,
+    IMediaQualityCallback::IMediaQualityCallback,
+    AmbientBacklightEvent::AmbientBacklightEvent,
+    AmbientBacklightSettings::AmbientBacklightSettings,
+};
+use binder::Interface;
+use std::sync::{Arc, Mutex};
+use std::thread;
+use binder::Strong;
+
+/// Defined so we can implement the IMediaQuality AIDL interface.
+pub struct MediaQualityService {
+    callback: Arc<Mutex<Option<Strong<dyn IMediaQualityCallback>>>>,
+    ambient_backlight_enabled: Arc<Mutex<bool>>,
+    ambient_backlight_detector_settings: Arc<Mutex<AmbientBacklightSettings>>
+}
+
+impl MediaQualityService {
+
+    /// Create a new instance of the MediaQualityService.
+    pub fn new() -> Self {
+        Self {
+            callback: Arc::new(Mutex::new(None)),
+            ambient_backlight_enabled: Arc::new(Mutex::new(true)),
+            ambient_backlight_detector_settings:
+                    Arc::new(Mutex::new(AmbientBacklightSettings::default())),
+        }
+    }
+}
+
+impl Interface for MediaQualityService {}
+
+impl IMediaQuality for MediaQualityService {
+
+    fn setCallback(
+        &self,
+        callback: &Strong<dyn IMediaQualityCallback>
+    ) -> binder::Result<()> {
+        println!("Received callback: {:?}", callback);
+        let mut cb = self.callback.lock().unwrap();
+        *cb = Some(callback.clone());
+        Ok(())
+    }
+
+    fn setAmbientBacklightDetector(
+        &self,
+        settings: &AmbientBacklightSettings
+    ) -> binder::Result<()> {
+        println!("Received settings: {:?}", settings);
+        let mut ambient_backlight_detector_settings = self.ambient_backlight_detector_settings.lock().unwrap();
+        ambient_backlight_detector_settings.packageName = settings.packageName.clone();
+        ambient_backlight_detector_settings.source = settings.source;
+        ambient_backlight_detector_settings.maxFramerate = settings.maxFramerate;
+        ambient_backlight_detector_settings.colorFormat = settings.colorFormat;
+        ambient_backlight_detector_settings.hZonesNumber = settings.hZonesNumber;
+        ambient_backlight_detector_settings.vZonesNumber = settings.vZonesNumber;
+        ambient_backlight_detector_settings.hasLetterbox = settings.hasLetterbox;
+        ambient_backlight_detector_settings.threshold = settings.threshold;
+        Ok(())
+    }
+
+    fn setAmbientBacklightDetectionEnabled(&self, enabled: bool) -> binder::Result<()> {
+        println!("Received enabled: {}", enabled);
+        let mut ambient_backlight_enabled = self.ambient_backlight_enabled.lock().unwrap();
+        *ambient_backlight_enabled = enabled;
+        if enabled {
+            println!("Enable Ambient Backlight detection");
+            thread::scope(|s| {
+                s.spawn(|| {
+                    let cb = self.callback.lock().unwrap();
+                    if let Some(cb) = &*cb {
+                        let enabled_event = AmbientBacklightEvent::Enabled(true);
+                        cb.notifyAmbientBacklightEvent(&enabled_event).unwrap();
+                    }
+                });
+            });
+        } else {
+            println!("Disable Ambient Backlight detection");
+            thread::scope(|s| {
+                s.spawn(|| {
+                    let cb = self.callback.lock().unwrap();
+                    if let Some(cb) = &*cb {
+                        let disabled_event = AmbientBacklightEvent::Enabled(false);
+                        cb.notifyAmbientBacklightEvent(&disabled_event).unwrap();
+                    }
+                });
+            });
+        }
+        Ok(())
+    }
+
+    fn getAmbientBacklightDetectionEnabled(&self) -> binder::Result<bool> {
+        let ambient_backlight_enabled = self.ambient_backlight_enabled.lock().unwrap();
+        Ok(*ambient_backlight_enabled)
+    }
+}
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/tv/mediaquality/aidl/default/hal/mod.rs
similarity index 61%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
copy to tv/mediaquality/aidl/default/hal/mod.rs
index c7be950..5b5d4ac 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ b/tv/mediaquality/aidl/default/hal/mod.rs
@@ -14,22 +14,4 @@
  * 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;
-}
+pub mod media_quality_hal_impl;
\ No newline at end of file
diff --git a/tv/mediaquality/aidl/default/main.rs b/tv/mediaquality/aidl/default/main.rs
new file mode 100644
index 0000000..f0cccb4
--- /dev/null
+++ b/tv/mediaquality/aidl/default/main.rs
@@ -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.
+ */
+//! This implements the MediaQuality Example Service.
+use android_hardware_tv_mediaquality::aidl::android::hardware::tv::mediaquality::IMediaQuality::{BnMediaQuality, IMediaQuality};
+use binder::BinderFeatures;
+
+mod hal;
+use hal::media_quality_hal_impl::MediaQualityService;
+
+const LOG_TAG: &str = "mediaquality_service_example_rust";
+
+use log::LevelFilter;
+
+fn main() {
+
+    android_logger::init_once(
+        android_logger::Config::default()
+            .with_tag(LOG_TAG)
+            .with_max_level(LevelFilter::Info),
+    );
+
+    let media_quality_service = MediaQualityService::new();
+    let media_quality_service_binder = BnMediaQuality::new_binder(media_quality_service, BinderFeatures::default());
+
+    let service_name = format!("{}/default", MediaQualityService::get_descriptor());
+    binder::add_service(&service_name, media_quality_service_binder.as_binder())
+        .expect("Failed to register service");
+
+    log::info!("MediaQualityHal service is running...");
+
+    binder::ProcessState::join_thread_pool();
+}
diff --git a/tv/mediaquality/aidl/default/mediaquality-default.rc b/tv/mediaquality/aidl/default/mediaquality-default.rc
new file mode 100644
index 0000000..5a103a9
--- /dev/null
+++ b/tv/mediaquality/aidl/default/mediaquality-default.rc
@@ -0,0 +1,4 @@
+service vendor.mediaquality-default /vendor/bin/hw/android.hardware.tv.mediaquality-service.example
+    class hal
+    user nobody
+    group nobody
diff --git a/tv/mediaquality/aidl/default/mediaquality-default.xml b/tv/mediaquality/aidl/default/mediaquality-default.xml
new file mode 100644
index 0000000..865f663
--- /dev/null
+++ b/tv/mediaquality/aidl/default/mediaquality-default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.tv.mediaquality</name>
+        <fqname>IMediaQuality/default</fqname>
+    </hal>
+</manifest>
\ No newline at end of file
diff --git a/tv/mediaquality/aidl/vts/functional/Android.bp b/tv/mediaquality/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..226569e
--- /dev/null
+++ b/tv/mediaquality/aidl/vts/functional/Android.bp
@@ -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.
+
+package {
+    default_team: "trendy_team_tv_os",
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsHalMediaQualityTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalMediaQualityTest.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libbinder_ndk",
+    ],
+    static_libs: [
+        "android.hardware.tv.mediaquality-V1-ndk",
+    ],
+    test_suites: [
+        "vts",
+    ],
+}
diff --git a/tv/mediaquality/aidl/vts/functional/VtsHalMediaQualityTest.cpp b/tv/mediaquality/aidl/vts/functional/VtsHalMediaQualityTest.cpp
new file mode 100644
index 0000000..c11ebcb
--- /dev/null
+++ b/tv/mediaquality/aidl/vts/functional/VtsHalMediaQualityTest.cpp
@@ -0,0 +1,120 @@
+/*
+ * 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 "ambient_backlight_aidl_hal_test"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/tv/mediaquality/AmbientBacklightEvent.h>
+#include <aidl/android/hardware/tv/mediaquality/AmbientBacklightSettings.h>
+#include <aidl/android/hardware/tv/mediaquality/BnMediaQualityCallback.h>
+#include <aidl/android/hardware/tv/mediaquality/IMediaQuality.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_manager.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <future>
+
+using aidl::android::hardware::graphics::common::PixelFormat;
+using aidl::android::hardware::tv::mediaquality::AmbientBacklightEvent;
+using aidl::android::hardware::tv::mediaquality::AmbientBacklightSettings;
+using aidl::android::hardware::tv::mediaquality::AmbientBacklightSource;
+using aidl::android::hardware::tv::mediaquality::BnMediaQualityCallback;
+using aidl::android::hardware::tv::mediaquality::IMediaQuality;
+using android::ProcessState;
+using android::String16;
+using ndk::ScopedAStatus;
+using ndk::SpAIBinder;
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
+
+class MediaQualityCallback : public BnMediaQualityCallback {
+  public:
+    explicit MediaQualityCallback(
+            const std::function<void(const AmbientBacklightEvent& event)>& on_hal_event_cb)
+        : on_hal_event_cb_(on_hal_event_cb) {}
+    ScopedAStatus notifyAmbientBacklightEvent(const AmbientBacklightEvent& event) override {
+        on_hal_event_cb_(event);
+        return ScopedAStatus::ok();
+    }
+
+  private:
+    std::function<void(const AmbientBacklightEvent& event)> on_hal_event_cb_;
+};
+
+class MediaQualityAidl : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        mediaquality = IMediaQuality::fromBinder(
+                SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+        ASSERT_NE(mediaquality, nullptr);
+    }
+    std::shared_ptr<IMediaQuality> mediaquality;
+};
+
+TEST_P(MediaQualityAidl, TestSetAmbientBacklightDetectionEnabled) {
+    std::promise<void> open_cb_promise;
+    std::future<void> open_cb_future{open_cb_promise.get_future()};
+    std::shared_ptr<MediaQualityCallback> callback =
+            ndk::SharedRefBase::make<MediaQualityCallback>([&open_cb_promise](auto event) {
+                EXPECT_EQ(event.getTag(), AmbientBacklightEvent::Tag::enabled);
+                EXPECT_EQ(event.template get<AmbientBacklightEvent::Tag::enabled>(), true);
+                open_cb_promise.set_value();
+                return ScopedAStatus::ok();
+            });
+    ASSERT_OK(mediaquality->setCallback(callback));
+    ASSERT_OK(mediaquality->setAmbientBacklightDetectionEnabled(true));
+    std::chrono::milliseconds timeout{10000};
+    EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready);
+}
+
+TEST_P(MediaQualityAidl, TestGetAmbientBacklightDetectionEnabled) {
+    bool enabled;
+    ASSERT_OK(mediaquality->getAmbientBacklightDetectionEnabled(&enabled));
+}
+
+TEST_P(MediaQualityAidl, TestSetMediaQualityCallback) {
+    std::shared_ptr<MediaQualityCallback> callback = ndk::SharedRefBase::make<MediaQualityCallback>(
+            [](auto /* event */) { return ScopedAStatus::ok(); });
+    ASSERT_OK(mediaquality->setCallback(callback));
+}
+
+TEST_P(MediaQualityAidl, TestSetAmbientBacklightDetector) {
+    AmbientBacklightSettings in_settings = {
+            .packageName = "com.android.mediaquality",
+            .source = AmbientBacklightSource::VIDEO,
+            .colorFormat = PixelFormat::RGB_888,
+            .hZonesNumber = 32,
+            .vZonesNumber = 20,
+            .hasLetterbox = true,
+            .threshold = 0,
+    };
+    ASSERT_OK(mediaquality->setAmbientBacklightDetector(in_settings));
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MediaQualityAidl);
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, MediaQualityAidl,
+        testing::ValuesIn(android::getAidlHalInstanceNames(IMediaQuality::descriptor)),
+        android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ProcessState::self()->setThreadPoolMaxThreadCount(1);
+    ProcessState::self()->startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/tv/tuner/aidl/Android.bp b/tv/tuner/aidl/Android.bp
index 6cbf362..e53e84d 100644
--- a/tv/tuner/aidl/Android.bp
+++ b/tv/tuner/aidl/Android.bp
@@ -39,8 +39,7 @@
                 "android.hardware.common.fmq-V1",
             ],
         },
-
     ],
-    frozen: true,
+    frozen: false,
 
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/AudioPreselectionRenderingIndicationType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/AudioPreselectionRenderingIndicationType.aidl
index 783511f..2977ff6 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/AudioPreselectionRenderingIndicationType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/AudioPreselectionRenderingIndicationType.aidl
@@ -35,9 +35,9 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum AudioPreselectionRenderingIndicationType {
-  NOT_INDICATED = 0,
-  STEREO = 1,
-  TWO_DIMENSIONAL = 2,
-  THREE_DIMENSIONAL = 3,
-  HEADPHONE = 4,
+  NOT_INDICATED,
+  STEREO,
+  TWO_DIMENSIONAL,
+  THREE_DIMENSIONAL,
+  HEADPHONE,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/AudioPresentation.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/AudioPresentation.aidl
index 96a6d98..eba820c 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/AudioPresentation.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/AudioPresentation.aidl
@@ -36,5 +36,5 @@
 @VintfStability
 parcelable AudioPresentation {
   android.hardware.tv.tuner.AudioPreselection preselection;
-  int ac4ShortProgramId = -1;
+  int ac4ShortProgramId = (-1) /* -1 */;
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/AudioStreamType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/AudioStreamType.aidl
index 6c538ea..4754bb1 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/AudioStreamType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/AudioStreamType.aidl
@@ -35,24 +35,24 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum AudioStreamType {
-  UNDEFINED = 0,
-  PCM = 1,
-  MP3 = 2,
-  MPEG1 = 3,
-  MPEG2 = 4,
-  MPEGH = 5,
-  AAC = 6,
-  AC3 = 7,
-  EAC3 = 8,
-  AC4 = 9,
-  DTS = 10,
-  DTS_HD = 11,
-  WMA = 12,
-  OPUS = 13,
-  VORBIS = 14,
-  DRA = 15,
-  AAC_ADTS = 16,
-  AAC_LATM = 17,
-  AAC_HE_ADTS = 18,
-  AAC_HE_LATM = 19,
+  UNDEFINED,
+  PCM,
+  MP3,
+  MPEG1,
+  MPEG2,
+  MPEGH,
+  AAC,
+  AC3,
+  EAC3,
+  AC4,
+  DTS,
+  DTS_HD,
+  WMA,
+  OPUS,
+  VORBIS,
+  DRA,
+  AAC_ADTS,
+  AAC_LATM,
+  AAC_HE_ADTS,
+  AAC_HE_LATM,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/Constant.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/Constant.aidl
index 95ecc51..1f7153b 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/Constant.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/Constant.aidl
@@ -35,17 +35,17 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum Constant {
-  INVALID_TS_PID = 65535,
-  INVALID_STREAM_ID = 65535,
-  INVALID_FILTER_ID = -1,
-  INVALID_AV_SYNC_ID = -1,
-  INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM = -1,
-  INVALID_FIRST_MACROBLOCK_IN_SLICE = -1,
-  INVALID_FRONTEND_SETTING_FREQUENCY = -1,
-  INVALID_IP_FILTER_CONTEXT_ID = -1,
-  INVALID_LTS_ID = -1,
-  INVALID_FRONTEND_ID = -1,
-  INVALID_LNB_ID = -1,
-  INVALID_KEYTOKEN = 0,
-  INVALID_TABINFO_VERSION = -1,
+  INVALID_TS_PID = 0xFFFF,
+  INVALID_STREAM_ID = 0xFFFF,
+  INVALID_FILTER_ID = 0xFFFFFFFF,
+  INVALID_AV_SYNC_ID = 0xFFFFFFFF,
+  INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM = 0xFFFFFFFF,
+  INVALID_FIRST_MACROBLOCK_IN_SLICE = 0xFFFFFFFF,
+  INVALID_FRONTEND_SETTING_FREQUENCY = 0xFFFFFFFF,
+  INVALID_IP_FILTER_CONTEXT_ID = 0xFFFFFFFF,
+  INVALID_LTS_ID = 0xFFFFFFFF,
+  INVALID_FRONTEND_ID = 0xFFFFFFFF,
+  INVALID_LNB_ID = 0xFFFFFFFF,
+  INVALID_KEYTOKEN = 0x00,
+  INVALID_TABINFO_VERSION = 0xFFFFFFFF,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/Constant64Bit.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/Constant64Bit.aidl
index a56a0cf..ccbfd1a 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/Constant64Bit.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/Constant64Bit.aidl
@@ -35,7 +35,7 @@
 /* @hide */
 @Backing(type="long") @VintfStability
 enum Constant64Bit {
-  INVALID_FILTER_ID_64BIT = -1,
-  INVALID_AV_SYNC_ID_64BIT = -1,
-  INVALID_PRESENTATION_TIME_STAMP = -1,
+  INVALID_FILTER_ID_64BIT = 0xFFFFFFFFFFFFFFFF,
+  INVALID_AV_SYNC_ID_64BIT = 0xFFFFFFFFFFFFFFFF,
+  INVALID_PRESENTATION_TIME_STAMP = 0xFFFFFFFFFFFFFFFF,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DataFormat.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DataFormat.aidl
index 3b8fee4..5fb34ba 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DataFormat.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DataFormat.aidl
@@ -35,9 +35,9 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum DataFormat {
-  TS = 0,
-  PES = 1,
-  ES = 2,
-  SHV_TLV = 3,
-  UNDEFINED = 4,
+  TS,
+  PES,
+  ES,
+  SHV_TLV,
+  UNDEFINED,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxAlpFilterType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxAlpFilterType.aidl
index f0df497..c164f19 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxAlpFilterType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxAlpFilterType.aidl
@@ -35,8 +35,8 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum DemuxAlpFilterType {
-  UNDEFINED = 0,
-  SECTION = 1,
-  PTP = 2,
-  PAYLOAD_THROUGH = 3,
+  UNDEFINED,
+  SECTION,
+  PTP,
+  PAYLOAD_THROUGH,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxAlpLengthType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxAlpLengthType.aidl
index ccca6de..59edc34 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxAlpLengthType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxAlpLengthType.aidl
@@ -36,6 +36,6 @@
 @Backing(type="byte") @VintfStability
 enum DemuxAlpLengthType {
   UNDEFINED = 0,
-  WITHOUT_ADDITIONAL_HEADER = 1,
-  WITH_ADDITIONAL_HEADER = 2,
+  WITHOUT_ADDITIONAL_HEADER,
+  WITH_ADDITIONAL_HEADER,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterMainType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterMainType.aidl
index 6abd87b..b78965d 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterMainType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterMainType.aidl
@@ -36,9 +36,9 @@
 @Backing(type="int") @VintfStability
 enum DemuxFilterMainType {
   UNDEFINED = 0,
-  TS = 1,
-  MMTP = 2,
-  IP = 4,
-  TLV = 8,
-  ALP = 16,
+  TS = (1 << 0) /* 1 */,
+  MMTP = (1 << 1) /* 2 */,
+  IP = (1 << 2) /* 4 */,
+  TLV = (1 << 3) /* 8 */,
+  ALP = (1 << 4) /* 16 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterMediaEvent.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterMediaEvent.aidl
index 61a9555..126c740 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterMediaEvent.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterMediaEvent.aidl
@@ -49,4 +49,7 @@
   boolean isPesPrivateData;
   android.hardware.tv.tuner.DemuxFilterMediaEventExtraMetaData extraMetaData;
   android.hardware.tv.tuner.DemuxFilterScIndexMask scIndexMask;
+  int numDataPieces;
+  int indexInDataGroup;
+  int dataGroupId;
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterMonitorEventType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterMonitorEventType.aidl
index 5d27f76..062650b 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterMonitorEventType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterMonitorEventType.aidl
@@ -35,6 +35,6 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum DemuxFilterMonitorEventType {
-  SCRAMBLING_STATUS = 1,
-  IP_CID_CHANGE = 2,
+  SCRAMBLING_STATUS = (1 << 0) /* 1 */,
+  IP_CID_CHANGE = (1 << 1) /* 2 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterStatus.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterStatus.aidl
index 1dc593a..cfc5838 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterStatus.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterStatus.aidl
@@ -35,9 +35,9 @@
 /* @hide */
 @Backing(type="byte") @VintfStability
 enum DemuxFilterStatus {
-  DATA_READY = 1,
-  LOW_WATER = 2,
-  HIGH_WATER = 4,
-  OVERFLOW = 8,
-  NO_DATA = 16,
+  DATA_READY = (1 << 0) /* 1 */,
+  LOW_WATER = (1 << 1) /* 2 */,
+  HIGH_WATER = (1 << 2) /* 4 */,
+  OVERFLOW = (1 << 3) /* 8 */,
+  NO_DATA = (1 << 4) /* 16 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxInfo.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxInfo.aidl
index 872d963..12f9dc8 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxInfo.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxInfo.aidl
@@ -35,5 +35,5 @@
 /* @hide */
 @VintfStability
 parcelable DemuxInfo {
-  int filterTypes = 0;
+  int filterTypes = android.hardware.tv.tuner.DemuxFilterMainType.UNDEFINED /* 0 */;
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxIpFilterType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxIpFilterType.aidl
index b78ac9a..7320aec 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxIpFilterType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxIpFilterType.aidl
@@ -35,10 +35,10 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum DemuxIpFilterType {
-  UNDEFINED = 0,
-  SECTION = 1,
-  NTP = 2,
-  IP_PAYLOAD = 3,
-  IP = 4,
-  PAYLOAD_THROUGH = 5,
+  UNDEFINED,
+  SECTION,
+  NTP,
+  IP_PAYLOAD,
+  IP,
+  PAYLOAD_THROUGH,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxMmtpFilterType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxMmtpFilterType.aidl
index 7e9e3a6..a89c5b1 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxMmtpFilterType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxMmtpFilterType.aidl
@@ -35,12 +35,12 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum DemuxMmtpFilterType {
-  UNDEFINED = 0,
-  SECTION = 1,
-  PES = 2,
-  MMTP = 3,
-  AUDIO = 4,
-  VIDEO = 5,
-  RECORD = 6,
-  DOWNLOAD = 7,
+  UNDEFINED,
+  SECTION,
+  PES,
+  MMTP,
+  AUDIO,
+  VIDEO,
+  RECORD,
+  DOWNLOAD,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxQueueNotifyBits.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxQueueNotifyBits.aidl
index bcd0aeb..ecb4e8b 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxQueueNotifyBits.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxQueueNotifyBits.aidl
@@ -35,6 +35,6 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum DemuxQueueNotifyBits {
-  DATA_READY = 1,
-  DATA_CONSUMED = 2,
+  DATA_READY = (1 << 0) /* 1 */,
+  DATA_CONSUMED = (1 << 1) /* 2 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxRecordScIndexType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxRecordScIndexType.aidl
index fb4430b..5556bb2 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxRecordScIndexType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxRecordScIndexType.aidl
@@ -35,9 +35,9 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum DemuxRecordScIndexType {
-  NONE = 0,
-  SC = 1,
-  SC_HEVC = 2,
-  SC_AVC = 3,
-  SC_VVC = 4,
+  NONE,
+  SC,
+  SC_HEVC,
+  SC_AVC,
+  SC_VVC,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxScAvcIndex.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxScAvcIndex.aidl
index 651b66c..5c51793 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxScAvcIndex.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxScAvcIndex.aidl
@@ -36,9 +36,9 @@
 @Backing(type="int") @VintfStability
 enum DemuxScAvcIndex {
   UNDEFINED = 0,
-  I_SLICE = 1,
-  P_SLICE = 2,
-  B_SLICE = 4,
-  SI_SLICE = 8,
-  SP_SLICE = 16,
+  I_SLICE = (1 << 0) /* 1 */,
+  P_SLICE = (1 << 1) /* 2 */,
+  B_SLICE = (1 << 2) /* 4 */,
+  SI_SLICE = (1 << 3) /* 8 */,
+  SP_SLICE = (1 << 4) /* 16 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxScHevcIndex.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxScHevcIndex.aidl
index 670b34e..d07bcb7 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxScHevcIndex.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxScHevcIndex.aidl
@@ -36,12 +36,12 @@
 @Backing(type="int") @VintfStability
 enum DemuxScHevcIndex {
   UNDEFINED = 0,
-  SPS = 1,
-  AUD = 2,
-  SLICE_CE_BLA_W_LP = 4,
-  SLICE_BLA_W_RADL = 8,
-  SLICE_BLA_N_LP = 16,
-  SLICE_IDR_W_RADL = 32,
-  SLICE_IDR_N_LP = 64,
-  SLICE_TRAIL_CRA = 128,
+  SPS = (1 << 0) /* 1 */,
+  AUD = (1 << 1) /* 2 */,
+  SLICE_CE_BLA_W_LP = (1 << 2) /* 4 */,
+  SLICE_BLA_W_RADL = (1 << 3) /* 8 */,
+  SLICE_BLA_N_LP = (1 << 4) /* 16 */,
+  SLICE_IDR_W_RADL = (1 << 5) /* 32 */,
+  SLICE_IDR_N_LP = (1 << 6) /* 64 */,
+  SLICE_TRAIL_CRA = (1 << 7) /* 128 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxScIndex.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxScIndex.aidl
index 25f0585..509c1ab 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxScIndex.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxScIndex.aidl
@@ -36,8 +36,8 @@
 @Backing(type="int") @VintfStability
 enum DemuxScIndex {
   UNDEFINED = 0,
-  I_FRAME = 1,
-  P_FRAME = 2,
-  B_FRAME = 4,
-  SEQUENCE = 8,
+  I_FRAME = (1 << 0) /* 1 */,
+  P_FRAME = (1 << 1) /* 2 */,
+  B_FRAME = (1 << 2) /* 4 */,
+  SEQUENCE = (1 << 3) /* 8 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxScVvcIndex.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxScVvcIndex.aidl
index 3e08d26..ac3a5e6 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxScVvcIndex.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxScVvcIndex.aidl
@@ -36,11 +36,11 @@
 @Backing(type="int") @VintfStability
 enum DemuxScVvcIndex {
   UNDEFINED = 0,
-  SLICE_IDR_W_RADL = 1,
-  SLICE_IDR_N_LP = 2,
-  SLICE_CRA = 4,
-  SLICE_GDR = 8,
-  VPS = 16,
-  SPS = 32,
-  AUD = 64,
+  SLICE_IDR_W_RADL = (1 << 0) /* 1 */,
+  SLICE_IDR_N_LP = (1 << 1) /* 2 */,
+  SLICE_CRA = (1 << 2) /* 4 */,
+  SLICE_GDR = (1 << 3) /* 8 */,
+  VPS = (1 << 4) /* 16 */,
+  SPS = (1 << 5) /* 32 */,
+  AUD = (1 << 6) /* 64 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxTlvFilterType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxTlvFilterType.aidl
index a4e1ff1..bd9e583 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxTlvFilterType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxTlvFilterType.aidl
@@ -35,8 +35,8 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum DemuxTlvFilterType {
-  UNDEFINED = 0,
-  SECTION = 1,
-  TLV = 2,
-  PAYLOAD_THROUGH = 3,
+  UNDEFINED,
+  SECTION,
+  TLV,
+  PAYLOAD_THROUGH,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxTsFilterType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxTsFilterType.aidl
index 8b806bf..8be0e95 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxTsFilterType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxTsFilterType.aidl
@@ -35,13 +35,13 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum DemuxTsFilterType {
-  UNDEFINED = 0,
-  SECTION = 1,
-  PES = 2,
-  TS = 3,
-  AUDIO = 4,
-  VIDEO = 5,
-  PCR = 6,
-  RECORD = 7,
-  TEMI = 8,
+  UNDEFINED,
+  SECTION,
+  PES,
+  TS,
+  AUDIO,
+  VIDEO,
+  PCR,
+  RECORD,
+  TEMI,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxTsIndex.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxTsIndex.aidl
index ed03477..9ca684f 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxTsIndex.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxTsIndex.aidl
@@ -35,22 +35,22 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum DemuxTsIndex {
-  FIRST_PACKET = 1,
-  PAYLOAD_UNIT_START_INDICATOR = 2,
-  CHANGE_TO_NOT_SCRAMBLED = 4,
-  CHANGE_TO_EVEN_SCRAMBLED = 8,
-  CHANGE_TO_ODD_SCRAMBLED = 16,
-  DISCONTINUITY_INDICATOR = 32,
-  RANDOM_ACCESS_INDICATOR = 64,
-  PRIORITY_INDICATOR = 128,
-  PCR_FLAG = 256,
-  OPCR_FLAG = 512,
-  SPLICING_POINT_FLAG = 1024,
-  PRIVATE_DATA = 2048,
-  ADAPTATION_EXTENSION_FLAG = 4096,
-  MPT_INDEX_MPT = 65536,
-  MPT_INDEX_VIDEO = 131072,
-  MPT_INDEX_AUDIO = 262144,
-  MPT_INDEX_TIMESTAMP_TARGET_VIDEO = 524288,
-  MPT_INDEX_TIMESTAMP_TARGET_AUDIO = 1048576,
+  FIRST_PACKET = (1 << 0) /* 1 */,
+  PAYLOAD_UNIT_START_INDICATOR = (1 << 1) /* 2 */,
+  CHANGE_TO_NOT_SCRAMBLED = (1 << 2) /* 4 */,
+  CHANGE_TO_EVEN_SCRAMBLED = (1 << 3) /* 8 */,
+  CHANGE_TO_ODD_SCRAMBLED = (1 << 4) /* 16 */,
+  DISCONTINUITY_INDICATOR = (1 << 5) /* 32 */,
+  RANDOM_ACCESS_INDICATOR = (1 << 6) /* 64 */,
+  PRIORITY_INDICATOR = (1 << 7) /* 128 */,
+  PCR_FLAG = (1 << 8) /* 256 */,
+  OPCR_FLAG = (1 << 9) /* 512 */,
+  SPLICING_POINT_FLAG = (1 << 10) /* 1024 */,
+  PRIVATE_DATA = (1 << 11) /* 2048 */,
+  ADAPTATION_EXTENSION_FLAG = (1 << 12) /* 4096 */,
+  MPT_INDEX_MPT = (1 << 16) /* 65536 */,
+  MPT_INDEX_VIDEO = (1 << 17) /* 131072 */,
+  MPT_INDEX_AUDIO = (1 << 18) /* 262144 */,
+  MPT_INDEX_TIMESTAMP_TARGET_VIDEO = (1 << 19) /* 524288 */,
+  MPT_INDEX_TIMESTAMP_TARGET_AUDIO = (1 << 20) /* 1048576 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DvrType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DvrType.aidl
index 3a0c1e4..6dab74b 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DvrType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DvrType.aidl
@@ -35,6 +35,6 @@
 /* @hide */
 @Backing(type="byte") @VintfStability
 enum DvrType {
-  RECORD = 0,
-  PLAYBACK = 1,
+  RECORD,
+  PLAYBACK,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FilterDelayHintType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FilterDelayHintType.aidl
index 8c5a3f5..af35c70 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FilterDelayHintType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FilterDelayHintType.aidl
@@ -35,7 +35,7 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum FilterDelayHintType {
-  INVALID = 0,
-  TIME_DELAY_IN_MS = 1,
-  DATA_SIZE_DELAY_IN_BYTES = 2,
+  INVALID,
+  TIME_DELAY_IN_MS,
+  DATA_SIZE_DELAY_IN_BYTES,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAnalogAftFlag.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAnalogAftFlag.aidl
index 6b32110..45aa2af 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAnalogAftFlag.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAnalogAftFlag.aidl
@@ -35,7 +35,7 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum FrontendAnalogAftFlag {
-  UNDEFINED = 0,
-  AFT_TRUE = 1,
-  AFT_FALSE = 2,
+  UNDEFINED,
+  AFT_TRUE,
+  AFT_FALSE,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAnalogSifStandard.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAnalogSifStandard.aidl
index 3502522..8d19461 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAnalogSifStandard.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAnalogSifStandard.aidl
@@ -36,22 +36,22 @@
 @Backing(type="int") @VintfStability
 enum FrontendAnalogSifStandard {
   UNDEFINED = 0,
-  AUTO = 1,
-  BG = 2,
-  BG_A2 = 4,
-  BG_NICAM = 8,
-  I = 16,
-  DK = 32,
-  DK1_A2 = 64,
-  DK2_A2 = 128,
-  DK3_A2 = 256,
-  DK_NICAM = 512,
-  L = 1024,
-  M = 2048,
-  M_BTSC = 4096,
-  M_A2 = 8192,
-  M_EIAJ = 16384,
-  I_NICAM = 32768,
-  L_NICAM = 65536,
-  L_PRIME = 131072,
+  AUTO = (1 << 0) /* 1 */,
+  BG = (1 << 1) /* 2 */,
+  BG_A2 = (1 << 2) /* 4 */,
+  BG_NICAM = (1 << 3) /* 8 */,
+  I = (1 << 4) /* 16 */,
+  DK = (1 << 5) /* 32 */,
+  DK1_A2 = (1 << 6) /* 64 */,
+  DK2_A2 = (1 << 7) /* 128 */,
+  DK3_A2 = (1 << 8) /* 256 */,
+  DK_NICAM = (1 << 9) /* 512 */,
+  L = (1 << 10) /* 1024 */,
+  M = (1 << 11) /* 2048 */,
+  M_BTSC = (1 << 12) /* 4096 */,
+  M_A2 = (1 << 13) /* 8192 */,
+  M_EIAJ = (1 << 14) /* 16384 */,
+  I_NICAM = (1 << 15) /* 32768 */,
+  L_NICAM = (1 << 16) /* 65536 */,
+  L_PRIME = (1 << 17) /* 131072 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAnalogType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAnalogType.aidl
index 33fd93d..bf8b000 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAnalogType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAnalogType.aidl
@@ -36,12 +36,12 @@
 @Backing(type="int") @VintfStability
 enum FrontendAnalogType {
   UNDEFINED = 0,
-  AUTO = 1,
-  PAL = 2,
-  PAL_M = 4,
-  PAL_N = 8,
-  PAL_60 = 16,
-  NTSC = 32,
-  NTSC_443 = 64,
-  SECAM = 128,
+  AUTO = (1 << 0) /* 1 */,
+  PAL = (1 << 1) /* 2 */,
+  PAL_M = (1 << 2) /* 4 */,
+  PAL_N = (1 << 3) /* 8 */,
+  PAL_60 = (1 << 4) /* 16 */,
+  NTSC = (1 << 5) /* 32 */,
+  NTSC_443 = (1 << 6) /* 64 */,
+  SECAM = (1 << 7) /* 128 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtsc3Bandwidth.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtsc3Bandwidth.aidl
index 51a3fc5..9704f40 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtsc3Bandwidth.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtsc3Bandwidth.aidl
@@ -36,8 +36,8 @@
 @Backing(type="int") @VintfStability
 enum FrontendAtsc3Bandwidth {
   UNDEFINED = 0,
-  AUTO = 1,
-  BANDWIDTH_6MHZ = 2,
-  BANDWIDTH_7MHZ = 4,
-  BANDWIDTH_8MHZ = 8,
+  AUTO = (1 << 0) /* 1 */,
+  BANDWIDTH_6MHZ = (1 << 1) /* 2 */,
+  BANDWIDTH_7MHZ = (1 << 2) /* 4 */,
+  BANDWIDTH_8MHZ = (1 << 3) /* 8 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtsc3CodeRate.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtsc3CodeRate.aidl
index aec0718..2d09271 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtsc3CodeRate.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtsc3CodeRate.aidl
@@ -36,17 +36,17 @@
 @Backing(type="int") @VintfStability
 enum FrontendAtsc3CodeRate {
   UNDEFINED = 0,
-  AUTO = 1,
-  CODERATE_2_15 = 2,
-  CODERATE_3_15 = 4,
-  CODERATE_4_15 = 8,
-  CODERATE_5_15 = 16,
-  CODERATE_6_15 = 32,
-  CODERATE_7_15 = 64,
-  CODERATE_8_15 = 128,
-  CODERATE_9_15 = 256,
-  CODERATE_10_15 = 512,
-  CODERATE_11_15 = 1024,
-  CODERATE_12_15 = 2048,
-  CODERATE_13_15 = 4096,
+  AUTO = (1 << 0) /* 1 */,
+  CODERATE_2_15 = (1 << 1) /* 2 */,
+  CODERATE_3_15 = (1 << 2) /* 4 */,
+  CODERATE_4_15 = (1 << 3) /* 8 */,
+  CODERATE_5_15 = (1 << 4) /* 16 */,
+  CODERATE_6_15 = (1 << 5) /* 32 */,
+  CODERATE_7_15 = (1 << 6) /* 64 */,
+  CODERATE_8_15 = (1 << 7) /* 128 */,
+  CODERATE_9_15 = (1 << 8) /* 256 */,
+  CODERATE_10_15 = (1 << 9) /* 512 */,
+  CODERATE_11_15 = (1 << 10) /* 1024 */,
+  CODERATE_12_15 = (1 << 11) /* 2048 */,
+  CODERATE_13_15 = (1 << 12) /* 4096 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtsc3DemodOutputFormat.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtsc3DemodOutputFormat.aidl
index 8702a49..22267e7 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtsc3DemodOutputFormat.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtsc3DemodOutputFormat.aidl
@@ -36,6 +36,6 @@
 @Backing(type="byte") @VintfStability
 enum FrontendAtsc3DemodOutputFormat {
   UNDEFINED = 0,
-  ATSC3_LINKLAYER_PACKET = 1,
-  BASEBAND_PACKET = 2,
+  ATSC3_LINKLAYER_PACKET = (1 << 0) /* 1 */,
+  BASEBAND_PACKET = (1 << 1) /* 2 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtsc3Fec.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtsc3Fec.aidl
index a2c140a..2e229c0 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtsc3Fec.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtsc3Fec.aidl
@@ -36,11 +36,11 @@
 @Backing(type="int") @VintfStability
 enum FrontendAtsc3Fec {
   UNDEFINED = 0,
-  AUTO = 1,
-  BCH_LDPC_16K = 2,
-  BCH_LDPC_64K = 4,
-  CRC_LDPC_16K = 8,
-  CRC_LDPC_64K = 16,
-  LDPC_16K = 32,
-  LDPC_64K = 64,
+  AUTO = (1 << 0) /* 1 */,
+  BCH_LDPC_16K = (1 << 1) /* 2 */,
+  BCH_LDPC_64K = (1 << 2) /* 4 */,
+  CRC_LDPC_16K = (1 << 3) /* 8 */,
+  CRC_LDPC_64K = (1 << 4) /* 16 */,
+  LDPC_16K = (1 << 5) /* 32 */,
+  LDPC_64K = (1 << 6) /* 64 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtsc3Modulation.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtsc3Modulation.aidl
index 09e513d..cbe8c1f 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtsc3Modulation.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtsc3Modulation.aidl
@@ -36,11 +36,11 @@
 @Backing(type="int") @VintfStability
 enum FrontendAtsc3Modulation {
   UNDEFINED = 0,
-  AUTO = 1,
-  MOD_QPSK = 2,
-  MOD_16QAM = 4,
-  MOD_64QAM = 8,
-  MOD_256QAM = 16,
-  MOD_1024QAM = 32,
-  MOD_4096QAM = 64,
+  AUTO = (1 << 0) /* 1 */,
+  MOD_QPSK = (1 << 1) /* 2 */,
+  MOD_16QAM = (1 << 2) /* 4 */,
+  MOD_64QAM = (1 << 3) /* 8 */,
+  MOD_256QAM = (1 << 4) /* 16 */,
+  MOD_1024QAM = (1 << 5) /* 32 */,
+  MOD_4096QAM = (1 << 6) /* 64 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtsc3TimeInterleaveMode.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtsc3TimeInterleaveMode.aidl
index a9747f0..4e70641 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtsc3TimeInterleaveMode.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtsc3TimeInterleaveMode.aidl
@@ -36,7 +36,7 @@
 @Backing(type="int") @VintfStability
 enum FrontendAtsc3TimeInterleaveMode {
   UNDEFINED = 0,
-  AUTO = 1,
-  CTI = 2,
-  HTI = 4,
+  AUTO = (1 << 0) /* 1 */,
+  CTI = (1 << 1) /* 2 */,
+  HTI = (1 << 2) /* 4 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtscModulation.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtscModulation.aidl
index 426fe20..7da48f1 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtscModulation.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendAtscModulation.aidl
@@ -36,7 +36,7 @@
 @Backing(type="int") @VintfStability
 enum FrontendAtscModulation {
   UNDEFINED = 0,
-  AUTO = 1,
-  MOD_8VSB = 4,
-  MOD_16VSB = 8,
+  AUTO = (1 << 0) /* 1 */,
+  MOD_8VSB = (1 << 2) /* 4 */,
+  MOD_16VSB = (1 << 3) /* 8 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendCableTimeInterleaveMode.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendCableTimeInterleaveMode.aidl
index ff71df3..61cbf12 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendCableTimeInterleaveMode.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendCableTimeInterleaveMode.aidl
@@ -36,14 +36,14 @@
 @Backing(type="int") @VintfStability
 enum FrontendCableTimeInterleaveMode {
   UNDEFINED = 0,
-  AUTO = 1,
-  INTERLEAVING_128_1_0 = 2,
-  INTERLEAVING_128_1_1 = 4,
-  INTERLEAVING_64_2 = 8,
-  INTERLEAVING_32_4 = 16,
-  INTERLEAVING_16_8 = 32,
-  INTERLEAVING_8_16 = 64,
-  INTERLEAVING_128_2 = 128,
-  INTERLEAVING_128_3 = 256,
-  INTERLEAVING_128_4 = 512,
+  AUTO = (1 << 0) /* 1 */,
+  INTERLEAVING_128_1_0 = (1 << 1) /* 2 */,
+  INTERLEAVING_128_1_1 = (1 << 2) /* 4 */,
+  INTERLEAVING_64_2 = (1 << 3) /* 8 */,
+  INTERLEAVING_32_4 = (1 << 4) /* 16 */,
+  INTERLEAVING_16_8 = (1 << 5) /* 32 */,
+  INTERLEAVING_8_16 = (1 << 6) /* 64 */,
+  INTERLEAVING_128_2 = (1 << 7) /* 128 */,
+  INTERLEAVING_128_3 = (1 << 8) /* 256 */,
+  INTERLEAVING_128_4 = (1 << 9) /* 512 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDtmbBandwidth.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDtmbBandwidth.aidl
index 18d71d2..6f62d91 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDtmbBandwidth.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDtmbBandwidth.aidl
@@ -36,7 +36,7 @@
 @Backing(type="int") @VintfStability
 enum FrontendDtmbBandwidth {
   UNDEFINED = 0,
-  AUTO = 1,
-  BANDWIDTH_8MHZ = 2,
-  BANDWIDTH_6MHZ = 4,
+  AUTO = (1 << 0) /* 1 */,
+  BANDWIDTH_8MHZ = (1 << 1) /* 2 */,
+  BANDWIDTH_6MHZ = (1 << 2) /* 4 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDtmbCodeRate.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDtmbCodeRate.aidl
index c9454e7..d6be639 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDtmbCodeRate.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDtmbCodeRate.aidl
@@ -36,8 +36,8 @@
 @Backing(type="int") @VintfStability
 enum FrontendDtmbCodeRate {
   UNDEFINED = 0,
-  AUTO = 1,
-  CODERATE_2_5 = 2,
-  CODERATE_3_5 = 4,
-  CODERATE_4_5 = 8,
+  AUTO = (1 << 0) /* 1 */,
+  CODERATE_2_5 = (1 << 1) /* 2 */,
+  CODERATE_3_5 = (1 << 2) /* 4 */,
+  CODERATE_4_5 = (1 << 3) /* 8 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDtmbGuardInterval.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDtmbGuardInterval.aidl
index 872eb6a..5626064 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDtmbGuardInterval.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDtmbGuardInterval.aidl
@@ -36,11 +36,11 @@
 @Backing(type="int") @VintfStability
 enum FrontendDtmbGuardInterval {
   UNDEFINED = 0,
-  AUTO = 1,
-  PN_420_VARIOUS = 2,
-  PN_595_CONST = 4,
-  PN_945_VARIOUS = 8,
-  PN_420_CONST = 16,
-  PN_945_CONST = 32,
-  PN_RESERVED = 64,
+  AUTO = (1 << 0) /* 1 */,
+  PN_420_VARIOUS = (1 << 1) /* 2 */,
+  PN_595_CONST = (1 << 2) /* 4 */,
+  PN_945_VARIOUS = (1 << 3) /* 8 */,
+  PN_420_CONST = (1 << 4) /* 16 */,
+  PN_945_CONST = (1 << 5) /* 32 */,
+  PN_RESERVED = (1 << 6) /* 64 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDtmbModulation.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDtmbModulation.aidl
index 088aac5..036e64b 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDtmbModulation.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDtmbModulation.aidl
@@ -36,10 +36,10 @@
 @Backing(type="int") @VintfStability
 enum FrontendDtmbModulation {
   UNDEFINED = 0,
-  AUTO = 1,
-  CONSTELLATION_4QAM = 2,
-  CONSTELLATION_4QAM_NR = 4,
-  CONSTELLATION_16QAM = 8,
-  CONSTELLATION_32QAM = 16,
-  CONSTELLATION_64QAM = 32,
+  AUTO = (1 << 0) /* 1 */,
+  CONSTELLATION_4QAM = (1 << 1) /* 2 */,
+  CONSTELLATION_4QAM_NR = (1 << 2) /* 4 */,
+  CONSTELLATION_16QAM = (1 << 3) /* 8 */,
+  CONSTELLATION_32QAM = (1 << 4) /* 16 */,
+  CONSTELLATION_64QAM = (1 << 5) /* 32 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDtmbTimeInterleaveMode.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDtmbTimeInterleaveMode.aidl
index 8321ad0..1223887 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDtmbTimeInterleaveMode.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDtmbTimeInterleaveMode.aidl
@@ -36,7 +36,7 @@
 @Backing(type="int") @VintfStability
 enum FrontendDtmbTimeInterleaveMode {
   UNDEFINED = 0,
-  AUTO = 1,
-  TIMER_INT_240 = 2,
-  TIMER_INT_720 = 4,
+  AUTO = (1 << 0) /* 1 */,
+  TIMER_INT_240 = (1 << 1) /* 2 */,
+  TIMER_INT_720 = (1 << 2) /* 4 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDtmbTransmissionMode.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDtmbTransmissionMode.aidl
index 5298291..0498825 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDtmbTransmissionMode.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDtmbTransmissionMode.aidl
@@ -36,7 +36,7 @@
 @Backing(type="int") @VintfStability
 enum FrontendDtmbTransmissionMode {
   UNDEFINED = 0,
-  AUTO = 1,
-  C1 = 2,
-  C3780 = 4,
+  AUTO = (1 << 0) /* 1 */,
+  C1 = (1 << 1) /* 2 */,
+  C3780 = (1 << 2) /* 4 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbcAnnex.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbcAnnex.aidl
index cdfedb6..985add1 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbcAnnex.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbcAnnex.aidl
@@ -36,7 +36,7 @@
 @Backing(type="byte") @VintfStability
 enum FrontendDvbcAnnex {
   UNDEFINED = 0,
-  A = 1,
-  B = 2,
-  C = 4,
+  A = (1 << 0) /* 1 */,
+  B = (1 << 1) /* 2 */,
+  C = (1 << 2) /* 4 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbcBandwidth.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbcBandwidth.aidl
index f0fe460..c253cfe 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbcBandwidth.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbcBandwidth.aidl
@@ -36,8 +36,8 @@
 @Backing(type="int") @VintfStability
 enum FrontendDvbcBandwidth {
   UNDEFINED = 0,
-  BANDWIDTH_5MHZ = 1,
-  BANDWIDTH_6MHZ = 2,
-  BANDWIDTH_7MHZ = 4,
-  BANDWIDTH_8MHZ = 8,
+  BANDWIDTH_5MHZ = (1 << 0) /* 1 */,
+  BANDWIDTH_6MHZ = (1 << 1) /* 2 */,
+  BANDWIDTH_7MHZ = (1 << 2) /* 4 */,
+  BANDWIDTH_8MHZ = (1 << 3) /* 8 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbcModulation.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbcModulation.aidl
index 0871777..c18e83e 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbcModulation.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbcModulation.aidl
@@ -36,10 +36,10 @@
 @Backing(type="int") @VintfStability
 enum FrontendDvbcModulation {
   UNDEFINED = 0,
-  AUTO = 1,
-  MOD_16QAM = 2,
-  MOD_32QAM = 4,
-  MOD_64QAM = 8,
-  MOD_128QAM = 16,
-  MOD_256QAM = 32,
+  AUTO = (1 << 0) /* 1 */,
+  MOD_16QAM = (1 << 1) /* 2 */,
+  MOD_32QAM = (1 << 2) /* 4 */,
+  MOD_64QAM = (1 << 3) /* 8 */,
+  MOD_128QAM = (1 << 4) /* 16 */,
+  MOD_256QAM = (1 << 5) /* 32 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbcOuterFec.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbcOuterFec.aidl
index f1e92c9..a6fbc6d 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbcOuterFec.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbcOuterFec.aidl
@@ -36,6 +36,6 @@
 @Backing(type="int") @VintfStability
 enum FrontendDvbcOuterFec {
   UNDEFINED = 0,
-  OUTER_FEC_NONE = 1,
-  OUTER_FEC_RS = 2,
+  OUTER_FEC_NONE,
+  OUTER_FEC_RS,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbsModulation.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbsModulation.aidl
index 25951cc..71957d5 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbsModulation.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbsModulation.aidl
@@ -36,18 +36,18 @@
 @Backing(type="int") @VintfStability
 enum FrontendDvbsModulation {
   UNDEFINED = 0,
-  AUTO = 1,
-  MOD_QPSK = 2,
-  MOD_8PSK = 4,
-  MOD_16QAM = 8,
-  MOD_16PSK = 16,
-  MOD_32PSK = 32,
-  MOD_ACM = 64,
-  MOD_8APSK = 128,
-  MOD_16APSK = 256,
-  MOD_32APSK = 512,
-  MOD_64APSK = 1024,
-  MOD_128APSK = 2048,
-  MOD_256APSK = 4096,
-  MOD_RESERVED = 8192,
+  AUTO = (1 << 0) /* 1 */,
+  MOD_QPSK = (1 << 1) /* 2 */,
+  MOD_8PSK = (1 << 2) /* 4 */,
+  MOD_16QAM = (1 << 3) /* 8 */,
+  MOD_16PSK = (1 << 4) /* 16 */,
+  MOD_32PSK = (1 << 5) /* 32 */,
+  MOD_ACM = (1 << 6) /* 64 */,
+  MOD_8APSK = (1 << 7) /* 128 */,
+  MOD_16APSK = (1 << 8) /* 256 */,
+  MOD_32APSK = (1 << 9) /* 512 */,
+  MOD_64APSK = (1 << 10) /* 1024 */,
+  MOD_128APSK = (1 << 11) /* 2048 */,
+  MOD_256APSK = (1 << 12) /* 4096 */,
+  MOD_RESERVED = (1 << 13) /* 8192 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbsPilot.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbsPilot.aidl
index 4f2c6eb..e3543b3 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbsPilot.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbsPilot.aidl
@@ -35,8 +35,8 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum FrontendDvbsPilot {
-  UNDEFINED = 0,
-  ON = 1,
-  OFF = 2,
-  AUTO = 3,
+  UNDEFINED,
+  ON,
+  OFF,
+  AUTO,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbsRolloff.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbsRolloff.aidl
index 56ee37b..2181abf 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbsRolloff.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbsRolloff.aidl
@@ -35,11 +35,11 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum FrontendDvbsRolloff {
-  UNDEFINED = 0,
-  ROLLOFF_0_35 = 1,
-  ROLLOFF_0_25 = 2,
-  ROLLOFF_0_20 = 3,
-  ROLLOFF_0_15 = 4,
-  ROLLOFF_0_10 = 5,
-  ROLLOFF_0_5 = 6,
+  UNDEFINED,
+  ROLLOFF_0_35,
+  ROLLOFF_0_25,
+  ROLLOFF_0_20,
+  ROLLOFF_0_15,
+  ROLLOFF_0_10,
+  ROLLOFF_0_5,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbsScanType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbsScanType.aidl
index 110b1d8..46edb56 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbsScanType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbsScanType.aidl
@@ -36,8 +36,8 @@
 @Backing(type="int") @VintfStability
 enum FrontendDvbsScanType {
   UNDEFINED = 0,
-  DIRECT = 1,
-  DISEQC = 2,
-  UNICABLE = 3,
-  JESS = 4,
+  DIRECT,
+  DISEQC,
+  UNICABLE,
+  JESS,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbsStandard.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbsStandard.aidl
index b9cb657..bcb1c6d 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbsStandard.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbsStandard.aidl
@@ -36,8 +36,8 @@
 @Backing(type="byte") @VintfStability
 enum FrontendDvbsStandard {
   UNDEFINED = 0,
-  AUTO = 1,
-  S = 2,
-  S2 = 4,
-  S2X = 8,
+  AUTO = (1 << 0) /* 1 */,
+  S = (1 << 1) /* 2 */,
+  S2 = (1 << 2) /* 4 */,
+  S2X = (1 << 3) /* 8 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbsVcmMode.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbsVcmMode.aidl
index 2cbff7c..af87423 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbsVcmMode.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbsVcmMode.aidl
@@ -35,7 +35,7 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum FrontendDvbsVcmMode {
-  UNDEFINED = 0,
-  AUTO = 1,
-  MANUAL = 2,
+  UNDEFINED,
+  AUTO,
+  MANUAL,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtBandwidth.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtBandwidth.aidl
index f5d14e8..ff2d9e4 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtBandwidth.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtBandwidth.aidl
@@ -36,11 +36,11 @@
 @Backing(type="int") @VintfStability
 enum FrontendDvbtBandwidth {
   UNDEFINED = 0,
-  AUTO = 1,
-  BANDWIDTH_8MHZ = 2,
-  BANDWIDTH_7MHZ = 4,
-  BANDWIDTH_6MHZ = 8,
-  BANDWIDTH_5MHZ = 16,
-  BANDWIDTH_1_7MHZ = 32,
-  BANDWIDTH_10MHZ = 64,
+  AUTO = (1 << 0) /* 1 */,
+  BANDWIDTH_8MHZ = (1 << 1) /* 2 */,
+  BANDWIDTH_7MHZ = (1 << 2) /* 4 */,
+  BANDWIDTH_6MHZ = (1 << 3) /* 8 */,
+  BANDWIDTH_5MHZ = (1 << 4) /* 16 */,
+  BANDWIDTH_1_7MHZ = (1 << 5) /* 32 */,
+  BANDWIDTH_10MHZ = (1 << 6) /* 64 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtCoderate.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtCoderate.aidl
index 8bd0489..8d2df06 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtCoderate.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtCoderate.aidl
@@ -36,14 +36,14 @@
 @Backing(type="int") @VintfStability
 enum FrontendDvbtCoderate {
   UNDEFINED = 0,
-  AUTO = 1,
-  CODERATE_1_2 = 2,
-  CODERATE_2_3 = 4,
-  CODERATE_3_4 = 8,
-  CODERATE_5_6 = 16,
-  CODERATE_7_8 = 32,
-  CODERATE_3_5 = 64,
-  CODERATE_4_5 = 128,
-  CODERATE_6_7 = 256,
-  CODERATE_8_9 = 512,
+  AUTO = (1 << 0) /* 1 */,
+  CODERATE_1_2 = (1 << 1) /* 2 */,
+  CODERATE_2_3 = (1 << 2) /* 4 */,
+  CODERATE_3_4 = (1 << 3) /* 8 */,
+  CODERATE_5_6 = (1 << 4) /* 16 */,
+  CODERATE_7_8 = (1 << 5) /* 32 */,
+  CODERATE_3_5 = (1 << 6) /* 64 */,
+  CODERATE_4_5 = (1 << 7) /* 128 */,
+  CODERATE_6_7 = (1 << 8) /* 256 */,
+  CODERATE_8_9 = (1 << 9) /* 512 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtConstellation.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtConstellation.aidl
index bc40901..4bd5691 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtConstellation.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtConstellation.aidl
@@ -36,13 +36,13 @@
 @Backing(type="int") @VintfStability
 enum FrontendDvbtConstellation {
   UNDEFINED = 0,
-  AUTO = 1,
-  CONSTELLATION_QPSK = 2,
-  CONSTELLATION_16QAM = 4,
-  CONSTELLATION_64QAM = 8,
-  CONSTELLATION_256QAM = 16,
-  CONSTELLATION_QPSK_R = 32,
-  CONSTELLATION_16QAM_R = 64,
-  CONSTELLATION_64QAM_R = 128,
-  CONSTELLATION_256QAM_R = 256,
+  AUTO = (1 << 0) /* 1 */,
+  CONSTELLATION_QPSK = (1 << 1) /* 2 */,
+  CONSTELLATION_16QAM = (1 << 2) /* 4 */,
+  CONSTELLATION_64QAM = (1 << 3) /* 8 */,
+  CONSTELLATION_256QAM = (1 << 4) /* 16 */,
+  CONSTELLATION_QPSK_R = (1 << 5) /* 32 */,
+  CONSTELLATION_16QAM_R = (1 << 6) /* 64 */,
+  CONSTELLATION_64QAM_R = (1 << 7) /* 128 */,
+  CONSTELLATION_256QAM_R = (1 << 8) /* 256 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtGuardInterval.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtGuardInterval.aidl
index 073a77e..01c2b66 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtGuardInterval.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtGuardInterval.aidl
@@ -36,12 +36,12 @@
 @Backing(type="int") @VintfStability
 enum FrontendDvbtGuardInterval {
   UNDEFINED = 0,
-  AUTO = 1,
-  INTERVAL_1_32 = 2,
-  INTERVAL_1_16 = 4,
-  INTERVAL_1_8 = 8,
-  INTERVAL_1_4 = 16,
-  INTERVAL_1_128 = 32,
-  INTERVAL_19_128 = 64,
-  INTERVAL_19_256 = 128,
+  AUTO = (1 << 0) /* 1 */,
+  INTERVAL_1_32 = (1 << 1) /* 2 */,
+  INTERVAL_1_16 = (1 << 2) /* 4 */,
+  INTERVAL_1_8 = (1 << 3) /* 8 */,
+  INTERVAL_1_4 = (1 << 4) /* 16 */,
+  INTERVAL_1_128 = (1 << 5) /* 32 */,
+  INTERVAL_19_128 = (1 << 6) /* 64 */,
+  INTERVAL_19_256 = (1 << 7) /* 128 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtHierarchy.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtHierarchy.aidl
index 9ed5c8c..bd86479 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtHierarchy.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtHierarchy.aidl
@@ -36,13 +36,13 @@
 @Backing(type="int") @VintfStability
 enum FrontendDvbtHierarchy {
   UNDEFINED = 0,
-  AUTO = 1,
-  HIERARCHY_NON_NATIVE = 2,
-  HIERARCHY_1_NATIVE = 4,
-  HIERARCHY_2_NATIVE = 8,
-  HIERARCHY_4_NATIVE = 16,
-  HIERARCHY_NON_INDEPTH = 32,
-  HIERARCHY_1_INDEPTH = 64,
-  HIERARCHY_2_INDEPTH = 128,
-  HIERARCHY_4_INDEPTH = 256,
+  AUTO = (1 << 0) /* 1 */,
+  HIERARCHY_NON_NATIVE = (1 << 1) /* 2 */,
+  HIERARCHY_1_NATIVE = (1 << 2) /* 4 */,
+  HIERARCHY_2_NATIVE = (1 << 3) /* 8 */,
+  HIERARCHY_4_NATIVE = (1 << 4) /* 16 */,
+  HIERARCHY_NON_INDEPTH = (1 << 5) /* 32 */,
+  HIERARCHY_1_INDEPTH = (1 << 6) /* 64 */,
+  HIERARCHY_2_INDEPTH = (1 << 7) /* 128 */,
+  HIERARCHY_4_INDEPTH = (1 << 8) /* 256 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtPlpMode.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtPlpMode.aidl
index c80bc2a..dc8e12c 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtPlpMode.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtPlpMode.aidl
@@ -35,7 +35,7 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum FrontendDvbtPlpMode {
-  UNDEFINED = 0,
-  AUTO = 1,
-  MANUAL = 2,
+  UNDEFINED,
+  AUTO,
+  MANUAL,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtStandard.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtStandard.aidl
index c7ba68a..080cc5c 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtStandard.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtStandard.aidl
@@ -36,7 +36,7 @@
 @Backing(type="byte") @VintfStability
 enum FrontendDvbtStandard {
   UNDEFINED = 0,
-  AUTO = 1,
-  T = 2,
-  T2 = 4,
+  AUTO = (1 << 0) /* 1 */,
+  T = (1 << 1) /* 2 */,
+  T2 = (1 << 2) /* 4 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtTransmissionMode.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtTransmissionMode.aidl
index e3ca2e3..3731f86 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtTransmissionMode.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendDvbtTransmissionMode.aidl
@@ -36,14 +36,14 @@
 @Backing(type="int") @VintfStability
 enum FrontendDvbtTransmissionMode {
   UNDEFINED = 0,
-  AUTO = 1,
-  MODE_2K = 2,
-  MODE_8K = 4,
-  MODE_4K = 8,
-  MODE_1K = 16,
-  MODE_16K = 32,
-  MODE_32K = 64,
-  MODE_8K_E = 128,
-  MODE_16K_E = 256,
-  MODE_32K_E = 512,
+  AUTO = (1 << 0) /* 1 */,
+  MODE_2K = (1 << 1) /* 2 */,
+  MODE_8K = (1 << 2) /* 4 */,
+  MODE_4K = (1 << 3) /* 8 */,
+  MODE_1K = (1 << 4) /* 16 */,
+  MODE_16K = (1 << 5) /* 32 */,
+  MODE_32K = (1 << 6) /* 64 */,
+  MODE_8K_E = (1 << 7) /* 128 */,
+  MODE_16K_E = (1 << 8) /* 256 */,
+  MODE_32K_E = (1 << 9) /* 512 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendEventType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendEventType.aidl
index 443313f..101e347 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendEventType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendEventType.aidl
@@ -35,7 +35,7 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum FrontendEventType {
-  LOCKED = 0,
-  NO_SIGNAL = 1,
-  LOST_LOCK = 2,
+  LOCKED,
+  NO_SIGNAL,
+  LOST_LOCK,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendInnerFec.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendInnerFec.aidl
index 19599a3..da91888 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendInnerFec.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendInnerFec.aidl
@@ -36,57 +36,57 @@
 @Backing(type="long") @VintfStability
 enum FrontendInnerFec {
   FEC_UNDEFINED = 0,
-  AUTO = 1,
-  FEC_1_2 = 2,
-  FEC_1_3 = 4,
-  FEC_1_4 = 8,
-  FEC_1_5 = 16,
-  FEC_2_3 = 32,
-  FEC_2_5 = 64,
-  FEC_2_9 = 128,
-  FEC_3_4 = 256,
-  FEC_3_5 = 512,
-  FEC_4_5 = 1024,
-  FEC_4_15 = 2048,
-  FEC_5_6 = 4096,
-  FEC_5_9 = 8192,
-  FEC_6_7 = 16384,
-  FEC_7_8 = 32768,
-  FEC_7_9 = 65536,
-  FEC_7_15 = 131072,
-  FEC_8_9 = 262144,
-  FEC_8_15 = 524288,
-  FEC_9_10 = 1048576,
-  FEC_9_20 = 2097152,
-  FEC_11_15 = 4194304,
-  FEC_11_20 = 8388608,
-  FEC_11_45 = 16777216,
-  FEC_13_18 = 33554432,
-  FEC_13_45 = 67108864,
-  FEC_14_45 = 134217728,
-  FEC_23_36 = 268435456,
-  FEC_25_36 = 536870912,
-  FEC_26_45 = 1073741824,
-  FEC_28_45 = 2147483648,
-  FEC_29_45 = 4294967296,
-  FEC_31_45 = 8589934592,
-  FEC_32_45 = 17179869184,
-  FEC_77_90 = 34359738368,
-  FEC_2_15 = 68719476736,
-  FEC_3_15 = 137438953472,
-  FEC_5_15 = 274877906944,
-  FEC_6_15 = 549755813888,
-  FEC_9_15 = 1099511627776,
-  FEC_10_15 = 2199023255552,
-  FEC_12_15 = 4398046511104,
-  FEC_13_15 = 8796093022208,
-  FEC_18_30 = 17592186044416,
-  FEC_20_30 = 35184372088832,
-  FEC_90_180 = 70368744177664,
-  FEC_96_180 = 140737488355328,
-  FEC_104_180 = 281474976710656,
-  FEC_128_180 = 562949953421312,
-  FEC_132_180 = 1125899906842624,
-  FEC_135_180 = 2251799813685248,
-  FEC_140_180 = 4503599627370496,
+  AUTO = (1L << 0) /* 1 */,
+  FEC_1_2 = (1L << 1) /* 2 */,
+  FEC_1_3 = (1L << 2) /* 4 */,
+  FEC_1_4 = (1L << 3) /* 8 */,
+  FEC_1_5 = (1L << 4) /* 16 */,
+  FEC_2_3 = (1L << 5) /* 32 */,
+  FEC_2_5 = (1L << 6) /* 64 */,
+  FEC_2_9 = (1L << 7) /* 128 */,
+  FEC_3_4 = (1L << 8) /* 256 */,
+  FEC_3_5 = (1L << 9) /* 512 */,
+  FEC_4_5 = (1L << 10) /* 1024 */,
+  FEC_4_15 = (1L << 11) /* 2048 */,
+  FEC_5_6 = (1L << 12) /* 4096 */,
+  FEC_5_9 = (1L << 13) /* 8192 */,
+  FEC_6_7 = (1L << 14) /* 16384 */,
+  FEC_7_8 = (1L << 15) /* 32768 */,
+  FEC_7_9 = (1L << 16) /* 65536 */,
+  FEC_7_15 = (1L << 17) /* 131072 */,
+  FEC_8_9 = (1L << 18) /* 262144 */,
+  FEC_8_15 = (1L << 19) /* 524288 */,
+  FEC_9_10 = (1L << 20) /* 1048576 */,
+  FEC_9_20 = (1L << 21) /* 2097152 */,
+  FEC_11_15 = (1L << 22) /* 4194304 */,
+  FEC_11_20 = (1L << 23) /* 8388608 */,
+  FEC_11_45 = (1L << 24) /* 16777216 */,
+  FEC_13_18 = (1L << 25) /* 33554432 */,
+  FEC_13_45 = (1L << 26) /* 67108864 */,
+  FEC_14_45 = (1L << 27) /* 134217728 */,
+  FEC_23_36 = (1L << 28) /* 268435456 */,
+  FEC_25_36 = (1L << 29) /* 536870912 */,
+  FEC_26_45 = (1L << 30) /* 1073741824 */,
+  FEC_28_45 = (1L << 31) /* 2147483648 */,
+  FEC_29_45 = (1L << 32) /* 4294967296 */,
+  FEC_31_45 = (1L << 33) /* 8589934592 */,
+  FEC_32_45 = (1L << 34) /* 17179869184 */,
+  FEC_77_90 = (1L << 35) /* 34359738368 */,
+  FEC_2_15 = (1L << 36) /* 68719476736 */,
+  FEC_3_15 = (1L << 37) /* 137438953472 */,
+  FEC_5_15 = (1L << 38) /* 274877906944 */,
+  FEC_6_15 = (1L << 39) /* 549755813888 */,
+  FEC_9_15 = (1L << 40) /* 1099511627776 */,
+  FEC_10_15 = (1L << 41) /* 2199023255552 */,
+  FEC_12_15 = (1L << 42) /* 4398046511104 */,
+  FEC_13_15 = (1L << 43) /* 8796093022208 */,
+  FEC_18_30 = (1L << 44) /* 17592186044416 */,
+  FEC_20_30 = (1L << 45) /* 35184372088832 */,
+  FEC_90_180 = (1L << 46) /* 70368744177664 */,
+  FEC_96_180 = (1L << 47) /* 140737488355328 */,
+  FEC_104_180 = (1L << 48) /* 281474976710656 */,
+  FEC_128_180 = (1L << 49) /* 562949953421312 */,
+  FEC_132_180 = (1L << 50) /* 1125899906842624 */,
+  FEC_135_180 = (1L << 51) /* 2251799813685248 */,
+  FEC_140_180 = (1L << 52) /* 4503599627370496 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIptvSettingsFecType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIptvSettingsFecType.aidl
index 50a1208..5806cc5 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIptvSettingsFecType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIptvSettingsFecType.aidl
@@ -36,7 +36,7 @@
 @Backing(type="int") @VintfStability
 enum FrontendIptvSettingsFecType {
   UNDEFINED = 0,
-  COLUMN = 1,
-  ROW = 2,
-  COLUMN_ROW = 4,
+  COLUMN = (1 << 0) /* 1 */,
+  ROW = (1 << 1) /* 2 */,
+  COLUMN_ROW = (1 << 2) /* 4 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIptvSettingsIgmp.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIptvSettingsIgmp.aidl
index aa08496..43ae523 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIptvSettingsIgmp.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIptvSettingsIgmp.aidl
@@ -36,7 +36,7 @@
 @Backing(type="int") @VintfStability
 enum FrontendIptvSettingsIgmp {
   UNDEFINED = 0,
-  V1 = 1,
-  V2 = 2,
-  V3 = 4,
+  V1 = (1 << 0) /* 1 */,
+  V2 = (1 << 1) /* 2 */,
+  V3 = (1 << 2) /* 4 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIptvSettingsProtocol.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIptvSettingsProtocol.aidl
index 08a01f1..2e4c478 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIptvSettingsProtocol.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIptvSettingsProtocol.aidl
@@ -36,6 +36,6 @@
 @Backing(type="int") @VintfStability
 enum FrontendIptvSettingsProtocol {
   UNDEFINED = 0,
-  UDP = 1,
-  RTP = 2,
+  UDP = (1 << 0) /* 1 */,
+  RTP = (1 << 1) /* 2 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbs3Coderate.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbs3Coderate.aidl
index 1ee7f07..de865ca 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbs3Coderate.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbs3Coderate.aidl
@@ -36,16 +36,16 @@
 @Backing(type="int") @VintfStability
 enum FrontendIsdbs3Coderate {
   UNDEFINED = 0,
-  AUTO = 1,
-  CODERATE_1_3 = 2,
-  CODERATE_2_5 = 4,
-  CODERATE_1_2 = 8,
-  CODERATE_3_5 = 16,
-  CODERATE_2_3 = 32,
-  CODERATE_3_4 = 64,
-  CODERATE_7_9 = 128,
-  CODERATE_4_5 = 256,
-  CODERATE_5_6 = 512,
-  CODERATE_7_8 = 1024,
-  CODERATE_9_10 = 2048,
+  AUTO = (1 << 0) /* 1 */,
+  CODERATE_1_3 = (1 << 1) /* 2 */,
+  CODERATE_2_5 = (1 << 2) /* 4 */,
+  CODERATE_1_2 = (1 << 3) /* 8 */,
+  CODERATE_3_5 = (1 << 4) /* 16 */,
+  CODERATE_2_3 = (1 << 5) /* 32 */,
+  CODERATE_3_4 = (1 << 6) /* 64 */,
+  CODERATE_7_9 = (1 << 7) /* 128 */,
+  CODERATE_4_5 = (1 << 8) /* 256 */,
+  CODERATE_5_6 = (1 << 9) /* 512 */,
+  CODERATE_7_8 = (1 << 10) /* 1024 */,
+  CODERATE_9_10 = (1 << 11) /* 2048 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbs3Modulation.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbs3Modulation.aidl
index 3603292..adc902d 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbs3Modulation.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbs3Modulation.aidl
@@ -36,10 +36,10 @@
 @Backing(type="int") @VintfStability
 enum FrontendIsdbs3Modulation {
   UNDEFINED = 0,
-  AUTO = 1,
-  MOD_BPSK = 2,
-  MOD_QPSK = 4,
-  MOD_8PSK = 8,
-  MOD_16APSK = 16,
-  MOD_32APSK = 32,
+  AUTO = (1 << 0) /* 1 */,
+  MOD_BPSK = (1 << 1) /* 2 */,
+  MOD_QPSK = (1 << 2) /* 4 */,
+  MOD_8PSK = (1 << 3) /* 8 */,
+  MOD_16APSK = (1 << 4) /* 16 */,
+  MOD_32APSK = (1 << 5) /* 32 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbs3Rolloff.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbs3Rolloff.aidl
index 733760c..c93cf20 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbs3Rolloff.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbs3Rolloff.aidl
@@ -35,6 +35,6 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum FrontendIsdbs3Rolloff {
-  UNDEFINED = 0,
-  ROLLOFF_0_03 = 1,
+  UNDEFINED,
+  ROLLOFF_0_03,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbsCoderate.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbsCoderate.aidl
index 09e9c59..a0e436f 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbsCoderate.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbsCoderate.aidl
@@ -36,10 +36,10 @@
 @Backing(type="int") @VintfStability
 enum FrontendIsdbsCoderate {
   UNDEFINED = 0,
-  AUTO = 1,
-  CODERATE_1_2 = 2,
-  CODERATE_2_3 = 4,
-  CODERATE_3_4 = 8,
-  CODERATE_5_6 = 16,
-  CODERATE_7_8 = 32,
+  AUTO = (1 << 0) /* 1 */,
+  CODERATE_1_2 = (1 << 1) /* 2 */,
+  CODERATE_2_3 = (1 << 2) /* 4 */,
+  CODERATE_3_4 = (1 << 3) /* 8 */,
+  CODERATE_5_6 = (1 << 4) /* 16 */,
+  CODERATE_7_8 = (1 << 5) /* 32 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbsModulation.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbsModulation.aidl
index 7b9bde6..61a21c3 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbsModulation.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbsModulation.aidl
@@ -36,8 +36,8 @@
 @Backing(type="int") @VintfStability
 enum FrontendIsdbsModulation {
   UNDEFINED = 0,
-  AUTO = 1,
-  MOD_BPSK = 2,
-  MOD_QPSK = 4,
-  MOD_TC8PSK = 8,
+  AUTO = (1 << 0) /* 1 */,
+  MOD_BPSK = (1 << 1) /* 2 */,
+  MOD_QPSK = (1 << 2) /* 4 */,
+  MOD_TC8PSK = (1 << 3) /* 8 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbsRolloff.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbsRolloff.aidl
index a2ab154..b769231 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbsRolloff.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbsRolloff.aidl
@@ -35,6 +35,6 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum FrontendIsdbsRolloff {
-  UNDEFINED = 0,
-  ROLLOFF_0_35 = 1,
+  UNDEFINED,
+  ROLLOFF_0_35,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbsStreamIdType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbsStreamIdType.aidl
index 089f611..77956b6 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbsStreamIdType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbsStreamIdType.aidl
@@ -35,7 +35,7 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum FrontendIsdbsStreamIdType {
-  STREAM_ID = 0,
-  RELATIVE_STREAM_NUMBER = 1,
-  UNDEFINED = 2,
+  STREAM_ID,
+  RELATIVE_STREAM_NUMBER,
+  UNDEFINED,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtBandwidth.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtBandwidth.aidl
index cd49214..209620f 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtBandwidth.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtBandwidth.aidl
@@ -36,8 +36,8 @@
 @Backing(type="int") @VintfStability
 enum FrontendIsdbtBandwidth {
   UNDEFINED = 0,
-  AUTO = 1,
-  BANDWIDTH_8MHZ = 2,
-  BANDWIDTH_7MHZ = 4,
-  BANDWIDTH_6MHZ = 8,
+  AUTO = (1 << 0) /* 1 */,
+  BANDWIDTH_8MHZ = (1 << 1) /* 2 */,
+  BANDWIDTH_7MHZ = (1 << 2) /* 4 */,
+  BANDWIDTH_6MHZ = (1 << 3) /* 8 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtCoderate.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtCoderate.aidl
index 2b747ed..4236b7c 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtCoderate.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtCoderate.aidl
@@ -36,14 +36,14 @@
 @Backing(type="int") @VintfStability
 enum FrontendIsdbtCoderate {
   UNDEFINED = 0,
-  AUTO = 1,
-  CODERATE_1_2 = 2,
-  CODERATE_2_3 = 4,
-  CODERATE_3_4 = 8,
-  CODERATE_5_6 = 16,
-  CODERATE_7_8 = 32,
-  CODERATE_3_5 = 64,
-  CODERATE_4_5 = 128,
-  CODERATE_6_7 = 256,
-  CODERATE_8_9 = 512,
+  AUTO = (1 << 0) /* 1 */,
+  CODERATE_1_2 = (1 << 1) /* 2 */,
+  CODERATE_2_3 = (1 << 2) /* 4 */,
+  CODERATE_3_4 = (1 << 3) /* 8 */,
+  CODERATE_5_6 = (1 << 4) /* 16 */,
+  CODERATE_7_8 = (1 << 5) /* 32 */,
+  CODERATE_3_5 = (1 << 6) /* 64 */,
+  CODERATE_4_5 = (1 << 7) /* 128 */,
+  CODERATE_6_7 = (1 << 8) /* 256 */,
+  CODERATE_8_9 = (1 << 9) /* 512 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtGuardInterval.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtGuardInterval.aidl
index 42a023a..86225e2 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtGuardInterval.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtGuardInterval.aidl
@@ -36,12 +36,12 @@
 @Backing(type="int") @VintfStability
 enum FrontendIsdbtGuardInterval {
   UNDEFINED = 0,
-  AUTO = 1,
-  INTERVAL_1_32 = 2,
-  INTERVAL_1_16 = 4,
-  INTERVAL_1_8 = 8,
-  INTERVAL_1_4 = 16,
-  INTERVAL_1_128 = 32,
-  INTERVAL_19_128 = 64,
-  INTERVAL_19_256 = 128,
+  AUTO = (1 << 0) /* 1 */,
+  INTERVAL_1_32 = (1 << 1) /* 2 */,
+  INTERVAL_1_16 = (1 << 2) /* 4 */,
+  INTERVAL_1_8 = (1 << 3) /* 8 */,
+  INTERVAL_1_4 = (1 << 4) /* 16 */,
+  INTERVAL_1_128 = (1 << 5) /* 32 */,
+  INTERVAL_19_128 = (1 << 6) /* 64 */,
+  INTERVAL_19_256 = (1 << 7) /* 128 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtMode.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtMode.aidl
index 54698ab..0e38c26 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtMode.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtMode.aidl
@@ -36,8 +36,8 @@
 @Backing(type="int") @VintfStability
 enum FrontendIsdbtMode {
   UNDEFINED = 0,
-  AUTO = 1,
-  MODE_1 = 2,
-  MODE_2 = 4,
-  MODE_3 = 8,
+  AUTO = (1 << 0) /* 1 */,
+  MODE_1 = (1 << 1) /* 2 */,
+  MODE_2 = (1 << 2) /* 4 */,
+  MODE_3 = (1 << 3) /* 8 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtModulation.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtModulation.aidl
index a31e0cf..4474c83 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtModulation.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtModulation.aidl
@@ -36,9 +36,9 @@
 @Backing(type="int") @VintfStability
 enum FrontendIsdbtModulation {
   UNDEFINED = 0,
-  AUTO = 1,
-  MOD_DQPSK = 2,
-  MOD_QPSK = 4,
-  MOD_16QAM = 8,
-  MOD_64QAM = 16,
+  AUTO = (1 << 0) /* 1 */,
+  MOD_DQPSK = (1 << 1) /* 2 */,
+  MOD_QPSK = (1 << 2) /* 4 */,
+  MOD_16QAM = (1 << 3) /* 8 */,
+  MOD_64QAM = (1 << 4) /* 16 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtPartialReceptionFlag.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtPartialReceptionFlag.aidl
index 133887f..1387e66 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtPartialReceptionFlag.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtPartialReceptionFlag.aidl
@@ -36,7 +36,7 @@
 @Backing(type="int") @VintfStability
 enum FrontendIsdbtPartialReceptionFlag {
   UNDEFINED = 0,
-  AUTO = 1,
-  FALSE = 2,
-  TRUE = 4,
+  AUTO = (1 << 0) /* 1 */,
+  FALSE = (1 << 1) /* 2 */,
+  TRUE = (1 << 2) /* 4 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtTimeInterleaveMode.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtTimeInterleaveMode.aidl
index 50adde9..b9d76ee 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtTimeInterleaveMode.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendIsdbtTimeInterleaveMode.aidl
@@ -36,17 +36,17 @@
 @Backing(type="int") @VintfStability
 enum FrontendIsdbtTimeInterleaveMode {
   UNDEFINED = 0,
-  AUTO = 1,
-  INTERLEAVE_1_0 = 2,
-  INTERLEAVE_1_4 = 4,
-  INTERLEAVE_1_8 = 8,
-  INTERLEAVE_1_16 = 16,
-  INTERLEAVE_2_0 = 32,
-  INTERLEAVE_2_2 = 64,
-  INTERLEAVE_2_4 = 128,
-  INTERLEAVE_2_8 = 256,
-  INTERLEAVE_3_0 = 512,
-  INTERLEAVE_3_1 = 1024,
-  INTERLEAVE_3_2 = 2048,
-  INTERLEAVE_3_4 = 4096,
+  AUTO = (1 << 0) /* 1 */,
+  INTERLEAVE_1_0 = (1 << 1) /* 2 */,
+  INTERLEAVE_1_4 = (1 << 2) /* 4 */,
+  INTERLEAVE_1_8 = (1 << 3) /* 8 */,
+  INTERLEAVE_1_16 = (1 << 4) /* 16 */,
+  INTERLEAVE_2_0 = (1 << 5) /* 32 */,
+  INTERLEAVE_2_2 = (1 << 6) /* 64 */,
+  INTERLEAVE_2_4 = (1 << 7) /* 128 */,
+  INTERLEAVE_2_8 = (1 << 8) /* 256 */,
+  INTERLEAVE_3_0 = (1 << 9) /* 512 */,
+  INTERLEAVE_3_1 = (1 << 10) /* 1024 */,
+  INTERLEAVE_3_2 = (1 << 11) /* 2048 */,
+  INTERLEAVE_3_4 = (1 << 12) /* 4096 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendScanMessageType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendScanMessageType.aidl
index 6976ecd..186dbd7 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendScanMessageType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendScanMessageType.aidl
@@ -35,20 +35,20 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum FrontendScanMessageType {
-  LOCKED = 0,
-  END = 1,
-  PROGRESS_PERCENT = 2,
-  FREQUENCY = 3,
-  SYMBOL_RATE = 4,
-  HIERARCHY = 5,
-  ANALOG_TYPE = 6,
-  PLP_IDS = 7,
-  GROUP_IDS = 8,
-  INPUT_STREAM_IDS = 9,
-  STANDARD = 10,
-  ATSC3_PLP_INFO = 11,
-  MODULATION = 12,
-  DVBC_ANNEX = 13,
-  HIGH_PRIORITY = 14,
-  DVBT_CELL_IDS = 15,
+  LOCKED,
+  END,
+  PROGRESS_PERCENT,
+  FREQUENCY,
+  SYMBOL_RATE,
+  HIERARCHY,
+  ANALOG_TYPE,
+  PLP_IDS,
+  GROUP_IDS,
+  INPUT_STREAM_IDS,
+  STANDARD,
+  ATSC3_PLP_INFO,
+  MODULATION,
+  DVBC_ANNEX,
+  HIGH_PRIORITY,
+  DVBT_CELL_IDS,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendScanType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendScanType.aidl
index ed42d0a..cef02cc 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendScanType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendScanType.aidl
@@ -36,6 +36,6 @@
 @Backing(type="int") @VintfStability
 enum FrontendScanType {
   SCAN_UNDEFINED = 0,
-  SCAN_AUTO = 1,
-  SCAN_BLIND = 2,
+  SCAN_AUTO = (1 << 0) /* 1 */,
+  SCAN_BLIND = (1 << 1) /* 2 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendSpectralInversion.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendSpectralInversion.aidl
index ff11bb8..14ec2fd 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendSpectralInversion.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendSpectralInversion.aidl
@@ -35,7 +35,7 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum FrontendSpectralInversion {
-  UNDEFINED = 0,
-  NORMAL = 1,
-  INVERTED = 2,
+  UNDEFINED,
+  NORMAL,
+  INVERTED,
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStandardExt.aidl
similarity index 81%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStandardExt.aidl
index 173ac17..88637db 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStandardExt.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2024 The Android Open Source Project
+ * 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.
@@ -31,10 +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.biometrics.fingerprint;
+package android.hardware.tv.tuner;
 /* @hide */
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+union FrontendStandardExt {
+  android.hardware.tv.tuner.FrontendDvbsStandard dvbsStandardExt = android.hardware.tv.tuner.FrontendDvbsStandard.UNDEFINED;
+  android.hardware.tv.tuner.FrontendDvbtStandard dvbtStandardExt = android.hardware.tv.tuner.FrontendDvbtStandard.UNDEFINED;
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatus.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatus.aidl
index b991ab6..e79eba6 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatus.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatus.aidl
@@ -82,4 +82,5 @@
   long iptvPacketsLost;
   int iptvWorstJitterMs;
   int iptvAverageJitterMs;
+  android.hardware.tv.tuner.FrontendStandardExt standardExt;
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatusReadiness.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatusReadiness.aidl
index 41944ce..13735fa 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatusReadiness.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatusReadiness.aidl
@@ -35,9 +35,9 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum FrontendStatusReadiness {
-  UNDEFINED = 0,
-  UNAVAILABLE = 1,
-  UNSTABLE = 2,
-  STABLE = 3,
-  UNSUPPORTED = 4,
+  UNDEFINED,
+  UNAVAILABLE,
+  UNSTABLE,
+  STABLE,
+  UNSUPPORTED,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatusType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatusType.aidl
index 3791299..bfd2145 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatusType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatusType.aidl
@@ -35,51 +35,52 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum FrontendStatusType {
-  DEMOD_LOCK = 0,
-  SNR = 1,
-  BER = 2,
-  PER = 3,
-  PRE_BER = 4,
-  SIGNAL_QUALITY = 5,
-  SIGNAL_STRENGTH = 6,
-  SYMBOL_RATE = 7,
-  FEC = 8,
-  MODULATION = 9,
-  SPECTRAL = 10,
-  LNB_VOLTAGE = 11,
-  PLP_ID = 12,
-  EWBS = 13,
-  AGC = 14,
-  LNA = 15,
-  LAYER_ERROR = 16,
-  MER = 17,
-  FREQ_OFFSET = 18,
-  HIERARCHY = 19,
-  RF_LOCK = 20,
-  ATSC3_PLP_INFO = 21,
-  MODULATIONS = 22,
-  BERS = 23,
-  CODERATES = 24,
-  BANDWIDTH = 25,
-  GUARD_INTERVAL = 26,
-  TRANSMISSION_MODE = 27,
-  UEC = 28,
-  T2_SYSTEM_ID = 29,
-  INTERLEAVINGS = 30,
-  ISDBT_SEGMENTS = 31,
-  TS_DATA_RATES = 32,
-  ROLL_OFF = 33,
-  IS_MISO = 34,
-  IS_LINEAR = 35,
-  IS_SHORT_FRAMES = 36,
-  ISDBT_MODE = 37,
-  ISDBT_PARTIAL_RECEPTION_FLAG = 38,
-  STREAM_ID_LIST = 39,
-  DVBT_CELL_IDS = 40,
-  ATSC3_ALL_PLP_INFO = 41,
-  IPTV_CONTENT_URL = 42,
-  IPTV_PACKETS_LOST = 43,
-  IPTV_PACKETS_RECEIVED = 44,
-  IPTV_WORST_JITTER_MS = 45,
-  IPTV_AVERAGE_JITTER_MS = 46,
+  DEMOD_LOCK,
+  SNR,
+  BER,
+  PER,
+  PRE_BER,
+  SIGNAL_QUALITY,
+  SIGNAL_STRENGTH,
+  SYMBOL_RATE,
+  FEC,
+  MODULATION,
+  SPECTRAL,
+  LNB_VOLTAGE,
+  PLP_ID,
+  EWBS,
+  AGC,
+  LNA,
+  LAYER_ERROR,
+  MER,
+  FREQ_OFFSET,
+  HIERARCHY,
+  RF_LOCK,
+  ATSC3_PLP_INFO,
+  MODULATIONS,
+  BERS,
+  CODERATES,
+  BANDWIDTH,
+  GUARD_INTERVAL,
+  TRANSMISSION_MODE,
+  UEC,
+  T2_SYSTEM_ID,
+  INTERLEAVINGS,
+  ISDBT_SEGMENTS,
+  TS_DATA_RATES,
+  ROLL_OFF,
+  IS_MISO,
+  IS_LINEAR,
+  IS_SHORT_FRAMES,
+  ISDBT_MODE,
+  ISDBT_PARTIAL_RECEPTION_FLAG,
+  STREAM_ID_LIST,
+  DVBT_CELL_IDS,
+  ATSC3_ALL_PLP_INFO,
+  IPTV_CONTENT_URL,
+  IPTV_PACKETS_LOST,
+  IPTV_PACKETS_RECEIVED,
+  IPTV_WORST_JITTER_MS,
+  IPTV_AVERAGE_JITTER_MS,
+  STANDARD_EXT,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendType.aidl
index cbf5b47..455bbc0 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendType.aidl
@@ -36,15 +36,15 @@
 @Backing(type="int") @VintfStability
 enum FrontendType {
   UNDEFINED = 0,
-  ANALOG = 1,
-  ATSC = 2,
-  ATSC3 = 3,
-  DVBC = 4,
-  DVBS = 5,
-  DVBT = 6,
-  ISDBS = 7,
-  ISDBS3 = 8,
-  ISDBT = 9,
-  DTMB = 10,
-  IPTV = 11,
+  ANALOG,
+  ATSC,
+  ATSC3,
+  DVBC,
+  DVBS,
+  DVBT,
+  ISDBS,
+  ISDBS3,
+  ISDBT,
+  DTMB,
+  IPTV,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/LnbEventType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/LnbEventType.aidl
index e6e2b05..7bec809 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/LnbEventType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/LnbEventType.aidl
@@ -35,8 +35,8 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum LnbEventType {
-  DISEQC_RX_OVERFLOW = 0,
-  DISEQC_RX_TIMEOUT = 1,
-  DISEQC_RX_PARITY_ERROR = 2,
-  LNB_OVERLOAD = 3,
+  DISEQC_RX_OVERFLOW,
+  DISEQC_RX_TIMEOUT,
+  DISEQC_RX_PARITY_ERROR,
+  LNB_OVERLOAD,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/LnbPosition.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/LnbPosition.aidl
index 5fc4d15..a4a5740 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/LnbPosition.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/LnbPosition.aidl
@@ -35,7 +35,7 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum LnbPosition {
-  UNDEFINED = 0,
-  POSITION_A = 1,
-  POSITION_B = 2,
+  UNDEFINED,
+  POSITION_A,
+  POSITION_B,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/LnbTone.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/LnbTone.aidl
index 3217de9..0628354 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/LnbTone.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/LnbTone.aidl
@@ -35,6 +35,6 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum LnbTone {
-  NONE = 0,
-  CONTINUOUS = 1,
+  NONE,
+  CONTINUOUS,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/LnbVoltage.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/LnbVoltage.aidl
index 034c7e6..b18ff0e 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/LnbVoltage.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/LnbVoltage.aidl
@@ -35,13 +35,13 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum LnbVoltage {
-  NONE = 0,
-  VOLTAGE_5V = 1,
-  VOLTAGE_11V = 2,
-  VOLTAGE_12V = 3,
-  VOLTAGE_13V = 4,
-  VOLTAGE_14V = 5,
-  VOLTAGE_15V = 6,
-  VOLTAGE_18V = 7,
-  VOLTAGE_19V = 8,
+  NONE,
+  VOLTAGE_5V,
+  VOLTAGE_11V,
+  VOLTAGE_12V,
+  VOLTAGE_13V,
+  VOLTAGE_14V,
+  VOLTAGE_15V,
+  VOLTAGE_18V,
+  VOLTAGE_19V,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/PlaybackStatus.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/PlaybackStatus.aidl
index 850b737..a8b6378 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/PlaybackStatus.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/PlaybackStatus.aidl
@@ -35,8 +35,8 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum PlaybackStatus {
-  SPACE_EMPTY = 1,
-  SPACE_ALMOST_EMPTY = 2,
-  SPACE_ALMOST_FULL = 4,
-  SPACE_FULL = 8,
+  SPACE_EMPTY = (1 << 0) /* 1 */,
+  SPACE_ALMOST_EMPTY = (1 << 1) /* 2 */,
+  SPACE_ALMOST_FULL = (1 << 2) /* 4 */,
+  SPACE_FULL = (1 << 3) /* 8 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/RecordStatus.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/RecordStatus.aidl
index 48bf9ec..e06b616 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/RecordStatus.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/RecordStatus.aidl
@@ -35,8 +35,8 @@
 /* @hide */
 @Backing(type="byte") @VintfStability
 enum RecordStatus {
-  DATA_READY = 1,
-  LOW_WATER = 2,
-  HIGH_WATER = 4,
-  OVERFLOW = 8,
+  DATA_READY = (1 << 0) /* 1 */,
+  LOW_WATER = (1 << 1) /* 2 */,
+  HIGH_WATER = (1 << 2) /* 4 */,
+  OVERFLOW = (1 << 3) /* 8 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/Result.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/Result.aidl
index 4e22f67..ae43350 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/Result.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/Result.aidl
@@ -35,11 +35,11 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum Result {
-  SUCCESS = 0,
-  UNAVAILABLE = 1,
-  NOT_INITIALIZED = 2,
-  INVALID_STATE = 3,
-  INVALID_ARGUMENT = 4,
-  OUT_OF_MEMORY = 5,
-  UNKNOWN_ERROR = 6,
+  SUCCESS,
+  UNAVAILABLE,
+  NOT_INITIALIZED,
+  INVALID_STATE,
+  INVALID_ARGUMENT,
+  OUT_OF_MEMORY,
+  UNKNOWN_ERROR,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/ScramblingStatus.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/ScramblingStatus.aidl
index 656fe20..4d52de1 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/ScramblingStatus.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/ScramblingStatus.aidl
@@ -35,7 +35,7 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum ScramblingStatus {
-  UNKNOWN = 1,
-  NOT_SCRAMBLED = 2,
-  SCRAMBLED = 4,
+  UNKNOWN = (1 << 0) /* 1 */,
+  NOT_SCRAMBLED = (1 << 1) /* 2 */,
+  SCRAMBLED = (1 << 2) /* 4 */,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/VideoStreamType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/VideoStreamType.aidl
index dbb6033..530f454 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/VideoStreamType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/VideoStreamType.aidl
@@ -35,18 +35,18 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum VideoStreamType {
-  UNDEFINED = 0,
-  RESERVED = 1,
-  MPEG1 = 2,
-  MPEG2 = 3,
-  MPEG4P2 = 4,
-  AVC = 5,
-  HEVC = 6,
-  VC1 = 7,
-  VP8 = 8,
-  VP9 = 9,
-  AV1 = 10,
-  AVS = 11,
-  AVS2 = 12,
-  VVC = 13,
+  UNDEFINED,
+  RESERVED,
+  MPEG1,
+  MPEG2,
+  MPEG4P2,
+  AVC,
+  HEVC,
+  VC1,
+  VP8,
+  VP9,
+  AV1,
+  AVS,
+  AVS2,
+  VVC,
 }
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterMediaEvent.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterMediaEvent.aidl
index 32f0cb2..06f087b 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterMediaEvent.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterMediaEvent.aidl
@@ -17,7 +17,6 @@
 package android.hardware.tv.tuner;
 
 import android.hardware.common.NativeHandle;
-
 import android.hardware.tv.tuner.DemuxFilterMediaEventExtraMetaData;
 import android.hardware.tv.tuner.DemuxFilterScIndexMask;
 
@@ -91,4 +90,32 @@
      * access unit framing at decode stage.
      */
     DemuxFilterScIndexMask scIndexMask;
+
+    /**
+     * This attribute is used together with dataGroupId and indexInDataGroup to
+     * associate fragmented data.
+     *
+     * 1 if the media event contains the complete data. dataGroupId can be
+     * ignored.
+     * Greater than 1 if the media event contains incomplete data. Data can be
+     * reassembled by gathering all media events with the same dataGroupId.
+     */
+    int numDataPieces;
+
+    /**
+     * This attribute is used together with numDataPieces and dataGroupId to
+     * associate fragmented data.
+     *
+     * The value should be in the range of [0, numDataPieces - 1], indicating
+     * this piece is the Nth piece.
+     */
+    int indexInDataGroup;
+
+    /**
+     * This attribute is used together with numDataPieces and indexInDataGroup to
+     * associate fragmented data.
+     *
+     * The value is the id of the data group.
+     */
+    int dataGroupId;
 }
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStandardExt.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStandardExt.aidl
new file mode 100644
index 0000000..0b68e89
--- /dev/null
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStandardExt.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.tv.tuner;
+
+import android.hardware.tv.tuner.FrontendDvbsStandard;
+import android.hardware.tv.tuner.FrontendDvbtStandard;
+
+/**
+ * @hide
+ */
+@VintfStability
+union FrontendStandardExt {
+    /**
+     * The DVB-S standard extension after standard transition.
+     */
+    FrontendDvbsStandard dvbsStandardExt = FrontendDvbsStandard.UNDEFINED;
+
+    /**
+     * The DVB-T standard extension after standard transition.
+     */
+    FrontendDvbtStandard dvbtStandardExt = FrontendDvbtStandard.UNDEFINED;
+}
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatus.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatus.aidl
index 391f29b..a3902df 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatus.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatus.aidl
@@ -28,6 +28,7 @@
 import android.hardware.tv.tuner.FrontendRollOff;
 import android.hardware.tv.tuner.FrontendScanAtsc3PlpInfo;
 import android.hardware.tv.tuner.FrontendSpectralInversion;
+import android.hardware.tv.tuner.FrontendStandardExt;
 import android.hardware.tv.tuner.FrontendStatusAtsc3PlpInfo;
 import android.hardware.tv.tuner.FrontendTransmissionMode;
 import android.hardware.tv.tuner.LnbVoltage;
@@ -272,4 +273,13 @@
      * Average jitter (milliseconds).
      */
     int iptvAverageJitterMs;
+
+    /**
+     * Standard extension.
+     *
+     * DVB-T and DVB-S can transition to another standard within the same standard series. For
+     * example, DVB-T can transition to DVB-T2 and back. This attribute represents the standard
+     * extension. Valid values include FrontendDvbtStandard.T or FrontendDvbsStandard.S2 etc.
+     */
+    FrontendStandardExt standardExt;
 }
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatusType.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatusType.aidl
index 6804b2d..3225c42 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatusType.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatusType.aidl
@@ -259,4 +259,9 @@
      * Average jitter (milliseconds).
      */
     IPTV_AVERAGE_JITTER_MS,
+
+    /**
+     * Standard extension.
+     */
+    STANDARD_EXT,
 }
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/default/Filter.cpp b/tv/tuner/aidl/default/Filter.cpp
index 5f7a4cd..946ec3a 100644
--- a/tv/tuner/aidl/default/Filter.cpp
+++ b/tv/tuner/aidl/default/Filter.cpp
@@ -333,8 +333,8 @@
     // All the filter event callbacks in start are for testing purpose.
     switch (mType.mainType) {
         case DemuxFilterMainType::TS:
-            createMediaEvent(events, false);
-            createMediaEvent(events, true);
+            createMediaEvent(events, false, 0);
+            createMediaEvent(events, true, 1);
             createTsRecordEvent(events);
             createTemiEvent(events);
             break;
@@ -1235,7 +1235,8 @@
     return (stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino);
 }
 
-void Filter::createMediaEvent(vector<DemuxFilterEvent>& events, bool isAudioPresentation) {
+void Filter::createMediaEvent(vector<DemuxFilterEvent>& events, bool isAudioPresentation,
+                              int indexInDataGroup) {
     DemuxFilterMediaEvent mediaEvent;
     mediaEvent.streamId = 1;
     mediaEvent.isPtsPresent = true;
@@ -1302,6 +1303,10 @@
     mediaEvent.avDataId = static_cast<int64_t>(dataId);
     mediaEvent.avMemory = ::android::dupToAidl(nativeHandle);
 
+    mediaEvent.numDataPieces = 2;
+    mediaEvent.indexInDataGroup = indexInDataGroup;
+    mediaEvent.dataGroupId = 321;
+
     events.push_back(DemuxFilterEvent::make<DemuxFilterEvent::Tag::media>(std::move(mediaEvent)));
 
     native_handle_close(nativeHandle);
diff --git a/tv/tuner/aidl/default/Filter.h b/tv/tuner/aidl/default/Filter.h
index e2a0c7a..4be15e2 100644
--- a/tv/tuner/aidl/default/Filter.h
+++ b/tv/tuner/aidl/default/Filter.h
@@ -231,7 +231,8 @@
     ::ndk::ScopedAStatus createShareMemMediaEvents(vector<int8_t>& output);
     bool sameFile(int fd1, int fd2);
 
-    void createMediaEvent(vector<DemuxFilterEvent>&, bool isAudioPresentation);
+    void createMediaEvent(vector<DemuxFilterEvent>&, bool isAudioPresentation,
+                          int indexInDataGroup);
     void createTsRecordEvent(vector<DemuxFilterEvent>&);
     void createMmtpRecordEvent(vector<DemuxFilterEvent>&);
     void createSectionEvent(vector<DemuxFilterEvent>&);
diff --git a/tv/tuner/aidl/default/Frontend.cpp b/tv/tuner/aidl/default/Frontend.cpp
index 1031604..bba004a 100644
--- a/tv/tuner/aidl/default/Frontend.cpp
+++ b/tv/tuner/aidl/default/Frontend.cpp
@@ -81,6 +81,7 @@
                     FrontendStatusType::SIGNAL_STRENGTH, FrontendStatusType::SYMBOL_RATE,
                     FrontendStatusType::MODULATION,      FrontendStatusType::MODULATIONS,
                     FrontendStatusType::ROLL_OFF,        FrontendStatusType::IS_MISO,
+                    FrontendStatusType::STANDARD_EXT,
             };
             break;
         }
@@ -96,6 +97,7 @@
                     FrontendStatusType::TRANSMISSION_MODE,
                     FrontendStatusType::T2_SYSTEM_ID,
                     FrontendStatusType::DVBT_CELL_IDS,
+                    FrontendStatusType::STANDARD_EXT,
             };
             break;
         }
@@ -985,6 +987,17 @@
                 status.set<FrontendStatus::iptvAverageJitterMs>(5);
                 break;
             }
+            case FrontendStatusType::STANDARD_EXT: {
+                FrontendStandardExt standardExt;
+                if (mType == FrontendType::DVBS) {
+                    standardExt.set<FrontendStandardExt::dvbsStandardExt>(
+                            FrontendDvbsStandard::S2X);
+                } else if (mType == FrontendType::DVBT) {
+                    standardExt.set<FrontendStandardExt::dvbtStandardExt>(FrontendDvbtStandard::T2);
+                }
+                status.set<FrontendStatus::standardExt>(standardExt);
+                break;
+            }
             default: {
                 continue;
             }
diff --git a/tv/tuner/aidl/default/tuner-default.xml b/tv/tuner/aidl/default/tuner-default.xml
index bff8ff0..261fcbf 100644
--- a/tv/tuner/aidl/default/tuner-default.xml
+++ b/tv/tuner/aidl/default/tuner-default.xml
@@ -2,6 +2,6 @@
     <hal format="aidl">
         <name>android.hardware.tv.tuner</name>
         <fqname>ITuner/default</fqname>
-        <version>2</version>
+        <version>3</version>
     </hal>
 </manifest>
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/FilterTests.cpp b/tv/tuner/aidl/vts/functional/FilterTests.cpp
index 533d0e6..788ebbd 100644
--- a/tv/tuner/aidl/vts/functional/FilterTests.cpp
+++ b/tv/tuner/aidl/vts/functional/FilterTests.cpp
@@ -105,17 +105,30 @@
     // todo separate filter handlers
     for (int i = 0; i < events.size(); i++) {
         switch (events[i].getTag()) {
-            case DemuxFilterEvent::Tag::media:
-                ALOGD("[vts] Media filter event, avMemHandle numFds=%zu.",
-                      events[i].get<DemuxFilterEvent::Tag::media>().avMemory.fds.size());
+            case DemuxFilterEvent::Tag::media: {
+                int numDataPieces = events[i].get<DemuxFilterEvent::Tag::media>().numDataPieces;
+                int indexInDataGroup
+                    = events[i].get<DemuxFilterEvent::Tag::media>().indexInDataGroup;
+                ALOGD("[vts] Media filter event, avMemHandle numFds=%zu, numDataPieces=%d,"
+                      " indexInDataGroup=%d, dataGroupId=%d.",
+                      events[i].get<DemuxFilterEvent::Tag::media>().avMemory.fds.size(),
+                      numDataPieces,
+                      indexInDataGroup,
+                      events[i].get<DemuxFilterEvent::Tag::media>().dataGroupId);
+                if (numDataPieces > 1) {
+                    EXPECT_TRUE(indexInDataGroup >= 0);
+                    EXPECT_TRUE(indexInDataGroup < numDataPieces);
+                }
                 dumpAvData(events[i].get<DemuxFilterEvent::Tag::media>());
                 break;
-            case DemuxFilterEvent::Tag::tsRecord:
+            }
+            case DemuxFilterEvent::Tag::tsRecord: {
                 ALOGD("[vts] TS record filter event, pts=%" PRIu64 ", firstMbInSlice=%d",
                       events[i].get<DemuxFilterEvent::Tag::tsRecord>().pts,
                       events[i].get<DemuxFilterEvent::Tag::tsRecord>().firstMbInSlice);
                 break;
-            case DemuxFilterEvent::Tag::mmtpRecord:
+            }
+            case DemuxFilterEvent::Tag::mmtpRecord: {
                 ALOGD("[vts] MMTP record filter event, pts=%" PRIu64
                       ", firstMbInSlice=%d, mpuSequenceNumber=%d, tsIndexMask=%d",
                       events[i].get<DemuxFilterEvent::Tag::mmtpRecord>().pts,
@@ -123,7 +136,8 @@
                       events[i].get<DemuxFilterEvent::Tag::mmtpRecord>().mpuSequenceNumber,
                       events[i].get<DemuxFilterEvent::Tag::mmtpRecord>().tsIndexMask);
                 break;
-            case DemuxFilterEvent::Tag::monitorEvent:
+            }
+            case DemuxFilterEvent::Tag::monitorEvent: {
                 switch (events[i].get<DemuxFilterEvent::Tag::monitorEvent>().getTag()) {
                     case DemuxFilterMonitorEvent::Tag::scramblingStatus:
                         mScramblingStatusEvent++;
@@ -135,13 +149,16 @@
                         break;
                 }
                 break;
-            case DemuxFilterEvent::Tag::startId:
+            }
+            case DemuxFilterEvent::Tag::startId: {
                 ALOGD("[vts] Restart filter event, startId=%d",
                       events[i].get<DemuxFilterEvent::Tag::startId>());
                 mStartIdReceived = true;
                 break;
-            default:
+            }
+            default: {
                 break;
+            }
         }
     }
 }
diff --git a/tv/tuner/aidl/vts/functional/FrontendTests.cpp b/tv/tuner/aidl/vts/functional/FrontendTests.cpp
index 85d0496..99c0283 100644
--- a/tv/tuner/aidl/vts/functional/FrontendTests.cpp
+++ b/tv/tuner/aidl/vts/functional/FrontendTests.cpp
@@ -636,7 +636,7 @@
     ASSERT_TRUE(tuneFrontend(frontendConf, false /*testWithDemux*/));
 
     // TODO: find a better way to push all frontend status types
-    for (int32_t i = 0; i <= static_cast<int32_t>(FrontendStatusType::ATSC3_ALL_PLP_INFO); i++) {
+    for (int32_t i = 0; i <= static_cast<int32_t>(FrontendStatusType::STANDARD_EXT); i++) {
         allTypes.push_back(static_cast<FrontendStatusType>(i));
     }
 
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/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositePwleV2.aidl
similarity index 88%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositePwleV2.aidl
index 173ac17..de0bdb5 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositePwleV2.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.vibrator;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable CompositePwleV2 {
+  android.hardware.vibrator.PwleV2Primitive[] pwlePrimitives;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/FrequencyAccelerationMapEntry.aidl
similarity index 88%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/FrequencyAccelerationMapEntry.aidl
index 173ac17..e6743f9 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/FrequencyAccelerationMapEntry.aidl
@@ -31,10 +31,9 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
+package android.hardware.vibrator;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable FrequencyAccelerationMapEntry {
+  float frequencyHz;
+  float maxOutputAccelerationGs;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrationSession.aidl
similarity index 88%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrationSession.aidl
index 173ac17..ec301b2 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrationSession.aidl
@@ -31,10 +31,9 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
+package android.hardware.vibrator;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+interface IVibrationSession {
+  void close();
+  void abort();
 }
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..9fad952 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
@@ -51,22 +51,51 @@
   void alwaysOnDisable(in int id);
   float getResonantFrequency();
   float getQFactor();
+  /**
+   * @deprecated This method is deprecated from AIDL v3 and is no longer required to be implemented even if CAP_FREQUENCY_CONTROL capability is reported.
+   */
   float getFrequencyResolution();
+  /**
+   * @deprecated This method is deprecated from AIDL v3 and is no longer required to be implemented even if CAP_FREQUENCY_CONTROL capability is reported.
+   */
   float getFrequencyMinimum();
+  /**
+   * @deprecated This method is deprecated from AIDL v3 and is no longer required to be implemented even if CAP_FREQUENCY_CONTROL capability is reported.
+   */
   float[] getBandwidthAmplitudeMap();
+  /**
+   * @deprecated This method is deprecated from AIDL v3 and is no longer required to be implemented. Use `IVibrator.getPwleV2PrimitiveDurationMaxMillis` instead.
+   */
   int getPwlePrimitiveDurationMax();
+  /**
+   * @deprecated This method is deprecated from AIDL v3 and is no longer required to be implemented. Use `IVibrator.getPwleV2CompositionSizeMax` instead.
+   */
   int getPwleCompositionSizeMax();
+  /**
+   * @deprecated This method is deprecated from AIDL v3 and is no longer required to be implemented.
+   */
   android.hardware.vibrator.Braking[] getSupportedBraking();
+  /**
+   * @deprecated This method is deprecated from AIDL v3 and is no longer required to be implemented. Use `IVibrator.composePwleV2` instead.
+   */
   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.FrequencyAccelerationMapEntry> getFrequencyToOutputAccelerationMap();
+  int getPwleV2PrimitiveDurationMaxMillis();
+  int getPwleV2CompositionSizeMax();
+  int getPwleV2PrimitiveDurationMinMillis();
+  void composePwleV2(in android.hardware.vibrator.CompositePwleV2 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..081d9dc 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,15 @@
   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;
+  android.hardware.vibrator.IVibrationSession startSession(in int[] vibratorIds, in android.hardware.vibrator.VibrationSessionConfig config, in android.hardware.vibrator.IVibratorCallback callback);
+  void clearSessions();
+  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 */;
+  const int CAP_START_SESSIONS = (1 << 8) /* 256 */;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PwleV2Primitive.aidl
similarity index 88%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PwleV2Primitive.aidl
index 173ac17..c4f3ea9 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PwleV2Primitive.aidl
@@ -31,10 +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.biometrics.fingerprint;
-/* @hide */
+package android.hardware.vibrator;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+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/EnrollmentProgressStep.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/VendorEffect.aidl
similarity index 86%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/VendorEffect.aidl
index 173ac17..62a7380 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.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
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable VendorEffect {
+  android.os.PersistableBundle vendorData;
+  android.hardware.vibrator.EffectStrength strength = android.hardware.vibrator.EffectStrength.MEDIUM;
+  float scale;
+  float vendorScale;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/VibrationSessionConfig.aidl
similarity index 88%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/VibrationSessionConfig.aidl
index 173ac17..01136aa 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/VibrationSessionConfig.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.vibrator;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable VibrationSessionConfig {
+  ParcelableHolder vendorExtension;
 }
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/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/vibrator/aidl/android/hardware/vibrator/CompositePwleV2.aidl
similarity index 65%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
copy to vibrator/aidl/android/hardware/vibrator/CompositePwleV2.aidl
index c7be950..9662ca0 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/CompositePwleV2.aidl
@@ -14,22 +14,14 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+package android.hardware.vibrator;
 
-import android.hardware.biometrics.fingerprint.AcquiredInfo;
+import android.hardware.vibrator.PwleV2Primitive;
 
-/**
- * @hide
- */
 @VintfStability
-union AcquiredInfoAndVendorCode {
+parcelable CompositePwleV2 {
     /**
-     * Acquired info as specified in AcqauiredInfo.aidl
+     * An array of primitives that represents the PWLE effect
      */
-    AcquiredInfo acquiredInfo = AcquiredInfo.UNKNOWN;
-
-    /**
-     * Vendor specific code
-     */
-    int vendorCode;
+    PwleV2Primitive[] pwlePrimitives;
 }
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/FrequencyAccelerationMapEntry.aidl b/vibrator/aidl/android/hardware/vibrator/FrequencyAccelerationMapEntry.aidl
new file mode 100644
index 0000000..470dc80
--- /dev/null
+++ b/vibrator/aidl/android/hardware/vibrator/FrequencyAccelerationMapEntry.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 FrequencyAccelerationMapEntry {
+    /**
+     * 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/IVibrationSession.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrationSession.aidl
new file mode 100644
index 0000000..88382e5
--- /dev/null
+++ b/vibrator/aidl/android/hardware/vibrator/IVibrationSession.aidl
@@ -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.
+ */
+
+package android.hardware.vibrator;
+
+@VintfStability
+interface IVibrationSession {
+    /**
+     * Request the end of this session.
+     *
+     * This will cause this session to end once the ongoing vibration commands are completed in each
+     * individual vibrator. The immediate end of this session can stll be trigged via abort().
+     *
+     * This should not block on the end of this session. The callback provided during the creation
+     * of this session should be used to indicate the vibrations are done and the session has
+     * ended. The session object can be safely destroyed after this is called, and the session
+     * should end as expected.
+     */
+    void close();
+
+    /**
+     * Immediately end this session.
+     *
+     * This will cause this session to end immediately and stop any ongoing vibration. The vibrator
+     * manager and each individual vibrator in this session will be reset and available when this
+     * returns.
+     */
+    void abort();
+}
diff --git a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
index b4e7e44..a2f0017 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.CompositePwleV2;
+import android.hardware.vibrator.Effect;
+import android.hardware.vibrator.EffectStrength;
+import android.hardware.vibrator.FrequencyAccelerationMapEntry;
+import android.hardware.vibrator.IVibratorCallback;
 import android.hardware.vibrator.PrimitivePwle;
+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)
@@ -279,6 +290,8 @@
      *
      * @return The frequency resolution of the bandwidth amplitude map.
      *         Non-zero value if supported, or value should be ignored if not supported.
+     * @deprecated This method is deprecated from AIDL v3 and is no longer required to be
+     * implemented even if CAP_FREQUENCY_CONTROL capability is reported.
      */
     float getFrequencyResolution();
 
@@ -290,6 +303,8 @@
      *
      * @return The minimum frequency allowed. Non-zero value if supported,
      *         or value should be ignored if not supported.
+     * @deprecated This method is deprecated from AIDL v3 and is no longer required to be
+     * implemented even if CAP_FREQUENCY_CONTROL capability is reported.
      */
     float getFrequencyMinimum();
 
@@ -311,6 +326,8 @@
      *
      * @return The maximum output acceleration amplitude for each supported frequency,
      *         starting at getMinimumFrequency()
+     * @deprecated This method is deprecated from AIDL v3 and is no longer required to be
+     * implemented even if CAP_FREQUENCY_CONTROL capability is reported.
      */
     float[] getBandwidthAmplitudeMap();
 
@@ -322,6 +339,8 @@
      *
      * @return The maximum duration allowed for a single PrimitivePwle.
      *         Non-zero value if supported, or value should be ignored if not supported.
+     * @deprecated This method is deprecated from AIDL v3 and is no longer required to be
+     * implemented. Use `IVibrator.getPwleV2PrimitiveDurationMaxMillis` instead.
      */
     int getPwlePrimitiveDurationMax();
 
@@ -333,6 +352,8 @@
      *
      * @return The maximum count allowed. Non-zero value if supported,
      *         or value should be ignored if not supported.
+     * @deprecated This method is deprecated from AIDL v3 and is no longer required to be
+     * implemented. Use `IVibrator.getPwleV2CompositionSizeMax` instead.
      */
     int getPwleCompositionSizeMax();
 
@@ -344,6 +365,8 @@
      * Implementations are optional but encouraged if available.
      *
      * @return The braking mechanisms which are supported by the composePwle API.
+     * @deprecated This method is deprecated from AIDL v3 and is no longer required to be
+     * implemented.
      */
     Braking[] getSupportedBraking();
 
@@ -357,6 +380,111 @@
      * explicitly call off. IVibratorCallback.onComplete() support is required for this API.
      *
      * @param composite Array of PWLEs.
+     * @deprecated This method is deprecated from AIDL v3 and is no longer required to be
+     * implemented. Use `IVibrator.composePwleV2` instead.
      */
     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 `FrequencyAccelerationMapEntry` (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_FREQUENCY_CONTROL). 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<FrequencyAccelerationMapEntry> getFrequencyToOutputAccelerationMap();
+
+    /**
+     * 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).
+     *
+     * Note: Devices reporting CAP_COMPOSE_PWLE_EFFECTS_V2 support MUST also have the
+     * CAP_FREQUENCY_CONTROL capability and provide a valid frequency to output acceleration map.
+     *
+     * 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 A CompositePwleV2 representing a composite vibration effect, composed of an
+     *                  array of primitives that define the PWLE (Piecewise-Linear Envelope).
+     */
+    void composePwleV2(in CompositePwleV2 composite, in IVibratorCallback callback);
 }
diff --git a/vibrator/aidl/android/hardware/vibrator/IVibratorManager.aidl b/vibrator/aidl/android/hardware/vibrator/IVibratorManager.aidl
index eb5e9cc..e8b85c5 100644
--- a/vibrator/aidl/android/hardware/vibrator/IVibratorManager.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/IVibratorManager.aidl
@@ -16,8 +16,10 @@
 
 package android.hardware.vibrator;
 
+import android.hardware.vibrator.IVibrationSession;
 import android.hardware.vibrator.IVibrator;
 import android.hardware.vibrator.IVibratorCallback;
+import android.hardware.vibrator.VibrationSessionConfig;
 
 @VintfStability
 interface IVibratorManager {
@@ -42,17 +44,23 @@
      */
     const int CAP_MIXED_TRIGGER_ON = 1 << 4;
     /**
-     * Whether IVibrator 'perform' can be triggered with other functions in sync with 'triggerSynced'.
+     * Whether IVibrator 'perform' can be triggered with other functions in sync with
+     * 'triggerSynced'.
      */
     const int CAP_MIXED_TRIGGER_PERFORM = 1 << 5;
     /**
-     * Whether IVibrator 'compose' can be triggered with other functions in sync with 'triggerSynced'.
+     * Whether IVibrator 'compose' can be triggered with other functions in sync with
+     * 'triggerSynced'.
      */
     const int CAP_MIXED_TRIGGER_COMPOSE = 1 << 6;
     /**
      * Whether on w/ IVibratorCallback can be used w/ 'trigerSynced' function.
      */
     const int CAP_TRIGGER_CALLBACK = 1 << 7;
+    /**
+     * Whether vibration sessions are supported.
+     */
+    const int CAP_START_SESSIONS = 1 << 8;
 
     /**
      * Determine capabilities of the vibrator manager HAL (CAP_* mask)
@@ -75,8 +83,8 @@
      * This function must only be called after the previous synced vibration was triggered or
      * canceled (through cancelSynced()).
      *
-     * Doing this operation while any of the specified vibrators is already on is undefined behavior.
-     * Clients should explicitly call off in each vibrator.
+     * Doing this operation while any of the specified vibrators is already on is undefined
+     * behavior. Clients should explicitly call off in each vibrator.
      *
      * @param vibratorIds ids of the vibrators to play vibrations in sync.
      */
@@ -99,4 +107,41 @@
      * Cancel a previously-started preparation for synced vibration, if any.
      */
     void cancelSynced();
+
+    /**
+     * Start a vibration session.
+     *
+     * A vibration session can be used to send commands without resetting the vibrator state. Once a
+     * session starts, the individual vibrators can receive one or more commands like on(),
+     * performEffect(), setAmplitude(), etc. The vibrations performed in a session must have the
+     * same behavior they have outside them. Multiple commands can be synced in a session via
+     * prepareSynced as usual.
+     *
+     * Starting a session on a vibrator already in another session or in a prepareSynced state is
+     * not allowed and should throw illegal state. The end of a session should always notify the
+     * callback provided, even if it ends prematurely due to an error.
+     *
+     * This may not be supported and this support is reflected in
+     * getCapabilities (CAP_START_SESSIONS). IVibratorCallback.onComplete() support is required for
+     * this API.
+     *
+     * @param vibratorIds ids of the vibrators in the session.
+     * @param config The parameters for starting a vibration session.
+     * @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 invalid vibrator IDs.
+     *         - EX_ILLEGAL_STATE for vibrator IDs already in a session or in a prepareSynced state.
+     *         - EX_SERVICE_SPECIFIC for bad vendor data.
+     */
+    IVibrationSession startSession(
+            in int[] vibratorIds, in VibrationSessionConfig config, in IVibratorCallback callback);
+
+    /**
+     * Abort and clear all ongoing vibration sessions.
+     *
+     * This can be used to reset the vibrator manager and some individual vibrators to an idle
+     * state.
+     */
+    void clearSessions();
 }
diff --git a/vibrator/aidl/android/hardware/vibrator/PwleV2Primitive.aidl b/vibrator/aidl/android/hardware/vibrator/PwleV2Primitive.aidl
new file mode 100644
index 0000000..1ad1a9f
--- /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.getFrequencyToOutputAccelerationMap 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#getFrequencyToOutputAccelerationMap.
+     */
+    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/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/vibrator/aidl/android/hardware/vibrator/VibrationSessionConfig.aidl
similarity index 65%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
copy to vibrator/aidl/android/hardware/vibrator/VibrationSessionConfig.aidl
index c7be950..56cdde3 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/VibrationSessionConfig.aidl
@@ -14,22 +14,12 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+package android.hardware.vibrator;
 
-import android.hardware.biometrics.fingerprint.AcquiredInfo;
-
-/**
- * @hide
- */
 @VintfStability
-union AcquiredInfoAndVendorCode {
+parcelable VibrationSessionConfig {
     /**
-     * Acquired info as specified in AcqauiredInfo.aidl
+     * Vendor extension point for starting a vibration session.
      */
-    AcquiredInfo acquiredInfo = AcquiredInfo.UNKNOWN;
-
-    /**
-     * Vendor specific code
-     */
-    int vendorCode;
+    ParcelableHolder vendorExtension;
 }
diff --git a/vibrator/aidl/default/Android.bp b/vibrator/aidl/default/Android.bp
index 596c1a6..de228cd 100644
--- a/vibrator/aidl/default/Android.bp
+++ b/vibrator/aidl/default/Android.bp
@@ -15,10 +15,11 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.vibrator-V2-ndk",
+        "android.hardware.vibrator-V3-ndk",
     ],
     export_include_dirs: ["include"],
     srcs: [
+        "VibrationSession.cpp",
         "Vibrator.cpp",
         "VibratorManager.cpp",
     ],
@@ -49,7 +50,7 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.vibrator-V2-ndk",
+        "android.hardware.vibrator-V3-ndk",
     ],
     static_libs: [
         "libvibratorexampleimpl",
@@ -62,7 +63,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/VibrationSession.cpp b/vibrator/aidl/default/VibrationSession.cpp
new file mode 100644
index 0000000..cfb6608
--- /dev/null
+++ b/vibrator/aidl/default/VibrationSession.cpp
@@ -0,0 +1,44 @@
+/*
+ * 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-impl/VibrationSession.h"
+
+#include <android-base/logging.h>
+#include <thread>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace vibrator {
+
+static constexpr int32_t SESSION_END_DELAY_MS = 50;
+
+ndk::ScopedAStatus VibrationSession::close() {
+    LOG(VERBOSE) << "Vibration Session close";
+    mManager->closeSession(SESSION_END_DELAY_MS);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus VibrationSession::abort() {
+    LOG(VERBOSE) << "Vibration Session abort";
+    mManager->abortSession();
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp
index 01602ab..165a3bf 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,38 +42,115 @@
 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;
+
+void Vibrator::dispatchVibrate(int32_t timeoutMs,
+                               const std::shared_ptr<IVibratorCallback>& callback) {
+    std::lock_guard lock(mMutex);
+    if (mIsVibrating) {
+        // Already vibrating, ignore new request.
+        return;
+    }
+    mVibrationCallback = callback;
+    mIsVibrating = true;
+    // Note that thread lambdas aren't using implicit capture [=], to avoid capturing "this",
+    // which may be asynchronously destructed.
+    std::thread([timeoutMs, callback, sharedThis = this->ref<Vibrator>()] {
+        LOG(VERBOSE) << "Starting delayed callback on another thread";
+        usleep(timeoutMs * 1000);
+
+        if (sharedThis) {
+            std::lock_guard lock(sharedThis->mMutex);
+            sharedThis->mIsVibrating = false;
+            if (sharedThis->mVibrationCallback && (callback == sharedThis->mVibrationCallback)) {
+                LOG(VERBOSE) << "Notifying callback onComplete";
+                if (!sharedThis->mVibrationCallback->onComplete().isOk()) {
+                    LOG(ERROR) << "Failed to call onComplete";
+                }
+                sharedThis->mVibrationCallback = nullptr;
+            }
+            if (sharedThis->mGlobalVibrationCallback) {
+                LOG(VERBOSE) << "Notifying global callback onComplete";
+                if (!sharedThis->mGlobalVibrationCallback->onComplete().isOk()) {
+                    LOG(ERROR) << "Failed to call onComplete";
+                }
+                sharedThis->mGlobalVibrationCallback = nullptr;
+            }
+        }
+    }).detach();
+}
+
+void Vibrator::setGlobalVibrationCallback(const std::shared_ptr<IVibratorCallback>& callback) {
+    std::lock_guard lock(mMutex);
+    if (mIsVibrating) {
+        mGlobalVibrationCallback = callback;
+    } else if (callback) {
+        std::thread([callback] {
+            LOG(VERBOSE) << "Notifying global callback onComplete";
+            if (!callback->onComplete().isOk()) {
+                LOG(ERROR) << "Failed to call onComplete";
+            }
+        }).detach();
+    }
+}
+
 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) {
+        int32_t version;
+        if (!getInterfaceVersion(&version).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 (version >= 3) {
+            mCapabilities |=
+                    IVibrator::CAP_PERFORM_VENDOR_EFFECTS | IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2;
+        }
+    }
+
+    *_aidl_return = mCapabilities;
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Vibrator::off() {
     LOG(VERBOSE) << "Vibrator off";
+    std::lock_guard lock(mMutex);
+    std::shared_ptr<IVibratorCallback> callback = mVibrationCallback;
+    std::shared_ptr<IVibratorCallback> globalCallback = mGlobalVibrationCallback;
+    mIsVibrating = false;
+    mVibrationCallback = nullptr;
+    mGlobalVibrationCallback = nullptr;
+    if (callback || globalCallback) {
+        std::thread([callback, globalCallback] {
+            if (callback) {
+                LOG(VERBOSE) << "Notifying callback onComplete";
+                if (!callback->onComplete().isOk()) {
+                    LOG(ERROR) << "Failed to call onComplete";
+                }
+            }
+            if (globalCallback) {
+                LOG(VERBOSE) << "Notifying global callback onComplete";
+                if (!globalCallback->onComplete().isOk()) {
+                    LOG(ERROR) << "Failed to call onComplete";
+                }
+            }
+        }).detach();
+    }
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs,
                                 const std::shared_ptr<IVibratorCallback>& callback) {
     LOG(VERBOSE) << "Vibrator on for timeoutMs: " << timeoutMs;
-    if (callback != nullptr) {
-        // Note that thread lambdas aren't using implicit capture [=], to avoid capturing "this",
-        // which may be asynchronously destructed.
-        // If "this" is needed, use [sharedThis = this->ref<Vibrator>()].
-        std::thread([timeoutMs, callback] {
-            LOG(VERBOSE) << "Starting on on another thread";
-            usleep(timeoutMs * 1000);
-            LOG(VERBOSE) << "Notifying on complete";
-            if (!callback->onComplete().isOk()) {
-                LOG(ERROR) << "Failed to call onComplete";
-            }
-        }).detach();
-    }
+    dispatchVibrate(timeoutMs, callback);
     return ndk::ScopedAStatus::ok();
 }
 
@@ -88,17 +168,41 @@
     }
 
     constexpr size_t kEffectMillis = 100;
+    dispatchVibrate(kEffectMillis, callback);
+    *_aidl_return = kEffectMillis;
+    return ndk::ScopedAStatus::ok();
+}
 
-    if (callback != nullptr) {
-        std::thread([callback] {
-            LOG(VERBOSE) << "Starting perform on another thread";
-            usleep(kEffectMillis * 1000);
-            LOG(VERBOSE) << "Notifying perform complete";
-            callback->onComplete();
-        }).detach();
+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);
     }
 
-    *_aidl_return = kEffectMillis;
+    int32_t durationMs = 0;
+    if (!effect.vendorData.getInt("DURATION_MS", &durationMs) || durationMs <= 0) {
+        return ndk::ScopedAStatus::fromServiceSpecificError(ERROR_CODE_INVALID_DURATION);
+    }
+
+    dispatchVibrate(durationMs, callback);
     return ndk::ScopedAStatus::ok();
 }
 
@@ -177,28 +281,14 @@
         }
     }
 
-    // The thread may theoretically outlive the vibrator, so take a proper reference to it.
-    std::thread([sharedThis = this->ref<Vibrator>(), composite, callback] {
-        LOG(VERBOSE) << "Starting compose on another thread";
+    int32_t totalDuration = 0;
+    for (auto& e : composite) {
+        int32_t durationMs;
+        getPrimitiveDuration(e.primitive, &durationMs);
+        totalDuration += e.delayMs + durationMs;
+    }
 
-        for (auto& e : composite) {
-            if (e.delayMs) {
-                usleep(e.delayMs * 1000);
-            }
-            LOG(VERBOSE) << "triggering primitive " << static_cast<int>(e.primitive) << " @ scale "
-                         << e.scale;
-
-            int32_t durationMs;
-            sharedThis->getPrimitiveDuration(e.primitive, &durationMs);
-            usleep(durationMs * 1000);
-        }
-
-        if (callback != nullptr) {
-            LOG(VERBOSE) << "Notifying perform complete";
-            callback->onComplete();
-        }
-    }).detach();
-
+    dispatchVibrate(totalDuration, callback);
     return ndk::ScopedAStatus::ok();
 }
 
@@ -400,15 +490,127 @@
         }
     }
 
-    std::thread([totalDuration, callback] {
-        LOG(VERBOSE) << "Starting composePwle on another thread";
-        usleep(totalDuration * 1000);
-        if (callback != nullptr) {
-            LOG(VERBOSE) << "Notifying compose PWLE complete";
-            callback->onComplete();
-        }
-    }).detach();
+    dispatchVibrate(totalDuration, callback);
+    return ndk::ScopedAStatus::ok();
+}
 
+ndk::ScopedAStatus Vibrator::getFrequencyToOutputAccelerationMap(
+        std::vector<FrequencyAccelerationMapEntry>* _aidl_return) {
+    int32_t capabilities = 0;
+    if (!getCapabilities(&capabilities).isOk()) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if (!(capabilities & IVibrator::CAP_FREQUENCY_CONTROL)) {
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+    }
+
+    std::vector<FrequencyAccelerationMapEntry> 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(
+                FrequencyAccelerationMapEntry(/*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<FrequencyAccelerationMapEntry> 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<FrequencyAccelerationMapEntry> 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 CompositePwleV2& composite,
+                                           const std::shared_ptr<IVibratorCallback>& callback) {
+    LOG(VERBOSE) << "Vibrator compose PWLE V2";
+    int32_t capabilities = 0;
+    if (!getCapabilities(&capabilities).isOk()) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2) ||
+        !(capabilities & IVibrator::CAP_FREQUENCY_CONTROL)) {
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+    }
+
+    int compositionSizeMax;
+    getPwleV2CompositionSizeMax(&compositionSizeMax);
+    if (composite.pwlePrimitives.empty() || composite.pwlePrimitives.size() > compositionSizeMax) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+
+    int32_t totalEffectDuration = 0;
+    std::vector<FrequencyAccelerationMapEntry> frequencyToOutputAccelerationMap;
+    getFrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap);
+    float minFrequency = getPwleV2FrequencyMinHz(frequencyToOutputAccelerationMap);
+    float maxFrequency = getPwleV2FrequencyMaxHz(frequencyToOutputAccelerationMap);
+
+    for (auto& e : composite.pwlePrimitives) {
+        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;
+    }
+
+    dispatchVibrate(totalEffectDuration, callback);
     return ndk::ScopedAStatus::ok();
 }
 
diff --git a/vibrator/aidl/default/VibratorManager.cpp b/vibrator/aidl/default/VibratorManager.cpp
index 26edf5a..c3be468 100644
--- a/vibrator/aidl/default/VibratorManager.cpp
+++ b/vibrator/aidl/default/VibratorManager.cpp
@@ -15,6 +15,9 @@
  */
 
 #include "vibrator-impl/VibratorManager.h"
+#include "vibrator-impl/VibrationSession.h"
+
+#include <aidl/android/hardware/vibrator/BnVibratorCallback.h>
 
 #include <android-base/logging.h>
 #include <thread>
@@ -26,25 +29,52 @@
 
 static constexpr int32_t kDefaultVibratorId = 1;
 
+class VibratorCallback : public BnVibratorCallback {
+  public:
+    VibratorCallback(const std::function<void()>& callback) : mCallback(callback) {}
+    ndk::ScopedAStatus onComplete() override {
+        mCallback();
+        return ndk::ScopedAStatus::ok();
+    }
+
+  private:
+    std::function<void()> mCallback;
+};
+
 ndk::ScopedAStatus VibratorManager::getCapabilities(int32_t* _aidl_return) {
-    LOG(INFO) << "Vibrator manager reporting capabilities";
-    *_aidl_return =
-            IVibratorManager::CAP_SYNC | IVibratorManager::CAP_PREPARE_ON |
-            IVibratorManager::CAP_PREPARE_PERFORM | IVibratorManager::CAP_PREPARE_COMPOSE |
-            IVibratorManager::CAP_MIXED_TRIGGER_ON | IVibratorManager::CAP_MIXED_TRIGGER_PERFORM |
-            IVibratorManager::CAP_MIXED_TRIGGER_COMPOSE | IVibratorManager::CAP_TRIGGER_CALLBACK;
+    LOG(VERBOSE) << "Vibrator manager reporting capabilities";
+    std::lock_guard lock(mMutex);
+    if (mCapabilities == 0) {
+        int32_t version;
+        if (!getInterfaceVersion(&version).isOk()) {
+            return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_STATE));
+        }
+        mCapabilities = IVibratorManager::CAP_SYNC | IVibratorManager::CAP_PREPARE_ON |
+                        IVibratorManager::CAP_PREPARE_PERFORM |
+                        IVibratorManager::CAP_PREPARE_COMPOSE |
+                        IVibratorManager::CAP_MIXED_TRIGGER_ON |
+                        IVibratorManager::CAP_MIXED_TRIGGER_PERFORM |
+                        IVibratorManager::CAP_MIXED_TRIGGER_COMPOSE |
+                        IVibratorManager::CAP_TRIGGER_CALLBACK;
+
+        if (version >= 3) {
+            mCapabilities |= IVibratorManager::CAP_START_SESSIONS;
+        }
+    }
+
+    *_aidl_return = mCapabilities;
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus VibratorManager::getVibratorIds(std::vector<int32_t>* _aidl_return) {
-    LOG(INFO) << "Vibrator manager getting vibrator ids";
+    LOG(VERBOSE) << "Vibrator manager getting vibrator ids";
     *_aidl_return = {kDefaultVibratorId};
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus VibratorManager::getVibrator(int32_t vibratorId,
                                                 std::shared_ptr<IVibrator>* _aidl_return) {
-    LOG(INFO) << "Vibrator manager getting vibrator " << vibratorId;
+    LOG(VERBOSE) << "Vibrator manager getting vibrator " << vibratorId;
     if (vibratorId == kDefaultVibratorId) {
         *_aidl_return = mDefaultVibrator;
         return ndk::ScopedAStatus::ok();
@@ -55,32 +85,131 @@
 }
 
 ndk::ScopedAStatus VibratorManager::prepareSynced(const std::vector<int32_t>& vibratorIds) {
-    LOG(INFO) << "Vibrator Manager prepare synced";
-    if (vibratorIds.size() == 1 && vibratorIds[0] == kDefaultVibratorId) {
-        return ndk::ScopedAStatus::ok();
-    } else {
+    LOG(VERBOSE) << "Vibrator Manager prepare synced";
+    if (vibratorIds.size() != 1 || vibratorIds[0] != kDefaultVibratorId) {
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
+    std::lock_guard lock(mMutex);
+    if (mIsPreparing) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    mIsPreparing = true;
+    return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus VibratorManager::triggerSynced(
         const std::shared_ptr<IVibratorCallback>& callback) {
-    LOG(INFO) << "Vibrator Manager trigger synced";
+    LOG(VERBOSE) << "Vibrator Manager trigger synced";
+    std::lock_guard lock(mMutex);
+    if (!mIsPreparing) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
     std::thread([callback] {
         if (callback != nullptr) {
-            LOG(INFO) << "Notifying perform complete";
+            LOG(VERBOSE) << "Notifying perform complete";
             callback->onComplete();
         }
     }).detach();
-
+    mIsPreparing = false;
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus VibratorManager::cancelSynced() {
-    LOG(INFO) << "Vibrator Manager cancel synced";
+    LOG(VERBOSE) << "Vibrator Manager cancel synced";
+    std::lock_guard lock(mMutex);
+    mIsPreparing = false;
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus VibratorManager::startSession(const std::vector<int32_t>& vibratorIds,
+                                                 const VibrationSessionConfig&,
+                                                 const std::shared_ptr<IVibratorCallback>& callback,
+                                                 std::shared_ptr<IVibrationSession>* _aidl_return) {
+    LOG(VERBOSE) << "Vibrator Manager start session";
+    *_aidl_return = nullptr;
+    int32_t capabilities = 0;
+    if (!getCapabilities(&capabilities).isOk()) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if ((capabilities & IVibratorManager::CAP_START_SESSIONS) == 0) {
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+    }
+    if (vibratorIds.size() != 1 || vibratorIds[0] != kDefaultVibratorId) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    std::lock_guard lock(mMutex);
+    if (mIsPreparing || mSession) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    mSessionCallback = callback;
+    mSession = ndk::SharedRefBase::make<VibrationSession>(this->ref<VibratorManager>());
+    *_aidl_return = static_cast<std::shared_ptr<IVibrationSession>>(mSession);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus VibratorManager::clearSessions() {
+    LOG(VERBOSE) << "Vibrator Manager clear sessions";
+    abortSession();
+    return ndk::ScopedAStatus::ok();
+}
+
+void VibratorManager::abortSession() {
+    std::shared_ptr<IVibrationSession> session;
+    {
+        std::lock_guard lock(mMutex);
+        session = mSession;
+    }
+    if (session) {
+        mDefaultVibrator->off();
+        clearSession(session);
+    }
+}
+
+void VibratorManager::closeSession(int32_t delayMs) {
+    std::shared_ptr<IVibrationSession> session;
+    {
+        std::lock_guard lock(mMutex);
+        if (mIsClosingSession) {
+            // Already closing session, ignore this.
+            return;
+        }
+        session = mSession;
+        mIsClosingSession = true;
+    }
+    if (session) {
+        auto callback = ndk::SharedRefBase::make<VibratorCallback>(
+                [session, delayMs, sharedThis = this->ref<VibratorManager>()] {
+                    LOG(VERBOSE) << "Closing session after vibrator became idle";
+                    usleep(delayMs * 1000);
+
+                    if (sharedThis) {
+                        sharedThis->clearSession(session);
+                    }
+                });
+        mDefaultVibrator->setGlobalVibrationCallback(callback);
+    }
+}
+
+void VibratorManager::clearSession(const std::shared_ptr<IVibrationSession>& session) {
+    std::lock_guard lock(mMutex);
+    if (mSession != session) {
+        // Probably a delayed call from an old session that was already cleared, ignore it.
+        return;
+    }
+    std::shared_ptr<IVibratorCallback> callback = mSessionCallback;
+    mSession = nullptr;
+    mSessionCallback = nullptr;  // make sure any delayed call will not trigger this again.
+    mIsClosingSession = false;
+    if (callback) {
+        std::thread([callback] {
+            LOG(VERBOSE) << "Notifying session complete";
+            if (!callback->onComplete().isOk()) {
+                LOG(ERROR) << "Failed to call onComplete";
+            }
+        }).detach();
+    }
+}
+
 }  // 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/VibrationSession.h b/vibrator/aidl/default/include/vibrator-impl/VibrationSession.h
new file mode 100644
index 0000000..98bdd1c
--- /dev/null
+++ b/vibrator/aidl/default/include/vibrator-impl/VibrationSession.h
@@ -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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/vibrator/BnVibrationSession.h>
+#include <aidl/android/hardware/vibrator/IVibrator.h>
+#include <aidl/android/hardware/vibrator/IVibratorCallback.h>
+#include <android-base/thread_annotations.h>
+
+#include "vibrator-impl/VibratorManager.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace vibrator {
+
+class VibrationSession : public BnVibrationSession {
+  public:
+    VibrationSession(std::shared_ptr<VibratorManager> manager) : mManager(std::move(manager)) {};
+
+    ndk::ScopedAStatus close() override;
+    ndk::ScopedAStatus abort() override;
+
+  private:
+    mutable std::mutex mMutex;
+    std::shared_ptr<VibratorManager> mManager;
+};
+
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
index 4203bf2..354ba46 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 {
@@ -24,6 +25,7 @@
 namespace vibrator {
 
 class Vibrator : public BnVibrator {
+  public:
     ndk::ScopedAStatus getCapabilities(int32_t* _aidl_return) override;
     ndk::ScopedAStatus off() override;
     ndk::ScopedAStatus on(int32_t timeoutMs,
@@ -31,6 +33,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 +59,24 @@
     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 getFrequencyToOutputAccelerationMap(
+            std::vector<FrequencyAccelerationMapEntry>* _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 CompositePwleV2& composite,
+                                     const std::shared_ptr<IVibratorCallback>& callback) override;
 
+    void setGlobalVibrationCallback(const std::shared_ptr<IVibratorCallback>& callback);
+
+  private:
+    mutable std::mutex mMutex;
+    bool mIsVibrating GUARDED_BY(mMutex) = false;
+    int32_t mCapabilities GUARDED_BY(mMutex) = 0;
+    std::shared_ptr<IVibratorCallback> mVibrationCallback GUARDED_BY(mMutex) = nullptr;
+    std::shared_ptr<IVibratorCallback> mGlobalVibrationCallback GUARDED_BY(mMutex) = nullptr;
+
+    void dispatchVibrate(int32_t timeoutMs, const std::shared_ptr<IVibratorCallback>& callback);
 };
 
 }  // namespace vibrator
diff --git a/vibrator/aidl/default/include/vibrator-impl/VibratorManager.h b/vibrator/aidl/default/include/vibrator-impl/VibratorManager.h
index 319eb05..fe30394 100644
--- a/vibrator/aidl/default/include/vibrator-impl/VibratorManager.h
+++ b/vibrator/aidl/default/include/vibrator-impl/VibratorManager.h
@@ -17,6 +17,9 @@
 #pragma once
 
 #include <aidl/android/hardware/vibrator/BnVibratorManager.h>
+#include <android-base/thread_annotations.h>
+
+#include "vibrator-impl/Vibrator.h"
 
 namespace aidl {
 namespace android {
@@ -25,7 +28,8 @@
 
 class VibratorManager : public BnVibratorManager {
   public:
-    VibratorManager(std::shared_ptr<IVibrator> vibrator) : mDefaultVibrator(std::move(vibrator)){};
+    VibratorManager(std::shared_ptr<Vibrator> vibrator) : mDefaultVibrator(std::move(vibrator)) {};
+
     ndk::ScopedAStatus getCapabilities(int32_t* _aidl_return) override;
     ndk::ScopedAStatus getVibratorIds(std::vector<int32_t>* _aidl_return) override;
     ndk::ScopedAStatus getVibrator(int32_t vibratorId,
@@ -33,9 +37,25 @@
     ndk::ScopedAStatus prepareSynced(const std::vector<int32_t>& vibratorIds) override;
     ndk::ScopedAStatus triggerSynced(const std::shared_ptr<IVibratorCallback>& callback) override;
     ndk::ScopedAStatus cancelSynced() override;
+    ndk::ScopedAStatus startSession(const std::vector<int32_t>& vibratorIds,
+                                    const VibrationSessionConfig& config,
+                                    const std::shared_ptr<IVibratorCallback>& callback,
+                                    std::shared_ptr<IVibrationSession>* _aidl_return) override;
+    ndk::ScopedAStatus clearSessions() override;
+
+    void abortSession();
+    void closeSession(int32_t delayMs);
 
   private:
-    std::shared_ptr<IVibrator> mDefaultVibrator;
+    std::shared_ptr<Vibrator> mDefaultVibrator;
+    mutable std::mutex mMutex;
+    int32_t mCapabilities GUARDED_BY(mMutex) = 0;
+    bool mIsPreparing GUARDED_BY(mMutex) = false;
+    bool mIsClosingSession GUARDED_BY(mMutex) = false;
+    std::shared_ptr<IVibrationSession> mSession GUARDED_BY(mMutex) = nullptr;
+    std::shared_ptr<IVibratorCallback> mSessionCallback GUARDED_BY(mMutex) = nullptr;
+
+    void clearSession(const std::shared_ptr<IVibrationSession>& session);
 };
 
 }  // 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..101d4f5 100644
--- a/vibrator/aidl/vts/VtsHalVibratorManagerTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorManagerTargetTest.cpp
@@ -15,42 +15,51 @@
  */
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
+#include <aidl/android/hardware/vibrator/BnVibratorCallback.h>
+#include <aidl/android/hardware/vibrator/IVibrationSession.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 <algorithm>
 #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::IVibrationSession;
+using aidl::android::hardware::vibrator::IVibrator;
+using aidl::android::hardware::vibrator::IVibratorManager;
+using aidl::android::hardware::vibrator::VibrationSessionConfig;
 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()};
+using namespace ::std::chrono_literals;
+
+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()};
+
+// Timeout to wait for vibration callback completion.
+static constexpr std::chrono::milliseconds VIBRATION_CALLBACK_TIMEOUT = 100ms;
+
+static constexpr int32_t VIBRATION_SESSIONS_MIN_VERSION = 3;
 
 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 +69,70 @@
 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));
+        EXPECT_OK(manager->getInterfaceVersion(&version));
     }
 
-    sp<IVibratorManager> manager;
+    virtual void TearDown() override {
+        // Reset manager state between tests.
+        if (capabilities & IVibratorManager::CAP_SYNC) {
+            manager->cancelSynced();
+        }
+        if (capabilities & IVibratorManager::CAP_START_SESSIONS) {
+            manager->clearSessions();
+        }
+        // Reset all managed vibrators.
+        for (int32_t id : vibratorIds) {
+            std::shared_ptr<IVibrator> vibrator;
+            EXPECT_OK(manager->getVibrator(id, &vibrator));
+            ASSERT_NE(vibrator, nullptr);
+            EXPECT_OK(vibrator->off());
+        }
+    }
+
+    std::shared_ptr<IVibratorManager> manager;
+    std::shared_ptr<IVibrationSession> session;
+    int32_t version;
     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));
     }
 }
 
@@ -116,16 +140,15 @@
     if (vibratorIds.empty()) return;
     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());
+        int32_t durationMs = 250;
+        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 +156,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 +180,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 +199,487 @@
 
     std::promise<void> completionPromise;
     std::future<void> completionFuture{completionPromise.get_future()};
-    sp<CompletionCallback> callback =
-            new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
-    uint32_t durationMs = 250;
+    auto callback = ndk::SharedRefBase::make<CompletionCallback>(
+            [&completionPromise] { completionPromise.set_value(); });
+    int32_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());
     }
 }
 
+TEST_P(VibratorAidl, VibrationSessionsSupported) {
+    if (!(capabilities & IVibratorManager::CAP_START_SESSIONS)) return;
+    if (vibratorIds.empty()) return;
+
+    std::promise<void> sessionPromise;
+    std::future<void> sessionFuture{sessionPromise.get_future()};
+    auto sessionCallback = ndk::SharedRefBase::make<CompletionCallback>(
+            [&sessionPromise] { sessionPromise.set_value(); });
+
+    VibrationSessionConfig sessionConfig;
+    EXPECT_OK(manager->startSession(vibratorIds, sessionConfig, sessionCallback, &session));
+    ASSERT_NE(session, nullptr);
+
+    int32_t durationMs = 250;
+    std::vector<std::promise<void>> vibrationPromises;
+    std::vector<std::future<void>> vibrationFutures;
+    for (int32_t id : vibratorIds) {
+        std::shared_ptr<IVibrator> vibrator;
+        EXPECT_OK(manager->getVibrator(id, &vibrator));
+        ASSERT_NE(vibrator, nullptr);
+
+        std::promise<void>& vibrationPromise = vibrationPromises.emplace_back();
+        vibrationFutures.push_back(vibrationPromise.get_future());
+        auto vibrationCallback = ndk::SharedRefBase::make<CompletionCallback>(
+                [&vibrationPromise] { vibrationPromise.set_value(); });
+        EXPECT_OK(vibrator->on(durationMs, vibrationCallback));
+    }
+
+    auto timeout = std::chrono::milliseconds(durationMs) + VIBRATION_CALLBACK_TIMEOUT;
+    for (std::future<void>& future : vibrationFutures) {
+        EXPECT_EQ(future.wait_for(timeout), std::future_status::ready);
+    }
+
+    // Session callback not triggered.
+    EXPECT_EQ(sessionFuture.wait_for(VIBRATION_CALLBACK_TIMEOUT), std::future_status::timeout);
+
+    // Ending a session should not take long since the vibration was already completed
+    EXPECT_OK(session->close());
+    EXPECT_EQ(sessionFuture.wait_for(VIBRATION_CALLBACK_TIMEOUT), std::future_status::ready);
+}
+
+TEST_P(VibratorAidl, VibrationSessionInterrupted) {
+    if (!(capabilities & IVibratorManager::CAP_START_SESSIONS)) return;
+    if (vibratorIds.empty()) return;
+
+    std::promise<void> sessionPromise;
+    std::future<void> sessionFuture{sessionPromise.get_future()};
+    auto sessionCallback = ndk::SharedRefBase::make<CompletionCallback>(
+            [&sessionPromise] { sessionPromise.set_value(); });
+
+    VibrationSessionConfig sessionConfig;
+    EXPECT_OK(manager->startSession(vibratorIds, sessionConfig, sessionCallback, &session));
+    ASSERT_NE(session, nullptr);
+
+    std::vector<std::promise<void>> vibrationPromises;
+    std::vector<std::future<void>> vibrationFutures;
+    for (int32_t id : vibratorIds) {
+        std::shared_ptr<IVibrator> vibrator;
+        EXPECT_OK(manager->getVibrator(id, &vibrator));
+        ASSERT_NE(vibrator, nullptr);
+
+        std::promise<void>& vibrationPromise = vibrationPromises.emplace_back();
+        vibrationFutures.push_back(vibrationPromise.get_future());
+        auto vibrationCallback = ndk::SharedRefBase::make<CompletionCallback>(
+                [&vibrationPromise] { vibrationPromise.set_value(); });
+
+        // Vibration longer than test timeout.
+        EXPECT_OK(vibrator->on(2000, vibrationCallback));
+    }
+
+    // Session callback not triggered.
+    EXPECT_EQ(sessionFuture.wait_for(VIBRATION_CALLBACK_TIMEOUT), std::future_status::timeout);
+
+    // Interrupt vibrations and session.
+    EXPECT_OK(session->abort());
+
+    // Both callbacks triggered.
+    EXPECT_EQ(sessionFuture.wait_for(VIBRATION_CALLBACK_TIMEOUT), std::future_status::ready);
+    for (std::future<void>& future : vibrationFutures) {
+        EXPECT_EQ(future.wait_for(VIBRATION_CALLBACK_TIMEOUT), std::future_status::ready);
+    }
+}
+
+TEST_P(VibratorAidl, VibrationSessionEndingInterrupted) {
+    if (!(capabilities & IVibratorManager::CAP_START_SESSIONS)) return;
+    if (vibratorIds.empty()) return;
+
+    std::promise<void> sessionPromise;
+    std::future<void> sessionFuture{sessionPromise.get_future()};
+    auto sessionCallback = ndk::SharedRefBase::make<CompletionCallback>(
+            [&sessionPromise] { sessionPromise.set_value(); });
+
+    VibrationSessionConfig sessionConfig;
+    EXPECT_OK(manager->startSession(vibratorIds, sessionConfig, sessionCallback, &session));
+    ASSERT_NE(session, nullptr);
+
+    std::vector<std::promise<void>> vibrationPromises;
+    std::vector<std::future<void>> vibrationFutures;
+    for (int32_t id : vibratorIds) {
+        std::shared_ptr<IVibrator> vibrator;
+        EXPECT_OK(manager->getVibrator(id, &vibrator));
+        ASSERT_NE(vibrator, nullptr);
+
+        std::promise<void>& vibrationPromise = vibrationPromises.emplace_back();
+        vibrationFutures.push_back(vibrationPromise.get_future());
+        auto vibrationCallback = ndk::SharedRefBase::make<CompletionCallback>(
+                [&vibrationPromise] { vibrationPromise.set_value(); });
+
+        // Vibration longer than test timeout.
+        EXPECT_OK(vibrator->on(2000, vibrationCallback));
+    }
+
+    // Session callback not triggered.
+    EXPECT_EQ(sessionFuture.wait_for(VIBRATION_CALLBACK_TIMEOUT), std::future_status::timeout);
+
+    // End session, this might take a while
+    EXPECT_OK(session->close());
+
+    // Interrupt ending session.
+    EXPECT_OK(session->abort());
+
+    // Both callbacks triggered.
+    EXPECT_EQ(sessionFuture.wait_for(VIBRATION_CALLBACK_TIMEOUT), std::future_status::ready);
+    for (std::future<void>& future : vibrationFutures) {
+        EXPECT_EQ(future.wait_for(VIBRATION_CALLBACK_TIMEOUT), std::future_status::ready);
+    }
+}
+
+TEST_P(VibratorAidl, VibrationSessionCleared) {
+    if (!(capabilities & IVibratorManager::CAP_START_SESSIONS)) return;
+    if (vibratorIds.empty()) return;
+
+    std::promise<void> sessionPromise;
+    std::future<void> sessionFuture{sessionPromise.get_future()};
+    auto sessionCallback = ndk::SharedRefBase::make<CompletionCallback>(
+            [&sessionPromise] { sessionPromise.set_value(); });
+
+    VibrationSessionConfig sessionConfig;
+    EXPECT_OK(manager->startSession(vibratorIds, sessionConfig, sessionCallback, &session));
+    ASSERT_NE(session, nullptr);
+
+    int32_t durationMs = 250;
+    std::vector<std::promise<void>> vibrationPromises;
+    std::vector<std::future<void>> vibrationFutures;
+    for (int32_t id : vibratorIds) {
+        std::shared_ptr<IVibrator> vibrator;
+        EXPECT_OK(manager->getVibrator(id, &vibrator));
+        ASSERT_NE(vibrator, nullptr);
+
+        std::promise<void>& vibrationPromise = vibrationPromises.emplace_back();
+        vibrationFutures.push_back(vibrationPromise.get_future());
+        auto vibrationCallback = ndk::SharedRefBase::make<CompletionCallback>(
+                [&vibrationPromise] { vibrationPromise.set_value(); });
+        EXPECT_OK(vibrator->on(durationMs, vibrationCallback));
+    }
+
+    // Session callback not triggered.
+    EXPECT_EQ(sessionFuture.wait_for(VIBRATION_CALLBACK_TIMEOUT), std::future_status::timeout);
+
+    // Clearing sessions should abort ongoing session
+    EXPECT_OK(manager->clearSessions());
+
+    EXPECT_EQ(sessionFuture.wait_for(VIBRATION_CALLBACK_TIMEOUT), std::future_status::ready);
+    for (std::future<void>& future : vibrationFutures) {
+        EXPECT_EQ(future.wait_for(VIBRATION_CALLBACK_TIMEOUT), std::future_status::ready);
+    }
+}
+
+TEST_P(VibratorAidl, VibrationSessionsClearedWithoutSession) {
+    if (!(capabilities & IVibratorManager::CAP_START_SESSIONS)) return;
+
+    EXPECT_OK(manager->clearSessions());
+}
+
+TEST_P(VibratorAidl, VibrationSessionsWithSyncedVibrations) {
+    if (!(capabilities & IVibratorManager::CAP_START_SESSIONS)) return;
+    if (!(capabilities & IVibratorManager::CAP_SYNC)) return;
+    if (!(capabilities & IVibratorManager::CAP_PREPARE_ON)) return;
+    if (!(capabilities & IVibratorManager::CAP_TRIGGER_CALLBACK)) return;
+    if (vibratorIds.empty()) return;
+
+    std::promise<void> sessionPromise;
+    std::future<void> sessionFuture{sessionPromise.get_future()};
+    auto sessionCallback = ndk::SharedRefBase::make<CompletionCallback>(
+            [&sessionPromise] { sessionPromise.set_value(); });
+
+    VibrationSessionConfig sessionConfig;
+    EXPECT_OK(manager->startSession(vibratorIds, sessionConfig, sessionCallback, &session));
+    ASSERT_NE(session, nullptr);
+
+    EXPECT_OK(manager->prepareSynced(vibratorIds));
+
+    int32_t durationMs = 250;
+    std::vector<std::promise<void>> vibrationPromises;
+    std::vector<std::future<void>> vibrationFutures;
+    for (int32_t id : vibratorIds) {
+        std::shared_ptr<IVibrator> vibrator;
+        EXPECT_OK(manager->getVibrator(id, &vibrator));
+        ASSERT_NE(vibrator, nullptr);
+
+        std::promise<void>& vibrationPromise = vibrationPromises.emplace_back();
+        vibrationFutures.push_back(vibrationPromise.get_future());
+        auto vibrationCallback = ndk::SharedRefBase::make<CompletionCallback>(
+                [&vibrationPromise] { vibrationPromise.set_value(); });
+        EXPECT_OK(vibrator->on(durationMs, vibrationCallback));
+    }
+
+    std::promise<void> triggerPromise;
+    std::future<void> triggerFuture{triggerPromise.get_future()};
+    auto triggerCallback = ndk::SharedRefBase::make<CompletionCallback>(
+            [&triggerPromise] { triggerPromise.set_value(); });
+
+    EXPECT_OK(manager->triggerSynced(triggerCallback));
+
+    auto timeout = std::chrono::milliseconds(durationMs) + VIBRATION_CALLBACK_TIMEOUT;
+    EXPECT_EQ(triggerFuture.wait_for(timeout), std::future_status::ready);
+    for (std::future<void>& future : vibrationFutures) {
+        EXPECT_EQ(future.wait_for(timeout), std::future_status::ready);
+    }
+
+    // Session callback not triggered.
+    EXPECT_EQ(sessionFuture.wait_for(VIBRATION_CALLBACK_TIMEOUT), std::future_status::timeout);
+
+    // Ending a session should not take long since the vibration was already completed
+    EXPECT_OK(session->close());
+    EXPECT_EQ(sessionFuture.wait_for(VIBRATION_CALLBACK_TIMEOUT), std::future_status::ready);
+}
+
+TEST_P(VibratorAidl, VibrationSessionWithMultipleIndependentVibrations) {
+    if (!(capabilities & IVibratorManager::CAP_START_SESSIONS)) return;
+    if (vibratorIds.empty()) return;
+
+    std::promise<void> sessionPromise;
+    std::future<void> sessionFuture{sessionPromise.get_future()};
+    auto sessionCallback = ndk::SharedRefBase::make<CompletionCallback>(
+            [&sessionPromise] { sessionPromise.set_value(); });
+
+    VibrationSessionConfig sessionConfig;
+    EXPECT_OK(manager->startSession(vibratorIds, sessionConfig, sessionCallback, &session));
+    ASSERT_NE(session, nullptr);
+
+    for (int32_t id : vibratorIds) {
+        std::shared_ptr<IVibrator> vibrator;
+        EXPECT_OK(manager->getVibrator(id, &vibrator));
+        ASSERT_NE(vibrator, nullptr);
+
+        EXPECT_OK(vibrator->on(100, nullptr));
+        EXPECT_OK(vibrator->on(200, nullptr));
+        EXPECT_OK(vibrator->on(300, nullptr));
+    }
+
+    // Session callback not triggered.
+    EXPECT_EQ(sessionFuture.wait_for(VIBRATION_CALLBACK_TIMEOUT), std::future_status::timeout);
+
+    EXPECT_OK(session->close());
+
+    int32_t maxDurationMs = 100 + 200 + 300;
+    auto timeout = std::chrono::milliseconds(maxDurationMs) + VIBRATION_CALLBACK_TIMEOUT;
+    EXPECT_EQ(sessionFuture.wait_for(timeout), std::future_status::ready);
+}
+
+TEST_P(VibratorAidl, VibrationSessionsIgnoresSecondSessionWhenFirstIsOngoing) {
+    if (!(capabilities & IVibratorManager::CAP_START_SESSIONS)) return;
+    if (vibratorIds.empty()) return;
+
+    std::promise<void> sessionPromise;
+    std::future<void> sessionFuture{sessionPromise.get_future()};
+    auto sessionCallback = ndk::SharedRefBase::make<CompletionCallback>(
+            [&sessionPromise] { sessionPromise.set_value(); });
+
+    VibrationSessionConfig sessionConfig;
+    EXPECT_OK(manager->startSession(vibratorIds, sessionConfig, sessionCallback, &session));
+    ASSERT_NE(session, nullptr);
+
+    std::shared_ptr<IVibrationSession> secondSession;
+    EXPECT_ILLEGAL_STATE(
+            manager->startSession(vibratorIds, sessionConfig, nullptr, &secondSession));
+    EXPECT_EQ(secondSession, nullptr);
+
+    // First session was not cancelled.
+    EXPECT_EQ(sessionFuture.wait_for(VIBRATION_CALLBACK_TIMEOUT), std::future_status::timeout);
+
+    // First session still ongoing, we can still vibrate.
+    int32_t durationMs = 100;
+    for (int32_t id : vibratorIds) {
+        std::shared_ptr<IVibrator> vibrator;
+        EXPECT_OK(manager->getVibrator(id, &vibrator));
+        ASSERT_NE(vibrator, nullptr);
+        EXPECT_OK(vibrator->on(durationMs, nullptr));
+    }
+
+    EXPECT_OK(session->close());
+
+    auto timeout = std::chrono::milliseconds(durationMs) + VIBRATION_CALLBACK_TIMEOUT;
+    EXPECT_EQ(sessionFuture.wait_for(timeout), std::future_status::ready);
+}
+
+TEST_P(VibratorAidl, VibrationSessionEndMultipleTimes) {
+    if (!(capabilities & IVibratorManager::CAP_START_SESSIONS)) return;
+    if (vibratorIds.empty()) return;
+
+    std::promise<void> sessionPromise;
+    std::future<void> sessionFuture{sessionPromise.get_future()};
+    auto sessionCallback = ndk::SharedRefBase::make<CompletionCallback>(
+            [&sessionPromise] { sessionPromise.set_value(); });
+
+    VibrationSessionConfig sessionConfig;
+    EXPECT_OK(manager->startSession(vibratorIds, sessionConfig, sessionCallback, &session));
+    ASSERT_NE(session, nullptr);
+
+    int32_t durationMs = 250;
+    std::vector<std::promise<void>> vibrationPromises;
+    std::vector<std::future<void>> vibrationFutures;
+    for (int32_t id : vibratorIds) {
+        std::shared_ptr<IVibrator> vibrator;
+        EXPECT_OK(manager->getVibrator(id, &vibrator));
+        ASSERT_NE(vibrator, nullptr);
+
+        std::promise<void>& vibrationPromise = vibrationPromises.emplace_back();
+        vibrationFutures.push_back(vibrationPromise.get_future());
+        auto vibrationCallback = ndk::SharedRefBase::make<CompletionCallback>(
+                [&vibrationPromise] { vibrationPromise.set_value(); });
+        EXPECT_OK(vibrator->on(durationMs, vibrationCallback));
+    }
+
+    // Session callback not triggered.
+    EXPECT_EQ(sessionFuture.wait_for(VIBRATION_CALLBACK_TIMEOUT), std::future_status::timeout);
+
+    // End session, this might take a while
+    EXPECT_OK(session->close());
+
+    // End session again
+    EXPECT_OK(session->close());
+
+    // Both callbacks triggered within timeout.
+    auto timeout = std::chrono::milliseconds(durationMs) + VIBRATION_CALLBACK_TIMEOUT;
+    EXPECT_EQ(sessionFuture.wait_for(timeout), std::future_status::ready);
+    for (std::future<void>& future : vibrationFutures) {
+        EXPECT_EQ(future.wait_for(timeout), std::future_status::ready);
+    }
+}
+
+TEST_P(VibratorAidl, VibrationSessionDeletedAfterEnded) {
+    if (!(capabilities & IVibratorManager::CAP_START_SESSIONS)) return;
+    if (vibratorIds.empty()) return;
+
+    std::promise<void> sessionPromise;
+    std::future<void> sessionFuture{sessionPromise.get_future()};
+    auto sessionCallback = ndk::SharedRefBase::make<CompletionCallback>(
+            [&sessionPromise] { sessionPromise.set_value(); });
+
+    VibrationSessionConfig sessionConfig;
+    EXPECT_OK(manager->startSession(vibratorIds, sessionConfig, sessionCallback, &session));
+    ASSERT_NE(session, nullptr);
+
+    int32_t durationMs = 250;
+    std::vector<std::promise<void>> vibrationPromises;
+    std::vector<std::future<void>> vibrationFutures;
+    for (int32_t id : vibratorIds) {
+        std::shared_ptr<IVibrator> vibrator;
+        EXPECT_OK(manager->getVibrator(id, &vibrator));
+        ASSERT_NE(vibrator, nullptr);
+
+        std::promise<void>& vibrationPromise = vibrationPromises.emplace_back();
+        vibrationFutures.push_back(vibrationPromise.get_future());
+        auto vibrationCallback = ndk::SharedRefBase::make<CompletionCallback>(
+                [&vibrationPromise] { vibrationPromise.set_value(); });
+        EXPECT_OK(vibrator->on(durationMs, vibrationCallback));
+    }
+
+    // Session callback not triggered.
+    EXPECT_EQ(sessionFuture.wait_for(VIBRATION_CALLBACK_TIMEOUT), std::future_status::timeout);
+
+    // End session, this might take a while
+    EXPECT_OK(session->close());
+
+    session.reset();
+
+    // Both callbacks triggered within timeout, even after session was deleted.
+    auto timeout = std::chrono::milliseconds(durationMs) + VIBRATION_CALLBACK_TIMEOUT;
+    EXPECT_EQ(sessionFuture.wait_for(timeout), std::future_status::ready);
+    for (std::future<void>& future : vibrationFutures) {
+        EXPECT_EQ(future.wait_for(timeout), std::future_status::ready);
+    }
+}
+
+TEST_P(VibratorAidl, VibrationSessionWrongVibratorIdsFail) {
+    if (!(capabilities & IVibratorManager::CAP_START_SESSIONS)) return;
+
+    auto maxIdIt = std::max_element(vibratorIds.begin(), vibratorIds.end());
+    int32_t wrongId = maxIdIt == vibratorIds.end() ? 0 : *maxIdIt + 1;
+
+    std::vector<int32_t> emptyIds;
+    std::vector<int32_t> wrongIds{wrongId};
+    VibrationSessionConfig sessionConfig;
+    EXPECT_ILLEGAL_ARGUMENT(manager->startSession(emptyIds, sessionConfig, nullptr, &session));
+    EXPECT_ILLEGAL_ARGUMENT(manager->startSession(wrongIds, sessionConfig, nullptr, &session));
+    EXPECT_EQ(session, nullptr);
+}
+
+TEST_P(VibratorAidl, VibrationSessionDuringPrepareSyncedFails) {
+    if (!(capabilities & IVibratorManager::CAP_SYNC)) return;
+    if (!(capabilities & IVibratorManager::CAP_START_SESSIONS)) return;
+    if (vibratorIds.empty()) return;
+
+    EXPECT_OK(manager->prepareSynced(vibratorIds));
+
+    VibrationSessionConfig sessionConfig;
+    EXPECT_ILLEGAL_STATE(manager->startSession(vibratorIds, sessionConfig, nullptr, &session));
+    EXPECT_EQ(session, nullptr);
+
+    EXPECT_OK(manager->cancelSynced());
+}
+
+TEST_P(VibratorAidl, VibrationSessionsUnsupported) {
+    if (version < VIBRATION_SESSIONS_MIN_VERSION) {
+        EXPECT_EQ(capabilities & IVibratorManager::CAP_START_SESSIONS, 0)
+                << "Vibrator manager version " << version
+                << " should not report start session capability";
+    }
+    if (capabilities & IVibratorManager::CAP_START_SESSIONS) return;
+
+    VibrationSessionConfig sessionConfig;
+    EXPECT_UNKNOWN_OR_UNSUPPORTED(
+            manager->startSession(vibratorIds, sessionConfig, nullptr, &session));
+    EXPECT_EQ(session, nullptr);
+    EXPECT_UNKNOWN_OR_UNSUPPORTED(manager->clearSessions());
+}
+
+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(2);
+    ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
 }
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index db474d6..03ecb1a 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -15,38 +15,52 @@
  */
 #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::CompositePwleV2;
+using aidl::android::hardware::vibrator::Effect;
+using aidl::android::hardware::vibrator::EffectStrength;
+using aidl::android::hardware::vibrator::FrequencyAccelerationMapEntry;
+using aidl::android::hardware::vibrator::IVibrator;
+using aidl::android::hardware::vibrator::IVibratorManager;
+using aidl::android::hardware::vibrator::PrimitivePwle;
+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 +73,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 +87,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,93 +131,106 @@
     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) {
-    float freqResolutionHz;
-    Status status = vibrator->getFrequencyResolution(&freqResolutionHz);
-    if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
+static bool shouldValidateLegacyFrequencyControlResult(int32_t capabilities, int32_t version,
+                                                       ndk::ScopedAStatus& status) {
+    bool hasFrequencyControl = capabilities & IVibrator::CAP_FREQUENCY_CONTROL;
+    // Legacy frequency control APIs deprecated with PWLE V2 feature.
+    bool isDeprecated = version >= PWLE_V2_MIN_VERSION;
+    bool isUnknownOrUnsupported = status.getExceptionCode() == EX_UNSUPPORTED_OPERATION ||
+                                  status.getStatus() == STATUS_UNKNOWN_TRANSACTION;
+
+    // Validate if older HAL or if result is provided, even after deprecation.
+    return hasFrequencyControl && (!isDeprecated || !isUnknownOrUnsupported);
+}
+
+static float getFrequencyResolutionHz(const std::shared_ptr<IVibrator>& vibrator,
+                                      int32_t capabilities, int32_t version) {
+    float freqResolutionHz = -1;
+    ndk::ScopedAStatus status = vibrator->getFrequencyResolution(&freqResolutionHz);
+    if (shouldValidateLegacyFrequencyControlResult(capabilities, version, status)) {
+        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,
+                                   int32_t version) {
     float freqMinimumHz;
-    Status status = vibrator->getFrequencyMinimum(&freqMinimumHz);
-    if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
-        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+    ndk::ScopedAStatus status = vibrator->getFrequencyMinimum(&freqMinimumHz);
+    if (shouldValidateLegacyFrequencyControlResult(capabilities, version, status)) {
+        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,
+                                   int32_t version) {
     std::vector<float> bandwidthAmplitudeMap;
-    Status status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap);
-    if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
-        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+    ndk::ScopedAStatus status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap);
+    if (shouldValidateLegacyFrequencyControlResult(capabilities, version, status)) {
+        EXPECT_OK(std::move(status));
     } else {
-        EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+        EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
     }
 
     float freqMaximumHz = ((bandwidthAmplitudeMap.size() - 1) *
-                           getFrequencyResolutionHz(vibrator, capabilities)) +
-                          getFrequencyMinimumHz(vibrator, capabilities);
+                           getFrequencyResolutionHz(vibrator, capabilities, version)) +
+                          getFrequencyMinimumHz(vibrator, capabilities, version);
     return freqMaximumHz;
 }
 
@@ -191,12 +242,17 @@
     return 1.0;
 }
 
-static ActivePwle composeValidActivePwle(sp<IVibrator> vibrator, int32_t capabilities) {
+static ActivePwle composeValidActivePwle(const std::shared_ptr<IVibrator>& vibrator,
+                                         int32_t capabilities, int32_t version) {
     float frequencyHz;
     if (capabilities & IVibrator::CAP_GET_RESONANT_FREQUENCY) {
         frequencyHz = getResonantFrequencyHz(vibrator, capabilities);
     } else if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
-        frequencyHz = getFrequencyMinimumHz(vibrator, capabilities);
+        if (version < PWLE_V2_MIN_VERSION) {
+            frequencyHz = getFrequencyMinimumHz(vibrator, capabilities, version);
+        } else {
+            frequencyHz = pwle_v2_utils::getPwleV2FrequencyMinHz(vibrator);
+        }
     } else {
         frequencyHz = 150.0;  // default value commonly used
     }
@@ -212,9 +268,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 +279,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 +305,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 +327,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 +336,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 +366,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 +378,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 +563,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 +579,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 +603,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 +633,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 +654,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 +664,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 +678,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 +702,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 +723,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 +732,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 +754,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 +764,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 +777,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 +800,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,33 +853,34 @@
 
 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));
     }
 }
 
 TEST_P(VibratorAidl, GetFrequencyResolution) {
-    getFrequencyResolutionHz(vibrator, capabilities);
+    getFrequencyResolutionHz(vibrator, capabilities, version);
 }
 
 TEST_P(VibratorAidl, GetFrequencyMinimum) {
-    getFrequencyMinimumHz(vibrator, capabilities);
+    getFrequencyMinimumHz(vibrator, capabilities, version);
 }
 
 TEST_P(VibratorAidl, GetBandwidthAmplitudeMap) {
     std::vector<float> bandwidthAmplitudeMap;
-    Status status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap);
-    if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
-        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+    ndk::ScopedAStatus status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap);
+
+    if (shouldValidateLegacyFrequencyControlResult(capabilities, version, status)) {
+        EXPECT_OK(std::move(status));
         ASSERT_FALSE(bandwidthAmplitudeMap.empty());
 
         int minMapSize = (getResonantFrequencyHz(vibrator, capabilities) -
-                          getFrequencyMinimumHz(vibrator, capabilities)) /
-                         getFrequencyResolutionHz(vibrator, capabilities);
+                          getFrequencyMinimumHz(vibrator, capabilities, version)) /
+                         getFrequencyResolutionHz(vibrator, capabilities, version);
         ASSERT_GT(bandwidthAmplitudeMap.size(), minMapSize);
 
         for (float e : bandwidthAmplitudeMap) {
@@ -702,74 +888,78 @@
             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));
     }
 }
 
 TEST_P(VibratorAidl, ComposeValidPwle) {
     if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
-        ActivePwle firstActive = composeValidActivePwle(vibrator, capabilities);
+        ActivePwle firstActive = composeValidActivePwle(vibrator, capabilities, version);
 
         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;
         firstBraking.braking = isClabSupported ? Braking::CLAB : Braking::NONE;
         firstBraking.duration = 100;
 
-        ActivePwle secondActive = composeValidActivePwle(vibrator, capabilities);
+        ActivePwle secondActive = composeValidActivePwle(vibrator, capabilities, version);
         if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
-            float minFrequencyHz = getFrequencyMinimumHz(vibrator, capabilities);
-            float maxFrequencyHz = getFrequencyMaximumHz(vibrator, capabilities);
-            float freqResolutionHz = getFrequencyResolutionHz(vibrator, capabilities);
-            secondActive.startFrequency = minFrequencyHz + (freqResolutionHz / 2.0f);
-            secondActive.endFrequency = maxFrequencyHz - (freqResolutionHz / 3.0f);
+            float minFrequencyHz = getFrequencyMinimumHz(vibrator, capabilities, version);
+            float maxFrequencyHz = getFrequencyMaximumHz(vibrator, capabilities, version);
+            float freqResolutionHz = getFrequencyResolutionHz(vibrator, capabilities, version);
+            // As of API 16 these APIs are deprecated and no longer required to be implemented
+            //  with frequency control capability.
+            if (minFrequencyHz >= 0 && maxFrequencyHz >= 0 && freqResolutionHz >= 0) {
+                secondActive.startFrequency = minFrequencyHz + (freqResolutionHz / 2.0f);
+                secondActive.endFrequency = maxFrequencyHz - (freqResolutionHz / 3.0f);
+            }
         }
         BrakingPwle secondBraking;
         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,39 +970,37 @@
 
     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
     auto timeout = std::chrono::milliseconds(durationMs) + VIBRATION_CALLBACK_TIMEOUT;
 
-    ActivePwle active = composeValidActivePwle(vibrator, capabilities);
+    ActivePwle active = composeValidActivePwle(vibrator, capabilities, version);
 
     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);
+        ActivePwle active = composeValidActivePwle(vibrator, capabilities, version);
 
         PrimitivePwle pwle;
         pwle = active;
@@ -824,98 +1012,287 @@
             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));
     }
 }
 
 TEST_P(VibratorAidl, ComposePwleAmplitudeParameterBoundary) {
     if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
-        ActivePwle active = composeValidActivePwle(vibrator, capabilities);
+        ActivePwle active = composeValidActivePwle(vibrator, capabilities, version);
         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));
     }
 }
 
 TEST_P(VibratorAidl, ComposePwleFrequencyParameterBoundary) {
     if ((capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) &&
         (capabilities & IVibrator::CAP_FREQUENCY_CONTROL)) {
-        float freqMinimumHz = getFrequencyMinimumHz(vibrator, capabilities);
-        float freqMaximumHz = getFrequencyMaximumHz(vibrator, capabilities);
-        float freqResolutionHz = getFrequencyResolutionHz(vibrator, capabilities);
+        float freqMinimumHz = getFrequencyMinimumHz(vibrator, capabilities, version);
+        float freqMaximumHz = getFrequencyMaximumHz(vibrator, capabilities, version);
+        float freqResolutionHz = getFrequencyResolutionHz(vibrator, capabilities, version);
 
-        ActivePwle active = composeValidActivePwle(vibrator, capabilities);
+        // As of API 16 these APIs are deprecated and no longer required to be implemented with
+        // frequency control capability.
+        if (freqMinimumHz < 0 || freqMaximumHz < 0 || freqResolutionHz < 0) {
+            GTEST_SKIP() << "PWLE V1 is not supported, skipping test";
+            return;
+        }
+
+        ActivePwle active = composeValidActivePwle(vibrator, capabilities, version);
         active.startFrequency =
             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));
     }
 }
 
 TEST_P(VibratorAidl, ComposePwleSegmentDurationBoundary) {
     if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
-        ActivePwle active = composeValidActivePwle(vibrator, capabilities);
+        ActivePwle active = composeValidActivePwle(vibrator, capabilities, version);
 
         int32_t segmentDurationMaxMs;
         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, FrequencyToOutputAccelerationMapHasValidFrequencyRange) {
+    if (version < PWLE_V2_MIN_VERSION || !(capabilities & IVibrator::CAP_FREQUENCY_CONTROL)) {
+        GTEST_SKIP() << "Frequency control is not supported, skipping test";
+        return;
+    }
+
+    std::vector<FrequencyAccelerationMapEntry> frequencyToOutputAccelerationMap;
+    ndk::ScopedAStatus status =
+            vibrator->getFrequencyToOutputAccelerationMap(&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, FrequencyToOutputAccelerationMapUnsupported) {
+    if ((capabilities & IVibrator::CAP_FREQUENCY_CONTROL)) return;
+
+    std::vector<FrequencyAccelerationMapEntry> frequencyToOutputAccelerationMap;
+
+    EXPECT_UNKNOWN_OR_UNSUPPORTED(
+            vibrator->getFrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap));
+}
+
+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, ValidatePwleV2DependencyOnFrequencyControl) {
+    if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) {
+        GTEST_SKIP() << "PWLE V2 not supported, skipping test";
+        return;
+    }
+
+    // Check if frequency control is supported
+    bool hasFrequencyControl = (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) != 0;
+    ASSERT_TRUE(hasFrequencyControl) << "Frequency control MUST be supported when PWLE V2 is.";
+}
+
+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;
+
+    CompositePwleV2 composite;
+    composite.pwlePrimitives.emplace_back(/*amplitude=*/1.0f, /*frequencyHz=*/100.0f,
+                                          /*timeMillis=*/50);
+
+    EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->composePwleV2(composite, 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);
+
+    CompositePwleV2 composite;
+    composite.pwlePrimitives.emplace_back(/*amplitude=*/0.5, minFrequency, minDuration);
+
+    EXPECT_OK(vibrator->composePwleV2(composite, 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));
+
+    CompositePwleV2 composePwle;
+
+    // Negative amplitude
+    composePwle.pwlePrimitives.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.pwlePrimitives.clear();
+
+    // Amplitude exceeding 1.0
+    composePwle.pwlePrimitives.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.pwlePrimitives.clear();
+
+    // Duration exceeding maximum
+    composePwle.pwlePrimitives.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.pwlePrimitives.clear();
+
+    // Negative duration
+    composePwle.pwlePrimitives.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.pwlePrimitives.clear();
+
+    // Frequency below minimum
+    float minFrequency = pwle_v2_utils::getPwleV2FrequencyMinHz(vibrator);
+    composePwle.pwlePrimitives.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.pwlePrimitives.clear();
+
+    // Frequency above maximum
+    float maxFrequency = pwle_v2_utils::getPwleV2FrequencyMaxHz(vibrator);
+    composePwle.pwlePrimitives.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 +1312,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..eaa024c
--- /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::FrequencyAccelerationMapEntry;
+using aidl::android::hardware::vibrator::IVibrator;
+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<FrequencyAccelerationMapEntry> frequencyToOutputAccelerationMap;
+    EXPECT_OK(vibrator->getFrequencyToOutputAccelerationMap(&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<FrequencyAccelerationMapEntry> frequencyToOutputAccelerationMap;
+    EXPECT_OK(vibrator->getFrequencyToOutputAccelerationMap(&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 CompositePwleV2 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));
+
+    CompositePwleV2 composite;
+
+    composite.pwlePrimitives.emplace_back(0.1f, minFrequency, minDurationMs);
+    composite.pwlePrimitives.emplace_back(0.5f, maxFrequency, maxDurationMs);
+
+    float variedFrequency = (minFrequency + maxFrequency) / 2.0f;
+    for (int i = 0; i < maxCompositionSize - 2; i++) {
+        composite.pwlePrimitives.emplace_back(0.7f, variedFrequency, minDurationMs);
+    }
+
+    return composite;
+}
+
+static CompositePwleV2 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));
+
+    CompositePwleV2 composite;
+    composite.pwlePrimitives = pwleEffect;
+
+    return composite;
+}
+
+static std::pair<float, float> getPwleV2SharpnessRange(
+        const std::shared_ptr<IVibrator>& vibrator,
+        std::vector<FrequencyAccelerationMapEntry> 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..e884bbd
--- /dev/null
+++ b/vibrator/aidl/vts/test_utils.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.
+ */
+#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
+
+#if !defined(EXPECT_ILLEGAL_STATE)
+#define EXPECT_ILLEGAL_STATE(expression)                                  \
+    GTEST_AMBIGUOUS_ELSE_BLOCKER_                                         \
+    if (const ::ndk::ScopedAStatus&& _status = (expression);              \
+        _status.getExceptionCode() == EX_ILLEGAL_STATE)                   \
+        ;                                                                 \
+    else                                                                  \
+        ADD_FAILURE() << "Expected EX_ILLEGAL_STATE for: " << #expression \
+                      << "\n  Actual: " << _status
+#else
+#error Macro EXPECT_ILLEGAL_STATE 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/wifi/aidl/Android.bp b/wifi/aidl/Android.bp
index 392d2e9..4b7e372 100644
--- a/wifi/aidl/Android.bp
+++ b/wifi/aidl/Android.bp
@@ -29,7 +29,7 @@
         "android/hardware/wifi/*.aidl",
     ],
     imports: [
-        "android.hardware.wifi.common-V1",
+        "android.hardware.wifi.common-V2",
     ],
     stability: "vintf",
     backend: {
@@ -64,5 +64,5 @@
         },
 
     ],
-    frozen: true,
+    frozen: false,
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/Akm.aidl
similarity index 79%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/Akm.aidl
index 173ac17..5baf2e8 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/Akm.aidl
@@ -31,10 +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.biometrics.fingerprint;
-/* @hide */
+package android.hardware.wifi;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable Akm {
+  const long NONE = 0;
+  const long PASN = (1 << 0) /* 1 */;
+  const long SAE = (1 << 1) /* 2 */;
+  const long FT_EAP_SHA256 = (1 << 2) /* 4 */;
+  const long FT_PSK_SHA256 = (1 << 3) /* 8 */;
+  const long FT_EAP_SHA384 = (1 << 4) /* 16 */;
+  const long FT_PSK_SHA384 = (1 << 5) /* 32 */;
+  const long FILS_EAP_SHA256 = (1 << 6) /* 64 */;
+  const long FILS_EAP_SHA384 = (1 << 7) /* 128 */;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/ApIfaceParams.aidl
similarity index 88%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/ApIfaceParams.aidl
index 173ac17..50e1bbb 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/ApIfaceParams.aidl
@@ -31,10 +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.biometrics.fingerprint;
-/* @hide */
+package android.hardware.wifi;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable ApIfaceParams {
+  android.hardware.wifi.IfaceConcurrencyType ifaceType;
+  boolean usesMlo;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/CipherSuite.aidl
similarity index 86%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/CipherSuite.aidl
index 173ac17..32fb5ba 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/CipherSuite.aidl
@@ -31,10 +31,12 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
+package android.hardware.wifi;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable CipherSuite {
+  const long NONE = 0;
+  const long CCMP_128 = (1 << 0) /* 1 */;
+  const long CCMP_256 = (1 << 1) /* 2 */;
+  const long GCMP_128 = (1 << 2) /* 4 */;
+  const long GCMP_256 = (1 << 3) /* 8 */;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiApIface.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiApIface.aidl
index e71dde4..af95bee 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiApIface.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiApIface.aidl
@@ -40,4 +40,5 @@
   void setCountryCode(in byte[2] code);
   void resetToFactoryMacAddress();
   void setMacAddress(in byte[6] mac);
+  boolean usesMlo();
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
index 5ed7517..1af0d65 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
@@ -35,7 +35,13 @@
 @VintfStability
 interface IWifiChip {
   void configureChip(in int modeId);
+  /**
+   * @deprecated This method is deprecated from AIDL v3, newer HALs should use createApOrBridgedApIfaceWithParams.
+   */
   @PropagateAllowBlocking android.hardware.wifi.IWifiApIface createApIface();
+  /**
+   * @deprecated This method is deprecated from AIDL v3, newer HALs should use createApOrBridgedApIfaceWithParams.
+   */
   @PropagateAllowBlocking android.hardware.wifi.IWifiApIface createBridgedApIface();
   @PropagateAllowBlocking android.hardware.wifi.IWifiNanIface createNanIface();
   @PropagateAllowBlocking android.hardware.wifi.IWifiP2pIface createP2pIface();
@@ -83,8 +89,12 @@
   void triggerSubsystemRestart();
   void enableStaChannelForPeerNetwork(in int channelCategoryEnableFlag);
   void setMloMode(in android.hardware.wifi.IWifiChip.ChipMloMode mode);
+  /**
+   * @deprecated This method is deprecated from AIDL v3, newer HALs should use createApOrBridgedApIfaceWithParams.
+   */
   @PropagateAllowBlocking android.hardware.wifi.IWifiApIface createApOrBridgedApIface(in android.hardware.wifi.IfaceConcurrencyType iface, in android.hardware.wifi.common.OuiKeyedData[] vendorData);
   void setVoipMode(in android.hardware.wifi.IWifiChip.VoipMode mode);
+  @PropagateAllowBlocking android.hardware.wifi.IWifiApIface createApOrBridgedApIfaceWithParams(in android.hardware.wifi.ApIfaceParams params);
   const int NO_POWER_CAP_CONSTANT = 0x7FFFFFFF;
   @Backing(type="int") @VintfStability
   enum FeatureSetMask {
@@ -98,6 +108,7 @@
     SET_AFC_CHANNEL_ALLOWANCE = (1 << 7) /* 128 */,
     T2LM_NEGOTIATION = (1 << 8) /* 256 */,
     SET_VOIP_MODE = (1 << 9) /* 512 */,
+    MLO_SAP = (1 << 10) /* 1024 */,
   }
   @VintfStability
   parcelable ChipConcurrencyCombinationLimit {
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/PasnConfig.aidl
similarity index 88%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/PasnConfig.aidl
index 173ac17..9b26c97 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/PasnConfig.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.wifi;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable PasnConfig {
+  long baseAkm;
+  long cipherSuite;
+  @nullable byte[] passphrase;
+  @nullable byte[] pmkid;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttCapabilities.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttCapabilities.aidl
index 6c64084..6197585 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttCapabilities.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttCapabilities.aidl
@@ -47,4 +47,8 @@
   boolean ntbInitiatorSupported;
   boolean ntbResponderSupported;
   @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
+  long akmsSupported;
+  long cipherSuitesSupported;
+  boolean secureHeLtfSupported;
+  boolean rangingFrameProtectionSupported;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttConfig.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttConfig.aidl
index 3613616..5507280 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttConfig.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttConfig.aidl
@@ -51,4 +51,5 @@
   long ntbMinMeasurementTime;
   long ntbMaxMeasurementTime;
   @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
+  @nullable android.hardware.wifi.RttSecureConfig secureConfig;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResult.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResult.aidl
index 13202ba..87257be 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResult.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResult.aidl
@@ -66,4 +66,9 @@
   byte numTxSpatialStreams;
   byte numRxSpatialStreams;
   @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
+  boolean isRangingFrameProtectionEnabled;
+  boolean isSecureLtfEnabled;
+  long baseAkm;
+  long cipherSuite;
+  int secureHeLtfProtocolVersion;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttSecureConfig.aidl
similarity index 88%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttSecureConfig.aidl
index 173ac17..c2d7866 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttSecureConfig.aidl
@@ -31,10 +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.biometrics.fingerprint;
-/* @hide */
+package android.hardware.wifi;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable RttSecureConfig {
+  android.hardware.wifi.PasnConfig pasnConfig;
+  boolean enableSecureHeLtf;
+  boolean enableRangingFrameProtection;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttStatus.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttStatus.aidl
index 2817497..08bca77 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttStatus.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttStatus.aidl
@@ -52,4 +52,9 @@
   FAIL_FTM_PARAM_OVERRIDE = 15,
   NAN_RANGING_PROTOCOL_FAILURE = 16,
   NAN_RANGING_CONCURRENCY_NOT_SUPPORTED = 17,
+  SECURE_RANGING_FAILURE_INVALID_AKM = 18,
+  SECURE_RANGING_FAILURE_INVALID_CIPHER = 19,
+  SECURE_RANGING_FAILURE_INVALID_CONFIG = 20,
+  SECURE_RANGING_FAILURE_REJECTED = 21,
+  SECURE_RANGING_FAILURE_UNKNOWN = 22,
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttType.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttType.aidl
index cb25673..8545d73 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttType.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttType.aidl
@@ -38,4 +38,5 @@
   TWO_SIDED = 2,
   TWO_SIDED_11MC = TWO_SIDED /* 2 */,
   TWO_SIDED_11AZ_NTB = 3,
+  TWO_SIDED_11AZ_NTB_SECURE = 4,
 }
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/wifi/aidl/android/hardware/wifi/Akm.aidl
similarity index 60%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
copy to wifi/aidl/android/hardware/wifi/Akm.aidl
index c7be950..e3a913b 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ b/wifi/aidl/android/hardware/wifi/Akm.aidl
@@ -14,22 +14,20 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
-
-import android.hardware.biometrics.fingerprint.AcquiredInfo;
+package android.hardware.wifi;
 
 /**
- * @hide
+ * Authentication and Key Management types.
  */
 @VintfStability
-union AcquiredInfoAndVendorCode {
-    /**
-     * Acquired info as specified in AcqauiredInfo.aidl
-     */
-    AcquiredInfo acquiredInfo = AcquiredInfo.UNKNOWN;
-
-    /**
-     * Vendor specific code
-     */
-    int vendorCode;
+parcelable Akm {
+    const long NONE = 0;
+    const long PASN = 1 << 0;
+    const long SAE = 1 << 1;
+    const long FT_EAP_SHA256 = 1 << 2;
+    const long FT_PSK_SHA256 = 1 << 3;
+    const long FT_EAP_SHA384 = 1 << 4;
+    const long FT_PSK_SHA384 = 1 << 5;
+    const long FILS_EAP_SHA256 = 1 << 6;
+    const long FILS_EAP_SHA384 = 1 << 7;
 }
diff --git a/wifi/aidl/android/hardware/wifi/ApIfaceParams.aidl b/wifi/aidl/android/hardware/wifi/ApIfaceParams.aidl
new file mode 100644
index 0000000..f075b72
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/ApIfaceParams.aidl
@@ -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 android.hardware.wifi;
+
+import android.hardware.wifi.IfaceConcurrencyType;
+import android.hardware.wifi.common.OuiKeyedData;
+
+/**
+ * Parameters to use for setting up the access point interfaces.
+ */
+@VintfStability
+parcelable ApIfaceParams {
+    /**
+     * IfaceConcurrencyType to be created. Takes one of
+     * |IfaceConcurrencyType.AP| or |IfaceConcurrencyType.AP_BRIDGED|
+     */
+    IfaceConcurrencyType ifaceType;
+    /**
+     * Whether the current iface will be operated on Multi-links on the one MLD device (MLO).
+     */
+    boolean usesMlo;
+    /**
+     * Optional vendor-specific configuration parameters.
+     */
+    @nullable OuiKeyedData[] vendorData;
+}
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/wifi/aidl/android/hardware/wifi/CipherSuite.aidl
similarity index 64%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
copy to wifi/aidl/android/hardware/wifi/CipherSuite.aidl
index c7be950..02b62e8 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ b/wifi/aidl/android/hardware/wifi/CipherSuite.aidl
@@ -14,22 +14,16 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
-
-import android.hardware.biometrics.fingerprint.AcquiredInfo;
+package android.hardware.wifi;
 
 /**
- * @hide
+ * Cipher Suite types.
  */
 @VintfStability
-union AcquiredInfoAndVendorCode {
-    /**
-     * Acquired info as specified in AcqauiredInfo.aidl
-     */
-    AcquiredInfo acquiredInfo = AcquiredInfo.UNKNOWN;
-
-    /**
-     * Vendor specific code
-     */
-    int vendorCode;
+parcelable CipherSuite {
+    const long NONE = 0;
+    const long CCMP_128 = 1 << 0;
+    const long CCMP_256 = 1 << 1;
+    const long GCMP_128 = 1 << 2;
+    const long GCMP_256 = 1 << 3;
 }
diff --git a/wifi/aidl/android/hardware/wifi/IWifiApIface.aidl b/wifi/aidl/android/hardware/wifi/IWifiApIface.aidl
index b14a800..a350e52 100644
--- a/wifi/aidl/android/hardware/wifi/IWifiApIface.aidl
+++ b/wifi/aidl/android/hardware/wifi/IWifiApIface.aidl
@@ -85,4 +85,11 @@
      *         |WifiStatusCode.ERROR_UNKNOWN|
      */
     void setMacAddress(in byte[6] mac);
+
+    /**
+     * Check if ApIface is for an AP using Multi-Link Operation
+     *
+     * @return true if it is MLO iface, false otherwise.
+     */
+    boolean usesMlo();
 }
diff --git a/wifi/aidl/android/hardware/wifi/IWifiChip.aidl b/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
index d12d26c..04f31d2 100644
--- a/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
+++ b/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
@@ -17,6 +17,7 @@
 package android.hardware.wifi;
 
 import android.hardware.wifi.AfcChannelAllowance;
+import android.hardware.wifi.ApIfaceParams;
 import android.hardware.wifi.IWifiApIface;
 import android.hardware.wifi.IWifiChipEventCallback;
 import android.hardware.wifi.IWifiNanIface;
@@ -87,6 +88,10 @@
          * Chip supports voip mode setting.
          */
         SET_VOIP_MODE = 1 << 9,
+        /**
+         * Chip supports Wi-Fi 7 MLO SoftAp.
+         */
+        MLO_SAP = 1 << 10,
     }
 
     /**
@@ -429,6 +434,9 @@
      * reached the maximum allowed (specified in |ChipIfaceCombination|) number
      * of ifaces of the AP type.
      *
+     * @deprecated This method is deprecated from AIDL v3, newer HALs should use
+     * createApOrBridgedApIfaceWithParams.
+     *
      * @return AIDL interface object representing the iface if
      *         successful, null otherwise.
      * @throws ServiceSpecificException with one of the following values:
@@ -446,6 +454,9 @@
      * reached the maximum allowed (specified in |ChipIfaceCombination|) number
      * of ifaces of the AP type.
      *
+     * @deprecated This method is deprecated from AIDL v3, newer HALs should use
+     * createApOrBridgedApIfaceWithParams.
+     *
      * @return AIDL interface object representing the iface if
      *         successful, null otherwise.
      * @throws ServiceSpecificException with one of the following values:
@@ -1173,6 +1184,9 @@
      * reached the maximum allowed (specified in |ChipIfaceCombination|) number
      * of ifaces of the AP or AP_BRIDGED type.
      *
+     * @deprecated This method is deprecated from AIDL v3, newer HALs should use
+     * createApOrBridgedApIfaceWithParams.
+     *
      * @param  iface IfaceConcurrencyType to be created. Takes one of
                |IfaceConcurrencyType.AP| or |IfaceConcurrencyType.AP_BRIDGED|
      * @param  vendorData Vendor-provided configuration data as a list of |OuiKeyedData|.
@@ -1206,4 +1220,22 @@
      *         |WifiStatusCode.ERROR_UNKNOWN|
      */
     void setVoipMode(in VoipMode mode);
+
+    /**
+     * Create an AP or bridged AP iface on the chip based on ApIfaceParamss.
+     *
+     * Depending on the mode the chip is configured in, the interface creation
+     * may fail (code: |WifiStatusCode.ERROR_NOT_AVAILABLE|) if we've already
+     * reached the maximum allowed (specified in |ChipIfaceCombination|) number
+     * of ifaces of the AP type.
+     *
+     * @return AIDL interface object representing the iface if
+     *         successful, null otherwise.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.ERROR_NOT_AVAILABLE|
+     */
+    @PropagateAllowBlocking
+    IWifiApIface createApOrBridgedApIfaceWithParams(in ApIfaceParams params);
 }
diff --git a/wifi/aidl/android/hardware/wifi/PasnConfig.aidl b/wifi/aidl/android/hardware/wifi/PasnConfig.aidl
new file mode 100644
index 0000000..4c6b5bf
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/PasnConfig.aidl
@@ -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.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Pre-Association Security Negotiation (PASN) configuration.
+ */
+@VintfStability
+parcelable PasnConfig {
+    /**
+     * Base Authentication and Key Management (AKM) protocol used for PASN as defined in |Akm|.
+     */
+    long baseAkm;
+    /**
+     * Pairwise cipher suite used for the PTKSA (Pairwise Transient Key Security Association)
+     * as defined in |CipherSuite|
+     */
+    long cipherSuite;
+    /**
+     * Passphrase for the base AKM. This can be null based on the AKM type.
+     */
+    @nullable byte[] passphrase;
+    /**
+     * PMKID corresponding to the cached PMK from the base AKM. PMKID can be null if no cached PMK
+     * is present.
+     */
+    @nullable byte[] pmkid;
+}
diff --git a/wifi/aidl/android/hardware/wifi/RttCapabilities.aidl b/wifi/aidl/android/hardware/wifi/RttCapabilities.aidl
index c193924..0cf048d 100644
--- a/wifi/aidl/android/hardware/wifi/RttCapabilities.aidl
+++ b/wifi/aidl/android/hardware/wifi/RttCapabilities.aidl
@@ -84,4 +84,20 @@
      * that no vendor data is provided.
      */
     @nullable OuiKeyedData[] vendorData;
+    /**
+     * Bitmap of |Akm| values indicating the set of supported AKMs.
+     */
+    long akmsSupported;
+    /**
+     * Bitmap of |CipherSuite| values indicating the set of supported pairwise cipher suites.
+     */
+    long cipherSuitesSupported;
+    /**
+     * Whether secure HE-LTF is supported.
+     */
+    boolean secureHeLtfSupported;
+    /**
+     * Whether frame protection for ranging is supported.
+     */
+    boolean rangingFrameProtectionSupported;
 }
diff --git a/wifi/aidl/android/hardware/wifi/RttConfig.aidl b/wifi/aidl/android/hardware/wifi/RttConfig.aidl
index 496ffd2..8dfbea8 100644
--- a/wifi/aidl/android/hardware/wifi/RttConfig.aidl
+++ b/wifi/aidl/android/hardware/wifi/RttConfig.aidl
@@ -19,6 +19,7 @@
 import android.hardware.wifi.RttBw;
 import android.hardware.wifi.RttPeerType;
 import android.hardware.wifi.RttPreamble;
+import android.hardware.wifi.RttSecureConfig;
 import android.hardware.wifi.RttType;
 import android.hardware.wifi.WifiChannelInfo;
 import android.hardware.wifi.common.OuiKeyedData;
@@ -140,4 +141,8 @@
      * that no vendor data is provided.
      */
     @nullable OuiKeyedData[] vendorData;
+    /**
+     * Secure Ranging configuration
+     */
+    @nullable RttSecureConfig secureConfig;
 }
diff --git a/wifi/aidl/android/hardware/wifi/RttResult.aidl b/wifi/aidl/android/hardware/wifi/RttResult.aidl
index 2f9aefe..dd41868 100644
--- a/wifi/aidl/android/hardware/wifi/RttResult.aidl
+++ b/wifi/aidl/android/hardware/wifi/RttResult.aidl
@@ -213,4 +213,25 @@
      * that no vendor data is provided.
      */
     @nullable OuiKeyedData[] vendorData;
+    /**
+     * Whether ranging frame protection is enabled.
+     */
+    boolean isRangingFrameProtectionEnabled;
+    /**
+     * Whether Secure HE-LTF is enabled.
+     */
+    boolean isSecureLtfEnabled;
+    /**
+     * Base Authentication and Key Management (AKM) protocol used for PASN as defined in |Akm|.
+     */
+    long baseAkm;
+    /**
+     * Pairwise cipher suite used for the PTKSA (Pairwise Transient Key Security Association)
+     * as defined in |CipherSuite|
+     */
+    long cipherSuite;
+    /**
+     * Secure HE-LTF protocol version used.
+     */
+    int secureHeLtfProtocolVersion;
 }
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/wifi/aidl/android/hardware/wifi/RttSecureConfig.aidl
similarity index 61%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
copy to wifi/aidl/android/hardware/wifi/RttSecureConfig.aidl
index c7be950..c10e6b5 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ b/wifi/aidl/android/hardware/wifi/RttSecureConfig.aidl
@@ -14,22 +14,25 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
+package android.hardware.wifi;
 
-import android.hardware.biometrics.fingerprint.AcquiredInfo;
+import android.hardware.wifi.PasnConfig;
 
 /**
- * @hide
+ * RTT secure configuration.
  */
 @VintfStability
-union AcquiredInfoAndVendorCode {
+parcelable RttSecureConfig {
     /**
-     * Acquired info as specified in AcqauiredInfo.aidl
+     * Pre-Association Security Negotiation (PASN) configuration.
      */
-    AcquiredInfo acquiredInfo = AcquiredInfo.UNKNOWN;
-
+    PasnConfig pasnConfig;
     /**
-     * Vendor specific code
+     * Enable secure HE-LTF (High Efficiency Long Training Field).
      */
-    int vendorCode;
+    boolean enableSecureHeLtf;
+    /**
+     * Enable Ranging frame protection.
+     */
+    boolean enableRangingFrameProtection;
 }
diff --git a/wifi/aidl/android/hardware/wifi/RttStatus.aidl b/wifi/aidl/android/hardware/wifi/RttStatus.aidl
index 600165c..94bc9e3 100644
--- a/wifi/aidl/android/hardware/wifi/RttStatus.aidl
+++ b/wifi/aidl/android/hardware/wifi/RttStatus.aidl
@@ -88,4 +88,24 @@
      * NAN concurrency not supported (NDP + RTT).
      */
     NAN_RANGING_CONCURRENCY_NOT_SUPPORTED = 17,
+    /**
+     * Secure Ranging failed due to invalid AKM (Authentication and Key Management)
+     */
+    SECURE_RANGING_FAILURE_INVALID_AKM = 18,
+    /**
+     * Secure Ranging failed due to invalid Cipher.
+     */
+    SECURE_RANGING_FAILURE_INVALID_CIPHER = 19,
+    /**
+     * Secure Ranging failed due to invalid configuration.
+     */
+    SECURE_RANGING_FAILURE_INVALID_CONFIG = 20,
+    /**
+     * Secure ranging rejected by the AP.
+     */
+    SECURE_RANGING_FAILURE_REJECTED = 21,
+    /**
+     * Secure ranging failure unknown.
+     */
+    SECURE_RANGING_FAILURE_UNKNOWN = 22,
 }
diff --git a/wifi/aidl/android/hardware/wifi/RttType.aidl b/wifi/aidl/android/hardware/wifi/RttType.aidl
index 3f1a2f1..d7cf9fe 100644
--- a/wifi/aidl/android/hardware/wifi/RttType.aidl
+++ b/wifi/aidl/android/hardware/wifi/RttType.aidl
@@ -37,4 +37,8 @@
      * Two-sided RTT 11az non trigger based (non-TB) type.
      */
     TWO_SIDED_11AZ_NTB = 3,
+    /**
+     * Two-sided RTT 11az non trigger based (non-TB) secure type.
+     */
+    TWO_SIDED_11AZ_NTB_SECURE = 4,
 }
diff --git a/wifi/aidl/default/Android.bp b/wifi/aidl/default/Android.bp
index 3fcb77f..c2e8541 100644
--- a/wifi/aidl/default/Android.bp
+++ b/wifi/aidl/default/Android.bp
@@ -106,7 +106,7 @@
         "libwifi-hal",
         "libwifi-system-iface",
         "libxml2",
-        "android.hardware.wifi-V2-ndk",
+        "android.hardware.wifi-V3-ndk",
     ],
 
     export_include_dirs: ["."],
@@ -138,7 +138,7 @@
         "libwifi-hal",
         "libwifi-system-iface",
         "libxml2",
-        "android.hardware.wifi-V2-ndk",
+        "android.hardware.wifi-V3-ndk",
     ],
     static_libs: ["android.hardware.wifi-service-lib"],
     init_rc: ["android.hardware.wifi-service.rc"],
@@ -167,7 +167,7 @@
         "libwifi-hal",
         "libwifi-system-iface",
         "libxml2",
-        "android.hardware.wifi-V2-ndk",
+        "android.hardware.wifi-V3-ndk",
     ],
     static_libs: ["android.hardware.wifi-service-lib"],
     init_rc: ["android.hardware.wifi-service-lazy.rc"],
@@ -199,8 +199,8 @@
     static_libs: [
         "libgmock",
         "libgtest",
-        "android.hardware.wifi-V2-ndk",
-        "android.hardware.wifi.common-V1-ndk",
+        "android.hardware.wifi-V3-ndk",
+        "android.hardware.wifi.common-V2-ndk",
         "android.hardware.wifi-service-lib",
     ],
     shared_libs: [
diff --git a/wifi/aidl/default/aidl_callback_util.h b/wifi/aidl/default/aidl_callback_util.h
index f8ba53b..2419db9 100644
--- a/wifi/aidl/default/aidl_callback_util.h
+++ b/wifi/aidl/default/aidl_callback_util.h
@@ -45,6 +45,11 @@
     ~AidlCallbackHandler() { invalidate(); }
 
     bool addCallback(const std::shared_ptr<CallbackType>& cb) {
+        if (cb == nullptr) {
+            LOG(ERROR) << "Unable to register a null callback";
+            return false;
+        }
+
         std::unique_lock<std::mutex> lk(callback_handler_lock_);
         void* cbPtr = reinterpret_cast<void*>(cb->asBinder().get());
         const auto& cbPosition = findCbInSet(cbPtr);
diff --git a/wifi/aidl/default/aidl_struct_util.cpp b/wifi/aidl/default/aidl_struct_util.cpp
index d82450e..bf6c206 100644
--- a/wifi/aidl/default/aidl_struct_util.cpp
+++ b/wifi/aidl/default/aidl_struct_util.cpp
@@ -61,6 +61,8 @@
             return IWifiChip::FeatureSetMask::SET_AFC_CHANNEL_ALLOWANCE;
         case WIFI_FEATURE_SET_VOIP_MODE:
             return IWifiChip::FeatureSetMask::SET_VOIP_MODE;
+        case WIFI_FEATURE_MLO_SAP:
+            return IWifiChip::FeatureSetMask::MLO_SAP;
     };
     CHECK(false) << "Unknown legacy feature: " << feature;
     return {};
@@ -2476,6 +2478,8 @@
             return legacy_hal::RTT_TYPE_2_SIDED_11MC;
         case RttType::TWO_SIDED_11AZ_NTB:
             return legacy_hal::RTT_TYPE_2_SIDED_11AZ_NTB;
+        case RttType::TWO_SIDED_11AZ_NTB_SECURE:
+            return legacy_hal::RTT_TYPE_2_SIDED_11AZ_NTB_SECURE;
     };
     CHECK(false);
 }
@@ -2489,6 +2493,8 @@
             return RttType::TWO_SIDED_11MC;
         case legacy_hal::RTT_TYPE_2_SIDED_11AZ_NTB:
             return RttType::TWO_SIDED_11AZ_NTB;
+        case legacy_hal::RTT_TYPE_2_SIDED_11AZ_NTB_SECURE:
+            return RttType::TWO_SIDED_11AZ_NTB_SECURE;
     };
     CHECK(false) << "Unknown legacy type: " << type;
 }
@@ -2721,6 +2727,16 @@
             return RttStatus::NAN_RANGING_PROTOCOL_FAILURE;
         case legacy_hal::RTT_STATUS_NAN_RANGING_CONCURRENCY_NOT_SUPPORTED:
             return RttStatus::NAN_RANGING_CONCURRENCY_NOT_SUPPORTED;
+        case legacy_hal::RTT_STATUS_SECURE_RANGING_FAILURE_INVALID_AKM:
+            return RttStatus::SECURE_RANGING_FAILURE_INVALID_AKM;
+        case legacy_hal::RTT_STATUS_SECURE_RANGING_FAILURE_INVALID_CIPHER:
+            return RttStatus::SECURE_RANGING_FAILURE_INVALID_CIPHER;
+        case legacy_hal::RTT_STATUS_SECURE_RANGING_FAILURE_INVALID_CONFIG:
+            return RttStatus::SECURE_RANGING_FAILURE_INVALID_CONFIG;
+        case legacy_hal::RTT_STATUS_SECURE_RANGING_FAILURE_REJECTED:
+            return RttStatus::SECURE_RANGING_FAILURE_REJECTED;
+        case legacy_hal::RTT_STATUS_SECURE_RANGING_FAILURE_UNKNOWN:
+            return RttStatus::SECURE_RANGING_FAILURE_UNKNOWN;
     };
     CHECK(false) << "Unknown legacy status: " << status;
 }
@@ -3394,6 +3410,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/android.hardware.wifi-service.xml b/wifi/aidl/default/android.hardware.wifi-service.xml
index 3b68c8e..9bfffb6 100644
--- a/wifi/aidl/default/android.hardware.wifi-service.xml
+++ b/wifi/aidl/default/android.hardware.wifi-service.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
 	<hal format="aidl">
 		<name>android.hardware.wifi</name>
-		<version>2</version>
+		<version>3</version>
 		<fqname>IWifi/default</fqname>
 	</hal>
 </manifest>
diff --git a/wifi/aidl/default/wifi_ap_iface.cpp b/wifi/aidl/default/wifi_ap_iface.cpp
index 7779750..6a73cc8 100644
--- a/wifi/aidl/default/wifi_ap_iface.cpp
+++ b/wifi/aidl/default/wifi_ap_iface.cpp
@@ -28,10 +28,12 @@
 namespace wifi {
 using aidl_return_util::validateAndCall;
 
-WifiApIface::WifiApIface(const std::string& ifname, const std::vector<std::string>& instances,
+WifiApIface::WifiApIface(const std::string& ifname, const bool usesMlo,
+                         const std::vector<std::string>& instances,
                          const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
                          const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
     : ifname_(ifname),
+      uses_mlo_(usesMlo),
       instances_(instances),
       legacy_hal_(legacy_hal),
       iface_util_(iface_util),
@@ -50,6 +52,10 @@
     return ifname_;
 }
 
+bool WifiApIface::usesMlo() {
+    return uses_mlo_;
+}
+
 void WifiApIface::removeInstance(std::string instance) {
     instances_.erase(std::remove(instances_.begin(), instances_.end(), instance), instances_.end());
 }
@@ -72,7 +78,7 @@
 ndk::ScopedAStatus WifiApIface::getFactoryMacAddress(std::array<uint8_t, 6>* _aidl_return) {
     return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
                            &WifiApIface::getFactoryMacAddressInternal, _aidl_return,
-                           instances_.size() > 0 ? instances_[0] : ifname_);
+                           getOperatingInstanceName());
 }
 
 ndk::ScopedAStatus WifiApIface::resetToFactoryMacAddress() {
@@ -90,14 +96,14 @@
 }
 
 ndk::ScopedAStatus WifiApIface::setCountryCodeInternal(const std::array<uint8_t, 2>& code) {
-    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->setCountryCode(
-            instances_.size() > 0 ? instances_[0] : ifname_, code);
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->setCountryCode(getOperatingInstanceName(), code);
     return createWifiStatusFromLegacyError(legacy_status);
 }
 
 ndk::ScopedAStatus WifiApIface::setMacAddressInternal(const std::array<uint8_t, 6>& mac) {
     // Support random MAC up to 2 interfaces
-    if (instances_.size() == 2) {
+    if (instances_.size() == 2 && !uses_mlo_) {
         int rbyte = 1;
         for (auto const& intf : instances_) {
             std::array<uint8_t, 6> rmac = mac;
@@ -131,7 +137,7 @@
 
 ndk::ScopedAStatus WifiApIface::resetToFactoryMacAddressInternal() {
     std::pair<std::array<uint8_t, 6>, ndk::ScopedAStatus> getMacResult;
-    if (instances_.size() == 2) {
+    if (instances_.size() == 2 && !uses_mlo_) {
         for (auto const& intf : instances_) {
             getMacResult = getFactoryMacAddressInternal(intf);
             LOG(DEBUG) << "Reset MAC to factory MAC on " << intf;
@@ -166,6 +172,11 @@
     return {instances_, ndk::ScopedAStatus::ok()};
 }
 
+ndk::ScopedAStatus WifiApIface::usesMlo(bool* _aidl_return) {
+    *_aidl_return = uses_mlo_;
+    return ndk::ScopedAStatus::ok();
+}
+
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/aidl/default/wifi_ap_iface.h b/wifi/aidl/default/wifi_ap_iface.h
index 7378f98..e07154d 100644
--- a/wifi/aidl/default/wifi_ap_iface.h
+++ b/wifi/aidl/default/wifi_ap_iface.h
@@ -33,13 +33,15 @@
  */
 class WifiApIface : public BnWifiApIface {
   public:
-    WifiApIface(const std::string& ifname, const std::vector<std::string>& instances,
+    WifiApIface(const std::string& ifname, const bool usesMlo,
+                const std::vector<std::string>& instances,
                 const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
                 const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
     // Refer to |WifiChip::invalidate()|.
     void invalidate();
     bool isValid();
     std::string getName();
+    bool usesMlo();
     void removeInstance(std::string instance);
 
     // AIDL methods exposed.
@@ -49,6 +51,7 @@
     ndk::ScopedAStatus getFactoryMacAddress(std::array<uint8_t, 6>* _aidl_return) override;
     ndk::ScopedAStatus resetToFactoryMacAddress() override;
     ndk::ScopedAStatus getBridgedInstances(std::vector<std::string>* _aidl_return) override;
+    ndk::ScopedAStatus usesMlo(bool* _aidl_return) override;
 
   private:
     // Corresponding worker functions for the AIDL methods.
@@ -61,11 +64,18 @@
     std::pair<std::vector<std::string>, ndk::ScopedAStatus> getBridgedInstancesInternal();
 
     std::string ifname_;
+    bool uses_mlo_;
     std::vector<std::string> instances_;
     std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
     std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
     bool is_valid_;
 
+    // The mlo is using one interface but owning two link instances.
+    // The operating should be based on interface.
+    inline std::string getOperatingInstanceName() {
+        return (instances_.size() > 0 && !uses_mlo_) ? instances_[0] : ifname_;
+    };
+
     DISALLOW_COPY_AND_ASSIGN(WifiApIface);
 };
 
diff --git a/wifi/aidl/default/wifi_chip.cpp b/wifi/aidl/default/wifi_chip.cpp
index 9b9c565..045e07d 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;
 }
@@ -367,7 +369,7 @@
 
 ndk::ScopedAStatus WifiChip::createBridgedApIface(std::shared_ptr<IWifiApIface>* _aidl_return) {
     return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::createBridgedApIfaceInternal, _aidl_return);
+                           &WifiChip::createBridgedApIfaceInternal, _aidl_return, false);
 }
 
 ndk::ScopedAStatus WifiChip::createApOrBridgedApIface(
@@ -611,6 +613,13 @@
                            &WifiChip::setVoipModeInternal, in_mode);
 }
 
+ndk::ScopedAStatus WifiChip::createApOrBridgedApIfaceWithParams(
+        const ApIfaceParams& in_params, std::shared_ptr<IWifiApIface>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createApOrBridgedApIfaceWithParamsInternal, _aidl_return,
+                           in_params);
+}
+
 void WifiChip::invalidateAndRemoveAllIfaces() {
     invalidateAndClearBridgedApAll();
     invalidateAndClearAll(ap_ifaces_);
@@ -795,15 +804,15 @@
     return ndk::ScopedAStatus::ok();
 }
 
-std::shared_ptr<WifiApIface> WifiChip::newWifiApIface(std::string& ifname) {
+std::shared_ptr<WifiApIface> WifiChip::newWifiApIface(std::string& ifname, bool usesMlo) {
     std::vector<std::string> ap_instances;
     for (auto const& it : br_ifaces_ap_instances_) {
         if (it.first == ifname) {
             ap_instances = it.second;
         }
     }
-    std::shared_ptr<WifiApIface> iface =
-            ndk::SharedRefBase::make<WifiApIface>(ifname, ap_instances, legacy_hal_, iface_util_);
+    std::shared_ptr<WifiApIface> iface = ndk::SharedRefBase::make<WifiApIface>(
+            ifname, usesMlo, ap_instances, legacy_hal_, iface_util_);
     ap_ifaces_.push_back(iface);
     for (const auto& callback : event_cb_handler_.getCallbacks()) {
         if (!callback->onIfaceAdded(IfaceType::AP, ifname).isOk()) {
@@ -824,47 +833,60 @@
     if (!status.isOk()) {
         return {std::shared_ptr<WifiApIface>(), std::move(status)};
     }
-    std::shared_ptr<WifiApIface> iface = newWifiApIface(ifname);
+    std::shared_ptr<WifiApIface> iface = newWifiApIface(ifname, false);
     return {iface, ndk::ScopedAStatus::ok()};
 }
 
-std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus>
-WifiChip::createBridgedApIfaceInternal() {
+std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> WifiChip::createBridgedApIfaceInternal(
+        bool usesMlo) {
     if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::AP_BRIDGED)) {
         return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
     }
-    std::vector<std::string> ap_instances = allocateBridgedApInstanceNames();
+    std::string br_ifname;
+    std::vector<std::string> ap_instances = allocateBridgedApInstanceNames(usesMlo);
     if (ap_instances.size() < 2) {
         LOG(ERROR) << "Fail to allocate two instances";
         return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
     }
-    std::string br_ifname = kApBridgeIfacePrefix + ap_instances[0];
-    for (int i = 0; i < 2; i++) {
-        ndk::ScopedAStatus status = createVirtualApInterface(ap_instances[i]);
-        if (!status.isOk()) {
-            if (i != 0) {  // The failure happened when creating second virtual
-                           // iface.
-                legacy_hal_.lock()->deleteVirtualInterface(
-                        ap_instances.front());  // Remove the first virtual iface.
+    if (usesMlo) {
+        // MLO SoftAp is using single interface with two links. So only need to create 1 interface.
+        br_ifname = allocateApIfaceName();
+    } else {
+        br_ifname = kApBridgeIfacePrefix + ap_instances[0];
+        for (int i = 0; i < 2; i++) {
+            ndk::ScopedAStatus status = createVirtualApInterface(ap_instances[i]);
+            if (!status.isOk()) {
+                if (i != 0) {  // The failure happened when creating second virtual
+                               // iface.
+                    legacy_hal_.lock()->deleteVirtualInterface(
+                            ap_instances.front());  // Remove the first virtual iface.
+                }
+                return {nullptr, std::move(status)};
             }
-            return {nullptr, std::move(status)};
         }
     }
     br_ifaces_ap_instances_[br_ifname] = ap_instances;
-    if (!iface_util_->createBridge(br_ifname)) {
-        LOG(ERROR) << "Failed createBridge - br_name=" << br_ifname.c_str();
-        deleteApIface(br_ifname);
-        return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
-    }
-    for (auto const& instance : ap_instances) {
-        // Bind ap instance interface to AP bridge
-        if (!iface_util_->addIfaceToBridge(br_ifname, instance)) {
-            LOG(ERROR) << "Failed add if to Bridge - if_name=" << instance.c_str();
+    if (usesMlo) {
+        ndk::ScopedAStatus status = createVirtualApInterface(br_ifname);
+        if (!status.isOk()) {
+            return {nullptr, std::move(status)};
+        }
+    } else {
+        if (!iface_util_->createBridge(br_ifname)) {
+            LOG(ERROR) << "Failed createBridge - br_name=" << br_ifname.c_str();
             deleteApIface(br_ifname);
             return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
         }
+        for (auto const& instance : ap_instances) {
+            // Bind ap instance interface to AP bridge
+            if (!iface_util_->addIfaceToBridge(br_ifname, instance)) {
+                LOG(ERROR) << "Failed add if to Bridge - if_name=" << instance.c_str();
+                deleteApIface(br_ifname);
+                return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
+            }
+        }
     }
-    std::shared_ptr<WifiApIface> iface = newWifiApIface(br_ifname);
+    std::shared_ptr<WifiApIface> iface = newWifiApIface(br_ifname, usesMlo);
     return {iface, ndk::ScopedAStatus::ok()};
 }
 
@@ -874,7 +896,18 @@
     if (ifaceType == IfaceConcurrencyType::AP) {
         return createApIfaceInternal();
     } else if (ifaceType == IfaceConcurrencyType::AP_BRIDGED) {
-        return createBridgedApIfaceInternal();
+        return createBridgedApIfaceInternal(false);
+    } else {
+        return {nullptr, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
+    }
+}
+
+std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus>
+WifiChip::createApOrBridgedApIfaceWithParamsInternal(const ApIfaceParams& params) {
+    if (params.ifaceType == IfaceConcurrencyType::AP) {
+        return createApIfaceInternal();
+    } else if (params.ifaceType == IfaceConcurrencyType::AP_BRIDGED) {
+        return createBridgedApIfaceInternal(params.usesMlo);
     } else {
         return {nullptr, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
     }
@@ -923,23 +956,28 @@
     if (!iface.get() || ifInstanceName.empty()) {
         return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
     }
+
     // Requires to remove one of the instance in bridge mode
     for (auto const& it : br_ifaces_ap_instances_) {
         if (it.first == ifname) {
             std::vector<std::string> ap_instances = it.second;
-            for (auto const& iface : ap_instances) {
-                if (iface == ifInstanceName) {
-                    if (!iface_util_->removeIfaceFromBridge(it.first, iface)) {
-                        LOG(ERROR) << "Failed to remove interface: " << ifInstanceName << " from "
-                                   << ifname;
-                        return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE);
-                    }
-                    legacy_hal::wifi_error legacy_status =
-                            legacy_hal_.lock()->deleteVirtualInterface(iface);
-                    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-                        LOG(ERROR) << "Failed to del interface: " << iface << " "
-                                   << legacyErrorToString(legacy_status);
-                        return createWifiStatusFromLegacyError(legacy_status);
+            for (auto const& instance : ap_instances) {
+                if (instance == ifInstanceName) {
+                    if (iface->usesMlo()) {
+                        LOG(INFO) << "Remove Link " << ifInstanceName << " from " << ifname;
+                    } else {
+                        if (!iface_util_->removeIfaceFromBridge(it.first, instance)) {
+                            LOG(ERROR) << "Failed to remove interface: " << ifInstanceName
+                                       << " from " << ifname;
+                            return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE);
+                        }
+                        legacy_hal::wifi_error legacy_status =
+                                legacy_hal_.lock()->deleteVirtualInterface(instance);
+                        if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+                            LOG(ERROR) << "Failed to del interface: " << instance << " "
+                                       << legacyErrorToString(legacy_status);
+                            return createWifiStatusFromLegacyError(legacy_status);
+                        }
                     }
                     ap_instances.erase(
                             std::remove(ap_instances.begin(), ap_instances.end(), ifInstanceName),
@@ -971,6 +1009,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()) {
@@ -1723,7 +1765,7 @@
         // If the first active wlan iface is bridged iface.
         // Return first instance name.
         for (auto const& it : br_ifaces_ap_instances_) {
-            if (it.first == ap_ifaces_[0]->getName()) {
+            if (it.first == ap_ifaces_[0]->getName() && !ap_ifaces_[0]->usesMlo()) {
                 return it.second[0];
             }
         }
@@ -1776,9 +1818,19 @@
     return allocateApOrStaIfaceName(IfaceType::AP, startIdxOfApIface());
 }
 
-std::vector<std::string> WifiChip::allocateBridgedApInstanceNames() {
-    // Check if we have a dedicated iface for AP.
-    std::vector<std::string> instances = getPredefinedApIfaceNames(true);
+std::vector<std::string> WifiChip::allocateBridgedApInstanceNames(bool usesMlo) {
+    std::vector<std::string> instances;
+    if (usesMlo) {
+        // For MLO AP, the instances are MLO links and it will be maintained in hostapd.
+        // The hostapd will use 0 as an initial link id and 1 as the next.
+        // Considering Android didn't support link reconfiguration. Forcing to use 0 & 1
+        // should work.
+        instances.push_back("0");
+        instances.push_back("1");
+    } else {
+        // Check if we have a dedicated iface for AP.
+        instances = getPredefinedApIfaceNames(true);
+    }
     if (instances.size() == 2) {
         return instances;
     } else {
@@ -1850,11 +1902,14 @@
 
 void WifiChip::invalidateAndClearBridgedApAll() {
     for (auto const& it : br_ifaces_ap_instances_) {
-        for (auto const& iface : it.second) {
-            iface_util_->removeIfaceFromBridge(it.first, iface);
-            legacy_hal_.lock()->deleteVirtualInterface(iface);
+        const auto iface = findUsingName(ap_ifaces_, it.first);
+        if (!iface->usesMlo()) {
+            for (auto const& iface : it.second) {
+                iface_util_->removeIfaceFromBridge(it.first, iface);
+                legacy_hal_.lock()->deleteVirtualInterface(iface);
+            }
+            iface_util_->deleteBridge(it.first);
         }
-        iface_util_->deleteBridge(it.first);
     }
     br_ifaces_ap_instances_.clear();
 }
@@ -1862,16 +1917,19 @@
 void WifiChip::deleteApIface(const std::string& if_name) {
     if (if_name.empty()) return;
     // delete bridged interfaces if any
-    for (auto const& it : br_ifaces_ap_instances_) {
-        if (it.first == if_name) {
-            for (auto const& iface : it.second) {
-                iface_util_->removeIfaceFromBridge(if_name, iface);
-                legacy_hal_.lock()->deleteVirtualInterface(iface);
+    const auto iface = findUsingName(ap_ifaces_, if_name);
+    if (!iface->usesMlo()) {
+        for (auto const& it : br_ifaces_ap_instances_) {
+            if (it.first == if_name) {
+                for (auto const& instance : it.second) {
+                    iface_util_->removeIfaceFromBridge(if_name, instance);
+                    legacy_hal_.lock()->deleteVirtualInterface(instance);
+                }
+                iface_util_->deleteBridge(if_name);
+                br_ifaces_ap_instances_.erase(if_name);
+                // ifname is bridged AP, return here.
+                return;
             }
-            iface_util_->deleteBridge(if_name);
-            br_ifaces_ap_instances_.erase(if_name);
-            // ifname is bridged AP, return here.
-            return;
         }
     }
 
diff --git a/wifi/aidl/default/wifi_chip.h b/wifi/aidl/default/wifi_chip.h
index ffd507f..24dd00d 100644
--- a/wifi/aidl/default/wifi_chip.h
+++ b/wifi/aidl/default/wifi_chip.h
@@ -159,6 +159,8 @@
     binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
     ndk::ScopedAStatus setMloMode(const ChipMloMode in_mode) override;
     ndk::ScopedAStatus setVoipMode(const VoipMode in_mode) override;
+    ndk::ScopedAStatus createApOrBridgedApIfaceWithParams(
+            const ApIfaceParams& in_params, std::shared_ptr<IWifiApIface>* _aidl_return) override;
 
   private:
     void invalidateAndRemoveAllIfaces();
@@ -178,12 +180,15 @@
     std::pair<IWifiChip::ChipDebugInfo, ndk::ScopedAStatus> requestChipDebugInfoInternal();
     std::pair<std::vector<uint8_t>, ndk::ScopedAStatus> requestDriverDebugDumpInternal();
     std::pair<std::vector<uint8_t>, ndk::ScopedAStatus> requestFirmwareDebugDumpInternal();
-    std::shared_ptr<WifiApIface> newWifiApIface(std::string& ifname);
+    std::shared_ptr<WifiApIface> newWifiApIface(std::string& ifname, bool usesMlo);
     ndk::ScopedAStatus createVirtualApInterface(const std::string& apVirtIf);
     std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> createApIfaceInternal();
-    std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> createBridgedApIfaceInternal();
+    std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> createBridgedApIfaceInternal(
+            bool usesMlo);
     std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> createApOrBridgedApIfaceInternal(
             IfaceConcurrencyType ifaceType, const std::vector<common::OuiKeyedData>& vendorData);
+    std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus>
+    createApOrBridgedApIfaceWithParamsInternal(const ApIfaceParams& params);
     std::pair<std::vector<std::string>, ndk::ScopedAStatus> getApIfaceNamesInternal();
     std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> getApIfaceInternal(
             const std::string& ifname);
@@ -258,7 +263,7 @@
     std::string getFirstActiveWlanIfaceName();
     std::string allocateApOrStaIfaceName(IfaceType type, uint32_t start_idx);
     std::string allocateApIfaceName();
-    std::vector<std::string> allocateBridgedApInstanceNames();
+    std::vector<std::string> allocateBridgedApInstanceNames(bool usesMlo);
     std::string allocateStaIfaceName();
     bool writeRingbufferFilesInternal();
     std::string getWlanIfaceNameWithType(IfaceType type, unsigned idx);
diff --git a/wifi/aidl/default/wifi_legacy_hal.h b/wifi/aidl/default/wifi_legacy_hal.h
index 3fd567b..aa563cb 100644
--- a/wifi/aidl/default/wifi_legacy_hal.h
+++ b/wifi/aidl/default/wifi_legacy_hal.h
@@ -212,10 +212,16 @@
 using ::RTT_STATUS_NAN_RANGING_CONCURRENCY_NOT_SUPPORTED;
 using ::RTT_STATUS_NAN_RANGING_PROTOCOL_FAILURE;
 using ::RTT_STATUS_NO_WIFI;
+using ::RTT_STATUS_SECURE_RANGING_FAILURE_INVALID_AKM;
+using ::RTT_STATUS_SECURE_RANGING_FAILURE_INVALID_CIPHER;
+using ::RTT_STATUS_SECURE_RANGING_FAILURE_INVALID_CONFIG;
+using ::RTT_STATUS_SECURE_RANGING_FAILURE_REJECTED;
+using ::RTT_STATUS_SECURE_RANGING_FAILURE_UNKNOWN;
 using ::RTT_STATUS_SUCCESS;
 using ::RTT_TYPE_1_SIDED;
 using ::RTT_TYPE_2_SIDED;
 using ::RTT_TYPE_2_SIDED_11AZ_NTB;
+using ::RTT_TYPE_2_SIDED_11AZ_NTB_SECURE;
 using ::RTT_TYPE_2_SIDED_11MC;
 using ::RX_PKT_FATE_DRV_DROP_FILTER;
 using ::RX_PKT_FATE_DRV_DROP_INVALID;
diff --git a/wifi/aidl/vts/functional/Android.bp b/wifi/aidl/vts/functional/Android.bp
index 9994d09..429c0c5 100644
--- a/wifi/aidl/vts/functional/Android.bp
+++ b/wifi/aidl/vts/functional/Android.bp
@@ -40,8 +40,8 @@
     ],
     static_libs: [
         "VtsHalWifiTargetTestUtil",
-        "android.hardware.wifi.common-V1-ndk",
-        "android.hardware.wifi-V2-ndk",
+        "android.hardware.wifi.common-V2-ndk",
+        "android.hardware.wifi-V3-ndk",
         "libwifi-system-iface",
     ],
     test_suites: [
@@ -66,8 +66,8 @@
     ],
     static_libs: [
         "VtsHalWifiTargetTestUtil",
-        "android.hardware.wifi.common-V1-ndk",
-        "android.hardware.wifi-V2-ndk",
+        "android.hardware.wifi.common-V2-ndk",
+        "android.hardware.wifi-V3-ndk",
         "libwifi-system-iface",
     ],
     test_suites: [
@@ -92,8 +92,8 @@
     ],
     static_libs: [
         "VtsHalWifiTargetTestUtil",
-        "android.hardware.wifi.common-V1-ndk",
-        "android.hardware.wifi-V2-ndk",
+        "android.hardware.wifi.common-V2-ndk",
+        "android.hardware.wifi-V3-ndk",
         "libwifi-system-iface",
     ],
     test_suites: [
@@ -118,8 +118,8 @@
     ],
     static_libs: [
         "VtsHalWifiTargetTestUtil",
-        "android.hardware.wifi.common-V1-ndk",
-        "android.hardware.wifi-V2-ndk",
+        "android.hardware.wifi.common-V2-ndk",
+        "android.hardware.wifi-V3-ndk",
         "libwifi-system-iface",
     ],
     test_suites: [
@@ -144,8 +144,8 @@
     ],
     static_libs: [
         "VtsHalWifiTargetTestUtil",
-        "android.hardware.wifi.common-V1-ndk",
-        "android.hardware.wifi-V2-ndk",
+        "android.hardware.wifi.common-V2-ndk",
+        "android.hardware.wifi-V3-ndk",
         "libwifi-system-iface",
     ],
     test_suites: [
@@ -169,8 +169,8 @@
         "libnativehelper",
     ],
     static_libs: [
-        "android.hardware.wifi.common-V1-ndk",
-        "android.hardware.wifi-V2-ndk",
+        "android.hardware.wifi.common-V2-ndk",
+        "android.hardware.wifi-V3-ndk",
         "libwifi-system-iface",
     ],
 }
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/common/aidl/Android.bp b/wifi/common/aidl/Android.bp
index 0920a55..8ea54be 100644
--- a/wifi/common/aidl/Android.bp
+++ b/wifi/common/aidl/Android.bp
@@ -54,6 +54,6 @@
             imports: [],
         },
     ],
-    frozen: true,
+    frozen: false,
 
 }
diff --git a/wifi/common/aidl/aidl_api/android.hardware.wifi.common/current/android/hardware/wifi/common/DeauthenticationReasonCode.aidl b/wifi/common/aidl/aidl_api/android.hardware.wifi.common/current/android/hardware/wifi/common/DeauthenticationReasonCode.aidl
new file mode 100644
index 0000000..2404b2c
--- /dev/null
+++ b/wifi/common/aidl/aidl_api/android.hardware.wifi.common/current/android/hardware/wifi/common/DeauthenticationReasonCode.aidl
@@ -0,0 +1,99 @@
+/*
+ * 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.wifi.common;
+@Backing(type="int") @VintfStability
+enum DeauthenticationReasonCode {
+  HOSTAPD_NO_REASON = 0,
+  UNSPECIFIED = 1,
+  PREV_AUTH_NOT_VALID = 2,
+  DEAUTH_LEAVING = 3,
+  DISASSOC_DUE_TO_INACTIVITY = 4,
+  DISASSOC_AP_BUSY = 5,
+  CLASS2_FRAME_FROM_NONAUTH_STA = 6,
+  CLASS3_FRAME_FROM_NONASSOC_STA = 7,
+  DISASSOC_STA_HAS_LEFT = 8,
+  STA_REQ_ASSOC_WITHOUT_AUTH = 9,
+  PWR_CAPABILITY_NOT_VALID = 10,
+  SUPPORTED_CHANNEL_NOT_VALID = 11,
+  BSS_TRANSITION_DISASSOC = 12,
+  INVALID_IE = 13,
+  MICHAEL_MIC_FAILURE = 14,
+  FOURWAY_HANDSHAKE_TIMEOUT = 15,
+  GROUP_KEY_UPDATE_TIMEOUT = 16,
+  IE_IN_4WAY_DIFFERS = 17,
+  GROUP_CIPHER_NOT_VALID = 18,
+  PAIRWISE_CIPHER_NOT_VALID = 19,
+  AKMP_NOT_VALID = 20,
+  UNSUPPORTED_RSN_IE_VERSION = 21,
+  INVALID_RSN_IE_CAPAB = 22,
+  IEEE_802_1X_AUTH_FAILED = 23,
+  CIPHER_SUITE_REJECTED = 24,
+  TDLS_TEARDOWN_UNREACHABLE = 25,
+  TDLS_TEARDOWN_UNSPECIFIED = 26,
+  SSP_REQUESTED_DISASSOC = 27,
+  NO_SSP_ROAMING_AGREEMENT = 28,
+  BAD_CIPHER_OR_AKM = 29,
+  NOT_AUTHORIZED_THIS_LOCATION = 30,
+  SERVICE_CHANGE_PRECLUDES_TS = 31,
+  UNSPECIFIED_QOS_REASON = 32,
+  NOT_ENOUGH_BANDWIDTH = 33,
+  DISASSOC_LOW_ACK = 34,
+  EXCEEDED_TXOP = 35,
+  STA_LEAVING = 36,
+  END_TS_BA_DLS = 37,
+  UNKNOWN_TS_BA = 38,
+  TIMEOUT = 39,
+  PEERKEY_MISMATCH = 45,
+  AUTHORIZED_ACCESS_LIMIT_REACHED = 46,
+  EXTERNAL_SERVICE_REQUIREMENTS = 47,
+  INVALID_FT_ACTION_FRAME_COUNT = 48,
+  INVALID_PMKID = 49,
+  INVALID_MDE = 50,
+  INVALID_FTE = 51,
+  MESH_PEERING_CANCELLED = 52,
+  MESH_MAX_PEERS = 53,
+  MESH_CONFIG_POLICY_VIOLATION = 54,
+  MESH_CLOSE_RCVD = 55,
+  MESH_MAX_RETRIES = 56,
+  MESH_CONFIRM_TIMEOUT = 57,
+  MESH_INVALID_GTK = 58,
+  MESH_INCONSISTENT_PARAMS = 59,
+  MESH_INVALID_SECURITY_CAP = 60,
+  MESH_PATH_ERROR_NO_PROXY_INFO = 61,
+  MESH_PATH_ERROR_NO_FORWARDING_INFO = 62,
+  MESH_PATH_ERROR_DEST_UNREACHABLE = 63,
+  MAC_ADDRESS_ALREADY_EXISTS_IN_MBSS = 64,
+  MESH_CHANNEL_SWITCH_REGULATORY_REQ = 65,
+  MESH_CHANNEL_SWITCH_UNSPECIFIED = 66,
+}
diff --git a/wifi/common/aidl/android/hardware/wifi/common/DeauthenticationReasonCode.aidl b/wifi/common/aidl/android/hardware/wifi/common/DeauthenticationReasonCode.aidl
new file mode 100644
index 0000000..95eb31d
--- /dev/null
+++ b/wifi/common/aidl/android/hardware/wifi/common/DeauthenticationReasonCode.aidl
@@ -0,0 +1,90 @@
+/*
+ * 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.wifi.common;
+
+/**
+ * Reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45).
+ *
+ * Note: HOSTAPD_NO_REASON is the default return from hostapd, even though it
+ * does not appear in the IEEE spec.
+ */
+@VintfStability
+@Backing(type="int")
+enum DeauthenticationReasonCode {
+    HOSTAPD_NO_REASON = 0,
+    UNSPECIFIED = 1,
+    PREV_AUTH_NOT_VALID = 2,
+    DEAUTH_LEAVING = 3,
+    DISASSOC_DUE_TO_INACTIVITY = 4,
+    DISASSOC_AP_BUSY = 5,
+    CLASS2_FRAME_FROM_NONAUTH_STA = 6,
+    CLASS3_FRAME_FROM_NONASSOC_STA = 7,
+    DISASSOC_STA_HAS_LEFT = 8,
+    STA_REQ_ASSOC_WITHOUT_AUTH = 9,
+    PWR_CAPABILITY_NOT_VALID = 10,
+    SUPPORTED_CHANNEL_NOT_VALID = 11,
+    BSS_TRANSITION_DISASSOC = 12,
+    INVALID_IE = 13,
+    MICHAEL_MIC_FAILURE = 14,
+    FOURWAY_HANDSHAKE_TIMEOUT = 15,
+    GROUP_KEY_UPDATE_TIMEOUT = 16,
+    IE_IN_4WAY_DIFFERS = 17,
+    GROUP_CIPHER_NOT_VALID = 18,
+    PAIRWISE_CIPHER_NOT_VALID = 19,
+    AKMP_NOT_VALID = 20,
+    UNSUPPORTED_RSN_IE_VERSION = 21,
+    INVALID_RSN_IE_CAPAB = 22,
+    IEEE_802_1X_AUTH_FAILED = 23,
+    CIPHER_SUITE_REJECTED = 24,
+    TDLS_TEARDOWN_UNREACHABLE = 25,
+    TDLS_TEARDOWN_UNSPECIFIED = 26,
+    SSP_REQUESTED_DISASSOC = 27,
+    NO_SSP_ROAMING_AGREEMENT = 28,
+    BAD_CIPHER_OR_AKM = 29,
+    NOT_AUTHORIZED_THIS_LOCATION = 30,
+    SERVICE_CHANGE_PRECLUDES_TS = 31,
+    UNSPECIFIED_QOS_REASON = 32,
+    NOT_ENOUGH_BANDWIDTH = 33,
+    DISASSOC_LOW_ACK = 34,
+    EXCEEDED_TXOP = 35,
+    STA_LEAVING = 36,
+    END_TS_BA_DLS = 37,
+    UNKNOWN_TS_BA = 38,
+    TIMEOUT = 39,
+    PEERKEY_MISMATCH = 45,
+    AUTHORIZED_ACCESS_LIMIT_REACHED = 46,
+    EXTERNAL_SERVICE_REQUIREMENTS = 47,
+    INVALID_FT_ACTION_FRAME_COUNT = 48,
+    INVALID_PMKID = 49,
+    INVALID_MDE = 50,
+    INVALID_FTE = 51,
+    MESH_PEERING_CANCELLED = 52,
+    MESH_MAX_PEERS = 53,
+    MESH_CONFIG_POLICY_VIOLATION = 54,
+    MESH_CLOSE_RCVD = 55,
+    MESH_MAX_RETRIES = 56,
+    MESH_CONFIRM_TIMEOUT = 57,
+    MESH_INVALID_GTK = 58,
+    MESH_INCONSISTENT_PARAMS = 59,
+    MESH_INVALID_SECURITY_CAP = 60,
+    MESH_PATH_ERROR_NO_PROXY_INFO = 61,
+    MESH_PATH_ERROR_NO_FORWARDING_INFO = 62,
+    MESH_PATH_ERROR_DEST_UNREACHABLE = 63,
+    MAC_ADDRESS_ALREADY_EXISTS_IN_MBSS = 64,
+    MESH_CHANNEL_SWITCH_REGULATORY_REQ = 65,
+    MESH_CHANNEL_SWITCH_UNSPECIFIED = 66,
+}
diff --git a/wifi/hostapd/aidl/Android.bp b/wifi/hostapd/aidl/Android.bp
index 2e4d4d1..e580573 100644
--- a/wifi/hostapd/aidl/Android.bp
+++ b/wifi/hostapd/aidl/Android.bp
@@ -29,7 +29,7 @@
         "android/hardware/wifi/hostapd/*.aidl",
     ],
     imports: [
-        "android.hardware.wifi.common-V1",
+        "android.hardware.wifi.common-V2",
     ],
     stability: "vintf",
     backend: {
@@ -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/ClientInfo.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/ClientInfo.aidl
index c4d62b6..c4db789 100644
--- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/ClientInfo.aidl
+++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/ClientInfo.aidl
@@ -38,4 +38,5 @@
   String apIfaceInstance;
   byte[] clientAddress;
   boolean isConnected;
+  android.hardware.wifi.common.DeauthenticationReasonCode disconnectReasonCode;
 }
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..7b67102 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 usesMlo;
 }
diff --git a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/ClientInfo.aidl b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/ClientInfo.aidl
index 7bed658..a7ca1ec 100644
--- a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/ClientInfo.aidl
+++ b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/ClientInfo.aidl
@@ -16,6 +16,8 @@
 
 package android.hardware.wifi.hostapd;
 
+import android.hardware.wifi.common.DeauthenticationReasonCode;
+
 /**
  * Parameters to control the channel selection for the interface.
  */
@@ -42,4 +44,9 @@
      * True when client connected, false when client disconnected.
      */
     boolean isConnected;
+
+    /**
+     * Reason for client disconnect from soft ap.
+     */
+    DeauthenticationReasonCode disconnectReasonCode;
 }
diff --git a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl
index 3f8ee39..f4e4647 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 using multi-link operation.
+     */
+    boolean usesMlo;
 }
diff --git a/wifi/hostapd/aidl/vts/functional/Android.bp b/wifi/hostapd/aidl/vts/functional/Android.bp
index f614679..de31e14 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",
@@ -37,8 +37,8 @@
         "android.hardware.wifi@1.4",
         "android.hardware.wifi@1.5",
         "android.hardware.wifi@1.6",
-        "android.hardware.wifi.common-V1-ndk",
-        "android.hardware.wifi-V2-ndk",
+        "android.hardware.wifi.common-V2-ndk",
+        "android.hardware.wifi-V3-ndk",
         "libwifi-system",
         "libwifi-system-iface",
         "VtsHalWifiTargetTestUtil",
diff --git a/wifi/legacy_headers/include/hardware_legacy/rtt.h b/wifi/legacy_headers/include/hardware_legacy/rtt.h
index 426abe0..631821d 100644
--- a/wifi/legacy_headers/include/hardware_legacy/rtt.h
+++ b/wifi/legacy_headers/include/hardware_legacy/rtt.h
@@ -7,24 +7,33 @@
 
 /* Ranging status */
 typedef enum {
-    RTT_STATUS_SUCCESS       = 0,
-    RTT_STATUS_FAILURE       = 1,           // general failure status
-    RTT_STATUS_FAIL_NO_RSP   = 2,           // target STA does not respond to request
-    RTT_STATUS_FAIL_REJECTED = 3,           // request rejected. Applies to 2-sided RTT only
-    RTT_STATUS_FAIL_NOT_SCHEDULED_YET  = 4,
-    RTT_STATUS_FAIL_TM_TIMEOUT         = 5, // timing measurement times out
-    RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL = 6, // Target on different channel, cannot range
-    RTT_STATUS_FAIL_NO_CAPABILITY  = 7,     // ranging not supported
-    RTT_STATUS_ABORTED             = 8,     // request aborted for unknown reason
-    RTT_STATUS_FAIL_INVALID_TS     = 9,     // Invalid T1-T4 timestamp
-    RTT_STATUS_FAIL_PROTOCOL       = 10,    // 11mc protocol failed
-    RTT_STATUS_FAIL_SCHEDULE       = 11,    // request could not be scheduled
-    RTT_STATUS_FAIL_BUSY_TRY_LATER = 12,    // responder cannot collaborate at time of request
-    RTT_STATUS_INVALID_REQ         = 13,    // bad request args
-    RTT_STATUS_NO_WIFI             = 14,    // WiFi not enabled
-    RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE = 15, // Responder overrides param info, cannot range with new params
-    RTT_STATUS_NAN_RANGING_PROTOCOL_FAILURE =16, //Negotiation failure
-    RTT_STATUS_NAN_RANGING_CONCURRENCY_NOT_SUPPORTED=17, //concurrency not supported (NDP+RTT)
+    RTT_STATUS_SUCCESS = 0,
+    RTT_STATUS_FAILURE = 1,        // general failure status
+    RTT_STATUS_FAIL_NO_RSP = 2,    // target STA does not respond to request
+    RTT_STATUS_FAIL_REJECTED = 3,  // request rejected. Applies to 2-sided RTT only
+    RTT_STATUS_FAIL_NOT_SCHEDULED_YET = 4,
+    RTT_STATUS_FAIL_TM_TIMEOUT = 5,          // timing measurement times out
+    RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL = 6,  // Target on different channel, cannot range
+    RTT_STATUS_FAIL_NO_CAPABILITY = 7,       // ranging not supported
+    RTT_STATUS_ABORTED = 8,                  // request aborted for unknown reason
+    RTT_STATUS_FAIL_INVALID_TS = 9,          // Invalid T1-T4 timestamp
+    RTT_STATUS_FAIL_PROTOCOL = 10,           // 11mc protocol failed
+    RTT_STATUS_FAIL_SCHEDULE = 11,           // request could not be scheduled
+    RTT_STATUS_FAIL_BUSY_TRY_LATER = 12,     // responder cannot collaborate at time of request
+    RTT_STATUS_INVALID_REQ = 13,             // bad request args
+    RTT_STATUS_NO_WIFI = 14,                 // WiFi not enabled
+    RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE =
+            15,  // Responder overrides param info, cannot range with new params
+    RTT_STATUS_NAN_RANGING_PROTOCOL_FAILURE = 16,           // Negotiation failure
+    RTT_STATUS_NAN_RANGING_CONCURRENCY_NOT_SUPPORTED = 17,  // concurrency not supported (NDP+RTT)
+    RTT_STATUS_SECURE_RANGING_FAILURE_INVALID_AKM = 18,  // Secure Ranging failed due to invalid AKM
+                                                         // (Authentication and Key Management)
+    RTT_STATUS_SECURE_RANGING_FAILURE_INVALID_CIPHER = 19,  // Secure Ranging failed due to invalid
+                                                            // Cipher
+    RTT_STATUS_SECURE_RANGING_FAILURE_INVALID_CONFIG = 20,  // Secure Ranging failed due to invalid
+                                                            // configuration
+    RTT_STATUS_SECURE_RANGING_FAILURE_REJECTED = 21,        // Secure ranging rejected by the AP.2
+    RTT_STATUS_SECURE_RANGING_FAILURE_UNKNOWN = 22,         // Secure ranging failure unknown
 } wifi_rtt_status;
 
 /* RTT peer type */
@@ -60,14 +69,57 @@
 
 /* RTT Type */
 typedef enum {
-    RTT_TYPE_1_SIDED          = 0x1,
+    RTT_TYPE_1_SIDED = 0x1,
     /* Deprecated. Use RTT_TYPE_2_SIDED_11MC instead. */
-    RTT_TYPE_2_SIDED          = 0x2,
-    RTT_TYPE_2_SIDED_11MC     = RTT_TYPE_2_SIDED,
+    RTT_TYPE_2_SIDED = 0x2,
+    RTT_TYPE_2_SIDED_11MC = RTT_TYPE_2_SIDED,
     RTT_TYPE_2_SIDED_11AZ_NTB = 0x3,
-
+    RTT_TYPE_2_SIDED_11AZ_NTB_SECURE = 0x4,
 } wifi_rtt_type;
 
+/* RTT AKM type */
+typedef enum {
+    WPA_KEY_MGMT_NONE = 0x0,
+    WPA_KEY_MGMT_PASN = 0x1,
+    WPA_KEY_MGMT_SAE = 0x2,
+    WPA_KEY_MGMT_EAP_FT_SHA256 = 0x4,
+    WPA_KEY_MGMT_FT_PSK_SHA256 = 0x8,
+    WPA_KEY_MGMT_EAP_FT_SHA384 = 0x10,
+    WPA_KEY_MGMT_FT_PSK_SHA384 = 0x20,
+    WPA_KEY_MGMT_EAP_FILS_SHA256 = 0x40,
+    WPA_KEY_MGMT_EAP_FILS_SHA384 = 0x80
+} wifi_rtt_akm;
+
+typedef enum {
+    WPA_CIPHER_NONE = 0x0,
+    WPA_CIPHER_CCMP_128 = 0x1,
+    WPA_CIPHER_CCMP_256 = 0x2,
+    WPA_CIPHER_GCMP_128 = 0x4,
+    WPA_CIPHER_GCMP_256 = 0x8,
+} wifi_rtt_cipher_suite;
+
+#define RTT_SECURITY_MAX_PASSPHRASE_LEN 63
+#define PMKID_LEN 16
+
+typedef struct {
+    wifi_rtt_akm base_akm;  // Base Authentication and Key Management (AKM) protocol used for PASN
+    wifi_rtt_cipher_suite pairwise_cipher_suite;  // Pairwise cipher suite used for the PTKSA
+                                                  // (Pairwise Transient Key Security Association)
+    u32 passphrase_len;
+    u8 passphrase[RTT_SECURITY_MAX_PASSPHRASE_LEN];  // Passphrase for the base AKM. This can be
+                                                     // empty based on the AKM type.
+    u32 pmkid_len;
+    u8 pmkid[PMKID_LEN];  // PMKID corresponding to the cached PMK from the base AKM. PMKID can be
+                          // null if no cached PMK is present.
+
+} wifi_rtt_pasn_config;
+
+typedef struct {
+    wifi_rtt_pasn_config pasn_config;
+    bool enable_secure_he_ltf;
+    bool enable_ranging_frame_protection;
+} wifi_rtt_secure_config;
+
 /* RTT configuration */
 typedef struct {
     mac_addr addr;                 // peer device mac address
@@ -127,6 +179,11 @@
                                   // units of 10 milliseconds
 } wifi_rtt_config_v3;
 
+typedef struct {
+    wifi_rtt_config_v3 rtt_config;
+    wifi_rtt_secure_config rtt_secure_config;
+} wifi_rtt_config_v4;
+
 /* RTT results */
 typedef struct {
     mac_addr addr;                // device mac address
@@ -197,6 +254,14 @@
   byte num_rx_sts;                 // Number of receive space-time streams used.
 } wifi_rtt_result_v3;
 
+typedef struct {
+    wifi_rtt_result_v3 rtt_result_v3;
+    bool is_ranging_protection_enabled;
+    bool is_secure_ltf_enabled;
+    wifi_rtt_akm base_akm;
+    wifi_rtt_cipher_suite cipher_suite;
+    int secure_he_ltf_protocol_version;
+} wifi_rtt_result_v4;
 
 /* RTT result callbacks */
 typedef struct {
@@ -234,6 +299,15 @@
                                wifi_rtt_result_v3 *rtt_result_v3[]);
 } wifi_rtt_event_handler_v3;
 
+/* RTT result v4 callback (secure ranging support) */
+typedef struct {
+    /*
+     * Called when vendor implementation supports sending RTT results version 4 (Added support for
+     * secure 11az ranging)
+     */
+    void (*on_rtt_results_v4)(wifi_request_id id, unsigned num_results,
+                              wifi_rtt_result_v4* rtt_result_v4[]);
+} wifi_rtt_event_handler_v4;
 
 /* v3 API to request RTT measurement(11az support).  */
 wifi_error wifi_rtt_range_request_v3(wifi_request_id id,
@@ -242,6 +316,11 @@
                                      wifi_rtt_config_v3 rtt_config_v3[],
                                      wifi_rtt_event_handler_v3 handler);
 
+/* v4 API to request RTT measurement(11az security support). */
+wifi_error wifi_rtt_range_request_v4(wifi_request_id id, wifi_interface_handle iface,
+                                     unsigned num_rtt_config, wifi_rtt_config_v4 rtt_config_v4[],
+                                     wifi_rtt_event_handler_v4 handler);
+
 /* API to cancel RTT measurements */
 wifi_error wifi_rtt_range_cancel(wifi_request_id id,  wifi_interface_handle iface,
         unsigned num_devices, mac_addr addr[]);
@@ -313,10 +392,26 @@
     byte ntb_responder_supported;   // if 11az non-TB responder is supported
 } wifi_rtt_capabilities_v3;
 
+/* RTT Capabilities v4 (11az secure support) */
+typedef struct {
+    wifi_rtt_capabilities_v3 rtt_capab_v3;
+    bool secure_ltf_supported;
+    bool ranging_fame_protection_supported;
+    wifi_rtt_akm supported_akms;  // Bitmap of wifi_rtt_akm values indicating the set of supported
+                                  // AKMs.
+    wifi_rtt_cipher_suite
+            supported_cipher_suites;  // Bitmap of wifi_rtt_cipher_suite values
+                                      // indicating the set of supported pairwise cipher suites.
+} wifi_rtt_capabilities_v4;
+
 /*  RTT capabilities v3 of the device (11az support) */
 wifi_error wifi_get_rtt_capabilities_v3(wifi_interface_handle iface,
                                         wifi_rtt_capabilities_v3 *capabilities);
 
+/*  RTT capabilities v4 of the device (11az secure support) */
+wifi_error wifi_get_rtt_capabilities_v4(wifi_interface_handle iface,
+                                        wifi_rtt_capabilities_v4* capabilities);
+
 /* debugging definitions */
 enum {
     RTT_DEBUG_DISABLE,
diff --git a/wifi/legacy_headers/include/hardware_legacy/wifi_hal.h b/wifi/legacy_headers/include/hardware_legacy/wifi_hal.h
index 9baa2c7..c68cdf6 100644
--- a/wifi/legacy_headers/include/hardware_legacy/wifi_hal.h
+++ b/wifi/legacy_headers/include/hardware_legacy/wifi_hal.h
@@ -494,6 +494,7 @@
 #define WIFI_FEATURE_ROAMING_MODE_CONTROL   (uint64_t)0x800000000 // Support for configuring roaming mode
 #define WIFI_FEATURE_SET_VOIP_MODE          (uint64_t)0x1000000000 // Support Voip mode setting
 #define WIFI_FEATURE_CACHED_SCAN_RESULTS    (uint64_t)0x2000000000 // Support cached scan result report
+#define WIFI_FEATURE_MLO_SAP (uint64_t)0x4000000000                // Support MLO SoftAp
 // Add more features here
 
 #define IS_MASK_SET(mask, flags)        (((flags) & (mask)) == (mask))
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..1fbe8e9 100644
--- a/wifi/supplicant/aidl/Android.bp
+++ b/wifi/supplicant/aidl/Android.bp
@@ -29,7 +29,7 @@
         "android/hardware/wifi/supplicant/*.aidl",
     ],
     imports: [
-        "android.hardware.wifi.common-V1",
+        "android.hardware.wifi.common-V2",
     ],
     stability: "vintf",
     backend: {
@@ -71,5 +71,5 @@
         },
 
     ],
-    frozen: true,
+    frozen: false,
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/BandMask.aidl
similarity index 88%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/BandMask.aidl
index 173ac17..6d16580 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/BandMask.aidl
@@ -31,10 +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.biometrics.fingerprint;
-/* @hide */
+package android.hardware.wifi.supplicant;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable BandMask {
+  const int BAND_2_GHZ = (1 << 0) /* 1 */;
+  const int BAND_5_GHZ = (1 << 1) /* 2 */;
+  const int BAND_6_GHZ = (1 << 2) /* 4 */;
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
index 0b068e0..d54e44c 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
@@ -74,6 +74,9 @@
   android.hardware.wifi.supplicant.IfaceType getType();
   void invite(in String groupIfName, in byte[] goDeviceAddress, in byte[] peerAddress);
   int[] listNetworks();
+  /**
+   * @deprecated This method is deprecated from AIDL v4, newer HALs should use provisionDiscoveryWithParams.
+   */
   void provisionDiscovery(in byte[] peerAddress, in android.hardware.wifi.supplicant.WpsProvisionMethod provisionMethod);
   void registerCallback(in android.hardware.wifi.supplicant.ISupplicantP2pIfaceCallback callback);
   void reinvoke(in int persistentNetworkId, in byte[] peerAddress);
@@ -123,4 +126,12 @@
   void configureExtListenWithParams(in android.hardware.wifi.supplicant.P2pExtListenInfo extListenInfo);
   void addGroupWithConfigurationParams(in android.hardware.wifi.supplicant.P2pAddGroupConfigurationParams groupConfigurationParams);
   void createGroupOwner(in android.hardware.wifi.supplicant.P2pCreateGroupOwnerInfo groupOwnerInfo);
+  long getFeatureSet();
+  int startUsdBasedServiceDiscovery(in android.hardware.wifi.supplicant.P2pUsdBasedServiceDiscoveryConfig serviceDiscoveryConfig);
+  void stopUsdBasedServiceDiscovery(in int sessionId);
+  int startUsdBasedServiceAdvertisement(in android.hardware.wifi.supplicant.P2pUsdBasedServiceAdvertisementConfig serviceAdvertisementConfig);
+  void stopUsdBasedServiceAdvertisement(in int sessionId);
+  void provisionDiscoveryWithParams(in android.hardware.wifi.supplicant.P2pProvisionDiscoveryParams params);
+  const long P2P_FEATURE_V2 = (1 << 0) /* 1 */;
+  const long P2P_FEATURE_PCC_MODE_WPA3_COMPATIBILITY = (1 << 1) /* 2 */;
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
index 65ad4c1..3b283b8 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
@@ -80,4 +80,7 @@
   oneway void onDeviceFoundWithParams(in android.hardware.wifi.supplicant.P2pDeviceFoundEventParams deviceFoundEventParams);
   oneway void onGoNegotiationRequestWithParams(in android.hardware.wifi.supplicant.P2pGoNegotiationReqEventParams params);
   oneway void onInvitationReceivedWithParams(in android.hardware.wifi.supplicant.P2pInvitationEventParams params);
+  oneway void onUsdBasedServiceDiscoveryResult(in android.hardware.wifi.supplicant.P2pUsdBasedServiceDiscoveryResultParams params);
+  oneway void onUsdBasedServiceDiscoveryTerminated(in int sessionId, in android.hardware.wifi.supplicant.UsdTerminateReasonCode reasonCode);
+  oneway void onUsdBasedServiceAdvertisementTerminated(in int sessionId, in android.hardware.wifi.supplicant.UsdTerminateReasonCode reasonCode);
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
index 9fa8f56..b617c57 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
@@ -86,5 +86,6 @@
   enum MloLinkInfoChangeReason {
     TID_TO_LINK_MAP = 0,
     MULTI_LINK_RECONFIG_AP_REMOVAL = 1,
+    MULTI_LINK_RECONFIG_AP_ADDITION = 2,
   }
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pConnectInfo.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pConnectInfo.aidl
index f4662de..88dd740 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pConnectInfo.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pConnectInfo.aidl
@@ -41,4 +41,6 @@
   boolean persistent;
   int goIntent;
   @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
+  int pairingBootstrappingMethod;
+  @nullable String password;
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pCreateGroupOwnerInfo.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pCreateGroupOwnerInfo.aidl
index 4451fb5..901b9d1 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pCreateGroupOwnerInfo.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pCreateGroupOwnerInfo.aidl
@@ -37,4 +37,5 @@
   boolean persistent;
   int persistentNetworkId;
   @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
+  boolean isP2pV2;
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pDeviceFoundEventParams.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pDeviceFoundEventParams.aidl
index ee8e6dc..68cde9e 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pDeviceFoundEventParams.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pDeviceFoundEventParams.aidl
@@ -45,4 +45,5 @@
   byte[] wfdR2DeviceInfo;
   byte[] vendorElemBytes;
   @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
+  int pairingBootstrappingMethods;
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.aidl
index e19ae44..227626c 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.aidl
@@ -46,4 +46,5 @@
   boolean isP2pClientEapolIpAddressInfoPresent;
   android.hardware.wifi.supplicant.P2pClientEapolIpAddressInfo p2pClientIpInfo;
   @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
+  int keyMgmtMask;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pPairingBootstrappingMethodMask.aidl
similarity index 80%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pPairingBootstrappingMethodMask.aidl
index 173ac17..6e83277 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pPairingBootstrappingMethodMask.aidl
@@ -31,10 +31,12 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
+package android.hardware.wifi.supplicant;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable P2pPairingBootstrappingMethodMask {
+  const int BOOTSTRAPPING_OPPORTUNISTIC = (1 << 0) /* 1 */;
+  const int BOOTSTRAPPING_DISPLAY_PINCODE = (1 << 1) /* 2 */;
+  const int BOOTSTRAPPING_DISPLAY_PASSPHRASE = (1 << 2) /* 4 */;
+  const int BOOTSTRAPPING_KEYPAD_PINCODE = (1 << 3) /* 8 */;
+  const int BOOTSTRAPPING_KEYPAD_PASSPHRASE = (1 << 4) /* 16 */;
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pPeerClientJoinedEventParams.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pPeerClientJoinedEventParams.aidl
index 40c8ff6..578176a 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pPeerClientJoinedEventParams.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pPeerClientJoinedEventParams.aidl
@@ -39,4 +39,5 @@
   byte[6] clientDeviceAddress;
   int clientIpAddress;
   @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
+  int keyMgmtMask;
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pProvisionDiscoveryCompletedEventParams.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pProvisionDiscoveryCompletedEventParams.aidl
index 46366cc..60da924 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pProvisionDiscoveryCompletedEventParams.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pProvisionDiscoveryCompletedEventParams.aidl
@@ -41,4 +41,6 @@
   String generatedPin;
   String groupInterfaceName;
   @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
+  int pairingBootstrappingMethod;
+  @nullable String password;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pProvisionDiscoveryParams.aidl
similarity index 88%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pProvisionDiscoveryParams.aidl
index 173ac17..b5dc4b1 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pProvisionDiscoveryParams.aidl
@@ -31,10 +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.biometrics.fingerprint;
-/* @hide */
+package android.hardware.wifi.supplicant;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable P2pProvisionDiscoveryParams {
+  byte[6] peerMacAddress;
+  android.hardware.wifi.supplicant.WpsProvisionMethod provisionMethod;
+  int pairingBootstrappingMethod;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pUsdBasedServiceAdvertisementConfig.aidl
similarity index 88%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pUsdBasedServiceAdvertisementConfig.aidl
index 173ac17..36ce742 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pUsdBasedServiceAdvertisementConfig.aidl
@@ -31,10 +31,12 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
+package android.hardware.wifi.supplicant;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable P2pUsdBasedServiceAdvertisementConfig {
+  String serviceName;
+  int serviceProtocolType;
+  byte[] serviceSpecificInfo;
+  int frequencyMHz;
+  int timeoutInSeconds;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pUsdBasedServiceDiscoveryConfig.aidl
similarity index 87%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pUsdBasedServiceDiscoveryConfig.aidl
index 173ac17..a13d107 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pUsdBasedServiceDiscoveryConfig.aidl
@@ -31,10 +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.wifi.supplicant;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable P2pUsdBasedServiceDiscoveryConfig {
+  String serviceName;
+  int serviceProtocolType;
+  byte[] serviceSpecificInfo;
+  int bandMask;
+  int[] frequencyListMhz;
+  int timeoutInSeconds;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pUsdBasedServiceDiscoveryResultParams.aidl
similarity index 88%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pUsdBasedServiceDiscoveryResultParams.aidl
index 173ac17..da129cf 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pUsdBasedServiceDiscoveryResultParams.aidl
@@ -31,10 +31,12 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.biometrics.fingerprint;
-/* @hide */
+package android.hardware.wifi.supplicant;
 @VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+parcelable P2pUsdBasedServiceDiscoveryResultParams {
+  byte[6] peerMacAddress;
+  int sessionId;
+  int peerSessionId;
+  int serviceProtocolType;
+  byte[] serviceSpecificInfo;
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/PmkSaCacheData.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/PmkSaCacheData.aidl
index c31b167..b1269ba 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/PmkSaCacheData.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/PmkSaCacheData.aidl
@@ -37,4 +37,5 @@
   byte[6] bssid;
   long expirationTimeInSec;
   byte[] serializedEntry;
+  @nullable byte[] pmkid;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/UsdTerminateReasonCode.aidl
similarity index 87%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
copy to wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/UsdTerminateReasonCode.aidl
index 173ac17..0f84783 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/UsdTerminateReasonCode.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 */
-@VintfStability
-parcelable EnrollmentProgressStep {
-  int durationMs;
-  android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum UsdTerminateReasonCode {
+  UNKNOWN = 0,
+  TIMEOUT = 1,
+  USER_REQUEST = 2,
+  FAILURE = 3,
 }
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/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsProvisionMethod.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsProvisionMethod.aidl
index 177d218..58ac0eb 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsProvisionMethod.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsProvisionMethod.aidl
@@ -34,6 +34,7 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum WpsProvisionMethod {
+  NONE = (-1) /* -1 */,
   PBC,
   DISPLAY,
   KEYPAD,
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/BandMask.aidl
similarity index 67%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
copy to wifi/supplicant/aidl/android/hardware/wifi/supplicant/BandMask.aidl
index c7be950..6d1b2be 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/BandMask.aidl
@@ -14,22 +14,23 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
-
-import android.hardware.biometrics.fingerprint.AcquiredInfo;
+package android.hardware.wifi.supplicant;
 
 /**
- * @hide
+ * Wifi bands
  */
 @VintfStability
-union AcquiredInfoAndVendorCode {
+parcelable BandMask {
     /**
-     * Acquired info as specified in AcqauiredInfo.aidl
+     * 2.4 GHz band.
      */
-    AcquiredInfo acquiredInfo = AcquiredInfo.UNKNOWN;
-
+    const int BAND_2_GHZ = 1 << 0;
     /**
-     * Vendor specific code
+     * 5 GHz band.
      */
-    int vendorCode;
+    const int BAND_5_GHZ = 1 << 1;
+    /**
+     * 6 GHz band.
+     */
+    const int BAND_6_GHZ = 1 << 2;
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
index 1230793..62f9fc3 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
@@ -29,6 +29,9 @@
 import android.hardware.wifi.supplicant.P2pExtListenInfo;
 import android.hardware.wifi.supplicant.P2pFrameTypeMask;
 import android.hardware.wifi.supplicant.P2pGroupCapabilityMask;
+import android.hardware.wifi.supplicant.P2pProvisionDiscoveryParams;
+import android.hardware.wifi.supplicant.P2pUsdBasedServiceAdvertisementConfig;
+import android.hardware.wifi.supplicant.P2pUsdBasedServiceDiscoveryConfig;
 import android.hardware.wifi.supplicant.WpsConfigMethods;
 import android.hardware.wifi.supplicant.WpsProvisionMethod;
 
@@ -39,6 +42,15 @@
 @VintfStability
 interface ISupplicantP2pIface {
     /**
+     * P2P features exposed by wpa_supplicant/chip.
+     */
+    /* Support for P2P2 (Wi-Fi Alliance P2P v2.0) */
+    const long P2P_FEATURE_V2 = 1 << 0;
+
+    /* Support for WPA3 Compatibility Mode in PCC Mode */
+    const long P2P_FEATURE_PCC_MODE_WPA3_COMPATIBILITY = 1 << 1;
+
+    /**
      * This command can be used to add a bonjour service.
      *
      * @param query Hex dump of the query data.
@@ -398,6 +410,9 @@
      * Send P2P provision discovery request to the specified peer. The
      * parameters for this command are the P2P device address of the peer and the
      * desired configuration method.
+     * <p>
+     * @deprecated This method is deprecated from AIDL v4, newer HALs should use
+     * provisionDiscoveryWithParams.
      *
      * @param peerAddress MAC address of the device to send discovery.
      * @method provisionMethod Provisioning method to use.
@@ -938,4 +953,73 @@
      *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
      */
     void createGroupOwner(in P2pCreateGroupOwnerInfo groupOwnerInfo);
+
+    /**
+     * Get the features supported by P2P interface.
+     *
+     * @return The bitmask of ISupplicantP2pIface.P2P_FEATURE_* values.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    long getFeatureSet();
+
+    /**
+     * Start an Unsynchronized Service Discovery (USD) based P2P service discovery.
+     *
+     * @param serviceDiscoveryConfig Configuration associated with this discovery operation.
+     * @return A non-zero identifier to identify the instance of a service discovery.
+     *         It is used to cancel the service discovery.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    int startUsdBasedServiceDiscovery(in P2pUsdBasedServiceDiscoveryConfig serviceDiscoveryConfig);
+
+    /**
+     * Stop an Unsynchronized Service Discovery (USD) based P2P service discovery.
+     *
+     * @param sessionId Identifier to cancel the service discovery instance.
+     *        Use zero to cancel all the service discovery instances.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     *         |SupplicantStatusCode.FAILURE_NOT_STARTED|
+     */
+    void stopUsdBasedServiceDiscovery(in int sessionId);
+
+    /**
+     * Start an Unsynchronized Service Discovery (USD) based P2P service advertisement.
+     *
+     * @param serviceDiscoveryConfig Configuration associated with this service advertisement.
+     * @return A non-zero identifier to identify the instance of a service advertisement.
+     *         It is used to cancel the service advertisement.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    int startUsdBasedServiceAdvertisement(
+            in P2pUsdBasedServiceAdvertisementConfig serviceAdvertisementConfig);
+
+    /**
+     * Stop an Unsynchronized Service Discovery (USD) based P2P service advertisement.
+     *
+     * @param sessionId Identifier to cancel the service advertisement.
+     *        Use zero to cancel all the service advertisement instances.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     *         |SupplicantStatusCode.FAILURE_NOT_STARTED|
+     */
+    void stopUsdBasedServiceAdvertisement(in int sessionId);
+
+    /**
+     * Send P2P provision discovery request to the specified peer.
+     *
+     * @param params Parameters associated with this provision discovery request.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void provisionDiscoveryWithParams(in P2pProvisionDiscoveryParams params);
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
index 44a5465..a52e150 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
@@ -26,6 +26,8 @@
 import android.hardware.wifi.supplicant.P2pProvDiscStatusCode;
 import android.hardware.wifi.supplicant.P2pProvisionDiscoveryCompletedEventParams;
 import android.hardware.wifi.supplicant.P2pStatusCode;
+import android.hardware.wifi.supplicant.P2pUsdBasedServiceDiscoveryResultParams;
+import android.hardware.wifi.supplicant.UsdTerminateReasonCode;
 import android.hardware.wifi.supplicant.WpsConfigMethods;
 import android.hardware.wifi.supplicant.WpsDevPasswordId;
 
@@ -325,4 +327,29 @@
      * @param params Parameters associated with the invitation request event.
      */
     void onInvitationReceivedWithParams(in P2pInvitationEventParams params);
+
+    /**
+     * Used to indicate the reception of an USD based service discovery response.
+     *
+     * @param params Parameters associated with the USD based service discovery result.
+     */
+    void onUsdBasedServiceDiscoveryResult(in P2pUsdBasedServiceDiscoveryResultParams params);
+
+    /**
+     * Used to indicate the termination of USD based service discovery.
+     *
+     * @param sessionId Identifier to identify the instance of a service discovery.
+     * @param reasonCode The reason for termination of service discovery.
+     */
+    void onUsdBasedServiceDiscoveryTerminated(
+            in int sessionId, in UsdTerminateReasonCode reasonCode);
+
+    /**
+     * Used to indicate the termination of USD based service Advertisement.
+     *
+     * @param sessionId Identifier to identify the instance of a service advertisement.
+     * @param reasonCode The reason for termination of service advertisement.
+     */
+    void onUsdBasedServiceAdvertisementTerminated(
+            in int sessionId, in UsdTerminateReasonCode reasonCode);
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
index 172fcda..8740ad0 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
@@ -338,11 +338,19 @@
         /**
          * Multi-link reconfiguration - AP removal as described in
          * IEEE 802.11be spec, section 35.3.6. This is a mandatory feature for
-         * station.
+         * station according to Wi-Fi 7 R1 MRD.
          *
          * Removed link will not be present in |ISupplicantStaIface.getConnectionMloLinksInfo|.
          */
         MULTI_LINK_RECONFIG_AP_REMOVAL = 1,
+        /**
+         * Multi-link reconfiguration - Adding affiliated AP(s) as described in
+         * IEEE 802.11be spec, section 35.3.6. This is an optional feature for
+         * station according to Wi-Fi 7 R2 MRD.
+         *
+         * Added link will be present in |ISupplicantStaIface.getConnectionMloLinksInfo|.
+         */
+        MULTI_LINK_RECONFIG_AP_ADDITION = 2,
     }
 
     /**
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pConnectInfo.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pConnectInfo.aidl
index f09b476..8f3c596 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pConnectInfo.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pConnectInfo.aidl
@@ -30,7 +30,9 @@
     byte[6] peerAddress;
 
     /**
-     * Provisioning method to use.
+     * Wi-Fi Protected Setup provisioning method. If using Wi-Fi Protected Setup,
+     * then must be set to a non-|WpsProvisionMethod.NONE| provisioning method,
+     * otherwise set to |WpsProvisionMethod.NONE|.
      */
     WpsProvisionMethod provisionMethod;
 
@@ -65,4 +67,19 @@
      * that no vendor data is provided.
      */
     @nullable OuiKeyedData[] vendorData;
+
+    /**
+     * Wi-Fi Direct pairing bootstrapping method. If using P2P pairing protocol,
+     * then must be set one of the |P2pPairingBootstrappingMethodMask|, otherwise
+     * set to zero.
+     */
+    int pairingBootstrappingMethod;
+
+    /**
+     * Password for pairing setup, if |bootstrappingMethod| uses one of the
+     * |P2pPairingBootstrappingMethodMask| methods other than
+     * P2pPairingBootstrappingMethodMask.BOOTSTRAPPING_OPPORTUNISTIC,
+     * null otherwise.
+     */
+    @nullable String password;
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pCreateGroupOwnerInfo.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pCreateGroupOwnerInfo.aidl
index 51e6ed9..83d480e 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pCreateGroupOwnerInfo.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pCreateGroupOwnerInfo.aidl
@@ -39,4 +39,9 @@
      * that no vendor data is provided.
      */
     @nullable OuiKeyedData[] vendorData;
+    /**
+     * Used to start a Group Owner that support P2P2 IE. The connection to this Group Owner can
+     * be established only using P2P Pairing protocol.
+     */
+    boolean isP2pV2;
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pDeviceFoundEventParams.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pDeviceFoundEventParams.aidl
index 15917b6..31e64ac 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pDeviceFoundEventParams.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pDeviceFoundEventParams.aidl
@@ -89,4 +89,10 @@
      * Null value indicates that no vendor data is provided.
      */
     @nullable OuiKeyedData[] vendorData;
+
+    /**
+     * The bitmask of P2pPairingBootstrappingMethodMask.BOOTSTRAPPING_* methods used to enable
+     * the pairing bootstrapping between bootstrapping initiator and a bootstrapping responder.
+     */
+    int pairingBootstrappingMethods;
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.aidl
index 9db7a1e..55e2b23 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.aidl
@@ -70,4 +70,10 @@
      * that no vendor data is provided.
      */
     @nullable OuiKeyedData[] vendorData;
+
+    /**
+     * Authentication key management protocol used to secure the group.
+     * This is a bitmask of |KeyMgmtMask| values.
+     */
+    int keyMgmtMask;
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pPairingBootstrappingMethodMask.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pPairingBootstrappingMethodMask.aidl
new file mode 100644
index 0000000..cac8c53
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pPairingBootstrappingMethodMask.aidl
@@ -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.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * P2P Pairing Bootstrapping Method.
+ */
+@VintfStability
+parcelable P2pPairingBootstrappingMethodMask {
+    /** Opportunistic bootstrapping */
+    const int BOOTSTRAPPING_OPPORTUNISTIC = 1 << 0;
+    /** Display pin-code only */
+    const int BOOTSTRAPPING_DISPLAY_PINCODE = 1 << 1;
+    /** Display passphrase */
+    const int BOOTSTRAPPING_DISPLAY_PASSPHRASE = 1 << 2;
+    /** Keypad pin-code only */
+    const int BOOTSTRAPPING_KEYPAD_PINCODE = 1 << 3;
+    /** Keypad passphrase */
+    const int BOOTSTRAPPING_KEYPAD_PASSPHRASE = 1 << 4;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pPeerClientJoinedEventParams.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pPeerClientJoinedEventParams.aidl
index 4f46d70..2b04461 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pPeerClientJoinedEventParams.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pPeerClientJoinedEventParams.aidl
@@ -47,4 +47,10 @@
      * that no vendor data is provided.
      */
     @nullable OuiKeyedData[] vendorData;
+
+    /**
+     * Authentication key management protocol used in connection.
+     * This is a bitmask of |KeyMgmtMask| values.
+     */
+    int keyMgmtMask;
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pProvisionDiscoveryCompletedEventParams.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pProvisionDiscoveryCompletedEventParams.aidl
index 05152a9..97659b6 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pProvisionDiscoveryCompletedEventParams.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pProvisionDiscoveryCompletedEventParams.aidl
@@ -33,7 +33,11 @@
     boolean isRequest;
     /** Status of the provision discovery */
     P2pProvDiscStatusCode status;
-    /** Mask of |WpsConfigMethods| indicating the supported methods */
+    /**
+     * Wi-Fi Protected Setup provisioning method. If using Wi-Fi Protected Setup,
+     * then must be set to a non-|WpsProvisionMethod.NONE| provisioning method,
+     * otherwise set to |WpsProvisionMethod.NONE|.
+     */
     int configMethods;
     /** 8-digit pin generated */
     String generatedPin;
@@ -50,4 +54,17 @@
      * that no vendor data is provided.
      */
     @nullable OuiKeyedData[] vendorData;
+    /**
+     * Wi-Fi Direct pairing bootstrapping method. If using P2P pairing protocol,
+     * then must be set one of the |P2pPairingBootstrappingMethodMask|, otherwise
+     * set to zero.
+     */
+    int pairingBootstrappingMethod;
+    /**
+     * Password for pairing setup, if |bootstrappingMethod| uses one of the
+     * |P2pPairingBootstrappingMethodMask| methods other than
+     * P2pPairingBootstrappingMethodMask.BOOTSTRAPPING_OPPORTUNISTIC,
+     * null otherwise.
+     */
+    @nullable String password;
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pProvisionDiscoveryParams.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pProvisionDiscoveryParams.aidl
new file mode 100644
index 0000000..37f2374
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pProvisionDiscoveryParams.aidl
@@ -0,0 +1,44 @@
+/*
+ * 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.wifi.supplicant;
+
+import android.hardware.wifi.supplicant.WpsProvisionMethod;
+
+/**
+ * Parameters used for |ISupplicantP2pIfaceCallback.provisionDiscoveryWithParams|
+ */
+@VintfStability
+parcelable P2pProvisionDiscoveryParams {
+    /**
+     * MAC address of the peer device to send the provision discovery request.
+     */
+    byte[6] peerMacAddress;
+
+    /**
+     * Wi-Fi Protected Setup provisioning method. If using Wi-Fi Protected Setup,
+     * then must be set to a non-|WpsProvisionMethod.NONE| provisioning method,
+     * otherwise set to |WpsProvisionMethod.NONE|.
+     */
+    WpsProvisionMethod provisionMethod;
+
+    /**
+     * Wi-Fi Direct pairing bootstrapping method. If using P2P pairing protocol,
+     * then must be set one of the |P2pPairingBootstrappingMethodMask|, otherwise
+     * set to zero.
+     */
+    int pairingBootstrappingMethod;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pUsdBasedServiceAdvertisementConfig.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pUsdBasedServiceAdvertisementConfig.aidl
new file mode 100644
index 0000000..1920f1a
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pUsdBasedServiceAdvertisementConfig.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.wifi.supplicant;
+
+/**
+ * Unsynchronized Service Discovery (USD) based P2P service advertisement configuration.
+ * Refer Wi-Fi Alliance Wi-Fi Direct R2 specification - Appendix H -
+ * Unsynchronized Service Discovery (as defined in Wi-Fi Aware) and section
+ * 4.2.13 USD frame format.
+ */
+@VintfStability
+parcelable P2pUsdBasedServiceAdvertisementConfig {
+    /** UTF-8 string defining the service */
+    String serviceName;
+
+    /** Service Protocol Type */
+    int serviceProtocolType;
+
+    /** Service specific information content determined by the application */
+    byte[] serviceSpecificInfo;
+
+    /**
+     * Channel frequency in MHz to listen for service discovery request.
+     */
+    int frequencyMHz;
+
+    /**
+     * Max time to be spent for service advertisement.
+     */
+    int timeoutInSeconds;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pUsdBasedServiceDiscoveryConfig.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pUsdBasedServiceDiscoveryConfig.aidl
new file mode 100644
index 0000000..c7d6f0e
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pUsdBasedServiceDiscoveryConfig.aidl
@@ -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 android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.supplicant.BandMask;
+
+/**
+ * Unsynchronized Service Discovery (USD) based P2P service discovery configuration.
+ * Refer Wi-Fi Alliance Wi-Fi Direct R2 specification - Appendix H -
+ * Unsynchronized Service Discovery (as defined in Wi-Fi Aware) and section
+ * 4.2.13 USD frame format
+ */
+@VintfStability
+parcelable P2pUsdBasedServiceDiscoveryConfig {
+    /** UTF-8 string defining the service */
+    String serviceName;
+
+    /** Service Protocol Type */
+    int serviceProtocolType;
+
+    /** Service specific information content determined by the application */
+    byte[] serviceSpecificInfo;
+
+    /**
+     * Bit mask of bands to scan for services.
+     * Set this value to Bitmask of |BandMask| only if its required to scan all the channels
+     * in a band.
+     */
+    int bandMask;
+
+    /**
+     * A list of frequencies in MHz to scan for services.
+     * This field is used only when the bandMask is set to zero.
+     */
+    int[] frequencyListMhz;
+
+    /**
+     * Max time to be spent in performing discovery.
+     * Set to 0 to indefinitely continue discovery until a service is
+     * discovered.
+     */
+    int timeoutInSeconds;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pUsdBasedServiceDiscoveryResultParams.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pUsdBasedServiceDiscoveryResultParams.aidl
new file mode 100644
index 0000000..becc437
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pUsdBasedServiceDiscoveryResultParams.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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.wifi.supplicant;
+
+import android.hardware.wifi.supplicant.BandMask;
+
+/**
+ * Unsynchronized Service Discovery (USD) based P2P service discovery result event.
+ * Refer Wi-Fi Alliance Wi-Fi Direct R2 specification - Appendix H -
+ * Unsynchronized Service Discovery (as defined in Wi-Fi Aware) and section
+ * 4.2.13 USD frame format
+ */
+@VintfStability
+parcelable P2pUsdBasedServiceDiscoveryResultParams {
+    /** MAC address of the device that sent the service discovery */
+    byte[6] peerMacAddress;
+
+    /** Identifier to identify the service discovery instance */
+    int sessionId;
+
+    /** Identifier to identify the peer service advertisement instance */
+    int peerSessionId;
+
+    /** Service Protocol Type */
+    int serviceProtocolType;
+
+    /** Service specific information content determined by the application */
+    byte[] serviceSpecificInfo;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/PmkSaCacheData.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/PmkSaCacheData.aidl
index e0f1d31..4071179 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/PmkSaCacheData.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/PmkSaCacheData.aidl
@@ -34,4 +34,9 @@
      * The content is opaque for the framework and depends on the native implementation.
      */
     byte[] serializedEntry;
+    /**
+     * Pairwise Master Key Identifier (PMKID), which is a unique key identifier used by AP to
+     * track PMK used (Pairwise Master Key) for a station.
+     */
+    @nullable byte[] pmkid;
 }
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/UsdTerminateReasonCode.aidl
similarity index 64%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
copy to wifi/supplicant/aidl/android/hardware/wifi/supplicant/UsdTerminateReasonCode.aidl
index c7be950..6725c3d 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/UsdTerminateReasonCode.aidl
@@ -14,22 +14,16 @@
  * limitations under the License.
  */
 
-package android.hardware.biometrics.fingerprint;
-
-import android.hardware.biometrics.fingerprint.AcquiredInfo;
+package android.hardware.wifi.supplicant;
 
 /**
- * @hide
+ * Status codes for P2P operations.
  */
 @VintfStability
-union AcquiredInfoAndVendorCode {
-    /**
-     * Acquired info as specified in AcqauiredInfo.aidl
-     */
-    AcquiredInfo acquiredInfo = AcquiredInfo.UNKNOWN;
-
-    /**
-     * Vendor specific code
-     */
-    int vendorCode;
+@Backing(type="int")
+enum UsdTerminateReasonCode {
+    UNKNOWN = 0,
+    TIMEOUT = 1,
+    USER_REQUEST = 2,
+    FAILURE = 3,
 }
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/android/hardware/wifi/supplicant/WpsProvisionMethod.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpsProvisionMethod.aidl
index 5b59392..b8ad3b8 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpsProvisionMethod.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpsProvisionMethod.aidl
@@ -19,6 +19,7 @@
 @VintfStability
 @Backing(type="int")
 enum WpsProvisionMethod {
+    NONE = -1,
     /**
      * Push button method.
      */
diff --git a/wifi/supplicant/aidl/vts/functional/Android.bp b/wifi/supplicant/aidl/vts/functional/Android.bp
index 4166850..f94eb46 100644
--- a/wifi/supplicant/aidl/vts/functional/Android.bp
+++ b/wifi/supplicant/aidl/vts/functional/Android.bp
@@ -43,17 +43,17 @@
         "android.hardware.wifi@1.3",
         "android.hardware.wifi@1.4",
         "android.hardware.wifi@1.5",
-        "android.hardware.wifi.common-V1-ndk",
+        "android.hardware.wifi.common-V2-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",
         "VtsHalWifiV1_5TargetTestUtil",
         "VtsHalWifiSupplicantV1_0TargetTestUtil",
-        "android.hardware.wifi.common-V1-ndk",
-        "android.hardware.wifi-V2-ndk",
+        "android.hardware.wifi.common-V2-ndk",
+        "android.hardware.wifi-V3-ndk",
         "VtsHalWifiTargetTestUtil",
     ],
     test_suites: [
@@ -81,17 +81,17 @@
         "android.hardware.wifi@1.3",
         "android.hardware.wifi@1.4",
         "android.hardware.wifi@1.5",
-        "android.hardware.wifi.common-V1-ndk",
+        "android.hardware.wifi.common-V2-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",
         "VtsHalWifiV1_5TargetTestUtil",
         "VtsHalWifiSupplicantV1_0TargetTestUtil",
-        "android.hardware.wifi.common-V1-ndk",
-        "android.hardware.wifi-V2-ndk",
+        "android.hardware.wifi.common-V2-ndk",
+        "android.hardware.wifi-V3-ndk",
         "VtsHalWifiTargetTestUtil",
     ],
     test_suites: [
@@ -119,17 +119,17 @@
         "android.hardware.wifi@1.3",
         "android.hardware.wifi@1.4",
         "android.hardware.wifi@1.5",
-        "android.hardware.wifi.common-V1-ndk",
+        "android.hardware.wifi.common-V2-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",
         "VtsHalWifiV1_5TargetTestUtil",
         "VtsHalWifiSupplicantV1_0TargetTestUtil",
-        "android.hardware.wifi.common-V1-ndk",
-        "android.hardware.wifi-V2-ndk",
+        "android.hardware.wifi.common-V2-ndk",
+        "android.hardware.wifi-V3-ndk",
         "VtsHalWifiTargetTestUtil",
     ],
     test_suites: [
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp b/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp
index 8f1c4bd..3226ffd 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp
@@ -17,8 +17,10 @@
 #include <VtsCoreUtil.h>
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
+#include <aidl/android/hardware/wifi/supplicant/BandMask.h>
 #include <aidl/android/hardware/wifi/supplicant/BnSupplicant.h>
 #include <aidl/android/hardware/wifi/supplicant/BnSupplicantP2pIfaceCallback.h>
+#include <aidl/android/hardware/wifi/supplicant/P2pPairingBootstrappingMethodMask.h>
 #include <aidl/android/hardware/wifi/supplicant/SupplicantStatusCode.h>
 #include <android/binder_manager.h>
 #include <android/binder_status.h>
@@ -29,6 +31,7 @@
 #include "supplicant_test_utils.h"
 #include "wifi_aidl_test_utils.h"
 
+using aidl::android::hardware::wifi::supplicant::BandMask;
 using aidl::android::hardware::wifi::supplicant::BnSupplicantP2pIfaceCallback;
 using aidl::android::hardware::wifi::supplicant::DebugLevel;
 using aidl::android::hardware::wifi::supplicant::FreqRange;
@@ -47,13 +50,20 @@
 using aidl::android::hardware::wifi::supplicant::P2pGroupCapabilityMask;
 using aidl::android::hardware::wifi::supplicant::P2pGroupStartedEventParams;
 using aidl::android::hardware::wifi::supplicant::P2pInvitationEventParams;
+using aidl::android::hardware::wifi::supplicant::P2pPairingBootstrappingMethodMask;
 using aidl::android::hardware::wifi::supplicant::P2pPeerClientDisconnectedEventParams;
 using aidl::android::hardware::wifi::supplicant::P2pPeerClientJoinedEventParams;
 using aidl::android::hardware::wifi::supplicant::P2pProvDiscStatusCode;
 using aidl::android::hardware::wifi::supplicant::P2pProvisionDiscoveryCompletedEventParams;
+using aidl::android::hardware::wifi::supplicant::P2pProvisionDiscoveryParams;
+;
 using aidl::android::hardware::wifi::supplicant::P2pScanType;
 using aidl::android::hardware::wifi::supplicant::P2pStatusCode;
+using aidl::android::hardware::wifi::supplicant::P2pUsdBasedServiceAdvertisementConfig;
+using aidl::android::hardware::wifi::supplicant::P2pUsdBasedServiceDiscoveryConfig;
+using aidl::android::hardware::wifi::supplicant::P2pUsdBasedServiceDiscoveryResultParams;
 using aidl::android::hardware::wifi::supplicant::SupplicantStatusCode;
+using aidl::android::hardware::wifi::supplicant::UsdTerminateReasonCode;
 using aidl::android::hardware::wifi::supplicant::WpsConfigMethods;
 using aidl::android::hardware::wifi::supplicant::WpsDevPasswordId;
 using aidl::android::hardware::wifi::supplicant::WpsProvisionMethod;
@@ -67,13 +77,18 @@
 const std::vector<uint8_t> kTestPeerMacAddr = {0x56, 0x67, 0x55,
                                                0xf4, 0x56, 0x92};
 const std::vector<uint8_t> kTestZeroMacAddr = std::vector<uint8_t>(6, 0);
+const std::string kTestServiceSpecificInfoStr = "TestServiceSpecificInfo";
+const std::vector<uint8_t> kTestServiceSpecificInfo = std::vector<uint8_t>(
+        kTestServiceSpecificInfoStr.begin(), kTestServiceSpecificInfoStr.end());
 const std::string kTestPassphrase = "P2pWorld1234";
 const std::string kTestConnectPin = "34556665";
 const std::string kTestGroupIfName = "TestGroup";
+const std::string kTestServiceName = "TestServiceName";
 const uint32_t kTestFindTimeout = 5;
 const uint32_t kTestConnectGoIntent = 6;
 const uint32_t kTestNetworkId = 7;
 const uint32_t kTestGroupFreq = 0;
+const uint32_t kTestServiceProtocolType = 1;
 const bool kTestGroupPersistent = false;
 const bool kTestGroupIsJoin = false;
 const auto& kTestVendorDataOptional = generateOuiKeyedDataListOptional(5);
@@ -222,6 +237,18 @@
             const P2pInvitationEventParams& /* invitationEventParams */) override {
         return ndk::ScopedAStatus::ok();
     }
+    ::ndk::ScopedAStatus onUsdBasedServiceDiscoveryResult(
+            const P2pUsdBasedServiceDiscoveryResultParams& /* discoveryResultParams*/) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onUsdBasedServiceDiscoveryTerminated(
+            int32_t /* sessionId */, UsdTerminateReasonCode /* reasonCode */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onUsdBasedServiceAdvertisementTerminated(
+            int32_t /* sessionId */, UsdTerminateReasonCode /* reasonCode */) override {
+        return ndk::ScopedAStatus::ok();
+    }
 };
 
 class SupplicantP2pIfaceAidlTest : public testing::TestWithParam<std::string> {
@@ -246,6 +273,9 @@
         EXPECT_TRUE(supplicant_->getP2pInterface(getP2pIfaceName(), &p2p_iface_)
                         .isOk());
         ASSERT_NE(p2p_iface_, nullptr);
+        if (interface_version_ >= 4) {
+            EXPECT_TRUE(p2p_iface_->getFeatureSet(&supported_features_).isOk());
+        }
     }
 
     void TearDown() override {
@@ -257,6 +287,7 @@
     std::shared_ptr<ISupplicant> supplicant_;
     std::shared_ptr<ISupplicantP2pIface> p2p_iface_;
     int interface_version_;
+    int64_t supported_features_;
 };
 
 /*
@@ -814,6 +845,85 @@
     LOG(INFO) << "SupplicantP2pIfaceAidlTest::SetVendorElements end";
 }
 
+/*
+ * GetFeatureSet
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, gGetFeatureSet) {
+    if (interface_version_ < 4) {
+        GTEST_SKIP() << "getFeatureSet is available as of Supplicant V4";
+    }
+    int64_t featureSet;
+    EXPECT_TRUE(p2p_iface_->getFeatureSet(&featureSet).isOk());
+}
+
+/*
+ * StartUsdBasedServiceDiscovery/stopUsdBasedServiceDiscovery
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, StartStopUsdBasedServiceDiscovery) {
+    if (interface_version_ < 4) {
+        GTEST_SKIP() << "Start/Stop UsdBasedServiceDiscovery is available as of Supplicant V4";
+    }
+    if (!(supported_features_ & ISupplicantP2pIface::P2P_FEATURE_V2)) {
+        GTEST_SKIP() << "P2P2 is not supported";
+    }
+
+    int32_t sessionId;
+    P2pUsdBasedServiceDiscoveryConfig config;
+    config.serviceName = kTestServiceName;
+    config.serviceProtocolType = kTestServiceProtocolType;
+    config.serviceSpecificInfo = kTestServiceSpecificInfo;
+    config.bandMask = BandMask::BAND_2_GHZ;
+    config.timeoutInSeconds = 30;
+
+    EXPECT_TRUE(p2p_iface_->startUsdBasedServiceDiscovery(config, &sessionId).isOk());
+    sleep(1);
+    EXPECT_TRUE(p2p_iface_->stopUsdBasedServiceDiscovery(sessionId).isOk());
+}
+
+/*
+ * StartUsdBasedServiceAdvertisement/StopUsdBasedServiceAdvertisement
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, StartStopUsdBasedServiceAdvertisement) {
+    if (interface_version_ < 4) {
+        GTEST_SKIP() << "start/Stop UsdBasedServiceAdvertisement is available as of Supplicant V4";
+    }
+    if (!(supported_features_ & ISupplicantP2pIface::P2P_FEATURE_V2)) {
+        GTEST_SKIP() << "P2P2 is not supported";
+    }
+
+    int32_t sessionId;
+    P2pUsdBasedServiceAdvertisementConfig config;
+    config.serviceName = kTestServiceName;
+    config.serviceProtocolType = kTestServiceProtocolType;
+    config.serviceSpecificInfo = kTestServiceSpecificInfo;
+    config.frequencyMHz = 2412;
+    config.timeoutInSeconds = 30;
+
+    EXPECT_TRUE(p2p_iface_->startUsdBasedServiceAdvertisement(config, &sessionId).isOk());
+    sleep(1);
+    EXPECT_TRUE(p2p_iface_->stopUsdBasedServiceAdvertisement(sessionId).isOk());
+}
+
+/*
+ * ProvisionDiscoveryWithParams
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, ProvisionDiscoveryWithParams) {
+    if (interface_version_ < 4) {
+        GTEST_SKIP() << "ProvisionDiscoveryWithParams is available as of Supplicant V4";
+    }
+    if (!(supported_features_ & ISupplicantP2pIface::P2P_FEATURE_V2)) {
+        GTEST_SKIP() << "P2P2 is not supported";
+    }
+
+    P2pProvisionDiscoveryParams params;
+    params.peerMacAddress = vecToArrayMacAddr(kTestMacAddr);
+    params.provisionMethod = WpsProvisionMethod::NONE;
+    params.pairingBootstrappingMethod =
+            P2pPairingBootstrappingMethodMask::BOOTSTRAPPING_OPPORTUNISTIC;
+
+    EXPECT_TRUE(p2p_iface_->provisionDiscoveryWithParams(params).isOk());
+}
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SupplicantP2pIfaceAidlTest);
 INSTANTIATE_TEST_SUITE_P(Supplicant, SupplicantP2pIfaceAidlTest,
                          testing::ValuesIn(android::getAidlHalInstanceNames(